commit b1069b9afd7da8d67c53eecfced3aa726f6ecb45 Author: jingquan huang Date: Thu Jun 20 16:06:18 2019 +0800 first commit diff --git a/.bashrc b/.bashrc new file mode 100644 index 000000000..d3f5a12fa --- /dev/null +++ b/.bashrc @@ -0,0 +1 @@ + diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ecc3e003a --- /dev/null +++ b/.gitignore @@ -0,0 +1,56 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# mac +*.DS_Store + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore uploaded files in development +/storage/* + +/node_modules +/yarn-error.log + +# /public/assets +.byebug_history + +# Ignore master key for decrypting credentials and more. +/config/master.key +/config/database.yml +/.idea/* + +# Ignore react node_modules +/public/react/build +/public/react/build/ +/public/react/node_modules/ +/public/react/config/stats.json +/public/react/stats.json + +/public/npm-debug.log + +# avatars +/public/images/avatars + +/config/secrets.yml +/files/archiveZip/* +/files/cache_store/* +public/upload.html +/config/configuration.yml +/config/initializers/gitlab_config.rb +/db/schema.rb +.vscode/ +vendor/bundle/ +.ruby-version +.ruby-gemset + diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..dfc9d41fd --- /dev/null +++ b/Gemfile @@ -0,0 +1,86 @@ +source 'https://gems.ruby-china.com' +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby '2.3.7' + +gem 'rails', '~> 5.2.0' +gem 'mysql2', '>= 0.4.4', '< 0.6.0' +gem 'puma', '~> 3.11' +gem 'sass-rails', '~> 5.0' +gem 'uglifier', '>= 1.3.0' + +# gem 'coffee-rails', '~> 4.2' +# gem 'turbolinks', '~> 5' +gem 'jbuilder', '~> 2.5' + +gem 'grape-entity', '~> 0.7.1' +gem 'kaminari', '~> 1.1', '>= 1.1.1' + +gem 'bootsnap', '>= 1.1.0', require: false + +gem 'gitlab', path: 'lib/gitlab-cli' + +gem 'rack-cors' +gem 'redis-rails' +gem 'roo-xls' +gem 'simple_xlsx_reader' + +gem 'rubyzip' + +gem 'spreadsheet' +gem 'ruby-ole' +# 导出为xlsx +gem 'axlsx', '~> 3.0.0.pre' +gem 'axlsx_rails', '~> 0.5.2' + +gem 'oauth2' +#导出为pdf +gem 'pdfkit' +gem 'wkhtmltopdf-binary' + +#gem 'iconv' + +gem 'rqrcode', '~> 0.10.1' +gem 'rqrcode_png' + +gem 'acts-as-taggable-on', '~> 6.0' + +group :development, :test do + gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] + gem 'rspec-rails', '~> 3.8' +end + +group :development do + gem 'awesome_print' + gem 'web-console', '>= 3.3.0' + gem 'listen', '>= 3.0.5', '< 3.2' + gem 'spring' + gem 'spring-watcher-listen', '~> 2.0.0' +end + +group :test do + gem 'capybara', '>= 2.15', '< 4.0' + gem 'selenium-webdriver' + gem 'chromedriver-helper' +end + +gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] + +#编码检测 +gem 'rchardet', '~> 1.8' + +# http client +gem 'faraday', '~> 0.15.4' + +# view +gem 'active_decorator' + +# i18n +gem 'rails-i18n', '~> 5.1' + +# job +gem 'sidekiq' + +# batch insert +gem 'bulk_insert' + diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..83bd79628 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,354 @@ +PATH + remote: lib/gitlab-cli + specs: + gitlab (3.2.0) + httparty + terminal-table + +GEM + remote: https://gems.ruby-china.com/ + specs: + actioncable (5.2.1) + actionpack (= 5.2.1) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailer (5.2.1) + actionpack (= 5.2.1) + actionview (= 5.2.1) + activejob (= 5.2.1) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (5.2.1) + actionview (= 5.2.1) + activesupport (= 5.2.1) + rack (~> 2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (5.2.1) + activesupport (= 5.2.1) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + active_decorator (1.2.0) + activejob (5.2.1) + activesupport (= 5.2.1) + globalid (>= 0.3.6) + activemodel (5.2.1) + activesupport (= 5.2.1) + activerecord (5.2.1) + activemodel (= 5.2.1) + activesupport (= 5.2.1) + arel (>= 9.0) + activestorage (5.2.1) + actionpack (= 5.2.1) + activerecord (= 5.2.1) + marcel (~> 0.3.1) + activesupport (5.2.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + acts-as-taggable-on (6.0.0) + activerecord (~> 5.0) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + archive-zip (0.11.0) + io-like (~> 0.3.0) + arel (9.0.0) + awesome_print (1.8.0) + axlsx (3.0.0.pre) + htmlentities (~> 4.3, >= 4.3.4) + mimemagic (~> 0.3) + nokogiri (~> 1.8, >= 1.8.2) + rubyzip (~> 1.2, >= 1.2.1) + axlsx_rails (0.5.2) + actionpack (>= 3.1) + axlsx (>= 2.0.1) + bindex (0.5.0) + bootsnap (1.3.1) + msgpack (~> 1.0) + builder (3.2.3) + bulk_insert (1.7.0) + activerecord (>= 3.2.0) + byebug (10.0.2) + capybara (3.5.1) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + xpath (~> 3.1) + childprocess (0.9.0) + ffi (~> 1.0, >= 1.0.11) + chromedriver-helper (1.2.0) + archive-zip (~> 0.10) + nokogiri (~> 1.8) + chunky_png (1.3.10) + concurrent-ruby (1.0.5) + connection_pool (2.2.2) + crass (1.0.4) + diff-lcs (1.3) + erubi (1.7.1) + execjs (2.7.0) + faraday (0.15.4) + multipart-post (>= 1.2, < 3) + ffi (1.9.25) + globalid (0.4.1) + activesupport (>= 4.2.0) + grape-entity (0.7.1) + activesupport (>= 4.0) + multi_json (>= 1.3.2) + htmlentities (4.3.4) + httparty (0.16.2) + multi_xml (>= 0.5.2) + i18n (1.1.0) + concurrent-ruby (~> 1.0) + io-like (0.3.0) + jbuilder (2.7.0) + activesupport (>= 4.2.0) + multi_json (>= 1.2) + jwt (2.1.0) + kaminari (1.1.1) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.1.1) + kaminari-activerecord (= 1.1.1) + kaminari-core (= 1.1.1) + kaminari-actionview (1.1.1) + actionview + kaminari-core (= 1.1.1) + kaminari-activerecord (1.1.1) + activerecord + kaminari-core (= 1.1.1) + kaminari-core (1.1.1) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + loofah (2.2.2) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.0) + mini_mime (>= 0.1.1) + marcel (0.3.2) + mimemagic (~> 0.3.2) + method_source (0.9.0) + mimemagic (0.3.2) + mini_mime (1.0.0) + mini_portile2 (2.3.0) + minitest (5.11.3) + msgpack (1.2.4) + multi_json (1.13.1) + multi_xml (0.6.0) + multipart-post (2.0.0) + mysql2 (0.5.2) + nio4r (2.3.1) + nokogiri (1.8.4) + mini_portile2 (~> 2.3.0) + oauth2 (1.4.1) + faraday (>= 0.8, < 0.16.0) + jwt (>= 1.0, < 3.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (>= 1.2, < 3) + pdfkit (0.8.4.1) + public_suffix (3.0.2) + puma (3.12.0) + rack (2.0.5) + rack-cors (1.0.2) + rack-protection (2.0.5) + rack + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (5.2.1) + actioncable (= 5.2.1) + actionmailer (= 5.2.1) + actionpack (= 5.2.1) + actionview (= 5.2.1) + activejob (= 5.2.1) + activemodel (= 5.2.1) + activerecord (= 5.2.1) + activestorage (= 5.2.1) + activesupport (= 5.2.1) + bundler (>= 1.3.0) + railties (= 5.2.1) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.0.4) + loofah (~> 2.2, >= 2.2.2) + rails-i18n (5.1.3) + i18n (>= 0.7, < 2) + railties (>= 5.0, < 6) + railties (5.2.1) + actionpack (= 5.2.1) + activesupport (= 5.2.1) + method_source + rake (>= 0.8.7) + thor (>= 0.19.0, < 2.0) + rake (12.3.1) + rb-fsevent (0.10.3) + rb-inotify (0.9.10) + ffi (>= 0.5.0, < 2) + rchardet (1.8.0) + redis (4.1.0) + redis-actionpack (5.0.2) + actionpack (>= 4.0, < 6) + redis-rack (>= 1, < 3) + redis-store (>= 1.1.0, < 2) + redis-activesupport (5.0.7) + activesupport (>= 3, < 6) + redis-store (>= 1.3, < 2) + redis-rack (2.0.5) + rack (>= 1.5, < 3) + redis-store (>= 1.2, < 2) + redis-rails (5.0.2) + redis-actionpack (>= 5.0, < 6) + redis-activesupport (>= 5.0, < 6) + redis-store (>= 1.2, < 2) + redis-store (1.6.0) + redis (>= 2.2, < 5) + roo (2.8.2) + nokogiri (~> 1) + rubyzip (>= 1.2.1, < 2.0.0) + roo-xls (1.2.0) + nokogiri + roo (>= 2.0.0, < 3) + spreadsheet (> 0.9.0) + rqrcode (0.10.1) + chunky_png (~> 1.0) + rqrcode_png (0.1.5) + chunky_png + rqrcode + rspec-core (3.8.0) + rspec-support (~> 3.8.0) + rspec-expectations (3.8.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-mocks (3.8.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-rails (3.8.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-support (~> 3.8.0) + rspec-support (3.8.0) + ruby-ole (1.2.12.2) + ruby_dep (1.5.0) + rubyzip (1.2.1) + sass (3.5.7) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sass-rails (5.0.7) + railties (>= 4.0.0, < 6) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + selenium-webdriver (3.14.0) + childprocess (~> 0.5) + rubyzip (~> 1.2) + sidekiq (5.2.7) + connection_pool (~> 2.2, >= 2.2.2) + rack (>= 1.5.0) + rack-protection (>= 1.5.0) + redis (>= 3.3.5, < 5) + simple_xlsx_reader (1.0.4) + nokogiri + rubyzip + spreadsheet (1.2.3) + ruby-ole (>= 1.0) + spring (2.0.2) + activesupport (>= 4.2) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + thor (0.20.0) + thread_safe (0.3.6) + tilt (2.0.8) + tzinfo (1.2.5) + thread_safe (~> 0.1) + uglifier (4.1.17) + execjs (>= 0.3.0, < 3) + unicode-display_width (1.4.0) + web-console (3.6.2) + actionview (>= 5.0) + activemodel (>= 5.0) + bindex (>= 0.4.0) + railties (>= 5.0) + websocket-driver (0.7.0) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.3) + wkhtmltopdf-binary (0.12.4) + xpath (3.1.0) + nokogiri (~> 1.8) + +PLATFORMS + ruby + +DEPENDENCIES + active_decorator + acts-as-taggable-on (~> 6.0) + awesome_print + axlsx (~> 3.0.0.pre) + axlsx_rails (~> 0.5.2) + bootsnap (>= 1.1.0) + bulk_insert + byebug + capybara (>= 2.15, < 4.0) + chromedriver-helper + faraday (~> 0.15.4) + gitlab! + grape-entity (~> 0.7.1) + jbuilder (~> 2.5) + kaminari (~> 1.1, >= 1.1.1) + listen (>= 3.0.5, < 3.2) + mysql2 (>= 0.4.4, < 0.6.0) + oauth2 + pdfkit + puma (~> 3.11) + rack-cors + rails (~> 5.2.0) + rails-i18n (~> 5.1) + rchardet (~> 1.8) + redis-rails + roo-xls + rqrcode (~> 0.10.1) + rqrcode_png + rspec-rails (~> 3.8) + ruby-ole + rubyzip + sass-rails (~> 5.0) + selenium-webdriver + sidekiq + simple_xlsx_reader + spreadsheet + spring + spring-watcher-listen (~> 2.0.0) + tzinfo-data + uglifier (>= 1.3.0) + web-console (>= 3.3.0) + wkhtmltopdf-binary + +RUBY VERSION + ruby 2.3.7p456 + +BUNDLED WITH + 1.17.3 diff --git a/README.md b/README.md new file mode 100644 index 000000000..1aa92e1f5 --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... +#### Jbuilder介绍 +Jbuilder: https://github.com/rails/jbuilder + +#### Rails5 介绍 +rails guide: https://ruby-china.github.io/rails-guides/v5.0/ + +#### API设计文档 +doc for api: https://www.showdoc.cc/web/#/127895880302646?page_id=729221359592009 +user:Hjqreturn PW:12345678 + +#### 测试版访问地址:https://testeduplus2.educoder.net + +#### 实训平台繁忙 + 仓库异常:繁忙等级(81) + +#### 新版域名跳转规则 +新版域名要求总结:testeduplus2.educoder.net/(主要提供实训、实训课堂等业务) +目前有两个域名testbdweb.educoder.net(老版:主要提供课堂、项目、个人主页、后台等服务) + +要求: +1、两服务域名都应该启动‘提供服务 + +2、如果请求链接包含以下的形式,则域名跳至testeduplus2.educoder.net +testeduplus2.educoder.net/shixuns +testeduplus2.educoder.net/shixuns/* +testeduplus2.educoder.net/paths +testeduplus2.educoder.net/paths/* +testeduplus2.educoder.net/myshixuns/ +testeduplus2.educoder.net/tasks/* +testeduplus2.educoder.net/games/* + +如果不满足上述需求的,域名全部跳转至testbdweb.educoder.net +比如:门户首页,如果访问:testeduplus2.educoder.net 应为没包含上述链接。则调制testbdweb.educoder.net +在比如:testeduplus2.educoder.net /users/Hjqreturn没包含上述规则,则跳转到testbdweb.educoder.net/users/Hjqreturn + + +# 需要重构user_extensions 相关sql语句的地方标记 REDO:Extention + +# 文件上传:ActiveStorage +# 新能:bootsnap diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..4d8b3eb3c --- /dev/null +++ b/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative 'config/application' + +Rails.application.load_tasks diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 000000000..2aa036ced --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,3 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css diff --git a/app/assets/images/.keep b/app/assets/images/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/images/logn.png b/app/assets/images/logn.png new file mode 100644 index 000000000..effc78666 Binary files /dev/null and b/app/assets/images/logn.png differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 000000000..a3fb4b534 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,16 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's +// vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// +//= require rails-ujs +//= require activestorage +//= require turbolinks +//= require_tree . diff --git a/app/assets/javascripts/boards.coffee b/app/assets/javascripts/boards.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/boards.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js new file mode 100644 index 000000000..1207d34c0 --- /dev/null +++ b/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/app/assets/javascripts/challenges.coffee b/app/assets/javascripts/challenges.coffee new file mode 100644 index 000000000..acc3d435c --- /dev/null +++ b/app/assets/javascripts/challenges.coffee @@ -0,0 +1,4 @@ + +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/channels/.keep b/app/assets/javascripts/channels/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/javascripts/course_groups.coffee b/app/assets/javascripts/course_groups.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/course_groups.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/course_modules.coffee b/app/assets/javascripts/course_modules.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/course_modules.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/course_second_categories.coffee b/app/assets/javascripts/course_second_categories.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/course_second_categories.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/courses.coffee b/app/assets/javascripts/courses.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/courses.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/discusses.coffee b/app/assets/javascripts/discusses.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/discusses.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/edu_settings.js b/app/assets/javascripts/edu_settings.js new file mode 100644 index 000000000..7576b10b7 --- /dev/null +++ b/app/assets/javascripts/edu_settings.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/javascripts/games.coffee b/app/assets/javascripts/games.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/games.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/graduation_tasks.coffee b/app/assets/javascripts/graduation_tasks.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/graduation_tasks.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/graduation_topics.coffee b/app/assets/javascripts/graduation_topics.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/graduation_topics.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/graduation_works.coffee b/app/assets/javascripts/graduation_works.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/graduation_works.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/home.coffee b/app/assets/javascripts/home.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/home.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/homework_commons.coffee b/app/assets/javascripts/homework_commons.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/homework_commons.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/memos.coffee b/app/assets/javascripts/memos.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/memos.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/myshixuns.coffee b/app/assets/javascripts/myshixuns.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/myshixuns.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/question_banks.coffee b/app/assets/javascripts/question_banks.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/question_banks.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/repositories.coffee b/app/assets/javascripts/repositories.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/repositories.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/schools.coffee b/app/assets/javascripts/schools.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/schools.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/stages.coffee b/app/assets/javascripts/stages.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/stages.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/student_works.coffee b/app/assets/javascripts/student_works.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/student_works.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/subjects.coffee b/app/assets/javascripts/subjects.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/subjects.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/tem_tests.coffee b/app/assets/javascripts/tem_tests.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/tem_tests.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/users.coffee b/app/assets/javascripts/users.coffee new file mode 100644 index 000000000..ce1bf9855 --- /dev/null +++ b/app/assets/javascripts/users.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css new file mode 100644 index 000000000..fad1eb25d --- /dev/null +++ b/app/assets/stylesheets/application.css @@ -0,0 +1,16 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's + * vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + *= require_tree . + *= require_self + + */ diff --git a/app/assets/stylesheets/boards.scss b/app/assets/stylesheets/boards.scss new file mode 100644 index 000000000..05eae3636 --- /dev/null +++ b/app/assets/stylesheets/boards.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the boards controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/challenges.scss b/app/assets/stylesheets/challenges.scss new file mode 100644 index 000000000..d4b2e588f --- /dev/null +++ b/app/assets/stylesheets/challenges.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Challenges controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/course_groups.scss b/app/assets/stylesheets/course_groups.scss new file mode 100644 index 000000000..e08f685ab --- /dev/null +++ b/app/assets/stylesheets/course_groups.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the course_groups controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/course_modules.scss b/app/assets/stylesheets/course_modules.scss new file mode 100644 index 000000000..4c7d61be9 --- /dev/null +++ b/app/assets/stylesheets/course_modules.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the course_modules controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/course_second_categories.scss b/app/assets/stylesheets/course_second_categories.scss new file mode 100644 index 000000000..39379db81 --- /dev/null +++ b/app/assets/stylesheets/course_second_categories.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the course_second_categories controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/courses.scss b/app/assets/stylesheets/courses.scss new file mode 100644 index 000000000..4959274bb --- /dev/null +++ b/app/assets/stylesheets/courses.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the courses controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/discusses.scss b/app/assets/stylesheets/discusses.scss new file mode 100644 index 000000000..fe8f9d1b2 --- /dev/null +++ b/app/assets/stylesheets/discusses.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Discusses controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/edu_settings.scss b/app/assets/stylesheets/edu_settings.scss new file mode 100644 index 000000000..8434d0b34 --- /dev/null +++ b/app/assets/stylesheets/edu_settings.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the edu_settings controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/games.scss b/app/assets/stylesheets/games.scss new file mode 100644 index 000000000..37f701d87 --- /dev/null +++ b/app/assets/stylesheets/games.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the games controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/graduation_tasks.scss b/app/assets/stylesheets/graduation_tasks.scss new file mode 100644 index 000000000..e55f655c8 --- /dev/null +++ b/app/assets/stylesheets/graduation_tasks.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the graduation_tasks controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/graduation_topics.scss b/app/assets/stylesheets/graduation_topics.scss new file mode 100644 index 000000000..372da261f --- /dev/null +++ b/app/assets/stylesheets/graduation_topics.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the graduation_topics controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/graduation_works.scss b/app/assets/stylesheets/graduation_works.scss new file mode 100644 index 000000000..63b1774c6 --- /dev/null +++ b/app/assets/stylesheets/graduation_works.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the graduation_works controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/home.scss b/app/assets/stylesheets/home.scss new file mode 100644 index 000000000..34e19e1be --- /dev/null +++ b/app/assets/stylesheets/home.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Home controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/homework_commons.scss b/app/assets/stylesheets/homework_commons.scss new file mode 100644 index 000000000..bc4830b5b --- /dev/null +++ b/app/assets/stylesheets/homework_commons.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the homework_commons controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/memos.scss b/app/assets/stylesheets/memos.scss new file mode 100644 index 000000000..88523db64 --- /dev/null +++ b/app/assets/stylesheets/memos.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the memos controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/myshixuns.scss b/app/assets/stylesheets/myshixuns.scss new file mode 100644 index 000000000..36108a3bb --- /dev/null +++ b/app/assets/stylesheets/myshixuns.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the myshixuns controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/question_banks.scss b/app/assets/stylesheets/question_banks.scss new file mode 100644 index 000000000..443239fc0 --- /dev/null +++ b/app/assets/stylesheets/question_banks.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the QuestionBank controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/repositories.scss b/app/assets/stylesheets/repositories.scss new file mode 100644 index 000000000..e533f5b30 --- /dev/null +++ b/app/assets/stylesheets/repositories.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the repositories controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/scaffolds.scss b/app/assets/stylesheets/scaffolds.scss new file mode 100644 index 000000000..42375b193 --- /dev/null +++ b/app/assets/stylesheets/scaffolds.scss @@ -0,0 +1,84 @@ +body { + background-color: #fff; + color: #333; + margin: 33px; + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; +} + +p, ol, ul, td { + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; +} + +pre { + background-color: #eee; + padding: 10px; + font-size: 11px; +} + +a { + color: #000; + + &:visited { + color: #666; + } + + &:hover { + color: #fff; + background-color: #000; + } +} + +th { + padding-bottom: 5px; +} + +td { + padding: 0 5px 7px; +} + +div { + &.field, &.actions { + margin-bottom: 10px; + } +} + +#notice { + color: green; +} + +.field_with_errors { + padding: 2px; + background-color: red; + display: table; +} + +#error_explanation { + width: 450px; + border: 2px solid red; + padding: 7px 7px 0; + margin-bottom: 20px; + background-color: #f0f0f0; + + h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px -7px 0; + background-color: #c00; + color: #fff; + } + + ul li { + font-size: 12px; + list-style: square; + } +} + +label { + display: block; +} diff --git a/app/assets/stylesheets/schools.scss b/app/assets/stylesheets/schools.scss new file mode 100644 index 000000000..dc7f6efe9 --- /dev/null +++ b/app/assets/stylesheets/schools.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the schools controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/stages.scss b/app/assets/stylesheets/stages.scss new file mode 100644 index 000000000..6ea463e44 --- /dev/null +++ b/app/assets/stylesheets/stages.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the stages controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/student_works.scss b/app/assets/stylesheets/student_works.scss new file mode 100644 index 000000000..2b6e61028 --- /dev/null +++ b/app/assets/stylesheets/student_works.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the StudentWorks controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/subjects.scss b/app/assets/stylesheets/subjects.scss new file mode 100644 index 000000000..3d0fb957c --- /dev/null +++ b/app/assets/stylesheets/subjects.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Subjects controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/tem_tests.scss b/app/assets/stylesheets/tem_tests.scss new file mode 100644 index 000000000..e67436f42 --- /dev/null +++ b/app/assets/stylesheets/tem_tests.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the tem_tests controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss new file mode 100644 index 000000000..80b1121cd --- /dev/null +++ b/app/assets/stylesheets/users.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Users controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 000000000..c915a1a7f --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 000000000..34286ffa4 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/constraint/react_constraint.rb b/app/constraint/react_constraint.rb new file mode 100644 index 000000000..50d89c16e --- /dev/null +++ b/app/constraint/react_constraint.rb @@ -0,0 +1,11 @@ +class ReactConstraint + + + def matches?(request) + # stuff + # + !File.exists?(File.join(Rails.root, "public", request.fullpath.split('?').first)) + end + + +end \ No newline at end of file diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb new file mode 100644 index 000000000..c3333c912 --- /dev/null +++ b/app/controllers/accounts_controller.rb @@ -0,0 +1,197 @@ +class AccountsController < ApplicationController + + include ErrorCommon + #skip_before_action :check_account, :only => [:logout] + + def index + render json: session + end + + # 用户注册 + # 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用 + # params[:login] 邮箱或者手机号 + # params[:code] 验证码 + # code_type 1:注册手机验证码 8:邮箱注册验证码 + def register + begin + # 查询验证码是否正确;type只可能是1或者8 + type = phone_mail_type(params[:login].strip) + code = params[:code].strip + + if type == 1 + uid_logger("start register by phone: type is #{type}") + pre = 'p' + email = nil + phone = params[:login] + verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last + else + uid_logger("start register by email: type is #{type}") + pre = 'm' + email = params[:login] + phone = nil + verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last + end + uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.created_at.to_i}") + check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60) + unless check_code + tip_exception("验证码无效") + end + + code = generate_identifier User, 8 + login = pre + code + @user = User.new(admin: false, login: login, mail: email, phone: phone) + @user.password = params[:password] + # 现在因为是验证码,所以在注册的时候就可以激活 + @user.activate + # 必须要用save操作,密码的保存是在users中 + if @user.save! + # 注册完成,手机号或邮箱想可以奖励500金币 + RewardGradeService.call( + @user, + container_id: @user.id, + container_type: pre == 'p' ? 'Phone' : 'Mail', + score: 500 + ) + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(-1, e.message) + end + end + + # 用户登录 + def login + @user = User.try_to_login(params[:login], params[:password]) + @user.update_column(:last_login_on, Time.now) + + successful_authentication(@user) + + session[:user_id] = @user.id + end + + # 忘记密码 + def reset_password + begin + code = params[:code] + login_type = phone_mail_type(params[:login].strip) + # 获取验证码 + if login_type == 1 + phone = params[:login] + verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last + user = User.find_by_phone(phone) + else + email = params[:login] + verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last + user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs + + end + check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60) + unless check_code + tip_exception("验证码无效") + end + + user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation] + if user.save! + sucess_status + end + # rescue Exception => e + # uid_logger_error(e.message) + # tip_exception("密码重置失败,请稍后再试") + end + end + + def successful_authentication(user) + uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}") + # Valid user + self.logged_user = user + # generate a key and set cookie if autologin + + set_autologin_cookie(user) + UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id)) + end + + def set_autologin_cookie(user) + token = Token.get_or_create_permanent_login_token(user, "autologin") + cookie_options = { + :value => token.value, + :expires => 1.month.from_now, + :path => '/', + :secure => false, + :httponly => true + } + if edu_setting('cookie_domain').present? + cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) + end + cookies[autologin_cookie_name] = cookie_options + logger.info("cookies is #{cookies}") + end + + def logout + UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id) + session[:user_id] = nil + logout_user + render :json => {status: 1, message: "退出成功!"} + end + + # 检验邮箱是否已被注册及邮箱或者手机号是否合法 + # 参数type为事件类型 1:注册;2:忘记密码 + def valid_email_and_phone + check_mail_and_phone_valid(params[:login], params[:type]) + end + + # 发送验证码 + # params[:login] 手机号或者邮箱号 + # params[:type]为事件通知类型 1:用户注册注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱 # 如果有新的继续后面加 + # 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 + # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 + def get_verification_code + code = %W(0 1 2 3 4 5 6 7 8 9) + value = params[:login] + type = params[:type].strip.to_i + login_type = phone_mail_type(value) + send_type = verify_type(login_type, type) + verification_code = code.sample(6).join + + # 记录验证码 + check_verification_code(verification_code, send_type, value) + sucess_status + end + + # 1 手机类型;0 邮箱类型 + # 注意新版的login是自动名生成的 + def phone_mail_type value + value =~ /^1\d{10}$/ ? 1 : 0 + end + + private + def autologin_cookie_name + edu_setting('autologin_cookie_name') || 'autologin' + end + + def logout_user + if User.current.logged? + if autologin = cookies.delete(autologin_cookie_name) + User.current.delete_autologin_token(autologin) + end + User.current.delete_session_token(session[:tk]) + self.logged_user = nil + end + session[:user_id] = nil + end + + # type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱 # 如果有新的继续后面加 + # login_type 1:手机类型 2:邮箱类型 + def verify_type login_type, type + case type + when 1 + login_type == 1 ? 1 : 8 + when 2 + login_type == 1 ? 2 : 3 + when 3 + login_type == 1 ? 4 : tip_exception('请填写正确的手机号') + when 4 + login_type == 1 ? tip_exception('请填写正确的邮箱') : 5 + end + end + +end \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 000000000..cffe2df15 --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,597 @@ +require 'oauth2' + +class ApplicationController < ActionController::Base + include CodeExample + include RenderExpand + include RenderHelper + include ControllerRescueHandler + + protect_from_forgery prepend: true, unless: -> { request.format.json? } + + before_action :user_setup + #before_action :check_account + + DCODES = %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) + + helper_method :current_user + + # 全局配置参数 + # 返回name对应的value + def edu_setting name + EduSetting.find_by_name(name).try(:value) + end + + def user_course_identity + @user_course_identity = current_user.course_identity(@course) + if @user_course_identity > Course::STUDENT && @course.is_public == 0 + tip_exception(403, "您没有权限进入") + end + uid_logger("###############user_course_identity:#{@user_course_identity}") + end + + + # 判断用户的邮箱或者手机是否可用 + # params[:type] 1: 注册;2:忘记密码 + def check_mail_and_phone_valid login, type + unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ + tip_exception("请输入正确的手机号或邮箱") + end + # 考虑到安全参数问题,多一次查询,去掉Union + user = User.where(phone: login).first || User.where(mail: login).first + if type.to_i == 1 && !user.nil? + tip_exception("该手机号码或邮箱已被注册") + elsif type.to_i == 2 && user.nil? + tip_exception("该手机号码或邮箱未注册") + end + sucess_status + end + + # 发送及记录激活码 + # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 + # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 + def check_verification_code(code, send_type, value) + case send_type + when 1, 2, 4 + # 手机类型的发送 + sigle_para = {phone: value} + status = Educoder::Sms.send(mobile: value, code: code) + tip_exception(code_msg(status)) if status != 0 + when 8, 3, 5 + # 邮箱类型的发送 + sigle_para = {email: value} + begin + UserMailer.register_email(value, code).deliver_now + # Mailer.run.email_register(code, value) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("邮件发送失败,请稍后重试") + end + end + ver_params = {code_type: send_type, code: code}.merge(sigle_para) + VerificationCode.create!(ver_params) + end + + def code_msg status + case status + when 0 + "验证码已经发送到您的手机,请注意查收" + when 8 + "同一手机号30秒内重复提交相同的内容" + when 9 + "同一手机号5分钟内重复提交相同的内容超过3次" + when 22 + "1小时内同一手机号发送次数超过限制" + when 33 + "验证码发送次数超过频率" + when 43 + "一天内同一手机号发送次数超过限制" + end + end + + def find_course + return normal_status(2, '缺少course_id参数!') if params[:course_id].blank? + @course = Course.find(params[:course_id]) + rescue Exception => e + tip_exception(e.message) + end + + def course_manager + return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR + end + + def find_board + return normal_status(2, "缺少board_id参数") if params[:board_id].blank? + @board = Board.find(params[:board_id]) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def validate_type(object_type) + normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) + end + + def set_pagination + @page = params[:page] || 1 + @page_size = params[:page_size] || 15 + end + + # 课堂教师权限 + def teacher_allowed + logger.info("#####identity: #{current_user.course_identity(@course)}") + unless current_user.course_identity(@course) < Course::STUDENT + normal_status(403, "") + end + end + + def require_admin + normal_status(403, "") unless User.current.admin? + end + + # 前端会捕捉401,弹登录弹框 + # 未授权的捕捉407,弹试用申请弹框 + def require_login + #6.13 -hs + if User.current.logged? + if !current_user.profile_completed? + info_url = "#{edu_setting('old_edu_host')}/account/user_info" + tip_exception(402, info_url) + # render :json => { status: 402, url: info_url } + elsif current_user.certification != 1 + day_cer = UserDayCertification.where(user_id: current_user.id).last + tip_exception(407, "系统未授权") unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 + end + else + tip_exception(401, "..") + end + + end + + # 异常提醒 + def tip_exception(status = -1, message) + raise Educoder::TipException.new(status, message) + end + + def missing_template + tip_exception(404, "...") + end + + # 弹框提醒 + def tip_show_exception(status = -2, message) + raise Educoder::TipException.new(status, message) + end + + def normal_status(status = 0, message) + case status + when 403 + message = "您没有权限进行该操作" + when 404 + message = "您访问的页面不存在或已被删除" + end + render :json => { status: status, message: message } + end + + # 系统全局认证 + # + def check_auth + old_edu_host = edu_setting('old_edu_host') + ue = current_user.user_extension + + if current_user.lastname.blank? || ue.school_id.blank? || ue.identity.blank? || current_user.mail.blank? + info_url = old_edu_host + '/account/user_info' + render :json => { status: 402, url: info_url } + elsif current_user.certification != 1 + day_cer = UserDayCertification.where(user_id: current_user.id).last + unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 + account_url = old_edu_host + "/my/account" + render :json => { status: 402, url: account_url } + end + end + end + + # 身份资料的认证: + # 如果试用过期则弹框提示认证,先跳入个人资料页面完善资料,资料完成后,弹框提醒用户试用申请 + def check_account + # # todo user_extension + # if User.current.logged? + # ue = current_user.user_extension + # if current_user.lastname.blank? || ue.school_id.blank? || ue.identity.blank? || current_user.mail.blank? + # info_url = "#{edu_setting('old_edu_host')}/account/user_info" + # render :json => { status: 402, url: info_url } + # end + # end + end + + # 版本库目录空间 + def repo_namespace(user_login, shixun_identifier) + "#{user_login}/#{shixun_identifier}.git" + end + + # 版本库文件内容,带转码 + def git_fle_content(repo_path, path) + begin + content = GitService.file_content(repo_path: repo_path, path: path)["content"] + logger.info("@@@@@@@@@@@@@@@@@@#{content}") + + decode_content = nil + if content.present? + content = Base64.decode64(content) + cd = CharDet.detect(content) + logger.info "encoding: #{cd['encoding']} confidence: #{cd['confidence']}" + + decode_content = + if cd["encoding"] == 'GB18030' && cd['confidence'] > 0.8 + content.encode('UTF-8', 'GBK', {:invalid => :replace, :undef => :replace, :replace => ' '}) + else + content.force_encoding('UTF-8') + end + end + + decode_content + rescue Exception => e + uid_logger_error(e.message) + raise Educoder::TipException.new("文档内容获取异常") + end + end + + # 更新文件代码 + # content: 文件内容;message:提交描述 + def update_file_content(content, repo_path, path, mail, username, message) + GitService.update_file(repo_path: repo_path, file_path: path, message: message, + content: content, author_name: username, author_email: mail) + end + + # 版本库Fork功能 + def project_fork(container, original_rep_path, username) + raise Educoder::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank? + # 将要生成的仓库名字 + new_repo_name = "#{username}/#{container.try(:identifier)}#{ Time.now.strftime("%Y%m%d%H%M%S")}" + uid_logger("start fork container: repo_name is #{new_repo_name}") + GitService.fork_repository(repo_path: original_rep_path, fork_repository_path: (new_repo_name + ".git")) + container.update_attributes!(:repo_name => new_repo_name) + end + + def start_user_session(user) + session[:user_id] = user.id + session[:ctime] = Time.now.utc.to_i + session[:atime] = Time.now.utc.to_i + end + + def user_setup + # Find the current user + User.current = find_current_user + uid_logger("user_step: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) + + if !User.current.logged? && Rails.env.development? + User.current = User.find 12 + end + + if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 + User.current = User.find 49610 + elsif params[:debug] == 'student' + User.current = User.find 8686 + elsif params[:debug] == 'admin' + User.current = User.find 1 + end + end + + # Sets the logged in user + def logged_user=(user) + reset_session + if user && user.is_a?(User) + User.current = user + start_user_session(user) + else + User.current = User.anonymous + end + end + + # Returns the current user or nil if no user is logged in + # and starts a session if needed + def find_current_user + if session[:user_id] + # existing session + (User.active.find(session[:user_id]) rescue nil) + elsif autologin_user = try_to_autologin + autologin_user + elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? + # RSS key authentication does not start a session + User.find_by_rss_key(params[:key]) + end + end + + def autologin_cookie_name + edu_setting('autologin_cookie_name').presence || 'autologin' + end + + def try_to_autologin + if cookies[autologin_cookie_name] + # auto-login feature starts a new session + user = User.try_to_autologin(cookies[autologin_cookie_name]) + if user + start_user_session(user) + end + user + end + end + + def api_request? + %w(xml json).include? params[:format] + end + + def current_user + User.current + end + + ## 默认输出json + def render_json + respond_to do |format| + format.json + end + end + + # 以用户id开始的日志定义 + def uid_logger(message) + Rails.logger.info("##:#{current_user.try(:id)} --#{message}") + end + + # 以用户id开始的日志定义 + def uid_logger_error(message) + Rails.logger.error("##:#{current_user.try(:id)} --#{message}") + end + + ## 输出错误信息 + def error_status(message = nil) + @status = -1 + @message = message + end + + # 实训等对应的仓库地址 + def repo_ip_url(repo_path) + "#{edu_setting('git_address_ip')}/#{repo_path}" + end + + def repo_url(repo_path) + "#{edu_setting('git_address_domain')}/#{repo_path}" + end + + # 通关后,把最后一次成功的代码存到数据库 + # type 0 创始内容, 1 最新内容 + def game_passed_code(path, myshixun, game_id) + file_content = git_fle_content myshixun.repo_path, path + unless file_content.present? + raise("获取文件代码异常") + end + game_code = GameCode.where(:game_id => game_id, :path => path).first + if game_code.nil? + GameCode.create!(:game_id => game_id, :new_code => file_content, :path => path) + else + game_code.update_attributes!(:new_code => file_content) + end + end + + # Post请求 + def uri_post(uri, params) + begin + uid_logger("--uri_exec: params is #{params}, url is #{uri}") + uri = URI.parse(URI.encode(uri.strip)) + res = Net::HTTP.post_form(uri, params).body + logger.info("--uri_exec: .....res is #{res}") + JSON.parse(res) + rescue Exception => e + uid_logger("--uri_exec: exception #{e.message}") + raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") + end + end + + # 处理返回非0就报错的请求 + def interface_post(uri, params, status, message) + begin + uid_logger("--uri_exec: params is #{params}, url is #{uri}") + uri = URI.parse(URI.encode(uri.strip)) + res = Net::HTTP.post_form(uri, params).body + logger.info("--uri_exec: .....res is #{res}") + res = JSON.parse(res) + if (res && res['code'] != 0) + tip_exception(status, message) + else + res + end + rescue Exception => e + uid_logger("--uri_exec: exception #{e.message}") + raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") + end + end + + #实训题的关卡url初始化 + def challenge_path(path) + cha_path = path.present? ? path.split(";") : [] + cha_path.reject(&:blank?)[0].try(:strip) + end + + # 适用与已经用url_safe编码后,回调字符串形式 + def tran_base64_decode64(str) + s_size = str.size % 4 + if s_size != 0 + str += "=" * (4 - s_size) + end + if str.blank? + str + else + Base64.decode64(str.tr("-_", "+/")).force_encoding("utf-8") + end + end + + def sucess_status(message = 'success') + render :json => { status: 1, message: message } + end + + # 随机生成字符 + def generate_identifier(container, num) + code = DCODES.sample(num).join + if container == User + while container.exists?(login: code) do + code = DCODES.sample(num).join + end + else + while container.exists?(identifier: code) do + code = DCODES.sample(num).join + end + end + code + end + + + # 实训主类别列表,自带描述 + def shixun_main_type + list = [] + mirrors = MirrorRepository.select([:id, :type_name]).published_main_mirror + mirrors.try(:each) do |mirror| + list << {id: mirror.id, type_name: mirror.type_name, description: mirror.try(:description)} + end + list + end + + # 小类别列表 + def shixun_small_type + list = [] + mirrors = MirrorRepository.select([:id, :type_name]).published_small_mirror + mirrors.try(:each) do |mirror| + list << {id: mirror.id, type_name: mirror.type_name} + end + list + end + + def container_limit(mirror_repositories) + container = [] + mirror_repositories.each do |mr| + if mr.name.present? + container << {:image => mr.name, :cpuLimit => mr.cpu_limit, :memoryLimit => "#{mr.memory_limit}M", :type => mr.try(:main_type) == "1" ? "main" : "sub"} + end + end + container.to_json + end + + # 毕设任务列表的赛选 + def course_work(task, **option) + logger.info("#############{option}") + course = task.course + work_list = task.graduation_works.includes(user: [:user_extension]) + # 教师评阅搜索 0: 未评, 1 已评 + if option[:teacher_comment] + graduation_work_ids = GraduationWorkScore.where(graduation_work_id: work_list.map(&:id)).pluck(:graduation_work_id) + if option[:teacher_comment].zero? + work_list = work_list.where.not(id: graduation_work_ids) + elsif option[:teacher_comment] == 1 + work_list = work_list.where(id: graduation_work_ids).where.not(work_status: 0) + end + end + + # 作品状态 0: 未提交, 1 按时提交, 2 延迟提交 + if option[:task_status] + work_list = work_list.where(work_status: option[:task_status]) + end + + # 分班情况 + if option[:course_group] + group_user_ids = course.course_members.where(course_group_id: option[:course_group]).pluck(:user_id) + # 有分组只可能是老师身份查看列表 + work_list = work_list.where(user_id: group_user_ids) + end + + # 只看我的交叉评阅 + if option[:cross_comment] + graduation_work_id = task.graduation_work_comment_assignations.where(:user_id => current_user.id) + .pluck(:graduation_work_id).uniq if task.graduation_work_comment_assignations + work_list = work_list.where(id: graduation_work_id) + end + + # 输入姓名和学号搜索 + # TODO user_extension 如果修改 请调整 + if option[:search] + work_list = work_list.joins(user: :user_extension).where("concat(lastname, firstname) like ? + or student_id like ?", "%#{option[:search]}%", "%#{option[:search]}%") + end + + # 排序 + rorder = option[:order] || "updated_at" + b_order = option[:b_order] || "desc" + if rorder == "created_at" || rorder == "work_score" + work_list = work_list.order("graduation_works.#{rorder} #{b_order}") + elsif rorder == "student_id" + work_list = work_list.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}") + end + work_list + end + + def strip_html(text, len=0, endss="...") + ss = "" + if !text.nil? && text.length>0 + ss=text.gsub(/<\/?.*?>/, '').strip + ss = ss.gsub(/ */, '') + ss = ss.gsub(/\r\n/,'') #新增 + ss = ss.gsub(/\n/,'') #新增 + if len > 0 && ss.length > len + ss = ss[0, len] + endss + elsif len > 0 && ss.length <= len + ss = ss + #ss = truncate(ss, :length => len) + end + end + ss + end + + # Returns a string that can be used as filename value in Content-Disposition header + def filename_for_content_disposition(name) + request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name + end + + def format_time(time) + time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M") + end + + # 获取Oauth Client + def get_client(site) + client_id = Rails.configuration.educoder['client_id'] + client_secret = Rails.configuration.educoder['client_secret'] + + OAuth2::Client.new(client_id, client_secret, site: site) + end + + def paginate(relation) + limit = params[:limit].to_i.zero? ? 20 : params[:limit].to_i + page = params[:page].to_i.zero? ? 1 : params[:page].to_i + offset = (page - 1) * limit + + if relation.is_a?(Array) + relation[offset, limit] + else + relation.limit(limit).offset(offset) + end + end + + def strf_time(time) + time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M:%S") + end + + def logger_error(error) + Rails.logger.error(error.message) + error.backtrace.each { |msg| Rails.logger.error(msg) } + end + + private + def object_not_found + uid_logger("Missing template or cant't find record, responding with 404") + render json: {message: "您访问的页面不存在或已被删除", status: 404} + false + end + + def tip_show(exception) + uid_logger("Tip show status is #{exception.status}, message is #{exception.message}") + render json: exception.tip_json + end + + def render_parameter_missing + render json: { status: -1, message: '参数缺失' } + end +end diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb new file mode 100644 index 000000000..0a89bb3f9 --- /dev/null +++ b/app/controllers/attachments_controller.rb @@ -0,0 +1,162 @@ +#coding=utf-8 +# +# 文件上传 +class AttachmentsController < ApplicationController + before_action :require_login + before_action :find_file, only: %i[show destroy] + + include ErrorCommon + include ApplicationHelper + + def show + # 1. 优先跳到cdn + # 2. 如果没有cdn,send_file + if @file.cloud_url.present? + update_downloads(@file) + redirect_to @file.cloud_url and return + end + send_file absolute_path(local_path(@file)), type: @file.content_type + + update_downloads(@file) + end + + def create + # 1. 本地存储 + # 2. 上传到云 + upload_file = params["file"] || params["#{params[:file_param_name]}"] # 这里的file_param_name是为了方便其他插件名称 + uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}") + if upload_file + folder = edu_setting('attachment_folder') + raise "存储目录未定义" unless folder.present? + + month_folder = current_month_folder + save_path = File.join(folder, month_folder) + + ext = file_ext(upload_file.original_filename) + + local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext) + + content_type = upload_file.content_type.presence || 'application/octet-stream' + + remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type) + + logger.info "local_path: #{local_path}" + logger.info "remote_path: #{remote_path}" + + + disk_filename = local_path[save_path.size + 1, local_path.size] + #存数据库 + # + @attachment = Attachment.where(disk_filename: disk_filename, + author_id: current_user.id, + cloud_url: remote_path).first + + unless @attachment.present? + @attachment = Attachment.new + @attachment.filename = upload_file.original_filename + @attachment.disk_filename = local_path[save_path.size + 1, local_path.size] + @attachment.filesize = upload_file.tempfile.size + @attachment.content_type = content_type + @attachment.digest = digest + @attachment.author_id = current_user.id + @attachment.disk_directory = month_folder + @attachment.cloud_url = remote_path + @attachment.save! + else + logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}" + end + + render_json + else + raise "未上传文件" + end + end + + def destroy + begin + @file_path = absolute_path(local_path(@file)) + #return normal_status(403, "") unless @file.author == current_user + @file.destroy! + + delete_file(@file_path) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + private + def find_file + @file = + if params[:type] == 'history' + AttachmentHistory.find params[:id] + else + Attachment.find params[:id] + end + end + + def delete_file(file_path) + File.delete(file_path) if File.exist?(file_path) + end + + def current_month_folder + date = Time.now + "#{date.year}/#{date.day.to_s.rjust(2, '0')}" + end + + def file_ext(file_name) + ext = '' + exts = file_name.split(".") + if exts.size > 1 + ext = ".#{exts.last}" + end + ext + end + + def file_save_to_local(save_path, temp_file, ext) + unless Dir.exists?(save_path) + FileUtils.mkdir_p(save_path) ##不成功这里会抛异常 + end + + digest = md5_file(temp_file) + digest = "#{digest}_#{Time.now.to_i}" + local_file_path = File.join(save_path, digest) + ext + save_temp_file(temp_file, local_file_path) + + [local_file_path, digest] + end + + def save_temp_file(temp_file, save_file_path) + File.open(save_file_path, 'wb') do |f| + temp_file.rewind + while (buffer = temp_file.read(8192)) + f.write(buffer) + end + end + end + + def md5_file(temp_file) + md5 = Digest::MD5.new + temp_file.rewind + while (buffer = temp_file.read(8192)) + md5.update(buffer) + end + md5.hexdigest + end + + def file_save_to_ucloud(path, file, content_type) + ufile = Educoder::Ufile.new( + ucloud_public_key: edu_setting('public_key'), + ucloud_private_key: edu_setting('private_key'), + ucloud_public_read: true, + ucloud_public_bucket: edu_setting('public_bucket'), + ucloud_public_bucket_host: edu_setting('public_bucket_host'), + ucloud_public_cdn_host: edu_setting('public_cdn_host'), + ) + File.open(file) do |f| + ufile.put(path, f, 'Content-Type' => content_type) + end + edu_setting('public_cdn_host') + "/" + path + end +end diff --git a/app/controllers/boards_controller.rb b/app/controllers/boards_controller.rb new file mode 100644 index 000000000..51c8397b1 --- /dev/null +++ b/app/controllers/boards_controller.rb @@ -0,0 +1,86 @@ +class BoardsController < ApplicationController + before_action :require_login + before_action :find_course, only: [:create] + before_action :set_board, except: [:create] + before_action :teacher_allowed + + def index + @boards = @course.boards.includes(messages: [:last_reply, :author]); + end + + def show + + end + + def new + end + + def create + ActiveRecord::Base.transaction do + begin + board = @course.course_board + new_board = Board.new(board_params) + new_board.course_id = @course.id + new_board.project_id = -1 + new_board.parent_id = board.try(:id) + new_board.position = board.children.count + 1 + new_board.save! + normal_status(0, "添加成功") + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 子目录的拖动 + def move_category + tip_exception("移动失败") if params[:position].blank? + unless params[:position].to_i == @board.position + course_board = @course.course_board + if params[:position].to_i < @board.position + course_board.children.where("position < #{@board.position} and position >= ?", params[:position]).update_all("position = position + 1") + else + course_board.children.where("position > #{@board.position} and position <= ?", params[:position]).update_all("position = position - 1") + end + @board.update_attributes(position: params[:position]) + normal_status(0, "移动成功") + else + normal_status(-1, "位置没有变化") + end + end + + def destroy + ActiveRecord::Base.transaction do + begin + @course_board = @course.course_board + @course_board.children.where("position > #{@board.position}").update_all("position = position - 1") + @board.messages.update_all(board_id: @course_board.id) + @board.destroy + rescue Exception => e + uid_logger_error(e.message) + tip_exception("子目录删除失败") + raise ActiveRecord::Rollback + end + end + end + + def update + @board.update_attributes(board_params) + normal_status(0, "更新成功") + end + + private + + def set_board + @board = Board.find_by!(id: params[:id]) + @course = @board.course + end + + def board_params + tip_exception("子目录名称不能为空") if params[:name].blank? + tip_exception("已存在同名讨论区") if @course.boards.exists?(name: params[:name].strip) + params.require(:board).permit(:name) + end +end diff --git a/app/controllers/challenges_controller.rb b/app/controllers/challenges_controller.rb new file mode 100644 index 000000000..d603904c4 --- /dev/null +++ b/app/controllers/challenges_controller.rb @@ -0,0 +1,305 @@ +class ChallengesController < ApplicationController + before_action :require_login + before_action :find_shixun, only: [:new, :create, :index] + skip_before_action :verify_authenticity_token, only: [:create, :update, :create_choose_question, :crud_answer] + before_action :find_challenge, only: [:edit, :show, :update, :create_choose_question, :index_down, :index_up, + :edit_choose_question, :show_choose_question, :destroy_challenge_choose, + :update_choose_question, :destroy, :crud_answer, :answer] + # before_action :allowed, except: [:index, :show, :edit_choose_question, :edit] + + + include ShixunsHelper + include ChallengesHelper + + # 新建实践题 + def new + @position = @shixun.challenges.count + 1 + @st = params[:st].to_i + @task_pass_default = PlatformSample.find_by(samples_type: "taskPass").try(:contents) + end + + # params + # challenge:{"subject": "标题", "task_pass": "过关任务", + # "diffculty": "关卡难度", "score": "关卡分数", "st": "关卡类型"} 关卡相关信息 + # challenge_tag: 关卡标签 + # + def create + ActiveRecord::Base.transaction do + begin + @challenge = Challenge.new(challenge_params) + @challenge.position = @shixun.challenges.count + 1 + @challenge.shixun_id = @shixun.id + @challenge.user_id = current_user.id + @challenge.modify_time = Time.now + @challenge.save! + + # 实训是否需要重置, 非实践任务创建第一个阶段调用, 避免不包含实践任务的实训进行模拟实战报错 todo: 新建实训需要重置TPI + # shixun_modify_status_without_publish(@shixun, 1) if @challenge.position != 1 + + tags = params[:challenge_tag] + if tags.present? + tags.each do |tag| + # TODO 创建tag的时候为什么一直报challenge choose必须存在?? + ChallengeTag.create!(name: tag, challenge_id: @challenge.id) + end + end + rescue Exception => e + uid_logger_error("create challenge failed #{e}") + end + end + end + + # 创建选择题 + def create_choose_question + ActiveRecord::Base.transaction do + begin + @challenge_choose = ChallengeChoose.new(chooce_params) + @challenge_choose.position = @challenge.challenge_chooses.count + 1 + @challenge_choose.category = @challenge_choose.standard_answer.length == 1 ? 1 : 2 + @challenge_choose.challenge_id = @challenge.id + + if @challenge_choose.save! + # 创建选项 + params[:question][:cnt].each_with_index do |test, index| + answer = params[:choice][:answer][index] + ChallengeQuestion.create(:option_name => test, + :challenge_choose_id => @challenge_choose.id, + :position => index, :right_key => answer) + end + # 创建单选多选的技能标签 + if params[:challenge_tag].present? + params[:challenge_tag].each do |tag| + ChallengeTag.create(:name => tag, :challenge_choose_id => @challenge_choose.id, :challenge_id => @challenge.id) + end + end + end + rescue Exception => e + raise ActiveRecord::Rollback + end + end + end + + # 选择题详情页面 + def show_choose_question + @challenge_choose = ChallengeChoose.find params[:choose_id] + + end + + # 选择题更新页面 + def update_choose_question + @challenge_choose = ChallengeChoose.find(params[:choose_id]) + ActiveRecord::Base.transaction do + if params[:standard_answer] != @challenge_choose.standard_answer + @challenge.update_column(:modify_time, Time.now) + end + @challenge_choose.update_attributes(chooce_params) + # 单选多选题的更新 + category = @challenge_choose.standard_answer.length > 1 ? 2 : 1 + @challenge_choose.update_column(:category, category) + begin + @challenge_choose.challenge_questions.delete_all + params[:question][:cnt].each_with_index do |test, index| + answer = params[:choice][:answer][index] + ChallengeQuestion.create(:option_name => test, :challenge_choose_id => @challenge_choose.id, :position => index, :right_key => answer) + end + @challenge_choose.challenge_tags.delete_all unless @challenge_choose.challenge_tags.blank? + if params[:challenge_tag].present? + params[:challenge_tag].each do |tag| + ChallengeTag.create(:name => tag, :challenge_choose_id => @challenge_choose.id, :challenge_id => @challenge.id) + end + end + @challenge_choose = ChallengeChoose.find params[:choose_id] + rescue Exception => e + raise ActiveRecord::Rollback + end + end + end + + # 选择题的编辑 + def edit_choose_question + @challenge_choose = ChallengeChoose.find params[:choose_id] + end + + def destroy_challenge_choose + ActiveRecord::Base.transaction do + @challenge_choose = ChallengeChoose.where(:id => params[:choose_id]).first + pos = @challenge_choose.position + @challenge.challenge_chooses.where("position > ?", pos).update_all("position = position - 1") + @challenge_choose.destroy + @status = 1 + # 发起重置请求 TODO: 重置实训需要后续做 + # shixun_modify_status_without_publish(@shixun, 1) + end + end + + # 编辑模式 + # tab 0,nil 过关任务, 1 评测设置, 2 参考答案 + def edit + @tab = params[:tab].to_i + @power = current_user.manager_of_shixun?(@shixun) && @shixun.status == 0 + challenge_num = Challenge.where(:shixun_id => @shixun).count + @position = @challenge.position + @chooses = @challenge.challenge_chooses + if @position < challenge_num + @next_challenge = Challenge.where(:shixun_id => @shixun, :position => @position + 1).first + end + @prev_challenge = Challenge.where(:shixun_id => @shixun, :position => @position - 1).first if @position - 1 > 0 + end + + def index + uid_logger("identifier: #{params}") + # 通过调试发现 这里includes(:games)性能会慢10倍 + @challenges = @shixun.challenges.fields_for_list + @editable = current_user.manager_of_shixun?(@shixun) && @shixun.status == 0 + @user = current_user + end + + def show + @tab = params[:tab].nil? ? 1 : params[:tab].to_i + challenge_num = Challenge.where(shixun_id: @shixun).count + @power = current_user.manager_of_shixun?(@shixun) && @shixun.status == 0 + @position = @challenge.position + if @position < challenge_num + @next_challenge = Challenge.where(:shixun_id => @shixun, :position => @position + 1).first + end + @prev_challenge = Challenge.where(:shixun_id => @shixun, :position => @position - 1).first if @position - 1 > 0 + end + + # tab 0:过关任务的更新; 1:评测设置的更新; 2:表示参考答案的更新; + def update + ActiveRecord::Base.transaction do + tab = params[:tab].to_i + @challenge.update_attributes(challenge_params) + if tab == 0 && @challenge.st == 0 + @challenge.challenge_tags.delete_all + if params[:challenge_tag].present? + params[:challenge_tag].each do |input| + ChallengeTag.create!(:name => input, :challenge_id => @challenge.id) + end + end + elsif tab == 1 + path = @challenge.path + exec_path = @challenge.exec_path + test_set = @challenge.test_sets + sets_output = test_set.map(&:output) + sets_input = test_set.map(&:input) + sets_open = test_set.map(&:is_public) + set_score = test_set.map(&:score) + params_hidden = params[:test_set].map{|set| set[:hidden].to_i == 0} + params_output = params[:test_set].map{|set| set[:output] } + params_input = params[:test_set].map{|set| set[:input] } + params_score = params[:test_set].map{|set| set[:score]} + # 测试集变化则需要更新(输入、 输出、 是否隐藏) + if sets_output != params_output || sets_open != params_hidden || sets_input != params_input || set_score != params_score + test_set.delete_all unless test_set.blank? + params[:test_set].each_with_index do |set, index| + TestSet.create(:challenge_id => @challenge.id, + :input => "#{set[:input]}", + :output => "#{set[:output]}", + :is_public => params_hidden[index], + :score => set[:score], + :position => (index + 1)) + end + @challenge.update_column(:modify_time, Time.now) + # 测试集的 + @shixun.myshixuns.update_all(:system_tip => 0) + end + # 关卡评测执行文件如果被修改,需要修改脚本内容 + script = modify_shixun_script @shixun, @shixun.evaluate_script + @shixun.update_column(:evaluate_script, script) + # TODO: + # if path != params[:challenge][:path] + # shixun_modify_status_without_publish(@shixun, 1) + # end + #Attachment.attach_files(@challenge, params[:attachments]) + end + + end + end + + # 参考答案的'增,删,改' + # POST: /shixuns/:id/challenges/:id/crud_answer + # {'challenge_answer': [ + # {'name': 'name', contents: 'contents', score: 10}, + # {...}, + # {...}, ...] + #} + def crud_answer + raise '参考答案不能为空' if params[:challenge_answer].empty? + raise '占比之和必须为100%' if params[:challenge_answer].map{|a| a[:score]}.sum != 100 + @challenge.challenge_answers.destroy_all if @challenge.challenge_answers + params[:challenge_answer].each_with_index do |answer, index| + ChallengeAnswer.create(name: answer[:name], contents: answer[:contents], + level: index+1, score: answer[:score], challenge_id: @challenge.id) + end + end + + # 查看参考答案接口 + def answer + @answers = @challenge.challenge_answers + end + + def index_down + next_challenge = @challenge.next_challenge + position = @challenge.position + @challenge.update_attribute(:position, (position + 1)) + next_challenge.update_attribute(:position, next_challenge.position - 1) + # 关卡位置被修改,需要修改脚本 + script = modify_shixun_script @shixun, @shixun.evaluate_script + @shixun.update_column(:evaluate_script, script) + + end + + def index_up + position = @challenge.position + last_challenge = @challenge.last_challenge + @challenge.update_attribute(:position, (position - 1)) + last_challenge.update_attribute(:position, last_challenge.position + 1) + # 关卡位置被修改,需要修改脚本 + script = modify_shixun_script @shixun, @shixun.evaluate_script + @shixun.update_column(:evaluate_script, script) + end + + def destroy + next_challenges = @shixun.challenges.where("position > #{@challenge.position}") + next_challenges.update_all("position = position - 1") + # Todo: 实训修改后,关卡需要重置 + # shixun_modify_status_without_publish(@shixun, 1) + @challenge.destroy + # 关卡位置被删除,需要修改脚本 + script = modify_shixun_script @shixun, @shixun.evaluate_script + @shixun.update_column(:evaluate_script, script) + end + + + private + + def find_shixun + @shixun = Shixun.find_by_identifier(params[:shixun_identifier]) + end + + # 通用接口 + def find_challenge + @challenge = Challenge.find params[:id] + @shixun = Shixun.find_by!(identifier: params[:shixun_identifier]) + end + + def challenge_params + params.require(:challenge).permit(:subject, :task_pass, :difficulty, :score, :st, :modify_time, :test_set_average, + :path, :exec_path, :show_type, :original_picture_path, :test_set_score, + :expect_picture_path, :picture_path, :web_route, :answer) + end + + def chooce_params + params.require(:challenge_choose).permit(:subject, :answer, + :standard_answer, :score, :difficult) + end + + def allowed + # 实训为发布前,除实训的管理者外,其他人都不人都不允许访问 + if !current_user.manager_of_shixun?(@shixun) && (@shixun.status < 1 || @shixun.hidden == 1) + raise Educoder::TipException.new(403, "..") + end + end + +end diff --git a/app/controllers/commons_controller.rb b/app/controllers/commons_controller.rb new file mode 100644 index 000000000..ca68c65d3 --- /dev/null +++ b/app/controllers/commons_controller.rb @@ -0,0 +1,58 @@ +class CommonsController < ApplicationController + OBJECT_TYPE = %W[message journals_for_message] + + before_action :require_login + before_action :validate_object_type + before_action :find_object + before_action :validate_power + + def delete + begin + @object.destroy! + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def hidden + action(true) + end + + def unhidden + action(false) + end + + private + def find_object + begin + @object = params[:object_type].strip.classify.constantize.find params[:object_id] + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + return + end + end + + def validate_object_type + return normal_status(2, "缺少object_id参数") if params[:object_id].blank? + return normal_status(2, "缺少object_type参数") if params[:object_type].blank? + return normal_status(2, "object_type参数格式错误") unless OBJECT_TYPE.include? params[:object_type].strip + end + + def validate_power + tip_exception(403, "无操作权限") unless current_user.admin? + end + + def action(flag) + begin + @object.has_attribute?(:is_hidden) ? @object.update_attributes(:is_hidden => flag ) + : @object.update_attributes(:hidden => flag ) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/app/controllers/concerns/code_example.rb b/app/controllers/concerns/code_example.rb new file mode 100644 index 000000000..55c250511 --- /dev/null +++ b/app/controllers/concerns/code_example.rb @@ -0,0 +1,137 @@ +module CodeExample + extend ActiveSupport::Concern + + #老师C语言的标准代码 + def c_stantard_code_teacher + "// 老师您好!这是一个C语言的样例程序 +// 程序功能:输入两个整数,输出两者之和 +// 测试集合:老师可以给出多组测试集,例如: +// 输入1和2,输出3 +// 输入3和4,输出7 +// ... ... +// 系统将根据您给出的测试集对学生代码进行自动评分 + +// 特别提醒:程序采用命令行传参方式,输入通过argv传入 +// 否则您的作业标准代码将不能通过测试 + +#include //引用必须头文件 +int main(int argc, char** argv) { + int a = atoi(argv[1]); //将第一个输入转成整型 + int b = atoi(argv[2]); //将第二个输入转换为整型 + + printf(\"%d\",a+b); //输出a+b + return 0; +}".html_safe + end + + #老师C++语言的标准代码 + def c_stantard_code_teacher_ + "// 老师您好!这是一个C++语言的样例程序 +// 程序功能:输入两个整数,输出两者之和 +// 测试集合:老师可以给出多组测试集,例如: +// 输入1和2,输出3 +// 输入3和4,输出7 +// ... ... +// 系统将根据您给出的测试集对学生代码进行自动评分 + +// 特别提醒:程序采用命令行传参方式,输入通过argv传入 +// 否则您的作业标准代码将不能通过测试 + +#include //引用必须头文件 +#include +using namespace std; +int main(int argc, char** argv){ + int a = atoi(argv[1]); //将第一个输入转成整型 + int b = atoi(argv[2]); //将第二个输入转换为整型 + cout< //引用必须头文件 +int main(int argc, char** argv) { + int a = atoi(argv[1]); //将第一个输入转成整型 + int b = atoi(argv[2]); //将第二个输入转换为整型 + + printf(\"%d\",a+b); //输出a+b + return 0; +}".html_safe + end + + #学生C++语言的标准代码 + def c_stantard_code_student_ + "// 同学好!这是一个C++语言的样例程序 +// 程序功能:输入两个整数,输出两者之和 +// 测试集合:老师可以给出多组测试集,例如: +// 输入1和2,输出3 +// 输入3和4,输出7 +// ... ... +// 系统将根据您给出的测试集对学生代码进行自动评分 + +// 特别提醒:程序采用命令行传参方式,输入通过argv传入 +// 否则您的作业标准代码将不能通过测试 + +#include //引用必须头文件 +#include +using namespace std; +int main(int argc, char** argv){ + int a = atoi(argv[1]); //将第一个输入转成整型 + int b = atoi(argv[2]); //将第二个输入转换为整型 + cout<&1 | base64) + if [ -z \"$compileResult\" ]; then + compileResult=$(echo -n \"compile successfully\" | base64) + fi + + } + compile $1" + end + + def execute_command + "execute(){ + #执行命令 + executeCommand=\"EXECUTECOMMAND\" + #执行文件名 + sourceClassName=${sourceClassNames[$1 - 1]} + challengeStage=$1 + + output='' + i=0 + while [[ i -lt ${#ins[*]} ]]; do + #执行,并拼接执行结果 + result=$(echo \"${ins[$i]}\" | base64 -d | $executeCommand $sourceClassName 2>&1 | base64) + #拼接输出结果 + output=$output\\\"$result\\\", + let i++ + done + output=\"[${output%?}]\" +} + +execute $1 +" + end +end \ No newline at end of file diff --git a/app/controllers/concerns/controller_rescue_handler.rb b/app/controllers/concerns/controller_rescue_handler.rb new file mode 100644 index 000000000..e9563d1e5 --- /dev/null +++ b/app/controllers/concerns/controller_rescue_handler.rb @@ -0,0 +1,16 @@ +module ControllerRescueHandler + extend ActiveSupport::Concern + + included do + # rescue_from ActionView::MissingTemplate, with: :object_not_found + # rescue_from ActiveRecord::RecordNotFound, with: :object_not_found + rescue_from Educoder::TipException, with: :tip_show + rescue_from ::ActionView::MissingTemplate, with: :missing_template + rescue_from ActiveRecord::RecordNotFound, with: :object_not_found + rescue_from ActionController::ParameterMissing, with: :render_parameter_missing + # form validation error + rescue_from ActiveModel::ValidationError do |ex| + render_error(ex.model.errors.full_messages.join(',')) + end + end +end \ No newline at end of file diff --git a/app/controllers/concerns/error_common.rb b/app/controllers/concerns/error_common.rb new file mode 100644 index 000000000..5a5f41673 --- /dev/null +++ b/app/controllers/concerns/error_common.rb @@ -0,0 +1,10 @@ +module ErrorCommon + extend ActiveSupport::Concern + + included do + rescue_from Exception do |e| + logger.error e + render json: {status: -1, message: e.message} + end + end +end \ No newline at end of file diff --git a/app/controllers/concerns/git_common.rb b/app/controllers/concerns/git_common.rb new file mode 100644 index 000000000..2f977245c --- /dev/null +++ b/app/controllers/concerns/git_common.rb @@ -0,0 +1,48 @@ +module GitCommon + + extend ActiveSupport::Concern + + included do + + end + + + # ------------------------ + # 版本库目录结构 + def repository + logger.info("ssssssseeeeeeee#{params}") + begin + @repo_url = repo_url @repo_path + @trees = GitService.file_tree(repo_path: @repo_path, path: @path) + logger.info("#11@@#@#@#@111#@@@@###{@trees}") + + # TPI(学员实训)不需要获取最近的一次提交 + if params[:controller] != "myshixuns" && @trees + logger.info("#@@#@#@#@#@@@@###{@trees.try(:count)}") + @latest_commit = [GitService.commits(repo_path: @repo_path).first] + Rails.logger.info("########## #{@latest_commit}") + end + rescue Exception => e + logger.error(e.message) + end + end + + def file_content + logger.info("#################{@repo_path}, #{@path}") + @content = git_fle_content @repo_path, @path + end + + # 版本库提交记录 + # Redo: commit接口需要按倒叙排列 + def commits + begin + @commits = GitService.commits(repo_path: @repo_path) + logger.info("git first commit is #{@commits.try(:first)}") + raise Educoder::TipException.new("请先创建版本库") if @commits.nil? + rescue Exception => e + uid_logger_error(e.message) + raise Educoder::TipException.new("提交记录异常") + end + end + +end \ No newline at end of file diff --git a/app/controllers/concerns/render_expand.rb b/app/controllers/concerns/render_expand.rb new file mode 100644 index 000000000..4fd77c285 --- /dev/null +++ b/app/controllers/concerns/render_expand.rb @@ -0,0 +1,20 @@ +module RenderExpand + extend ActiveSupport::Concern + + included do + ActionController.add_renderer :pdf do |template, options| + file = File.open(Rails.root.join('app/templates', template << '.html.erb')) + html = ERB.new(file.read).result(binding) + kit = PDFKit.new(html) + + base_css = %w(app/templates/shared/main.css) + base_css.each { |css| kit.stylesheets << Rails.root.join(css) } + + Array.wrap(options.delete(:stylesheets)).each do |path| + kit.stylesheets << Rails.root.join('app/templates', path) + end + + send_data kit.to_pdf, filename: options[:filename], type: 'application/pdf' + end + end +end \ No newline at end of file diff --git a/app/controllers/concerns/render_helper.rb b/app/controllers/concerns/render_helper.rb new file mode 100644 index 000000000..94ac351cd --- /dev/null +++ b/app/controllers/concerns/render_helper.rb @@ -0,0 +1,19 @@ +module RenderHelper + def render_ok(data = {}) + render json: { status: 0, message: 'success' }.merge(data) + end + + def render_error(message = '') + render json: { status: -1, message: message } + end + + def render_not_found(message = I18n.t('error.record_not_found')) + render json: { status: 404, message: message } + # render status: 404, json: { errors: errors } + end + + def render_forbidden(message = I18n.t('error.forbidden')) + render json: { status: 403, message: message } + # render status: 403, json: { errors: errors } + end +end \ No newline at end of file diff --git a/app/controllers/course_groups_controller.rb b/app/controllers/course_groups_controller.rb new file mode 100644 index 000000000..8b6737e0f --- /dev/null +++ b/app/controllers/course_groups_controller.rb @@ -0,0 +1,64 @@ +class CourseGroupsController < ApplicationController + before_action :require_login + before_action :set_group, except: [:create] + before_action :find_course, only: [:create] + before_action :teacher_allowed + + def create + tip_exception("分班名称不能为空") if params[:name].blank? + if @course.course_groups.where(name: params[:name]).count > 0 + normal_status(-1, "已存在同名分班") + else + @course.course_groups.create!(name: params[:name], position: @course.course_groups.count + 1) + normal_status(0, "创建成功") + end + end + + def destroy + ActiveRecord::Base.transaction do + begin + @course.course_groups.where("position > #{@group.position}").update_all("position = position - 1") + # 将该分班的学生转到未分班 + @group.course_members.update_all(course_group_id: 0) + @group.destroy + rescue Exception => e + uid_logger_error(e.message) + tip_exception("删除分班失败") + end + end + end + + # 分班重命名 + def rename_group + tip_exception("名称不能为空") if params[:name].blank? + if @course.course_groups.where(name: params[:name]).count > 0 + normal_status(-1, "已存在同名分班") + else + @group.update_attributes(name: params[:name].strip) + normal_status(0, "更新成功") + end + end + + # 分班的拖动 + def move_category + tip_exception("移动失败") if params[:position].blank? + unless params[:position].to_i == @group.position + if params[:position].to_i < @group.position + @course.course_groups.where("position < #{@group.position} and position >= ?", params[:position]).update_all("position = position + 1") + else + @course.course_groups.where("position > #{@group.position} and position <= ?", params[:position]).update_all("position = position - 1") + end + @group.update_attributes(position: params[:position]) + normal_status(0, "移动成功") + else + normal_status(-1, "位置没有变化") + end + end + + private + + def set_group + @group = CourseGroup.find_by!(id: params[:id]) + @course = @group.course + end +end diff --git a/app/controllers/course_modules_controller.rb b/app/controllers/course_modules_controller.rb new file mode 100644 index 000000000..d8d4ea128 --- /dev/null +++ b/app/controllers/course_modules_controller.rb @@ -0,0 +1,66 @@ +class CourseModulesController < ApplicationController + before_action :require_login + before_action :set_module, except: [:unhidden_modules] + before_action :find_course, only: [:unhidden_modules] + before_action :teacher_allowed + + # 模块置顶 + def sticky_module + # position为1则不做处理,否则该模块的position置为1,position小于当前模块的position加1 + unless @course_module.position == 1 + @course.course_modules.where("position < #{@course_module.position}").update_all("position = position + 1") + @course_module.update_attributes(position: 1) + end + normal_status(0, "置顶成功") + end + + # 模块隐藏 + def hidden_module + @course_module.update_attributes(hidden: 1) + normal_status(0, "更新成功") + end + + # 模块重命名 + def rename_module + name = params[:name].strip + tip_exception("名称不能为空") if name.blank? + tip_exception("已存在同名模块") if @course.course_modules.exists?(module_name: name) + @course_module.update_attributes(module_name: name) + + case @course_module.module_type + when 'board' + @course.course_board.update_columns(name: name) + end + normal_status(0, "更新成功") + end + + # 模块的显示 + def unhidden_modules + tip_exception("请选择要显示的模块") if params[:module_ids].blank? + @course.course_modules.where(id: params[:module_ids]).update_all(hidden: 0) + normal_status(0, "更新成功") + end + + # 添加二级目录 + def add_second_category + tip_exception("子目录名称不能为空") if params[:name].blank? + tip_exception("已存在同名子目录") if @course_module.course_second_categories.exists?(name: params[:name].strip) + ActiveRecord::Base.transaction do + begin + @course_module.course_second_categories.create!(name: params[:name].strip, category_type: @course_module.module_type, + course_id: @course.id, position: @course_module.course_second_categories.count + 1) + normal_status(0, "添加成功") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("添加子目录失败") + end + end + end + + private + + def set_module + @course_module = CourseModule.find_by!(id: params[:id]) + @course = @course_module.course + end +end diff --git a/app/controllers/course_second_categories_controller.rb b/app/controllers/course_second_categories_controller.rb new file mode 100644 index 000000000..d0f07f47f --- /dev/null +++ b/app/controllers/course_second_categories_controller.rb @@ -0,0 +1,60 @@ +class CourseSecondCategoriesController < ApplicationController + before_action :require_login + before_action :set_category + before_action :teacher_allowed + + # 目录重命名 + def rename_category + tip_exception("毕设子目录不能重命名") if @category.category_type == "graduation" + tip_exception("名称不能为空") if params[:name].blank? + tip_exception("已存在同名子目录") if @course_module.course_second_categories.exists?(name: params[:name].strip) + @category.update_attributes(name: params[:name].strip) + normal_status(0, "更新成功") + end + + # 子目录的拖动 + def move_category + tip_exception("移动失败") if params[:position].blank? + unless params[:position].to_i == @category.position + if params[:position].to_i < @category.position + @course_module.course_second_categories.where("position < #{@category.position} and position >= ?", params[:position]).update_all("position = position + 1") + else + @course_module.course_second_categories.where("position > #{@category.position} and position <= ?", params[:position]).update_all("position = position - 1") + end + @category.update_attributes(position: params[:position]) + normal_status(0, "移动成功") + else + normal_status(-1, "位置没有变化") + end + end + + def destroy + tip_exception("毕设子目录不能删除") if @category.category_type == "graduation" + ActiveRecord::Base.transaction do + begin + @course_module.course_second_categories.where("position > #{@category.position}").update_all("position = position - 1") + # 更新相应对象的子目录id + if @course_module.module_type == "shixun_homework" + @category.homework_commons.update_all(course_second_category_id: 0) + @right_url = "/courses/#{@course.id}/shixun_homeworks/#{@course_module.id}" + elsif @course_module.module_type == "attachment" + Attachment.where(course_second_category_id: @category.id).update_all(course_second_category_id: 0) + @right_url = "/courses/#{@course.id}/files/#{@course_module.id}" + end + + @category.destroy + rescue Exception => e + uid_logger_error(e.message) + tip_exception("删除子目录失败") + end + end + end + + private + + def set_category + @category = CourseSecondCategory.find_by!(id: params[:id]) + @course_module = @category.course_module + @course = @course_module.try(:course) + end +end diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb new file mode 100644 index 000000000..df23b6b25 --- /dev/null +++ b/app/controllers/courses_controller.rb @@ -0,0 +1,1322 @@ +class CoursesController < ApplicationController + include MessagesHelper + include ExportHelper + + rescue_from ::ActionView::MissingTemplate, with: :missing_template + rescue_from ActiveRecord::RecordNotFound, with: :object_not_found + # model validation error + rescue_from ActiveRecord::RecordInvalid do |ex| + render_error(ex.record.errors.full_messages.join(',')) + end + # form validation error + rescue_from ActiveModel::ValidationError do |ex| + render_error(ex.model.errors.full_messages.join(',')) + end + + before_action :require_login, except: [:index, :show, :students, :teachers, :board_list, :mine, :all_course_groups] + before_action :set_course, :user_course_identity, only: [:show, :update, :destroy, :settings, :set_invite_code_halt, + :set_public_or_private, :search_teacher_candidate, :teachers, + :top_banner, :left_banner, :add_teacher_popup, :add_teacher, + :graduation_group_list, :create_graduation_group, :join_graduation_group, + :course_group_list, :set_course_group, :change_course_admin, :change_course_teacher, + :delete_course_teacher, :teacher_application_review, :students, :all_course_groups, + :transfer_to_course_group, :delete_from_course, :search_users, :add_students_by_search, + :base_info, :get_historical_courses, :create_group_by_importing_file, + :attahcment_category_list,:export_member_scores_excel, :duplicate_course, + :switch_to_teacher, :switch_to_assistant, :switch_to_student, :exit_course] + before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate, + :transfer_to_course_group, :delete_from_course, + :search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup, :add_teacher] + before_action :admin_allowed, only: [:set_invite_code_halt, :set_public_or_private, + :set_course_group, :change_course_admin, :change_course_teacher, + :delete_course_teacher, :teacher_application_review, :create_group_by_importing_file] + before_action :teacher_or_admin_allowed, only: [:graduation_group_list, :create_graduation_group, :join_graduation_group, + :export_member_scores_excel, :course_group_list] + before_action :validate_course_name, only: [:create, :update] + before_action :find_board, only: :board_list + before_action :validate_page_size, only: :mine + + if RUBY_PLATFORM =~ /linux/ + require 'simple_xlsx_reader' + require 'roo-xls' + end + + # GET /courses + # GET /courses.json + def index + @user = current_user + # 根据分类查询课堂(全部,我的,最新,最热) + @order = params[:order].present? ? params[:order] : "all" + order_str = @order != "course_members_count" && @order != "created_at" ? "updated_at" : @order + + if @order == "all" + # @course = Course.where(is_delete: 0, is_hidden: 0).find_by_sql("select c.name, c.id, s.name, u.last_name from + # courses c, users u, user_extensions ue, schools s where c.is_delete=0 and c.tea_id=u.id and + # u.id=ue.user_id and ue.school_id=s.id limit 10;") + + @courses = Course.where(is_delete: 0, is_hidden: 0).select("courses.id, courses.tea_id, courses.name, courses.exercises_count, courses.polls_count, + courses.is_public, courses.is_end, courses.visits, courses.course_members_count,courses.homework_commons_count,(SELECT MAX(created_at) + FROM `course_activities` WHERE course_activities.course_id = courses.id) AS a") + .order("courses.id = 1309 desc, a desc") + elsif @order == "mine" + @courses = Course.joins(:course_members) + .where("is_delete = 0 AND is_hidden = 0 AND course_members.user_id = ?", @user.id) + .order("courses.id = 1309 DESC, courses.#{order_str} DESC") + elsif @order == "created_at" + # REDO:Extension + @courses = Course.joins(teacher: :user_extension) + .where(is_delete: 0, is_hidden: 0, is_end: 0) + .order("courses.id = 1309 DESC, courses.#{order_str} DESC") + else + # REDO:Extension + @courses = Course.joins(teacher: :user_extension) + .where(is_delete: 0, is_hidden: 0) + .order("courses.id = 1309 DESC, courses.#{order_str} DESC") + end + + # 根据搜索关键字进一步筛选 + if params[:search].present? + # REDO:Extension + user_ids = User.includes(user_extension: :school).where("schools.name like ?", "%#{params[:search]}%").pluck(:id) + course_ids = CourseMember.includes(:user, :course).where("course_members.course_id in (?) and course_members.role in (1,2,3) + and CONCAT(users.lastname, users.firstname) like ?", @courses.map(&:id), "%#{params[:search]}%") + .pluck(:course_id) + @courses = @courses.where("name like ?", "%#{params[:search]}%").or(@courses.where(tea_id: user_ids)).or(@courses.where(id: course_ids)) + end + @courses_count = @courses.size + + # 分页 + page = params[:page] || 1 + limit = params[:limit] || 16 + + @courses= @courses.page(page).per(limit) + end + + def visits_plus_one + new_visits = @course.visits + 1 + @course.update_visits(new_visits) + normal_status("成功") + end + + # GET /courses/1 + # GET /courses/1.json + def show + end + + # GET /courses/new + def new + @course = Course.new + end + + # Get /courses/:id/settings + # Edit Page + def settings + end + + # POST /courses + # POST /courses.json + def create + ActiveRecord::Base.transaction do + begin + @course = Course.new(name: params[:name], class_period: params[:class_period], credit: params[:credit], + end_date: params[:end_date], is_public: params[:is_public], school_id: @school.id, + authentication: params[:authentication], professional_certification: params[:professional_certification]) + @course.tea_id = current_user.id + + @course_list_name = params[:course_list_name].strip + @course_list = CourseList.find_by(name: @course_list_name) + if @course_list + @course.course_list_id = @course_list.id + else + new_course_list = CourseList.create!(name: @course_list_name, user_id: current_user.id, is_admin: 0) + @course.course_list_id = new_course_list.id + end + + @course.is_end = @course.end_date.present? && @course.end_date < Date.today + + if @course.save! + @course.generate_invite_code + CourseInfo.create!(user_id: current_user.id, course_id: @course.id) + CourseMember.create!(course_id: @course.id, user_id: current_user.id, role: 1) + + course_module_types = params[:course_module_types] + @course.create_course_modules(course_module_types) + end + rescue => e + uid_logger_error(e.message) + tip_exception("课堂创建失败!") + raise ActiveRecord::Rollback + end + end + end + + # PATCH/PUT /courses/1 + # PATCH/PUT /courses/1.json + def update + ActiveRecord::Base.transaction do + begin + extra_params = Hash.new + extra_params[:school_id] = @school.id + extra_params[:is_public] = params[:is_public].present? ? params[:is_public] : 0 + + if @course.is_end && (course_params[:end_date].nil? || course_params[:end_date].to_date > Date.today) + extra_params[:is_end] = 0 + elsif !@course.is_end && !course_params[:end_date].blank? && course_params[:end_date].to_date < Date.today + extra_params[:is_end] = 1 + end + + extra_params[:authentication] = params[:authentication] + extra_params[:professional_certification] = params[:professional_certification] + + @course_list_name = params[:course_list_name].strip + @course_list = CourseList.find_by(name: @course_list_name) + if @course_list + extra_params[:course_list_id] = @course_list.id + else + new_course_list = CourseList.create(name: @course_list_name, user_id: current_user.id, is_admin: 0) + extra_params[:course_list_id] = new_course_list.id + end + + @course.update_attributes!(course_params.merge(extra_params)) + @course.update_course_modules(params[:course_module_types]) + + normal_status(0, "成功") + rescue => e + uid_logger_error(e.message) + tip_exception("课堂更新失败") + raise ActiveRecord::Rollback + end + end + end + + def search_course_list + search = params[:search] ? "%#{params[:search].strip}%" : "%%" + @course_lists = CourseList.where("name like ?", "#{search}") + @search_count = @course_lists.size + end + + # 邀请码停用/启用 + def set_invite_code_halt + begin + @course.update_attribute('invite_code_halt', @course.invite_code_halt == 0 ? 1 : 0) + normal_status(0, "成功") + rescue => e + uid_logger_error(e.message) + tip_exception("停用/启用课堂失败") + end + end + + # 设置课堂私有/公有 + def set_public_or_private + begin + @course.update_attribute('is_public', @course.is_public == 1 ? 0 : 1) + normal_status(0, "成功") + rescue => e + uid_logger_error(e.message) + tip_exception("设置课堂公有/私有失败") + end + end + + # DELETE /courses/1 + # DELETE /courses/1.json + def destroy + if @course.is_delete == 0 + @course.delete! + normal_status(0, "成功") + else + normal_status(-1, "课堂已删除,无需重复操作") + end + end + + # 课堂的基本信息 + def base_info + + end + + # --- 教师列表相关API --- START + + # 教师列表以及教师搜索 + def teachers + @search_str = params[:search].present? ? params[:search].strip : "" + + if @course.try(:id) != 1309 || current_user.admin? || current_user.try(:id) == 15582 + @teacher_list = @course.course_members.joins(:user).where("course_members.role in (1, 2, 3) + and LOWER(concat(users.lastname, users.firstname)) LIKE '%#{@search_str}%'") + else + @teacher_list = @course.course_members.joins(:user).where("(course_members.role in (1, 3) or (course_members.user_id = #{current_user.id} + and course_members.role = 2)) and LOWER(concat(users.lastname, users.firstname)) + LIKE '%#{@search_str}%'") + end + + @teacher_list_size = @teacher_list.size + + @has_graduation_design = @course.course_modules.graduation_module_not_hidden.any? + + @order = params[:order].to_i + if @order.present? + case @order + when 1 + @teacher_list = @teacher_list.includes(:user).order("CONVERT(CONCAT(users.lastname, users.firstname) USING gbk) COLLATE gbk_chinese_ci asc") + when 2 + @teacher_list = @teacher_list.order("created_at") + when 3 + @teacher_list = @teacher_list.includes(:course, :graduation_group).order("graduation_groups.name") + else + @teacher_list = @teacher_list.order("created_at") + end + else + if @has_graduation_design + @teacher_list = @teacher_list.includes(:course, :graduation_group).order("graduation_groups.name") + else + @teacher_list = @teacher_list.order("created_at") + end + end + + @is_admin = current_user.creator_of_course? @course + + @applications= CourseMessage.unhandled_join_course_requests_by_course(@course) + + page = params[:page] || 1 + limit = params[:limit] || 20 + @teacher_list = @teacher_list.page(page).per(limit) + end + + # 打开添加教师或助教弹窗时访问的接口(需要返回该课堂所有答辩组和所有) + def add_teacher_popup + @graduation_groups = @course.graduation_groups + @course_groups = @course.course_groups + @school_name = School.find(current_user.school_id).try(:name) + end + + # 添加教师或助教弹窗中的搜索接口 + def search_teacher_candidate + name = params[:name] + school_name = params[:school_name] + + # user_ids_of_course_members = @course.course_members.where(role: [1,2,3]).pluck(:user_id) + # @users = User.where.not(id: user_ids_of_course_members) + + @users = User.where(status: User::STATUS_ACTIVE) + @users = @users.where("concat(users.firstname, users.lastname) like '%#{name}%'") if name.present? + # REDO:Extension + @users = @users.joins(user_extension: :school).where("schools.name like '%#{school_name}%'") if school_name.present? + + @users_size = @users.size + + page = params[:page] || 1 + limit = params[:limit] || 10 + @users = @users.page(page).per(limit) + end + + # 添加教师或者助教 + def add_teacher + ActiveRecord::Base.transaction do + begin + @user_list = params[:user_list].present? ? params[:user_list] : [] + return tip_exception("请先选择成员") if @user_list.blank? + + @graduation_group_id = params[:graduation_group_id].present? ? GraduationGroup.find(params[:graduation_group_id]).id : 0 + + @course_group_id = params[:course_group_id].present? ? CourseGroup.find(params[:course_group_id]).id : 0 + + role = params[:role].to_i + + teacher_ids = [] + @user_list.each do |user| + active_student_exist = CourseMember.where(user_id: user[:user_id], role: 4, course_id: @course.id, is_active: 1).any? + is_active = active_student_exist ? 0 : 1 + user_id = User.find(user[:user_id]).id + existing_teacher = CourseMember.find_by(course_id: @course.id, user_id: user_id, role: role) + if existing_teacher.blank? + teacher_ids << user_id + member = CourseMember.create(course_id: @course.id, graduation_group_id: @graduation_group_id, user_id: user_id, role: role, is_active: is_active) + + member.teacher_course_groups << TeacherCourseGroup.new(course_group_id: @course_group_id, user_id: user_id, course_id: @course.id) if @course_group_id != 0 + end + end + TeacherInviteJoinCourseNotifyJob.perform_later(current_user.id, @course.id, role, teacher_ids) if teacher_ids.present? + normal_status(0, "添加成功") + rescue => e + uid_logger_error(e.message) + tip_exception(-1, "添加失败") + raise ActiveRecord::Rollback + end + end + end + + # 获取当前课堂的所有答辩组 + def graduation_group_list + @graduation_group_list = @course.graduation_groups + end + + # 给当前课堂增加答辩组 + def create_graduation_group + begin + if params[:name].present? + identical_exist = GraduationGroup.where(course_id: @course.id, name: params[:name]).any? + if identical_exist + normal_status(-1, "已存在同名答辩组") + else + GraduationGroup.create(course_id: @course.id, user_id: current_user.id, name: params[:name]) + normal_status(0, "成功") + end + else + tip_exception(-1, "答辩组名称不能为空") + end + rescue => e + uid_logger_error(e.message) + tip_exception(-1, "添加失败") + raise ActiveRecord::Rollback + end + end + + # 将教师加入答辩组 + def join_graduation_group + ActiveRecord::Base.transaction do + begin + @course_member_list = params[:course_member_list].present? ? params[:course_member_list] : [] + + graduation_group_id = GraduationGroup.find(params[:graduation_group_id].to_i).id + @course_member_list.each do |course_member| + course_member = CourseMember.find(course_member[:course_member_id].to_i) + course_member.update_attributes(graduation_group_id: graduation_group_id) + end + normal_status(0, "成功") + rescue => e + uid_logger_error(e.message) + tip_exception(-1, "加入失败") + raise ActiveRecord::Rollback + end + end + end + + # 获取当前课堂的所有分班, 以及当前教师是否对分班具有管理权限的状态 + def course_group_list + course_member_id = params[:course_member_id] + user_id = params[:user_id] + + @existed_course_group_ids = TeacherCourseGroup.where(course_id: @course.id, course_member_id: course_member_id, user_id: user_id) + .pluck(:course_group_id) + @all_course_groups = CourseGroup.where(course_id: @course.id) + end + + # 设置教师的管理权限(即设置该教师所能管理的分班) + def set_course_group + ActiveRecord::Base.transaction do + begin + course_group_ids = params[:course_group_ids] + user_id = User.find(params[:user_id].to_i).id + course_member_id = CourseMember.find(params[:course_member_id]).id + + teacher_course_groups = TeacherCourseGroup.where(course_id: @course.id, user_id: user_id, course_member_id: course_member_id) + teacher_course_groups.destroy_all + + course_group_ids.each do |course_group_id| + course_group_id = CourseGroup.where(id: course_group_id.to_i, course_id: @course.id).first.id + TeacherCourseGroup.create(course_id: @course.id, user_id: user_id, course_member_id: course_member_id, course_group_id: course_group_id) + end + normal_status(0, "成功") + rescue => e + uid_logger_error(e.message) + tip_exception( "分配管理权限失败") + raise ActiveRecord::Rollback + end + end + end + + # 变更管理员 + def change_course_admin + ActiveRecord::Base.transaction do + begin + new_admin_user = User.find(params[:user_id].to_i) + new_admin = CourseMember.find_by!(id: params[:course_member_id].to_i, course_id: @course.id, user_id: new_admin_user.id) + current_admin = CourseMember.find_by!(course_id: @course.id, role: 1) + + new_admin.CREATOR! + current_admin.PROFESSOR! + + @course.update_attributes!(tea_id: new_admin_user.id) + normal_status(0, "变更管理员成功") + rescue => e + uid_logger_error(e.message) + tip_exception( "变更管理员失败") + raise ActiveRecord::Rollback + end + end + end + + # 教师和助教角色转换的接口 + def change_course_teacher + begin + course_member = CourseMember.find_by!(id: params[:course_member_id].to_i, course_id: @course.id) + if course_member.PROFESSOR? + course_member.ASSISTANT_PROFESSOR! + elsif course_member.ASSISTANT_PROFESSOR? + course_member.PROFESSOR! + else + tip_exception( "变更教师/助教失败") + end + course_member.save! + normal_status(0, "变更教师/助教成功") + rescue => e + uid_logger_error(e.message) + tip_exception( "变更教师/助教失败") + end + end + + # 删除教师或助教 + def delete_course_teacher + begin + course_member = CourseMember.find_by!(id: params[:course_member_id].to_i, course_id: @course.id) + tip_exception("删除失败") if course_member.CREATOR? or course_member.STUDENT? + + course_student = CourseMember.find_by(id: course_member.user_id, course_id: @course.id, role: %i[STUDENT]) + course_member.destroy! + course_student.update_attributes(is_active: 1) if course_student.present? && !course_student.is_active + normal_status(0, "删除成功") + rescue => e + uid_logger_error(e.message) + tip_exception("删除失败") + end + end + + # 切换为教师 + def switch_to_teacher + begin + course_member = @course.course_members.find_by!(user_id: current_user.id, is_active: 1) + tip_exception("切换失败") unless course_member.STUDENT? + + course_teacher = CourseMember.find_by!(user_id: current_user.id, role: %i[CREATOR PROFESSOR], course_id: @course.id) + course_member.update_attributes(is_active: 0) + course_teacher.update_attributes(is_active: 1) + normal_status(0, "切换成功") + rescue => e + uid_logger_error(e.message) + tip_exception("切换失败") + end + end + + # 切换为助教 + def switch_to_assistant + begin + course_member = @course.course_members.find_by!(user_id: current_user.id, is_active: 1) + tip_exception("切换失败") unless course_member.STUDENT? + + course_teacher = CourseMember.find_by!(user_id: current_user.id, role: %i[ASSISTANT_PROFESSOR], course_id: @course.id) + course_member.update_attributes(is_active: 0) + course_teacher.update_attributes(is_active: 1) + normal_status(0, "切换成功") + rescue => e + uid_logger_error(e.message) + tip_exception("切换失败") + end + end + + # 切换为学生 + def switch_to_student + ActiveRecord::Base.transaction do + begin + course_member = @course.course_members.find_by!(user_id: current_user.id, is_active: 1) + tip_exception("切换失败") if course_member.STUDENT? + + course_student = CourseMember.find_by!(user_id: current_user.id, role: %i[STUDENT], course_id: @course.id) + course_member.update_attributes(is_active: 0) + course_student.update_attributes(is_active: 1) + normal_status(0, "切换成功") + rescue => e + uid_logger_error("switch_to_student error: #{e.message}") + tip_exception("切换失败") + raise ActiveRecord::Rollback + end + end + end + + def exit_course + course_student = CourseMember.find_by!(user_id: current_user.id, role: %i[STUDENT], course_id: @course.id) + tip_exception("非课堂学生无法退出课堂") unless course_student.STUDENT? + # 课堂如果还有其他身份的用户则更新is_active + course_teacher = CourseMember.find_by(user_id: current_user.id, role: %i[CREATOR PROFESSOR ASSISTANT_PROFESSOR], course_id: @course.id) + course_student.destroy! + course_teacher.update_attributes(is_active: 1) if course_teacher.present? && !course_teacher.is_active + normal_status(0, "退出成功") + end + + # 教师申请加入课堂的审批 + def teacher_application_review + ActiveRecord::Base.transaction do + begin + course_message = CourseMessage.find_by!(id: params[:application_id].to_i, course_id: @course.id) + course_message.apply_user_id = current_user.id + applier_user = User.find_by!(id: params[:user_id].to_i) + + approval = params[:approval].to_i + if approval == 1 + course_message.pass! + + new_teacher = CourseMember.new(course_id: @course.id, user_id: applier_user.id) + content = course_message.content.to_i + if content == 3 || content == 7 + tip_exception("已存在教师/助教身份") if CourseMember.where(course_id: @course.id, user_id: applier_user.id, role: 3).any? + new_teacher.ASSISTANT_PROFESSOR! + elsif content == 2 || content == 9 + tip_exception("已存在教师/助教身份") if CourseMember.where(course_id: @course.id, user_id: applier_user.id, role: 2).any? + new_teacher.PROFESSOR! + else + tip_exception("申请角色错误") + end + + new_teacher.save! + elsif approval == 2 + course_message.reject! + else + tip_exception("参数错误") + end + course_message.save! + normal_status(0, "操作成功") + rescue => e + uid_logger_error(e.message) + tip_exception("操作失败") + raise ActiveRecord::Rollback + end + end + end + + # 已通过职业认证的教师复制课堂 + def duplicate_course + return tip_exception("没有复制权限") unless current_user.admin? || current_user.is_teacher? || current_user.teacher_of_course?(@course) + return tip_exception("教师职业认证未通过") unless current_user.pro_certification? + + new_course = @course.self_duplicate + render json: {new_course_id: new_course.id} + end + # --- 教师列表相关API --- END + + # --- 学生列表相关API --- START + + # 学生列表(包括各个子分班的学生列表)及搜索 + def students + search = params[:search].present? ? params[:search].strip : nil + order = params[:order].present? ? params[:order].to_i : 0 + course_group_id = params[:course_group_id].present? ? params[:course_group_id].to_i : nil + + @students = CourseMember.students(@course) + if search.present? + # REDO:Extension + @students = @students.joins(user: :user_extension).where("LOWER(CONCAT(users.lastname, users.firstname)) like ? or + user_extensions.student_id like ?", "%#{search}%", "%#{search}%") + end + + if order == 1 + # REDO:Extension + @students = @students.includes(user: :user_extension).order("user_extensions.student_id") + elsif order == 2 + @students = @students.includes(:course_group).order("course_groups.position") + else + # REDO:Extension + @students = @students.includes(user: :user_extension).order("user_extensions.student_id") + end + + if course_group_id.present? + @students = @students.where(course_group_id: course_group_id) + @course_group = CourseGroup.find(course_group_id) if course_group_id != 0 + end + + @students_count = @students.size + + page = params[:page] || 1 + limit = params[:limit] || 20 + @students= Kaminari.paginate_array(@students).page(page).per(limit) + end + + # 获取当前课程所有分班 + def all_course_groups + if params[:all] # 返回所有分班 + @course_groups_array = @course.course_groups.to_a + else # 返回权限下的分班 + charge_group_ids = @course.charge_group_ids(current_user) + @course_groups_array = @course.course_groups.where(id: charge_group_ids).to_a + end + + current_course_group_id = params[:course_group_id] + + if current_course_group_id.present? + current_course_group = CourseGroup.find(current_course_group_id) + @course_groups_array.delete(current_course_group) + end + end + + # 将学生批量移动到某个分班 + def transfer_to_course_group + ActiveRecord::Base.transaction do + begin + course_group_id = params[:course_group_id].to_i + + # course_group_id为0意味着移动学生到未分班 + if course_group_id != 0 + course_group = CourseGroup.find_by!(id: course_group_id, course_id: @course.id) + course_group_id = course_group.id + end + + @course.students.where(id: params[:students].pluck(:course_member_id)).each do |student| + student.update_attributes!(course_group_id: course_group_id) + end + normal_status(0, "操作成功") + rescue => e + uid_logger(e.message) + tip_exception("操作失败") + raise ActiveRecord::Rollback + end + end + end + + # 从当前课堂删除学生 + def delete_from_course + ActiveRecord::Base.transaction do + begin + students = params[:students] + + students.each do |student| + course_member = CourseMember.find_by!(id: student[:course_member_id].to_i, course_id: @course.id) + course_member.destroy! + end + normal_status(0, "操作成功") + rescue => e + uid_logger(e.message) + tip_exception("操作失败") + raise ActiveRecord::Rollback + end + end + end + + # 搜索添加学生 + def add_students_by_search + ActiveRecord::Base.transaction do + begin + user_ids = params[:user_ids] + course_group_id = params[:course_group_id].to_i + if course_group_id != 0 + course_group = CourseGroup.find(course_group_id) + course_group_id = course_group.id + end + + student_ids = [] + user_ids.each do |user_id| + existing_course_member = CourseMember.find_by(user_id: user_id.to_i, course_id: @course.id) + new_student = CourseMember.new(user_id: user_id.to_i, course_id: @course.id, course_group_id: course_group_id, role: 4) + + if existing_course_member.present? + if existing_course_member.STUDENT? + existing_course_member.update_attributes(course_group_id: course_group_id) + else + new_student.is_active = 0 if existing_course_member.is_active + new_student.save! + end + else + new_student.save! + student_ids << user_id + end + end + + TeacherInviteJoinCourseNotifyJob.perform_later(current_user.id, @course.id, 10, student_ids) if student_ids.present? + normal_status(0, "添加成功") + rescue => e + uid_logger(e.message) + tip_exception("添加失败") + raise ActiveRecord::Rollback + end + end + end + + # 获取历史课堂,即用户管理的所有课堂以及课堂下的分班 + def get_historical_courses + user_id = current_user.id + + @courses = Course.includes(:course_groups).where(tea_id: user_id, is_delete: 0) + end + + # 根据历史课堂的课堂id和分班id获取所有学生 + def get_historical_course_students + course_id = params[:course_id] + course_group_id = params[:course_group_id] + + @students = CourseMember.where(course_id: course_id, role: %i[STUDENT]) + if course_group_id.present? + @students = @students.where(course_group_id: course_group_id) + end + + @students_count = @students.size + end + + # 导入创建分班 + def create_group_by_importing_file + attachment_ids = [] + + params[:attachment_ids].each do |id| + attachment = Attachment.find(id.to_i) + attachment_ids << attachment.id + end + associate_result = Attachment.associate_container(attachment_ids, @course.id, @course.class) + return normal_status("参数错误") unless associate_result + + attachment_ids.each do |attachment_id| + attachment = Attachment.find attachment_id + + path = attachment.disk_directory + name = attachment.disk_filename + if name.split(".").last == "xls" + begin + attachment_folder = Rails.configuration.educoder['attachment_folder'] + full_path = "#{attachment_folder}/#{path}/#{name}" + xls = Roo::Spreadsheet.open(full_path, extension: :xls) + worksheet = xls.sheet(0) + rows = worksheet.last_row.to_i #最后一行数 + if rows < 2 + return normal_status(-1, "请按照模板格式导入") + else + group_count = 0 + (2..rows).each do |row| + name = worksheet.cell(row, 1).to_s + + if @course.course_groups.where(:name => name).blank? + @course.course_groups << CourseGroup.new(:name => name) + group_count += 1 + end + end + return normal_status("已导入#{group_count}个分班") + end + rescue => e + uid_logger_error(e.message) + normal_status(-1, "无法完成导入,原因:文件内容无法读取") + end + end + end + end + + # --- 学生列表相关API --- END + + # 根据姓名和单位搜索用户 + def search_users + name = params[:name] + school_name = params[:school_name] + + # REDO:Extension + @users = User.joins(user_extension: :school) + .where("CONCAT(users.lastname, users.firstname) like ? and schools.name like ?", "%#{name}%", "%#{school_name}%") + + @users_count = @users.size + + limit = params[:limit] || 20 + page = params[:page] || 1 + @users = @users.page(page).per(limit) + end + + # 申请加入课堂 + def apply_to_join_course + ActiveRecord::Base.transaction do + begin + + # 邀请码验证 + return normal_status(-1, "邀请码不能为空") if params[:invite_code].blank? + invite_code = params[:invite_code] + course = Course.find_by(invite_code: invite_code, is_delete: 0, invite_code_halt: 0, is_end: 0) + course_group = CourseGroup.find_by(invite_code: invite_code) + if course.blank? + return normal_status(-1, "邀请码无效") if course_group.blank? + + course = Course.find_by(id: course_group.course_id, is_delete: 0, invite_code_halt: 0, is_end: 0) + return normal_status(-1, "邀请码无效") if course.blank? + end + + # 实名认证和职业认证的身份判断 + return normal_status(-1, "该课堂要求成员完成实名和职业认证") if course.authentication && + course.professional_certification && (!current_user.authentication || !current_user.professional_certification) + return normal_status(-1, "该课堂要求成员完成实名认证") if course.authentication && !current_user.authentication + return normal_status(-1, "该课堂要求成员完成职业认证") if course.professional_certification && !current_user.professional_certification + + # 身份验证 + if params[:professor].blank? && params[:assistant_professor].blank? && params[:student].blank? + return normal_status(-1, "请先选择身份") + end + if params[:professor].present? && params[:assistant_professor].present? + return normal_status(-1, "同一课堂不允许申请多个教师身份") + end + + # 创建学生身份 + if params[:student].present? + existing_student = CourseMember.find_by(course_id: course.id, role: %i[STUDENT], user_id: current_user.id) + if existing_student.present? + # 如果在该课堂已经存在学生身份,且邀请码为分班邀请码,则将其直接加入分班 + existing_student.update_attributes(course_group_id: course_group.id) if course_group.present? + else + correspond_teacher_exist = current_user.teacher_of_course? course + new_student = CourseMember.new(user_id: current_user.id, course_id: course.id, role: 4) + new_student.is_active = 0 if correspond_teacher_exist + + new_student.course_group_id = course_group.id if course_group.present? + new_student.save! + + StudentJoinCourseNotifyJob.perform_later(current_user.id, course.id) + end + end + + # 创建教师身份 + if params[:professor].present? || params[:assistant_professor].present? + teacher_already_exist = current_user.teacher_of_course_non_active? course + unless teacher_already_exist + existing_course_message = CourseMessage.find_by(course_id: course.id, course_message_id: current_user.id, + course_message_type: "JoinCourseRequest", status: 0, viewed: false) + if existing_course_message.blank? + course_message = CourseMessage.new(course_id: course.id, user_id: course.tea_id, status: 0, + course_message_id: current_user.id, course_message_type: "JoinCourseRequest", + viewed: false) + course_message.content = 2 if params[:professor].present? + course_message.content = 3 if params[:assistant_professor].present? + + course_message.save! + + role = course_message.content == 2 ? '7' : '9' # 7:老师 9:助教 + ApplyTeacherRoleJoinCourseNotifyJob.perform_later(current_user.id, course.id, role) + end + end + end + + if current_user.student_of_course?(course) || current_user.teacher_of_course?(course) + render json: { status: 0, message: "成功", course_id: course.id} + else + normal_status("申请已提交,请等待审核") + end + rescue => e + uid_logger(e.message) + tip_exception("加入课堂失败") + raise ActiveRecord::Rollback + end + end + end + + def top_banner + @user = current_user + @is_teacher = @user.teacher_of_course?(@course) + @is_student = @course.course_members.where(user_id: @user.id, role: 4, is_active: 1).present? + @course.increment!(:visits) + end + + def left_banner + @user = current_user + @is_teacher = @user.teacher_of_course?(@course) + @course_modules = @course.course_modules.where.not(module_type: "activity").where(hidden: 0) + @hidden_modules = @course.course_modules.where(hidden: 1) + @second_category_type = ["shixun_homework", "graduation", "attachment", "board", "course_group"] + end + + def board_list + begin + @course = @board.course + @current_user = current_user + return normal_status(403, "你没有权限操作") if !@current_user.teacher_of_course?(@course) && !@current_user.course_identity(@current_user) == 4 + @boards = @course.boards + rescue Exception => e + uid_logger(e.message) + tip_exception("获取数据失败") + raise ActiveRecord::Rollback + end + end + + def attahcment_category_list + @has_course_groups = @course.course_groups.exists? + @course_modules = @course.attachment_course_modules + end + + def mine + @page = params[:page] || 1 + @page_size = params[:page_size] || 15 + + @courses = Course.by_user(current_user).hidden(false).ended(false).deleted(0).by_keywords(params[:search]).distinct + + # @total_count = @courses.count + # offset = 0 + # while offset < @total_count + # + # offset = offset + @page_size.to_i + 1 + # @courses = @courses.offset(offset) + # end + + @courses= @courses.page(@page).per(@page_size) + end + + def export_member_scores_excel + ActiveRecord::Base.transaction do + begin + name = params[:name] ? "#{params[:name].strip}" : "" #用户名或学生学号id搜索 + group_id = params[:group_id] #分班的班级id + if group_id && group_id != "0" && group_id != "-1" + @all_members = @course.students.course_find_by_ids("course_group_id",group_id) + elsif group_id && group_id == "0" # 未分班 + @all_members = @course.course_members.ungroup_students + else + @all_members = @course.students + end + if name.present? + nick_name_search = @all_members.joins(:user).where("nickname like ?","%#{name}%") + if nick_name_search.present? + @all_members = nick_name_search + else + @all_members = @all_members.joins(user: [:user_extension]).where('user_extensions.student_id like ? OR user_extensions.student_realname like ?',"%#{name}%","%#{name}%") + end + end + + @c_homeworks = @course.homework_commons.homework_published.order("publish_time asc, created_at asc") + @c_exercises = @course.exercises.is_exercise_published.order("publish_time asc, created_at asc") + @c_polls = @course.polls.publish_or_not.order("publish_time asc, created_at asc") + @c_tasks = @course.graduation_tasks.task_published.order("publish_time asc, created_at asc") + if @user_course_identity > Course::ASSISTANT_PROFESSOR + tip_exception(403,"无权限操作") + else + member_to_xlsx(@course,@all_members,@c_homeworks,@c_exercises,@c_tasks,@c_polls) + filename = current_user.real_name + "_" + @course.name + "_全部成绩" + Time.now.strftime('%Y%m%d_%H%M%S') + render xlsx: "#{filename.strip.first(30)}",template: "courses/export_member_scores_excel.xlsx.axlsx", + locals: {course_info:@course_info, activity_level:@user_activity_level, + course_scores:@course_user_scores,shixun_works:@shixun_work_arrays, + common_works:@common_work_arrays,group_works:@group_work_arrays,task_works:@task_work_arrays, + exercise_works:@exercise_work_arrays} + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + private + + # Use callbacks to share common setup or constraints between actions. + def set_course + @course = Course.find_by!(id: params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def course_params + params.require(:course).permit(:name, :class_period, :credit, :end_date, :is_public, :authentication, :professional_certification) + end + + def validate_course_name + tip_exception("课堂名称不能为空!") if params[:course][:name].blank? + tip_exception("课程名称不能为空!") if params[:course_list_name].blank? + tip_exception("课堂名称应以课程名称开头命名") unless params[:course][:name].index(params[:course_list_name]) && + params[:course][:name].index(params[:course_list_name]) == 0 + tip_exception("课堂所属单位不能为空!") if params[:school].blank? + @school = School.find_by!(name: params[:school].strip) + end + + # 超级管理员和课堂管理员的权限判断 + def admin_allowed + unless @user_course_identity < Course::PROFESSOR + tip_exception(403, "..") + end + end + + # 课堂教师的权限判断 + def teacher_allowed + unless @user_course_identity < Course::STUDENT + tip_exception(403, "..") + end + end + + # 课堂教师,课堂管理员以及超级管理员的权限判断 + def teacher_or_admin_allowed + unless @user_course_identity < Course::ASSISTANT_PROFESSOR + tip_exception(403, "..") + end + end + + def member_to_xlsx(course,all_members,homeworks,exercises,tasks,polls) + #课堂的作业信息 + shixun_homeworks = homeworks.search_homework_type(4) #全部实训作业 + shixun_titles = shixun_homeworks.pluck(:name) + ["总得分"] + common_homeworks = homeworks.search_homework_type(1) #全部普通作业 + common_titles = common_homeworks.pluck(:name)+ ["总得分"] + group_homeworks = homeworks.search_homework_type(3) #全部分组作业 + group_titles = group_homeworks.pluck(:name)+ ["总得分"] + task_titles = tasks.pluck(:name)+ ["总得分"] + exercise_titles = exercises.pluck(:exercise_name)+ ["总得分"] + total_user_score_array = [] #学生总成绩集合 + + #课堂信息 + @course_info = [] + course_info_title = "课堂信息概要" + course_id = course.id + course_name = course.name + course_list_name = course.course_list.present? ? course.course_list.name : "--" + course_assistants = course.course_members.course_user_role(%i[PROFESSOR ASSISTANT_PROFESSOR]) + course_assistants_count = course_assistants&.count + course_assistants_name = course_assistants_count > 0 ? course_assistants.map{|m| m.user.real_name}.join('、') : "--" + course_teacher_member = course.course_members.course_user_role(%i[CREATOR]) + course_teacher = course_teacher_member.present? ? course_teacher_member.first.user.real_name : "--" + course_class_counts = course.course_groups_count + course_students_count = course.students.count + course_1 = ["课堂编号",course_id] + course_2 = ["课程名称",course_list_name] + course_3 = ["课堂名称",course_name] + course_4 = ["教师团队(#{course_assistants_count})", course_assistants_name] + course_5 = ["主讲教师", course_teacher] + course_6 = ["分班",course_class_counts] + course_7 = ["学生", course_students_count] + course_main_info = [course_1,course_2,course_3,course_4,course_5,course_6,course_7] + course_group_info_head = %w(序号 分班名称 邀请码 学生数量) + course_group_info_body = [] + if course.course_groups.present? + course.course_groups.each_with_index do |group, index| + group_index = (index+1) + group_name = group.name + group_code = group.invite_code + group_count = group.course_members_count + group_array = [group_index,group_name,group_code,group_count] + course_group_info_body.push(group_array) + end + end + course_group_info = [course_group_info_head,course_group_info_body] + @course_info += [course_info_title,course_main_info,course_group_info] + + #课堂活跃度 + course_homework_ids = homeworks.pluck(:id) #该课堂的全部作业id + course_graduate_task_ids = tasks.pluck(:id) #该课堂的全部毕业任务id + course_exercise_ids = exercises.pluck(:id) #课堂的全部试卷数 + course_poll_ids = polls.pluck(:id) #课堂的全部问卷数 + course_board_ids = course.boards.pluck(:id) #课堂的全部讨论区 + @user_activity_level = [] + course_user_level = [] + course_activity_title = "课堂活跃度统计" + user_cell_head = %w(排名 真实姓名 登录名 邮箱 学号 分班 作业完成数(*10) 试卷完成数(*10) 问卷完成数(*7) 资源发布数(*5) 帖子发布数(*2) 帖子回复数(*1) 作业回复数(*1) 活跃度) + all_members.each do |u| + #用户的基本信息 + user = u.user + user_login = user.login + user_name = user.real_name + user_mail = user.mail + user_stu_id = user.student_id.present? ? (user.student_id.to_s + "\t") : "--" + user_course_group = u.course_group_name + user_info_array = [user_login,user_name,user_mail,user_stu_id,user_course_group] #用户的信息集合 + user_work_scores = [] + + #课堂活跃度统计 + user_homeworks_num = user.student_works.find_by_homework(course_homework_ids).has_committed.count #完成的作业数 + user_graduate_num = user.graduation_works.find_by_task(course_graduate_task_ids).has_committed.count #毕业任务完成数 + user_exercise_num = user.exercise_users.search_by_exercise(course_exercise_ids).commit_exercise_by_status(1).count #根据试卷的id来查找 + user_poll_num = user.poll_users.search_by_poll(course_poll_ids).commit_by_status(1).count #已完成问卷 + user_file_num = user.attachments.search_by_container(course.id).count + user_messages = user.messages + user_messages_num = user_messages.root_nodes.find_by_boards(course_board_ids).count #帖子发布数 + user_reply_num = user_messages.reply_nodes.find_by_boards(course_board_ids).count #帖子回复数 + user_work_reply_num = user.journals_for_messages.search_by_jour_type("HomeworkCommon",course_homework_ids).count #作业回复数的数量 + c_works_num = (user_homeworks_num + user_graduate_num)*10 + c_exercise_num = user_exercise_num*10 + c_poll_num = user_poll_num*7 + c_file_num = user_file_num*5 + c_message_num = user_messages_num*2 + c_reply_num = user_reply_num*2 + user_activity_levels = c_works_num + c_exercise_num + c_poll_num + c_file_num + c_message_num + c_reply_num + user_work_reply_num + user_ac_level = { + u_1: user_name, + u_2: user_login, + u_2_1: user_mail, + u_3: user_stu_id, + u_4: user_course_group, + u_5: c_works_num, + u_6: c_exercise_num, + u_7: c_poll_num, + u_8: c_file_num, + u_9: c_message_num, + u_10: c_reply_num, + u_11: user_work_reply_num, + u_12: user_activity_levels + } + course_user_level.push(user_ac_level) + + #学生总成绩 + shixun_score = 0.0 # 实训作业的总分 + common_score = 0.0 #普通作业的总分 + group_score = 0.0 #分组作业的总分 + task_score = 0.0 # 毕业任务的总得分 + exercise_score = 0.0 #试卷的总得分 + shixun_score_array = [] + common_score_array = [] + group_score_array = [] + task_score_array = [] + exercise_score_array = [] + + #实训作业 + if shixun_homeworks.count > 0 + shixun_homeworks.each do |s| + user_student_work = s.student_works.homework_by_user(user.id) #当前用户的对该作业的回答 + if user_student_work.blank? + h_score = 0.0 #该作业的得分为0 + else + user_stu_work = user_student_work.first + h_score = user_stu_work.work_score.nil? ? 0.0 : user_stu_work.work_score #用户对该作业的分数 + end + shixun_score_array.push(h_score) + end + end + shixun_score += shixun_score_array.sum + shixun_score_array.push(shixun_score) #shixun_score_array的最后一行为总分 + user_work_scores += user_info_array + shixun_score_array #单个用户的实训作业得分信息 + + #普通作业 + if common_homeworks.count > 0 + common_homeworks.each do |c| + user_student_work_1 = c.student_works.homework_by_user(user.id) #当前用户的对该作业的回答 + if user_student_work_1.blank? + h_score_1 = 0.0 #该作业的得分为0 + else + user_stu_work_1 = user_student_work_1.first + h_score_1 = user_stu_work_1.work_score.nil? ? 0.0 : user_stu_work_1.work_score #用户对该作业的分数 + end + common_score_array.push(h_score_1) + end + end + common_score += common_score_array.sum + common_score_array.push(common_score) #shixun_score_array的最后一行为总分 + user_work_scores += common_score_array #单个用户的普通作业得分信息 + + #分组作业 + if group_homeworks.count > 0 + group_homeworks.each do |g| + user_student_work_3 = g.student_works.homework_by_user(user.id) #当前用户的对该作业的回答 + if user_student_work_3.blank? + h_score_3 = 0.0 #该作业的得分为0 + else + user_stu_work_3 = user_student_work_3.first + h_score_3 = user_stu_work_3.work_score.nil? ? 0.0 : user_stu_work_3.work_score #用户对该作业的分数 + end + group_score_array.push(h_score_3) + end + end + group_score += group_score_array.sum + group_score_array.push(group_score) #shixun_score_array的最后一行为总分 + user_work_scores += group_score_array #单个用户的分组作业得分信息 + + #毕设作业 + if tasks.count > 0 + tasks.each do |task| + graduation_works = task.graduation_works.find_by_task_user(user.id) + if graduation_works.empty? + t_score = 0.0 + else + t_score = graduation_works.first.work_score.nil? ? 0.0 : graduation_works.first.work_score + end + task_score_array.push(t_score) + end + end + task_score += task_score_array.sum + task_score_array.push(task_score) + user_work_scores += task_score_array #单个用户的分组作业得分信息 + + #试卷 + if exercises.count > 0 + exercises.each do |ex| + exercise_works = ex.exercise_users.exercise_commit_users(user.id) + if exercise_works.empty? + e_score = 0.0 + else + e_score = exercise_works.first.score.nil? ? 0.0 : exercise_works.first.score + end + exercise_score_array.push(e_score) + end + end + exercise_score += exercise_score_array.sum + exercise_score_array.push(exercise_score) + + user_work_scores += exercise_score_array #单个用户的分组作业得分信息 + total_user_scores = shixun_score + common_score + group_score + task_score + exercise_score + user_work_scores.push(total_user_scores) #个人的行内容添加总成绩 + total_user_score_array.push(user_work_scores) # 全部成员的集合 + end + + #1.课堂活跃度统计的集合 + course_user_level = course_user_level.sort_by {|k| k[:u_12]}.reverse + @user_activity_level = [course_activity_title,user_cell_head,course_user_level] + + #2.学生总成绩的集合 + ## 作业标题的集合 + course_user_score_title = "学生总成绩" + score_title_cells = shixun_titles + common_titles + group_titles + task_titles + exercise_titles + score_title_counts = [shixun_titles.count,common_titles.count,group_titles.count,task_titles.count,exercise_titles.count] + score_cell_head = %w(序号 真实姓名 登录名 邮箱 学号 分班) + score_title_cells + ["个人总成绩"] + @course_user_scores = [course_user_score_title,score_cell_head,score_title_counts,total_user_score_array] + + #作业的全部集合 + @shixun_work_arrays = [] + @group_work_arrays = [] + @common_work_arrays = [] + @task_work_arrays = [] + @exercise_work_arrays = [] + count_1 = shixun_homeworks.count + count_2 = common_homeworks.count + count_3 = group_homeworks.count + count_4 = tasks.count + count_5 = exercises.count + #实训作业 + if count_1 > 0 + shixun_homeworks.each_with_index do |s,index| + all_student_works = s.student_works.has_committed.order("work_score desc") #该实训题的全部用户回答 + title_no = index.to_i + 1 + student_work_to_xlsx(all_student_works,s) + shixun_work_display_name = (title_no.to_s + "." + s.name).strip.first(30) + shixun_work_content = [shixun_work_display_name,@work_head_cells,@work_cells_column] + @shixun_work_arrays.push(shixun_work_content) + end + end + + #普通作业 + if count_2 > 0 + common_homeworks.each_with_index do |c,index| + all_student_works = c.student_works.has_committed.order("work_score desc") #当前用户的对该作业的回答 + title_no = count_1 + index.to_i + 1 + student_work_to_xlsx(all_student_works,c) + + work_name = (title_no.to_s + "." + c.name).strip.first(30) + work_content = [work_name,@work_head_cells,@work_cells_column] + @common_work_arrays.push(work_content) + title_no + end + end + + #分组作业 + if count_3 > 0 + group_homeworks.each_with_index do |c,index| + all_student_works = c.student_works.has_committed.order("work_score desc") #当前用户的对该作业的回答 + title_no = count_1 + count_2 + index.to_i + 1 + student_work_to_xlsx(all_student_works,c) + work_name = (title_no.to_s + "." + c.name).strip.first(30) + work_content = [work_name,@work_head_cells,@work_cells_column] + @group_work_arrays.push(work_content) + end + end + + #毕设任务 + if count_4 > 0 + tasks.each_with_index do |c,index| + all_student_works = c.graduation_works.has_committed.order("work_score desc") #当前用户的对该作业的回答 + title_no = count_1 + count_2 + count_3 + index.to_i + 1 + graduation_work_to_xlsx(all_student_works,c,current_user) + work_name = (title_no.to_s + "." + c.name).strip.first(30) + # work_content = [work_name,@work_head_cells,@work_cells_column] + work_content = [work_name,@head_cells_column,@task_cells_column] + @task_work_arrays.push(work_content) + end + end + + #试卷的导出 + if count_5 > 0 + exercises.each_with_index do |c,index| + all_student_works = c.exercise_users.exercise_user_committed #当前用户的对该作业的回答 + title_no = count_1 + count_2 + count_3 + count_4 + index.to_i + 1 + get_export_users(c,course,all_student_works) + work_name = (title_no.to_s + "." + c.exercise_name).strip.first(30) + # work_content = [work_name,@work_head_cells,@work_cells_column] + work_content = [work_name,@table_columns,@user_columns] + @exercise_work_arrays.push(work_content) + end + end + end +end diff --git a/app/controllers/discusses_controller.rb b/app/controllers/discusses_controller.rb new file mode 100644 index 000000000..6e9c1427e --- /dev/null +++ b/app/controllers/discusses_controller.rb @@ -0,0 +1,127 @@ +class DiscussesController < ApplicationController + LIMIT = 10 + before_action :find_container, only: [:index, :hidden] + before_action :find_discuss, except: [:create, :index, :new_message, :reward_code] + + def index + page = params[:page].to_i + offset = page * LIMIT + # 总数,分页使用 + @disscuss_count = Discuss.where(:dis_id => @container.id, :dis_type => @container.class.to_s, :root_id => nil).count + @discusses = Discuss.limit(LIMIT).where(:dis_id => @container.id, :dis_type => @container.class.to_s, :root_id => nil). + includes(:user, :praise_tread).offset(offset) + @current_user = current_user + end + + def new_message + onclick_time = Myshixun.find(params[:myshixun_id]).try(:onclick_time) + ids = Discuss.where(user_id: User.current.id, dis_id: params[:container_id], dis_type: params[:container_type]). + where("parent_id is null").pluck(:id) + @user_discuss = Discuss.where("user_id !=? and created_at >?", User.current.id, onclick_time).where(parent_id: ids, + dis_id: params[:container_id], dis_type: params[:container_type]).first + end + + def create + begin + @discuss = Discuss.create!(:dis_id => params[:container_id], :dis_type => params[:container_type], :content => params[:content].gsub(" \;", "").strip, + :user_id => current_user.id, :praise_count => 0, :position => params[:position], :challenge_id => params[:challenge_id]) + rescue Exception => e + uid_logger_error("create discuss failed : #{e.message}") + raise Educoder::TipException.new("评论异常") + end + end + + def reply + begin + @discuss = Discuss.create!(:content => params[:content].gsub(" \;", "").strip, :user_id => current_user.id, + :root_id => @discuss.root_id || params[:id], :parent_id => params[:id], :praise_count => 0, + :challenge_id => @discuss.challenge_id, :dis_id => @discuss.dis_id, + :dis_type => @discuss.dis_type, :position => @discuss.position) + rescue Exception => e + uid_logger_error("reply discuss failed : #{e.message}") + raise Educoder::TipException.new("回复评论异常") + end + end + + # 隐藏评论 + def hidden + logger.info("################{current_user.id}") + if current_user.manager_of_shixun?(@container) + logger.info("66666666#{current_user.id}") + @discuss.update_attribute(:hidden, params[:hidden] == "1") + sucess_status + else + Educoder::TipException(403, "..") + end + end + + # 点/取消赞,一个用户只能点一次 + # 0 取消赞; + def plus + pt = PraiseTread.where(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type], + :user_id => current_user, :praise_or_tread => 1).first + # 如果当前用户已赞过,则不能重复赞 + if params[:type] == 1 && pt.blank? + PraiseTread.create!(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type], + :user_id => current_user.id, :praise_or_tread => 1) if pt.blank? + else + pt.destroy if pt.present? # 如果已赞过,则删掉这条赞(取消);如果没赞过,则为非法请求不处理 + end + + @praise_count = PraiseTread.where(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type], + :praise_or_tread => 1).count + end + + # 奖励金币 + def reward_code + unless current_user.admin? + Educoder::TipException(403, "..") + end + + ActiveRecord::Base.transaction do + container_id = params[:id] + container_type = params[:container_type] + score = params[:score] + user_id = params[:user_id] + user = User.select([:id, :login, :grade]).find(user_id) + + # 金币来源记录 + Grade.create!(:user_id => user_id, :container_id => container_id, :container_type => container_type, :score => score) + # 更新用户总金币数 + user.update_column(:grade, (score.to_i + user.grade.to_i)) + # 多种类型都可以奖励金币 + case container_type + # Post为帖子回复类型,这个名字取的... + when 'Memo', 'Post' + container = Memo.find(container_id) + score = score.to_i + container.reward.to_i + container.update_attribute(:reward, score) + when 'Discusses' + container = Discuss.select([:id, :reward]).find(params[:id]) + score = score.to_i + container.reward.to_i + container.update_attribute(:reward, score) + end + @code = score + end + end + + def destroy + begin + @discuss.destroy + sucess_status + rescue Exception => e + uid_logger_error("destroy discuss failed: #{e.message}") + Educoder::TipException("帖子删除异常") + end + end + + private + def find_container + @container = Shixun.select([:id, :user_id]).find_by_identifier(params[:container_identifier]) + end + + def find_discuss + @discuss = Discuss.select([:id, :hidden, :reward, :dis_type, :dis_id, :position, :challenge_id, :root_id]).find(params[:id]) + end + +end diff --git a/app/controllers/ecs/base_controller.rb b/app/controllers/ecs/base_controller.rb new file mode 100644 index 000000000..ad11682c3 --- /dev/null +++ b/app/controllers/ecs/base_controller.rb @@ -0,0 +1,61 @@ +class Ecs::BaseController < ApplicationController + + # model validation error + rescue_from ActiveRecord::RecordInvalid do |ex| + render_error(ex.record.errors.full_messages.join(',')) + end + # form validation error + rescue_from ActiveModel::ValidationError do |ex| + render_error(ex.model.errors.full_messages.join(',')) + end + + before_action :require_login + before_action :check_user_permission! + + helper_method :current_user, :current_school + + private + + # --- 每个子类controller可能有不同的实现,查看时需要注意 --- + def current_year + @_current_year ||= EcYear.find(params[:ec_year_id]) + end + + def current_major_school + @_current_major_school ||= current_year.ec_major_school + end + + def current_school + @_current_school ||= current_major_school.school + end + + def major_or_course_manager? + !current_user.admin? && !current_school.manager?(current_user) + end + + def check_user_permission! + return if current_user.admin? || current_school.manage_permission?(current_user) + + render_forbidden + end + + def check_manager_permission! + return if current_user.admin? || current_school.manager?(current_user) + + render_forbidden + end + + def check_major_manager_permission! + return if current_user.admin? || current_school.manager?(current_user) + return if current_major_school.manager?(current_user) + + render_forbidden + 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 +end \ No newline at end of file diff --git a/app/controllers/ecs/course_achievement_methods_controller.rb b/app/controllers/ecs/course_achievement_methods_controller.rb new file mode 100644 index 000000000..389169258 --- /dev/null +++ b/app/controllers/ecs/course_achievement_methods_controller.rb @@ -0,0 +1,20 @@ +class Ecs::CourseAchievementMethodsController < Ecs::CourseBaseController + def show + include_associations = { ec_course_achievement_methods: [:ec_course_evaluation, :ec_course_evaluation_subitems] } + @course_targets = current_course.ec_course_targets.includes(include_associations) + end + + def create + @course_target = Ecs::CreateCourseAchievementMethodsService.call(current_course_target, create_params) + end + + private + + def create_params + params.permit(course_achievement_methods: %i[id course_evaluation_id course_evaluation_subitem_ids score percentage]) + end + + def current_course_target + @_current_course_target ||= current_course.ec_course_targets.find(params[:course_target_id]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/course_base_controller.rb b/app/controllers/ecs/course_base_controller.rb new file mode 100644 index 000000000..023db3be1 --- /dev/null +++ b/app/controllers/ecs/course_base_controller.rb @@ -0,0 +1,9 @@ +class Ecs::CourseBaseController < Ecs::BaseController + def current_course + @_current_course ||= EcCourse.find(params[:ec_course_id]) + end + + def current_year + @_current_year ||= current_course.ec_year + end +end diff --git a/app/controllers/ecs/course_evaluations_controller.rb b/app/controllers/ecs/course_evaluations_controller.rb new file mode 100644 index 000000000..f53bc71fe --- /dev/null +++ b/app/controllers/ecs/course_evaluations_controller.rb @@ -0,0 +1,64 @@ +class Ecs::CourseEvaluationsController < Ecs::CourseBaseController + def index + @course_evaluations = current_course.ec_course_evaluations.includes(:ec_course_evaluation_subitems) + end + + def create + course_evaluation = current_course.ec_course_evaluations.new + @course_evaluation = Ecs::SaveCourseEvaluationService.call(course_evaluation, create_params) + render 'show' + end + + def update + @course_evaluation = Ecs::SaveCourseEvaluationService.call(current_course_evaluation, update_params) + render 'show' + end + + def destroy + current_course_evaluation.destroy! + render_ok + end + + def slimmer + course_evaluations = current_course.ec_course_evaluations + + if params[:course_evaluation_id].present? + course_evaluations = course_evaluations.where(id: params[:course_evaluation_id]) + end + + @course_evaluations = course_evaluations.includes(:ec_course_evaluation_subitems) + end + + def average_score_import_template + @course_evaluation = current_course_evaluation + filename = "#{@course_evaluation.name}平均成绩导入模板_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'average_score_import_template', filename: filename + end + + def detail_score_import_template + @course_evaluation = current_course_evaluation + filename = "#{@course_evaluation.name}明细成绩导入模板_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'detail_score_import_template', filename: filename + end + + def import_student_achievement + Ecs::ImportCourseStudentAchievementService.call(current_course_evaluation, params[:attachment_id]) + render_ok + rescue Ecs::ImportCourseStudentAchievementService => ex + render_error(ex.message) + end + + private + + def create_params + params.permit(:name, :evaluation_count, :status, course_evaluation_subitems: [:name]) + end + + def update_params + params.permit(:name, :evaluation_count, :status, course_evaluation_subitems: [:id, :name]) + end + + def current_course_evaluation + @_current_course_evaluation ||= current_course.ec_course_evaluations.find(params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/course_managers_controller.rb b/app/controllers/ecs/course_managers_controller.rb new file mode 100644 index 000000000..714dac580 --- /dev/null +++ b/app/controllers/ecs/course_managers_controller.rb @@ -0,0 +1,20 @@ +class Ecs::CourseManagersController < Ecs::CourseBaseController + skip_before_action :check_user_permission!, only: [:create, :destroy] + before_action :check_major_manager_permission!, only: [:create, :destroy] + + def create + @user = Ecs::CreateCourseManagerService.call(current_course, params[:user_id]) + rescue Ecs::CreateCourseManagerService::Error => ex + render_error(ex.message) + end + + def destroy + # params[:id] 为 user_id + manager = current_course.ec_course_users.find_by(user_id: params[:id]) + return render_error('不存在该课程管理员!') if manager.blank? + + manager.destroy! + + render_ok + end +end \ No newline at end of file diff --git a/app/controllers/ecs/course_targets_controller.rb b/app/controllers/ecs/course_targets_controller.rb new file mode 100644 index 000000000..744840c39 --- /dev/null +++ b/app/controllers/ecs/course_targets_controller.rb @@ -0,0 +1,30 @@ +class Ecs::CourseTargetsController < Ecs::CourseBaseController + def index + @course_targets = current_course.ec_course_targets.includes(:ec_graduation_subitems) + + respond_to do |format| + format.json + format.xlsx do + filename = "#{current_year.year}届_#{current_course.name}_课程目标_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'index', filename: filename + end + end + end + + def create + Ecs::CreateCourseTargetsService.call(current_course, create_params) + @course_targets = current_course.ec_course_targets.includes(:ec_graduation_subitems) + + render 'index' + end + + def with_achievement_methods + @course_targets = current_course.ec_course_targets.includes(:ec_graduation_subitems, :ec_course_achievement_methods) + end + + private + + def create_params + params.permit(course_targets: %i[id content standard_grade weight graduation_subitem_id]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/ec_courses_controller.rb b/app/controllers/ecs/ec_courses_controller.rb new file mode 100644 index 000000000..3bad75a5d --- /dev/null +++ b/app/controllers/ecs/ec_courses_controller.rb @@ -0,0 +1,75 @@ +class Ecs::EcCoursesController < Ecs::BaseController + before_action :check_major_manager_permission!, only: [:create, :import, :destroy] + + def index + ec_courses = current_year.ec_courses + + @count = ec_courses.count + + @ec_courses = paginate ec_courses.includes(:course_managers) + + course_ids = @ec_courses.map(&:id) + # 课程目标数 + @target_count_map = EcCourseTarget.where(ec_course_id: course_ids).group(:ec_course_id).count + # 考核方式数 + @evaluation_count_map = EcCourseEvaluation.where(ec_course_id: course_ids).group(:ec_course_id).count + # 评价方法数 + @achievement_method_count_map = EcCourseAchievementMethod.where(ec_course_id: course_ids).group(:ec_course_id).count + # 毕业目标数 + @graduation_subitem_count_map = EcGraduationSubitemCourseTarget.joins(:ec_course_target) + .where(ec_course_targets: { ec_course_id: course_ids }) + .group('ec_course_targets.ec_course_id') + .count('distinct ec_graduation_subitem_id') + # 已达成毕业目标数 + @completed_subitem_count_map = EcCourseSupport.joins(:ec_graduation_requirement_calculation) + .where(ec_course_id: course_ids) + .where(ec_graduation_requirement_calculations: { status: 1 }) + .group('ec_course_supports.ec_course_id') + .count('distinct ec_graduation_subitem_id') + end + + def search + ec_courses = current_year.ec_courses + + search = params[:search].to_s.strip + if search + ec_courses = ec_courses.where('name LIKE ?', "%#{search}%") + end + + @count = ec_courses.count + @ec_courses = paginate ec_courses + end + + def create + create_params = params.permit(:name) + @ec_course = Ecs::CreateCourseService.call(current_year, create_params) + rescue Ecs::CreateCourseService::Error => ex + render_error(ex.message) + end + + def destroy + current_course.destroy! + render_ok + end + + def import + success_count = Ecs::ImportCourseService.call(current_year, params[:attachment_id]) + render_ok(success_count: success_count) + rescue Ecs::ImportCourseService::Error => ex + render_error(ex.message) + end + + def link_course + link_params = params.permit(:course_id) + Ecs::LinkCourseService.call(current_course, link_params) + render_ok + rescue Ecs::LinkCourseService::Error => ex + render_error(ex.message) + end + + private + + def current_course + @_current_course ||= current_year.ec_courses.find(params[:id]) + end +end diff --git a/app/controllers/ecs/ec_graduation_requirements_controller.rb b/app/controllers/ecs/ec_graduation_requirements_controller.rb new file mode 100644 index 000000000..95dafdb3c --- /dev/null +++ b/app/controllers/ecs/ec_graduation_requirements_controller.rb @@ -0,0 +1,38 @@ +class Ecs::EcGraduationRequirementsController < Ecs::BaseController + skip_before_action :check_user_permission!, only: [:create, :update] + before_action :check_major_manager_permission!, only: [:create, :update] + + def index + @graduation_requirements = current_year.ec_graduation_requirements.includes(:ec_graduation_subitems) + + respond_to do |format| + format.json + format.xlsx do + filename = "#{current_year.year}届毕业要求及指导点_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'index', filename: filename + end + end + end + + def create + graduation_requirement = current_year.graduation_requirements.new + @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, create_params) + render 'show' + end + + def update + graduation_requirement = current_year.graduation_requirements.find(params[:id]) + @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, update_params) + render 'show' + end + + private + + def create_params + params.permit(:position, :content, graduation_subitems: [:content]) + end + + def update_params + params.permit(:position, :content, graduation_subitems: [:id, :content]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/ec_major_schools_controller.rb b/app/controllers/ecs/ec_major_schools_controller.rb new file mode 100644 index 000000000..058bc888e --- /dev/null +++ b/app/controllers/ecs/ec_major_schools_controller.rb @@ -0,0 +1,56 @@ +class Ecs::EcMajorSchoolsController < Ecs::BaseController + def index + major_schools = current_school.ec_major_schools.not_template + + # 专业/课程管理员,则仅显示他们所在的专业 + if major_or_course_manager? + ec_major_school_ids = current_user.ec_major_school_users.pluck(:ec_major_school_id) + + ec_course_major_subquery = current_user.ec_course_users.select(:ec_year_id) + ec_year_school_ids = EcYear.where(id: ec_course_major_subquery).pluck(:ec_major_school_id) + + major_schools = major_schools.where(id: (ec_major_school_ids + ec_year_school_ids).uniq) + end + + if params[:search].present? + major_ids_subquery = EcMajor.search_name_or_code(params[:search]).select(:id) + major_schools = major_schools.where(ec_major_id: major_ids_subquery) + end + + @count = major_schools.count #检索后的数量,小于或等于全部数量 + @major_schools = paginate(major_schools.includes(:users, :ec_major)) + + @template_major_school = current_school.ec_major_schools.is_template.first #示例专业 + end + + def create + ActiveRecord::Base.transaction do + Array(params[:major_ids].presence).each do |id| + EcMajorSchool.create!(ec_major_id: id, school_id: current_school.id) + end + end + + render_ok + end + + def destroy + return render_forbidden if major_or_course_manager? + + major_school = current_school.ec_major_schools.find(params[:id]) + + if major_school.template_major? + render_error('示例专业不能被删除') + return + end + + major_school.destroy! + + render_ok + end + + private + + def current_school + @_current_school ||= School.find(params[:school_id]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/ec_majors_controller.rb b/app/controllers/ecs/ec_majors_controller.rb new file mode 100644 index 000000000..7b14237dc --- /dev/null +++ b/app/controllers/ecs/ec_majors_controller.rb @@ -0,0 +1,19 @@ +class Ecs::EcMajorsController < Ecs::BaseController + def index + school_major_subquery = current_school.ec_major_schools.select(:ec_major_id) #学校已选择的专业 + ec_majors = EcMajor.where.not(id: school_major_subquery) + + if params[:search].present? + ec_majors = ec_majors.search_name_or_code(params[:search]) + end + + @count = ec_majors.count + @ec_majors = paginate(ec_majors) + end + + private + + def current_school + @_current_school ||= School.find(params[:school_id]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/ec_training_objectives_controller.rb b/app/controllers/ecs/ec_training_objectives_controller.rb new file mode 100644 index 000000000..318faa6ff --- /dev/null +++ b/app/controllers/ecs/ec_training_objectives_controller.rb @@ -0,0 +1,26 @@ +class Ecs::EcTrainingObjectivesController < Ecs::BaseController + before_action :check_major_manager_permission!, only: [:create] + + def show + @training_objective = current_year.ec_training_objective + + respond_to do |format| + format.json + format.xlsx do + filename = "#{@training_objective.ec_year.year}届培养目标_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'show', filename: filename + end + end + end + + def create + @training_objective = Ecs::CreateTrainingObjectiveService.call(current_year, create_params) + render 'show' + end + + private + + def create_params + params.permit(:content, training_subitems: [:id, :content]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/ec_years_controller.rb b/app/controllers/ecs/ec_years_controller.rb new file mode 100644 index 000000000..2257911a7 --- /dev/null +++ b/app/controllers/ecs/ec_years_controller.rb @@ -0,0 +1,57 @@ +class Ecs::EcYearsController < Ecs::BaseController + before_action :check_major_manager_permission!, only: [:create, :destroy] + + def index + ec_years = current_major_school.ec_years + + search = params[:search].to_s.strip + if search.present? + ec_years = ec_years.where('year LIKE ?', "%#{search}%") + end + + @count = ec_years.count + @ec_years = paginate ec_years + + return if @ec_years.blank? + + # 防止N+1,手动查询数量 + year_ids = @ec_years.pluck(:id) + @student_count_map = EcYearStudent.where(ec_year_id: year_ids).group(:ec_year_id).count + @training_subitem_count_map = EcTrainingSubitem.joins(:ec_training_objective) + .where(ec_training_objectives: { ec_year_id: year_ids }).group('ec_year_id').count + @graduation_requirement_count_map = EcGraduationRequirement.where(ec_year_id: year_ids).group(:ec_year_id).count + @course_count_map = EcCourse.where(ec_year_id: year_ids).group(:ec_year_id).count + @course_target_count_map = EcCourseTarget.joins(:ec_course).where(ec_courses: { ec_year_id: year_ids }) + .group('ec_year_id').count + @graduation_subitem_count_map = EcGraduationSubitem.joins(:ec_graduation_requirement) + .where(ec_graduation_requirements: { ec_year_id: year_ids }).group('ec_year_id').count + end + + def create + if current_major_school.ec_years.exists?(year: params[:year].to_i) + render_error('届别已存在') + return + end + + @ec_year = CopyEcYearService.call(current_major_school, params[:year].to_i) + end + + def destroy + current_year.destroy! + render_ok + end + + private + + def current_year + @_current_year ||= current_major_school.ec_years.find(params[:id]) + end + + def current_major_school + @_ec_major_school ||= EcMajorSchool.find(params[:ec_major_school_id]) + end + + def current_school + @_current_school ||= current_major_school.school + end +end \ No newline at end of file diff --git a/app/controllers/ecs/evaluations_controller.rb b/app/controllers/ecs/evaluations_controller.rb new file mode 100644 index 000000000..18a78e1c9 --- /dev/null +++ b/app/controllers/ecs/evaluations_controller.rb @@ -0,0 +1,17 @@ +class Ecs::EvaluationsController < Ecs::CourseBaseController + def show + service = Ecs::QueryCourseEvaluationService.new(current_course) + + render_ok( + course_targets: service.course_targets, + course_achievement: service.course_achievement, + graduation_subitem_evaluations: service.graduation_subitem_evaluations, + score_levels_map: service.score_levels_map + ) + end + + def create + Ecs::CalculateCourseEvaluationService.call(current_course) + render_ok + end +end \ No newline at end of file diff --git a/app/controllers/ecs/graduation_course_supports_controller.rb b/app/controllers/ecs/graduation_course_supports_controller.rb new file mode 100644 index 000000000..2a6d59024 --- /dev/null +++ b/app/controllers/ecs/graduation_course_supports_controller.rb @@ -0,0 +1,28 @@ +class Ecs::GraduationCourseSupportsController < Ecs::BaseController + before_action :check_major_manager_permission!, only: [:create] + + def show + @graduation_subitems = current_year.ec_graduation_subitems + .includes(:ec_graduation_requirement, ec_course_supports: :ec_course) + @course_count = current_year.ec_courses.count + + respond_to do |format| + format.json + format.xlsx do + filename = "#{current_year.year}届课程体系对毕业要求的支撑_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'show', filename: filename + end + end + end + + def create + graduation_subitem = current_year.ec_graduation_subitems.find(params[:graduation_subitem_id]) + @graduation_subitem = Ecs::SaveGraduationCourseSupportsService.call(graduation_subitem, create_params) + end + + private + + def create_params + params.permit(course_supports: %i[id ec_course_id weights top_relation]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/homes_controller.rb b/app/controllers/ecs/homes_controller.rb new file mode 100644 index 000000000..7edbd7d78 --- /dev/null +++ b/app/controllers/ecs/homes_controller.rb @@ -0,0 +1,11 @@ +class Ecs::HomesController < Ecs::BaseController + def index + @school_managers = current_school.users + end + + private + + def current_school + @_current_school ||= School.find(params[:school_id]) + end +end diff --git a/app/controllers/ecs/major_managers_controller.rb b/app/controllers/ecs/major_managers_controller.rb new file mode 100644 index 000000000..da5682734 --- /dev/null +++ b/app/controllers/ecs/major_managers_controller.rb @@ -0,0 +1,30 @@ +class Ecs::MajorManagersController < Ecs::BaseController + skip_before_action :check_user_permission! + before_action :check_manager_permission! + + def create + @user = Ecs::CreateMajorManagerService.call(current_major_school, params[:user_id]) + rescue Ecs::CreateMajorManagerService::Error => ex + render_error(ex.message) + end + + def destroy + # params[:id] 为 user_id + manager = current_major_school.ec_major_school_users.find_by(user_id: params[:id]) + return render_error('不存在该专业管理员!') if manager.blank? + + manager.destroy! + + render_ok + end + + private + + def current_major_school + @_ec_major_school ||= EcMajorSchool.find(params[:ec_major_school_id]) + end + + def current_school + @_current_school ||= current_major_school.school + end +end diff --git a/app/controllers/ecs/reach_criteria_controller.rb b/app/controllers/ecs/reach_criteria_controller.rb new file mode 100644 index 000000000..bbfa123cd --- /dev/null +++ b/app/controllers/ecs/reach_criteria_controller.rb @@ -0,0 +1,16 @@ +class ReachCriteriaController < Ecs::BaseController + before_action :check_major_manager_permission!, only: [:create] + + def create + reach_criteria = params[:reach_criteria].to_f + + if reach_criteria.zero? + render_error('必须大于0') + return + end + + current_year.update!(calculation_value: reach_criteria) + + render_ok + end +end \ No newline at end of file diff --git a/app/controllers/ecs/reach_evaluations_controller.rb b/app/controllers/ecs/reach_evaluations_controller.rb new file mode 100644 index 000000000..97576447c --- /dev/null +++ b/app/controllers/ecs/reach_evaluations_controller.rb @@ -0,0 +1,18 @@ +class Ecs::ReachEvaluationsController < Ecs::BaseController + + def show + preload = { ec_graduation_subitems: { ec_course_support: [:ec_course, :ec_graduation_requirement_calculation] } } + @graduation_requirements = current_year.ec_graduation_requirements.includes(preload) + + respond_to do |format| + format.json + format.xlsx do + filename = "#{current_year.year}届达成度-毕业要求综合评价报表_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'show', filename: filename + end + end + end + + def create + end +end diff --git a/app/controllers/ecs/requirement_support_objectives_controller.rb b/app/controllers/ecs/requirement_support_objectives_controller.rb new file mode 100644 index 000000000..7aeba21bb --- /dev/null +++ b/app/controllers/ecs/requirement_support_objectives_controller.rb @@ -0,0 +1,53 @@ +class Ecs::RequirementSupportObjectivesController < Ecs::BaseController + before_action :check_major_manager_permission!, only: [:create, :destroy] + before_action :check_record_exists!, only: [:create, :destroy] + + def show + @graduation_requirements = current_year.ec_graduation_requirements + @training_subitems = current_year.ec_training_subitems + + ids = @graduation_requirements.map(&:id) + @requirement_support_objectives = EcRequirementVsObjective.where(ec_graduation_requirement_id: ids, status: true) + + respond_to do |format| + format.json + format.xlsx do + filename = "#{current_year.year}届毕业要求对培养目标的支撑_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'show', filename: filename + end + end + end + + def create + record = EcRequirementVsObjective.find_by_or_initialize(permit_params) + record.status = true + record.save! + + render_ok + end + + def destroy + record = EcRequirementVsObjective.find_by(permit_params) + record.destroy! if record.present? + + render_ok + end + + private + + def check_record_exists! + unless current_year.ec_graduation_requirements.exists?(id: params[:graduation_requirement_id]) + render_not_found + return + end + + unless current_year.ec_training_subitems.exists?(id: params[:training_subitem_id]) + render_not_found + return + end + end + + def permit_params + params.require(%i[graduation_requirement_id training_subitem_id]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/score_levels_controller.rb b/app/controllers/ecs/score_levels_controller.rb new file mode 100644 index 000000000..28682f758 --- /dev/null +++ b/app/controllers/ecs/score_levels_controller.rb @@ -0,0 +1,18 @@ +class Ecs::ScoreLevelsController < Ecs::CourseBaseController + def show + @score_levels = current_course.ec_score_levels + end + + def create + Ecs::CreateScoreLevelsService.call(current_course, create_params) + @score_levels = current_course.ec_score_levels + + render 'show' + end + + private + + def create_params + params.permit(score_levels: %i[id score level]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/students_controller.rb b/app/controllers/ecs/students_controller.rb new file mode 100644 index 000000000..c21d625e0 --- /dev/null +++ b/app/controllers/ecs/students_controller.rb @@ -0,0 +1,22 @@ +class Ecs::StudentsController < Ecs::BaseController + before_action :check_major_manager_permission!, only: [:destroy, :import] + + def show + students = current_year.ec_year_students + + @count = students.count + @students = paginate students + end + + def destroy + current_year.ec_year_students.where(id: params[:ids]).destroy_all + render_ok + end + + def import + success_count = Ecs::ImportStudentService.call(current_year, params[:attachment_id]) + render_ok(success_count: success_count) + rescue Ecs::ImportStudentService::Error => ex + render_error(ex.message) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/subitem_support_standards_controller.rb b/app/controllers/ecs/subitem_support_standards_controller.rb new file mode 100644 index 000000000..697d5acc4 --- /dev/null +++ b/app/controllers/ecs/subitem_support_standards_controller.rb @@ -0,0 +1,53 @@ +class Ecs::SubitemSupportStandardsController < Ecs::BaseController + before_action :check_major_manager_permission!, only: [:create, :destroy] + before_action :check_record_exists!, only: [:create, :destroy] + + def show + @graduation_standards = EcGraduationStandard.all + @graduation_subitems = current_year.ec_graduation_subitems + + ids = @graduation_subitems.map(&:id) + @subitem_support_standards = EcRequireSubVsStandard.where(ec_graduation_subitem_id: ids, status: true) + + respond_to do |format| + format.json + format.xlsx do + filename = "#{current_year.year}届毕业要求对通用标准的支撑_#{Time.current.strftime('%Y%m%d%H%M%S')}.xlsx" + render xlsx: 'show', filename: filename + end + end + end + + def create + record = EcRequireSubVsStandard.find_by_or_initialize(permit_params) + record.status = true + record.save! + + render_ok + end + + def destroy + record = EcRequireSubVsStandard.find_by(permit_params) + record.destroy! if record.present? + + render_ok + end + + private + + def check_record_exists! + unless current_year.ec_graduation_subitems.exists?(id: params[:graduation_subitem_id]) + render_not_found + return + end + + unless EcGraduationStandard.exists?(id: params[:graduation_standard_id]) + render_not_found + return + end + end + + def permit_params + params.require(%i[graduation_subitem_id graduation_standard_id]) + end +end \ No newline at end of file diff --git a/app/controllers/ecs_controller.rb b/app/controllers/ecs_controller.rb new file mode 100644 index 000000000..b516117c6 --- /dev/null +++ b/app/controllers/ecs_controller.rb @@ -0,0 +1,46 @@ +class EcsController < Ecs::BaseController + def index + major_schools = current_school.ec_major_schools.not_template + + # 专业/课程管理员,则仅显示他们所在的专业 + if major_or_course_manager? + ec_major_school_ids = current_user.ec_major_school_users.pluck(:ec_major_school_id) + + # 和旧版有区别,旧版是通过ec_course的ec_year_id来获取EcYear的 + ec_course_major_subquery = current_user.ec_course_users.select(:ec_year_id) + ec_year_school_ids = EcYear.where(id: ec_course_major_subquery).pluck(:ec_major_school_id) + + major_schools = major_schools.where(id: (ec_major_school_ids + ec_year_school_ids).uniq) + end + + if params[:search].present? + major_ids_subquery = EcMajor.search_name_or_code(params[:search]).select(:id) + major_schools = major_schools.where(ec_major_id: major_ids_subquery) + end + + @obj_count = major_schools.count #检索后的数量,小于或等于全部数量 + @major_schools = paginate(major_schools.includes(:users)) + + @school_managers = current_school.users # 管理员 + @template_major = current_school.ec_major_schools.is_template.first #示例专业 + rescue Exception => e + uid_logger_error(e.message) + tip_exception('页面打开失败!') + end + + private + + def check_user_permission! + if current_user.admin? + @user_permission = 0 + elsif current_school.manager?(current_user) + @user_permission = 1 + elsif current_school.major_manager?(current_user) + @user_permission = 2 + elsif current_school.course_manager?(current_user) + @user_permission = 3 + else + render_forbidden + end + end +end diff --git a/app/controllers/edu_settings_controller.rb b/app/controllers/edu_settings_controller.rb new file mode 100644 index 000000000..0d80cbf3d --- /dev/null +++ b/app/controllers/edu_settings_controller.rb @@ -0,0 +1,75 @@ +class EduSettingsController < ApplicationController + # before_action :require_admin + before_action :set_edu_setting, only: [:show, :edit, :update, :destroy] + + # GET /edu_settings + # GET /edu_settings.json + def index + @edu_settings = EduSetting.all + end + + # GET /edu_settings/1 + # GET /edu_settings/1.json + def show + end + + # GET /edu_settings/new + def new + @edu_setting = EduSetting.new + end + + # GET /edu_settings/1/edit + def edit + end + + # POST /edu_settings + # POST /edu_settings.json + def create + @edu_setting = EduSetting.new(edu_setting_params) + + respond_to do |format| + if @edu_setting.save + format.html { redirect_to @edu_setting, notice: 'Edu setting was successfully created.' } + format.json { render :show, status: :created, location: @edu_setting } + else + format.html { render :new } + format.json { render json: @edu_setting.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /edu_settings/1 + # PATCH/PUT /edu_settings/1.json + def update + respond_to do |format| + if @edu_setting.update(edu_setting_params) + format.html { redirect_to @edu_setting, notice: 'Edu setting was successfully updated.' } + format.json { render :show, status: :ok, location: @edu_setting } + else + format.html { render :edit } + format.json { render json: @edu_setting.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /edu_settings/1 + # DELETE /edu_settings/1.json + def destroy + @edu_setting.destroy + respond_to do |format| + format.html { redirect_to edu_settings_url, notice: 'Edu setting was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_edu_setting + @edu_setting = EduSetting.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def edu_setting_params + params.require(:edu_setting).permit(:name, :value) + end +end diff --git a/app/controllers/exercise_answers_controller.rb b/app/controllers/exercise_answers_controller.rb new file mode 100644 index 000000000..68ba83276 --- /dev/null +++ b/app/controllers/exercise_answers_controller.rb @@ -0,0 +1,116 @@ +class ExerciseAnswersController < ApplicationController + before_action :require_login + before_action :get_exercise_question + + def create #每一次答案的点击,请求一次,实训题不在这里回答 + ActiveRecord::Base.transaction do + begin + q_type = @exercise_question.question_type #试卷的类型 + choice_id = params[:exercise_choice_id].present? ? params[:exercise_choice_id] : "" + answer_text = params[:answer_text].present? ? params[:answer_text] : "" #为字符串 + if q_type < 4 && choice_id.blank? + normal_status(-1,"请选择序号") + else + ea = @exercise_question.exercise_answers.search_answer_users("user_id",current_user.id) #试卷的当前用户的答案 + if q_type == 0 || q_type == 2 #选择题(单选)/判断题 + ea_choice = ea.search_exercise_answer("exercise_choice_id",choice_id).first + answer_option = { + :user_id => current_user.id, + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => choice_id, + :answer_text => "" + } + if ea_choice.present? #如果当前用户的答案存在,再次点击,即为删除 + ea_choice.destroy + else + if @exercise_question.exercise_standard_answers.count <= 1 #单选题的时候 + ea.first.destroy if ea.present? + end + ex_a = ExerciseAnswer.new(answer_option) + ex_a.save! + end + elsif q_type == 1 #多选题的 + choice_ids = params[:exercise_choice_id].present? ? params[:exercise_choice_id] : [] + ea_ids = ea.pluck(:exercise_choice_id) + common_answer_ids = choice_ids & ea_ids #已经存在的试卷选项id + new_ids = choice_ids - common_answer_ids # 新增的id + old_ids = ea_ids - common_answer_ids #没有选择的,则删掉 + if new_ids.size > 0 + new_ids.each do |e| + answer_option = { + :user_id => current_user.id, + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => e, + :answer_text => "" + } + ex_a = ExerciseAnswer.new(answer_option) + ex_a.save! + end + end + if old_ids.size > 0 + ea_answer = ea.search_answer_users("exercise_choice_id",old_ids) + ea_answer.destroy_all + end + elsif q_type == 3 #填空题 + answer_option = { + :user_id => current_user.id, + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => choice_id, + :answer_text => answer_text + } + ea_answer = ea.search_answer_users("exercise_choice_id",choice_id) + if ea.present? && ea_answer.present? + ea_answer.update(answer_option) + else + ex_new = ExerciseAnswer.new(answer_option) + ex_new.save! + end + elsif q_type == 4 #简答题 + answer_option = { + :user_id => current_user.id, + :exercise_question_id => @exercise_question.id + } + if ea.present? #已经回答了的, + ea.first.update_attribute("answer_text",answer_text) + else + answer_option.merge!(answer_text:answer_text) + ex_a = ExerciseAnswer.new(answer_option) + ex_a.save! + end + end + normal_status(0,"回答成功") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + private + + def get_exercise_question + @exercise_question = ExerciseQuestion.find_by_id(params[:exercise_question_id]) + @exercise = @exercise_question.exercise + @course = @exercise.course + @exercise_user = @exercise.exercise_users.exercise_commit_users(current_user.id).first #当前用户 + + if @exercise_question.blank? + normal_status(-1,"试卷问题不存在!") + elsif @exercise.blank? + normal_status(-1,"试卷不存在!") + elsif @course.blank? + normal_status(-1,"该课堂不存在!") + elsif (@exercise_user.present? && @exercise_user.commit_status == 1) || (@exercise.end_time.present? && @exercise.end_time < Time.now) #已提交答案的/时间已结束的试卷不允许再修改 + normal_status(-1,"已提交/已结束的试卷不允许修改!") + elsif @exercise.time > 0 + user_start_at = @exercise.exercise_users.exercise_commit_users(current_user.id).first.start_at + exercise_time = @exercise.time.to_i + if (user_start_at + exercise_time.minutes) < Time.now + normal_status(-1,"限时试卷已结束!") + end + end + end + +end diff --git a/app/controllers/exercise_questions_controller.rb b/app/controllers/exercise_questions_controller.rb new file mode 100644 index 000000000..9e3259e6e --- /dev/null +++ b/app/controllers/exercise_questions_controller.rb @@ -0,0 +1,710 @@ +class ExerciseQuestionsController < ApplicationController + before_action :require_login #用户需登陆 + before_action :get_exercise,only:[:new,:create] #获取试卷 + before_action :get_exercise_question,except: [:new,:create] #获取试卷的问题及试卷 + before_action :is_course_teacher #是否为老师 + before_action :validate_params,only: [:create,:update] #传入参数的验证 + before_action :check_exercise_status,only: [:new,:create,:delete_answer,:destroy] #除未发布状态之外,其余状态不能进行增删操作 + before_action :cannot_change_column,only: [:update] #更新时不能更改的内容 + before_action :check_adjust_score,only: [:adjust_score] + include ExercisesHelper + + def new + ActiveRecord::Base.transaction do + begin + @exercise_question = @exercise.exercise_questions.new + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面访问失败失败!") + raise ActiveRecord::Rollback + end + end + end + + #question_type 0为单选题,1为多选题,2为判断题,3为填空题(单空和多空),4为简答题,5为实训题 + def create + ActiveRecord::Base.transaction do + begin + question_options = { + :question_title => params[:question_title], + :question_type => params[:question_type].present? ? params[:question_type].to_i : 0, #默认为单选题 + :question_number => @exercise.exercise_questions.count + 1, + :question_score => params[:question_score].present? ? params[:question_score].to_f.round(1) : 5.0, + :shixun_id => params[:shixun_id].blank? ? "" : params[:shixun_id], + :is_ordered => params[:is_ordered] # 填空题的答案是否为一一对应关系,默认为true即为一一对应 + } + @exercise_question = @exercise.exercise_questions.new(question_options) + #插入问题时,那么从插入的这个id以后的question_num都将要+1 + if params[:insert_id].present? + insert_exercise = @exercise.exercise_questions.find_by(id: params[:insert_id]) + if insert_exercise.present? #如果该问题存在的话,意思是如果是第一题,那么就不存在插入 + ques_num = insert_exercise.question_number.to_i + @exercise_question.question_number = ques_num + 1 #更新了问题的位置 + @exercise.exercise_questions.insert_question_ex(ques_num).update_all("question_number = question_number + 1") + end + end + + if @exercise_question.save + #为选择题(包括单选和多选)的时候,创建问题选项 + ques_type = @exercise_question.question_type + if ques_type <= 1 + choices_array = params[:question_choices] + choices_count= choices_array.count + standard_answer = params[:standard_answers] #为数组格式,因为可能会有单选和多选,标准答案,已提前判断不能为空, + standard_answer = standard_answer.uniq.reject(&:blank?) + (1..choices_count).each do |c| + choice = choices_array[c-1] #每一个选项的内容 + choice_option = { + :choice_position => c, + :choice_text => choice.strip + } + question_choices = @exercise_question.exercise_choices.new(choice_option) + question_choices.save + end + #标准答案的存储,如:["1","2","3"..]等,1对应A,2对应B,3对应C。。。 + standard_answer.each do |a| + choice_id = a.to_i + standard_option = { + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => choice_id #即为选择的位置参数 + } + question_standard_answer = ExerciseStandardAnswer.new(standard_option) + question_standard_answer.save + if standard_answer.count > 1 && ques_type == 0 #当标准答案数大于1,且不为多选时,修改为多选 + @exercise_question.update_attribute("question_type",1) + elsif standard_answer.count == 1 && ques_type == 1 + @exercise_question.update_attribute("question_type",0) + end + end + elsif ques_type == 2 #这个为判断题 + choices_array = params[:question_choices] #判断的选项,对/错等等 + choices_count= choices_array.count + (1..choices_count).each do |c| + choice = choices_array[c-1] #每一个选项的内容 + choice_option = { + :choice_position => c, + :choice_text => choice.strip + } + question_choices = @exercise_question.exercise_choices.create(choice_option) + question_choices.save + end + standard_answer = params[:standard_answers] #对应选项的id + standard_option = { + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => standard_answer.first.to_i + } + question_standard_answer = ExerciseStandardAnswer.new(standard_option) + question_standard_answer.save + elsif ques_type == 3 #填空题,每空的参考答案有多个,那么以位置对应 + standard_answer = params[:standard_answers] + standard_answer.each do |a| + null_choice_id = a[:choice_id] + null_choice_text = a[:answer_text] + null_choice_text.each do |n| + standard_option = { + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => null_choice_id, + :answer_text => n + } + question_standard_answer = ExerciseStandardAnswer.new(standard_option) + question_standard_answer.save + end + end + elsif ques_type == 4 #简答题 + if params[:standard_answers].present? && params[:standard_answers].reject(&:blank?).count > 0 + standard_answer = params[:standard_answers] + standard_answer.each do |a| + standard_option = { + :exercise_question_id => @exercise_question.id, + :answer_text => a, + } + question_standard_answer = ExerciseStandardAnswer.new(standard_option) + question_standard_answer.save + end + end + elsif ques_type == 5 #实训题 + shixun = Shixun.find_by(id: params[:shixun_id]) + shixun_scores = params[:question_scores] #试卷有多个的分值有多个分数表,所以为分数的数组 + shixun_name = params[:shixun_name] || shixun.name + question_score = 0 + shixun.challenges.each_with_index do |challenge,index| + shixun_option = { + :challenge_id => challenge.id, + :shixun_id => shixun.id, + :exercise_question_id => @exercise_question.id, + :position => (index + 1), + :question_score => shixun_scores[index].present? ? shixun_scores[index].to_f.round(1) : 5 + } + ex_shixun_challenge = ExerciseShixunChallenge.create(shixun_option) + question_score += ex_shixun_challenge.question_score # 问题的分数,为各个关卡分数的总和 + end + @exercise_question.update_attributes(:question_score => question_score,:shixun_name=> shixun_name) + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷问题创建失败!") + raise ActiveRecord::Rollback + end + end + end + + def show + ActiveRecord::Base.transaction do + begin + @exercise_choices = @exercise_question.exercise_choices + @exercise_question_shixun = @exercise_question.exercise_shixun_challenges + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + def edit + ActiveRecord::Base.transaction do + begin + @exercise_choices = @exercise_question.exercise_choices + @exercise_question_shixun = @exercise_question.exercise_shixun_challenges + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + def update + ActiveRecord::Base.transaction do + begin + # 更新试卷题目的内容 + question_options = { + :question_title => params[:question_title], + :is_ordered => params[:is_ordered], # 填空题的答案是否为一一对应关系,默认为true即为一一对应 + :question_score => params[:question_score].present? ? params[:question_score].to_f.round(1) : 5.0 #不可修改分数 + } + choices_array = params[:question_choices] + stan_answer_params = params[:standard_answers] + standard_answer = stan_answer_params.present? ? stan_answer_params.uniq.reject(&:blank?) : [] + @exercise_question.update_attributes(question_options) + #当选项存在时,可修改选项内容,但是不能更改选项的位置(即不能增删选项) + if choices_array.present? + ex_choices = @exercise_question.exercise_choices + ex_choice_count = ex_choices.count + choice_array_count = choices_array.count + ex_choice_count_array = (1..ex_choice_count).to_a + choice_array_count_array = (1..choice_array_count).to_a + if ex_choice_count > choice_array_count #如果选项有减少的,那么只更新传入的,删除以前的 + choice_array_count_array.each do |c| + choice = choices_array[c-1] #每一个选项的内容 + exercise_choice = @exercise_question.exercise_choices.find_choice_custom("choice_position",(c)) + exercise_choice.update(choice_text:choice) + end + drop_ex_choice = @exercise_question.exercise_choices.left_choice_choose("choice_position",(choice_array_count)) + drop_ex_choice.destroy_all + else + ex_choice_count_array.each do |c| + choice = choices_array[c-1] #每一个选项的内容 + exercise_choice = @exercise_question.exercise_choices.find_choice_custom("choice_position",(c)) + exercise_choice.update(choice_text:choice) + end + new_add_choice = choice_array_count_array - ex_choice_count_array #新传入的需新增 + if new_add_choice.count > 0 + new_add_choice.each do |i| + choice_option = { + :choice_position => i, + :choice_text => choices_array[i-1].strip + } + question_choices = @exercise_question.exercise_choices.new(choice_option) + question_choices.save + end + end + end + end + #试卷未发布时,当标准答案存在时,可修改标准答案内容,可增删标准答案,否则只能修改标准答案,不能增删标准答案 + st_count = 0 + @exercise_answers_array = @exercise_question.exercise_standard_answers #问卷的全部标准答案 + if standard_answer.present? + if @exercise_question.question_type <= 2 #选择题/判断题,标准答案为一个或多个 + exercise_standard_choices = @exercise_answers_array.pluck(:exercise_choice_id) #问题以前的全部标准答案选项位置 + common_standard_choices = standard_answer & exercise_standard_choices # 传入的标准答案的选项位置和以前的并集,即表示不用做更改的 + old_left_standard_choices = exercise_standard_choices - common_standard_choices # 以前的差集共同的,剩余的表示需要删掉 + new_left_standard_choices = standard_answer - common_standard_choices # 传入的标准答案差集共同的,剩余的表示需要新建 + if old_left_standard_choices.count > 0 + st_count += 1 + @exercise_answers_array.standard_by_ids(old_left_standard_choices).destroy_all + end + if new_left_standard_choices.count > 0 #新建标准答案 + new_left_standard_choices.each do |s| + standard_option = { + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => s.to_i #即为选择的位置参数 + } + question_standard_answer = ExerciseStandardAnswer.new(standard_option) + question_standard_answer.save + end + + end + if standard_answer.count > 1 && @exercise_question.question_type == 0 #当标准答案数大于1,且不为多选时,修改为多选 + @exercise_question.update_attribute("question_type",1) + elsif standard_answer.count == 1 && @exercise_question.question_type == 1 + @exercise_question.update_attribute("question_type",0) + end + elsif @exercise_question.question_type == 3 #填空题 + old_ex_answer = @exercise_question.exercise_standard_answers #当前问题的全部标准答案 + old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_choice_id).uniq #全部的答案数组序号 + new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号 + + #删除多余的选项 + if old_ex_answer_choice_ids.count > new_ex_answer_choice_ids.count #有减少的填空 + st_count += 1 + delete_ex_answer_choice_ids = old_ex_answer_choice_ids - new_ex_answer_choice_ids + old_ex_answer.standard_by_ids(delete_ex_answer_choice_ids).destroy_all + end + standard_answer.each do |aa| + null_choice_id = aa[:choice_id] + null_choice_text = aa[:answer_text] + null_choice_text_count = null_choice_text.count #当前传入的答案数量 + null_choice_text_count_array = (1..null_choice_text_count).to_a + + ex_answer_pre = old_ex_answer.standard_by_ids(null_choice_id) #当前问题的全部答案 + ex_answer_pre_count = ex_answer_pre.count + ex_answer_pre_count_array = (1..ex_answer_pre_count).to_a + + if old_ex_answer_choice_ids.include?(null_choice_id) #以前的填空题答案包含有现在的填空序号 + if null_choice_text_count >= ex_answer_pre_count + new_add_choice = null_choice_text_count_array - ex_answer_pre_count_array + ex_answer_pre_count_array.each do |n| + standard_option = { + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => null_choice_id, + :answer_text => null_choice_text[n-1] + } + ex_answer_pre[n-1].update(standard_option) + end + if new_add_choice.count > 0 #表示有新增的 + st_count += 1 + new_add_choice.each do |i| + standard_option = { + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => null_choice_id, + :answer_text => null_choice_text[i-1] + } + question_standard_answer = ExerciseStandardAnswer.new(standard_option) + question_standard_answer.save + end + end + else + new_delete_choice = ex_answer_pre_count_array - null_choice_text_count_array + null_choice_text.each_with_index do |n,index| + standard_option = { + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => null_choice_id, + :answer_text => n + } + ex_answer_pre[index].update(standard_option) + end + if new_delete_choice.count > 0 #表示填空题的答案有删减的 + st_count += 1 + new_delete_choice.each do |d| + ex_answer_pre[d-1].destroy + end + end + end + else + null_choice_text.each do |n| + standard_option = { + :exercise_question_id => @exercise_question.id, + :exercise_choice_id => null_choice_id, + :answer_text => n + } + question_standard_answer = ExerciseStandardAnswer.new(standard_option) + question_standard_answer.save + end + end + end + end + end + if @exercise_question.question_type == 4 #主观题 + main_standard_answer = standard_answer.present? ? standard_answer.first : nil + if @exercise_answers_array.present? + @exercise_answers_array.first.update_attribute("answer_text",main_standard_answer) + else + standard_option = { + :exercise_question_id => @exercise_question.id, + :answer_text => main_standard_answer, + } + question_standard_answer = ExerciseStandardAnswer.new(standard_option) + question_standard_answer.save + end + elsif @exercise_question.question_type == 5 + question_score = 0 + shixun_name = params[:shixun_name] || @exercise_question.shixun_name + @exercise_question.exercise_shixun_challenges.each_with_index do |challenge, index| + challenge.question_score = params[:question_scores][index].to_f.round(1) + challenge.save + question_score += challenge.question_score + end + @exercise_question.question_score = question_score + @exercise_question.shixun_name = shixun_name + end + + #当标准答案修改时,如有已提交的学生,需重新计算分数 + if st_count > 0 + ex_users_committed = @exercise.exercise_users.exercise_user_committed + if ex_users_committed.size > 0 + ex_users_committed.each do |ex_user| + user = ex_user.user + objective_score = calculate_student_score(@exercise,user)[:total_score] + subjective_score = ex_user.subjective_score + total_score_subjective_score = subjective_score < 0.0 ? 0.0 : subjective_score + total_score = objective_score + total_score_subjective_score + ex_user.update_attributes(objective_score:objective_score,score:total_score) + end + end + end + + if @exercise_question.save + normal_status(0,"试卷更新成功!") + else + normal_status(-1,"试卷更新失败!") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + # 试卷问题的上下移动 + def up_down + ActiveRecord::Base.transaction do + begin + opr = params[:opr] + current_q_p = @exercise_question.question_number.to_i #问题的当前位置 + # last_q_p = @exercise.exercise_questions.find_by_custom("question_number",(current_q_p - 1)).first # 当前问题的前一个问题 + # next_q_p = @exercise.exercise_questions.find_by_custom("question_number",(current_q_p + 1)).first # 当前问题的后一个问题 + last_q_p = @exercise.exercise_questions.last_exercise(current_q_p) # 当前问题的前一个问题 + next_q_p = @exercise.exercise_questions.next_exercise(current_q_p) # 当前问题的后一个问题 + if @exercise.exercise_status.to_i == 1 + if opr.present? + if opr.to_s == "up" + if last_q_p.present? + @exercise_question.update_attribute('question_number', (current_q_p - 1)) + last_q_p.update_attribute('question_number', (@exercise_question.question_number.to_i + 1)) # 重新获取当前问题的位置 + normal_status(0, "问题上移成功!") + else + normal_status(-1, "移动失败,已经是第一个问题了!") + end + elsif opr.to_s == "down" + if next_q_p.present? + @exercise_question.update_attribute('question_number', (current_q_p + 1)) + next_q_p.update_attribute('question_number', (@exercise_question.question_number.to_i - 1)) + normal_status(0, "问题下移成功!") + else + normal_status(-1, "移动失败,已经是最后一个问题了!") + end + end + else + normal_status(-1, "移动失败,请输入参数") + end + else + normal_status(-1, "已发布的不能移动问题") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问题移动失败!") + end + end + end + + #试卷选项的删除 + def delete_answer + ActiveRecord::Base.transaction do + begin + choice_d_id = params[:choice_no].to_i # 选项的当前位置 + question_choices = @exercise_question.exercise_choices + delete_answer = question_choices.find_choice_custom("choice_position",choice_d_id).first + left_choice = question_choices.left_choice_choose("choice_position",choice_d_id) + if left_choice.present? + left_choice.each do |p| + p.choice_position -= 1 + p.save + end + end + if delete_answer.destroy + normal_status(0, "答案删除成功!") + else + normal_status(-1, "答案删除失败!") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("答案删除失败!") + end + end + end + + #试卷问题的删除 + def destroy + ActiveRecord::Base.transaction do + begin + question_d_id = @exercise_question.question_number.to_i #问题的当前位置 + exercise_questions = @exercise.exercise_questions + left_question = exercise_questions.left_question_choose("question_number",question_d_id) + if left_question.present? + left_question.each do |q| + q.question_number -= 1 + q.save + end + end + if @exercise_question.destroy + normal_status(0, "问题删除成功!") + else + normal_status(-1, "问题删除失败!") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问题删除失败!") + end + end + end + + #老师调分窗口 + def adjust_score + ActiveRecord::Base.transaction do + begin + ex_obj_score = @exercise_current_user.objective_score #全部客观题得分 + ex_subj_score = @exercise_current_user.subjective_score < 0.0 ? 0.0 : @exercise_current_user.subjective_score #全部主观题得分 + ex_answers = @exercise_question.exercise_answers.search_answer_users("user_id",@user_id) #当前用户答案的得分 + if @exercise_question.question_type == 3 #当为填空题,更新问题的总分, + ex_answer_old = ex_answers.score_reviewed.pluck(:score).sum #每一关的得分总和 + each_right_score = (@c_score / ex_answers.count.to_f).round(1) #调分后,平均每关的分数 + new_obj_score = ex_obj_score - ex_answer_old + @c_score + total_scores = new_obj_score + ex_subj_score + ex_scores = { + :objective_score => new_obj_score, + :score => total_scores + } + @exercise_current_user.update_attributes(ex_scores) + ex_answers.update_all(:score => each_right_score) #所有的正确选项需重新更新 + elsif @exercise_question.question_type == 4 #当为主观题时 + if ex_answers.present? + ex_answers_old_score = ex_answers.first.score > 0.0 ? ex_answers.first.score : 0.0 #原分数小于0,取0 + new_sub_score = ex_subj_score - ex_answers_old_score + @c_score #原全部主观题总分减去原该主观题得分再加调分后的分数,即为当前全部主观题得分 + ex_answers.first.update_attribute("score",@c_score) + else #如果学生未答,则创建新的答题记录 + answer_option = { + :user_id => @user_id, + :exercise_question_id => @exercise_question.id, + :score => @c_score, + :answer_text => "" + } + ExerciseAnswer.create(answer_option) + new_sub_score = @c_score + end + total_scores = ex_obj_score + new_sub_score + ex_scores = { + :subjective_score => new_sub_score, + :score => total_scores + } + @exercise_current_user.update_attributes(ex_scores) + + elsif @exercise_question.question_type == 5 + # ex_answers = @exercise_question.exercise_shixun_answers.search_shixun_answers("user_id",@user_id).search_shixun_answers("exercise_shixun_challenge_id",@shixun_a_id) + ex_answers = @exercise_question.exercise_shixun_answers.where(user_id:@user_id,exercise_shixun_challenge_id:@shixun_a_id) + + if ex_answers.present? #当为实训题时 + ex_shixun_old_score = ex_answers.first.score > 0.0 ? ex_answers.first.score : 0.0 + new_obj_score = ex_obj_score - ex_shixun_old_score + @c_score + ex_answers.first.update_attribute("score",@c_score) + else + ex_shixun_option ={ + :exercise_question_id => @exercise_question.id, + :user_id => @user_id, + :exercise_shixun_challenge_id => @shixun_a_id, + :score => @c_score, + :status => 0 + } + ExerciseShixunAnswer.create(ex_shixun_option) + new_obj_score = @c_score + end + total_scores = new_obj_score + ex_subj_score + ex_scores = { + :objective_score => new_obj_score, + :score => total_scores + } + @exercise_current_user.update_attributes(ex_scores) + end + comments = params[:comment] + question_comment = @exercise_question.exercise_answer_comments.first + if question_comment.present? + comment_option = { + :comment => comments.present? ? comments : question_comment.comment, + :score => @c_score, + :exercise_answer_id => ex_answers.present? ? ex_answers.first.id : nil + } + question_comment.update_attributes(comment_option) + @exercise_comments = question_comment + else + comment_option = { + :user_id => current_user.id, + :comment => comments, + :score => @c_score, + :exercise_question_id => @exercise_question.id, + :exercise_shixun_answer_id => @shixun_a_id.present? ? @shixun_a_id : nil, + :exercise_answer_id => ex_answers.present? ? ex_answers.first.id : nil + } + @exercise_comments = ExerciseAnswerComment.new(comment_option) + @exercise_comments.save + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + private + + def questions_params + params.require(:exercise_question).permit(:question_title,:question_type, + :question_number,:exercise_id, + :question_score,:shixun_id,:is_ordered) + end + + def get_exercise + @exercise = Exercise.find_by(id:params[:exercise_id]) + if @exercise.blank? + tip_exception(404,"试卷不存在") + else + @course = @exercise.course + if @course.blank? + tip_exception(404,"课堂不存在") + end + end + end + + def is_course_teacher + @identity = current_user.course_identity(@course) + unless @identity < Course::STUDENT #为老师/助教/管理员 + tip_exception("403", "无权限操作") + end + end + + def get_exercise_question + @exercise_question = ExerciseQuestion.find_by(id: params[:id]) + if @exercise_question.present? + @exercise = @exercise_question.exercise + if @exercise.blank? + tip_exception(404) + else + @course = @exercise.course + if @course.blank? + tip_exception(404) + end + end + else + tip_exception(404) + end + end + + def validate_params + normal_status(-1,"题目不允许为空!") if (params[:question_title].blank? && params[:question_type].to_i !=5 ) #除了实训题,其余题目必需有题干 + normal_status(-1,"问题类型不允许为空!" ) if params[:question_type].blank? + normal_status(-1,"分值不允许为空!" ) if params[:question_score].blank? && params[:question_scores].blank? #分值的数组或参数必需存在一个 + if params[:question_score].present? && params[:question_score].to_f.round(1) <= 0.0 #问题类型存在,则分值不能为空,且必需大于0 + normal_status(-1,"分值必需大于0!") + elsif (params[:question_score].present? && params[:question_score].to_f.round(1) > 100.0) || (params[:question_scores].present? && (params[:question_scores].map{|a| a.to_f.round(1)}.max > 100.0)) + normal_status(-1,"分值不能超过100分!") + elsif params[:question_scores].present? && params[:question_scores].include?(0.0) #如果有负数,则自动取绝对值,#多个分数值,针对实训题的 + normal_status(-1,"分值必需大于0!") + elsif params[:standard_answers].present? && params[:question_choices].present? && (params[:standard_answers].count > params[:question_choices].count) + normal_status(-1,"标准答案数不能大于选项数!") + elsif [0,1,2,3].include?(params[:question_type].to_i) && (params[:standard_answers].blank? || params[:standard_answers].include?("")) #选择题/判断题/填空题 问题选项/标准答案不能为空,也不能包含空的内容 + normal_status(-1,"标准答案不能为空!") + elsif params[:question_type].to_i == 2 && (params[:standard_answers].count > 1 || params[:question_choices].blank? || params[:question_choices].include?("")) #判断题的标准答案不能大于1个,选项不能为空 + normal_status(-1,"判断题选项不能为空/标准答案不能大于1个!") + elsif params[:question_type].to_i <= 1 && (params[:question_choices].blank? || params[:question_choices].include?("") || params[:question_choices].count < 2) #选择题选项不能为空,且不能小于2 + normal_status(-1,"选择题选项内容不能为空,且不能少于3个!") + elsif params[:question_type].to_i == 3 && (params[:standard_answers].blank? || params[:standard_answers].count > 5 ) #填空题选项最多为5个,且如果为1个的话,不允许修改is_ordered + normal_status(-1,"填空题标准答案不能为空/不能超过5个!") + elsif params[:question_type].to_i == 4 && params[:standard_answers].count > 2 #简单题参考答案最多为1个 + normal_status(-1,"简答题的参考答案不能大于2个!") + elsif params[:question_type].to_i == 5 + if params[:shixun_id].blank? #实训题的id不能为空 + normal_status(-1,"实训题id不能为空!") + elsif params[:shixun_name].blank? + normal_status(-1,"实训题名称不能为空!") + end + end + end + + def check_exercise_status + normal_status(-1,"不能更改试卷问题!") if @exercise.exercise_status != 1 + end + + #更新时不能修改的内容 + def cannot_change_column + #已发布的/已截止的/评阅中的状态时,不能修改分数,不能增删问题和答案,不能修改标准答案,可以修改选项内容/题目内容,这里仅指单个问题 + if @exercise.exercise_status != 1 + question_score = @exercise_question.question_score #原来的分数 + update_question_score = params[:question_score].to_f.round(1) #传入的分数 + choices_count = @exercise_question.exercise_choices.count #原来的选项个数 + exercise_choice_ids = @exercise_question.exercise_standard_answers.pluck(:exercise_choice_id).uniq + standard_answers_text = @exercise_question.exercise_standard_answers.pluck(:answer_text).uniq + update_choices_count = params[:question_choices].present? ? params[:question_choices].count : choices_count #传入的选项个数 + standard_answer = params[:standard_answers] #传参数是怎么传的?能不能传空值? + if update_question_score.present? && question_score != update_question_score #分数有更改 + normal_status(-1,"已发布/已截止,分数不允许修改!") + elsif update_choices_count != choices_count #选项个数有修改 + normal_status(-1,"已发布/已截止,不允许增删答案!") + elsif standard_answer.present? + if @exercise_question.question_type == 3 + exercise_answers_text = standard_answer.map{|a| a[:answer_text]}.sum.uniq + unless (standard_answer.count == exercise_choice_ids.count) && (standard_answers_text.count == exercise_answers_text.count) + normal_status(-1,"已发布/已截止,不允许增删标准答案!") + end + elsif @exercise_question.question_type == 4 + unless standard_answers_text.count == standard_answer.count + normal_status(-1,"已发布/已截止,不允许增删标准答案!") + end + end + end + end + end + + def check_adjust_score + @c_score = params[:score].to_f.round(1) #调分后的分数 + @user_id = params[:user_id] + @exercise_current_user = @exercise.exercise_users.exercise_commit_users(@user_id).first #当前试卷用户的答案内容 + if @exercise_current_user.blank? + normal_status(-1,"用户不存在!") + elsif @c_score.blank? + normal_status(-1,"分数不能为空!") + elsif @exercise_question.question_type <= 1 || @exercise_question.question_type == 2 + normal_status(-1,"选择题/判断题不能调分!") + elsif params[:comment].present? && params[:comment].length > 100 + normal_status(-1,"评语不能超过100个字符!") + else + @shixun_a_id = params[:shixun_challenge_id] + if @exercise_question.question_type == 5 #当为实训题时,为关卡的分数 + @shixun_challenge = @exercise_question.exercise_shixun_challenges.cha_id_find(@shixun_a_id) + if @shixun_challenge.present? + @old_ques_score = @shixun_challenge.first.question_score + else + @old_ques_score = nil + normal_status(-1,"实训答案id不能为空!") + end + else + @old_ques_score = @exercise_question.question_score #当不为实训题时,为各问题的分数 + end + if @old_ques_score.present? && (@c_score > @old_ques_score) + normal_status(-1,"分数不能大于题目分数!") + end + end + end + +end diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb new file mode 100644 index 000000000..a18292047 --- /dev/null +++ b/app/controllers/exercises_controller.rb @@ -0,0 +1,1751 @@ +class ExercisesController < ApplicationController + before_action :require_login,except: [:index] + before_action :find_course,only: [:index,:new,:create,:my_exercises,:public_exercises,:set_public,:destroys, + :join_exercise_banks,:publish_modal,:publish,:end_modal,:end_exercise] #需要有课堂id参数的 + before_action :get_exercise,except: [:index,:new,:create,:my_exercises,:public_exercises,:set_public,:destroys, + :join_exercise_banks,:publish_modal,:publish,:end_modal,:end_exercise] + before_action :user_course_identity + before_action :is_course_teacher,except: [:index,:start_answer,:exercise_setting,:commit_exercise,:exercise_lists,:review_exercise, + :exercise_result,:common_header,:cancel_exercise,:begin_commit] + before_action :get_left_banner_id,only:[:common_header,:start_answer,:review_exercise,:index,:new,:edit] + before_action :validates_exercise_params,only: [:create,:update] + before_action :get_exercise_question_counts,only: [:show,:edit,:start_answer,:review_exercise,:blank_exercise,:export_exercise] + before_action :validate_publish_time,only: [:commit_setting] #提交设置时,需判断时间是否符合 + before_action :check_course_public,only: [:set_public] + before_action :check_user_on_answer,only: [:show,:start_answer,:commit_exercise,:exercise_lists] #判断当前用户在试卷的权限/老师是否属于分班的权限 + before_action :only_student_in,only: [:start_answer] + before_action :check_user_id_start_answer,only: [:start_answer,:review_exercise] + before_action :commit_user_exercise,only: [:start_answer,:exercise_lists,:review_exercise] #判断试卷时间到用户是否提交 + before_action :check_exercise_time,only: [:commit_exercise] #提交试卷时,判断时间是否超过 + before_action :check_exercise_status,only: [:redo_modal,:redo_exercise] + before_action :check_exercise_is_end, only: [:review_exercise] + before_action :check_exercise_public,only: [:exercise_result] #试卷是否为公开 + before_action :commit_shixun_present,only: [:commit_shixun] + include ExportHelper + include ExercisesHelper + # require 'pdfkit' + + def index + ActiveRecord::Base.transaction do + begin + # 按发布时间或创建时间排序 + @exercises_all = @course.exercises + member_show_exercises = @exercises_all.is_exercise_published #已发布的或已截止的试卷 + @current_user_ = current_user + @exercises_count = @exercises_all.count # 全部页面,需返回 + @exercises_unpublish_counts = @exercises_all.exercise_by_status(1).count #未发布的试卷数 + @exercises_published_counts = @exercises_all.exercise_by_status([2,3]).count # 已发布的试卷数,包含已截止的 + @exercises_ended_counts = @exercises_all.exercise_by_status(3).count #已截止的试卷数 + # 课堂的学生人数 + @course_all_members = @course.students #当前课堂的全部学生 + @course_all_members_count = @course_all_members.count #当前课堂的学生数 + @current_student = @course_all_members.course_find_by_ids("user_id",current_user.id) #当前用户是否为课堂的学生 + + # exercises的不同用户群体的显示 + if @user_course_identity < Course::STUDENT # @is_teacher_or 1为老师/管理员/助教 + @is_teacher_or = 1 + # @teacher_groups_ids = @course.teacher_course_groups.get_user_groups(current_user.id).pluck(:course_group_id).reject(&:blank?) + @exercises = @exercises_all #老师能看到全部的试卷,不管是已发布的/未发布的/已截止的/统一设置的/私有设置的(看到内容不同) + elsif @user_course_identity == Course::STUDENT # 2为课堂成员,能看到统一设置的和自己班级的 + @is_teacher_or = 2 + member_group_id = @current_student.first.try(:course_group_id).to_i # 成员的分班id,默认为0 + if member_group_id == 0 #表示是课堂的未分班成员,只能查看统一设置的试卷(已发布的/已截止的) + @exercises = member_show_exercises.present? ? member_show_exercises.unified_setting : [] + else #已分班级的成员,可以查看统一设置和单独设置(试卷是发布在该班级)试卷 + # 已发布 当前用户班级分组的 试卷id + exercise_settings_ids = @course.exercise_group_settings.exercise_group_published.where(course_group_id: member_group_id).pluck(:exercise_id).uniq + @exercises = member_show_exercises.present? ? member_show_exercises.unified_setting.or(member_show_exercises.where(id: exercise_settings_ids)) : [] + end + else #用户未登陆或不是该课堂成员,仅显示统一设置的(已发布的/已截止的),如有公开,则不显示锁,不公开,则显示锁 + @is_teacher_or = 0 + @exercises = member_show_exercises.present? ? member_show_exercises.unified_setting : [] + end + if @exercises.count > 0 + if params[:type].present? + choose_type = params[:type].to_i + member_group_id = @current_student.first.try(:course_group_id).to_i + if @is_teacher_or == 2 && member_group_id > 0 + exercise_groups_sets = @course.exercise_group_settings.where(course_group_id: member_group_id).exercise_group_published + exercise_settings_ids = exercise_groups_sets.pluck(:exercise_id) + exercise_ended_ids = exercise_groups_sets.exercise_group_ended.pluck(:exercise_id).uniq + if choose_type == 2 + @exercises = @exercises_all.present? ? @exercises_all.exercise_by_status(2).unified_setting.or(@exercises_all.where(id: (exercise_settings_ids - exercise_ended_ids).uniq)) : [] + elsif choose_type == 3 + @exercises = @exercises_all.present? ? @exercises_all.exercise_by_status(3).unified_setting.or(@exercises_all.where(id: exercise_ended_ids)) : [] + end + else + @exercises = @exercises.exercise_by_status(choose_type) + end + end + + if params[:search].present? + search_type = params[:search].to_s.strip + @exercises = @exercises.exercise_search(search_type) + end + + @exercises_select_count = @exercises.size # 全部页面,需返回 + @exercises = @exercises.distinct.order( "IF(ISNULL(publish_time),0,1), publish_time DESC,created_at DESC") #出现错误 + + # 分页 + @page = params[:page] || 1 + @limit = params[:limit] || 15 + @exercises = @exercises.page(@page).per(@limit) + @exercises = @exercises.includes(:exercise_users,:exercise_questions,:exercise_group_settings) + else + @exercises = [] + end + + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def new + ActiveRecord::Base.transaction do + begin + @exercise = Exercise.new + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷创建失败!") + raise ActiveRecord::Rollback + end + end + end + + def create + ActiveRecord::Base.transaction do + begin + ex_name = params[:exercise_name] + ex_desc = params[:exercise_description] + exercise_options = { + :exercise_name => ex_name, + :exercise_description => ex_desc, + :user_id => current_user.id, + :course_id => @course.id, + :time => -1, + :exercise_status => 1 + } + @exercise = Exercise.create(exercise_options) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷创建失败!") + raise ActiveRecord::Rollback + end + end + end + + #试卷的内容,及试题/答案的内容编辑 + def edit + ActiveRecord::Base.transaction do + begin + @exercise_questions = @exercise.exercise_questions.order("question_number ASC") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷创建失败!") + raise ActiveRecord::Rollback + end + end + end + + def update + ActiveRecord::Base.transaction do + begin + ex_name = params[:exercise_name] + ex_desc = params[:exercise_description] + exercise_options = { + :exercise_name => ex_name, + :exercise_description => ex_desc, + } + @exercise.update_attributes(exercise_options) + normal_status(0,"试卷更新成功!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷创建失败!") + raise ActiveRecord::Rollback + end + end + end + + def show + ActiveRecord::Base.transaction do + begin + if @user_course_identity < Course::STUDENT + @is_teacher_or = 1 #为老师/助教/管理员 + else + @is_teacher_or = 0 #为学生 + end + @exercise_questions = @exercise.exercise_questions.order("question_number ASC") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷创建失败!") + raise ActiveRecord::Rollback + end + end + end + + #试卷的公用头部 + def common_header + ActiveRecord::Base.transaction do + begin + if @user_course_identity > Course::ASSISTANT_PROFESSOR + @is_teacher_or = 0 + @user_exercise_answer = @exercise.check_user_answer_status(current_user) + @user_commit_counts = 0 + else + @is_teacher_or = 1 + @user_exercise_answer = 3 #教师页面 + @user_commit_counts = @exercise.exercise_users.where(commit_status:1).count #已提交的用户数 + end + @ex_status = @exercise.get_exercise_status(current_user.id) + + exercise_id_array = [@exercise.id] + @exercise_publish_count = get_user_permission_course(exercise_id_array,2).count #是否存在已发布的 + @exercise_unpublish_count = get_user_permission_course(exercise_id_array,1).count #是否存在未发布的 + + if (@exercise_publish_count == 0) && (@exercise_unpublish_count == 0) #即表示没有分班 + if @ex_status == 1 + @exercise_unpublish_count = 1 #试卷未发布,且课堂没有分班的时候 + elsif @ex_status == 2 + @exercise_publish_count = 1 #试卷未发布,且课堂没有分班的时候 + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + #实训题目的选用 + def choose_shixun + ActiveRecord::Base.transaction do + begin + search = params[:search] + if @user_course_identity > Course::ADMIN #当不为管理员的时候 + user_school_id = current_user.school_id #当前用户的学校id + if user_school_id.present? + none_shixun_ids = ShixunSchool.where("school_id != #{user_school_id}").pluck(:shixun_id) + @publish_shixuns = Shixun.where.not(id: none_shixun_ids).unhidden + end + else + @publish_shixuns = Shixun.unhidden + end + if search.present? + @publish_shixuns = @publish_shixuns.search_by_name(search) + end + + @shixuns = @publish_shixuns.joins(:challenges).where("challenges.st != 0").distinct + # 全部页面,需返回 + @shixuns_count = @shixuns.count + + # 分页 + @page = params[:page] || 1 + @limit = params[:limit] || 8 + + @shixuns = @shixuns.page(@page).per(@limit) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("实训选择失败!") + end + end + end + + #确认实训的选择 + def commit_shixun + ActiveRecord::Base.transaction do + begin + @shixun_challenges = @shixun.challenges + @shixun_challenges_count = @shixun_challenges.size + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + # 首页批量或单独删除 + def destroys + ActiveRecord::Base.transaction do + begin + check_ids = Exercise.where(id: params[:check_ids]) + check_ids.destroy_all + normal_status(0, "试卷已删除成功!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷删除失败!") + raise ActiveRecord::Rollback + end + end + end + + # 设为公开 + def set_public + ActiveRecord::Base.transaction do + begin + check_ids = Exercise.where(id: params[:check_ids]) + check_ids.each do |exercise| + exercise.update_attribute('is_public', true) + end + normal_status(0, "试卷已设为公开!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷设为公开失败!") + raise ActiveRecord::Rollback + end + end + end + + ## 加入题库 + def join_exercise_banks + ActiveRecord::Base.transaction do + begin + check_ids = Exercise.where(id: params[:check_ids]) + check_ids.each do |exercise| + current_ex_bank = current_user.exercise_banks.find_by_container(exercise.id,"Exercise").first + if current_ex_bank.present? #当前用户的选择试卷是否已加入习题库,存在则更新习题库和问题库,否则新建习题库和问题库 + ex_params = { + :name => exercise.exercise_name, + :description => exercise.exercise_description, + :course_list_id => exercise.course.try(:course_list_id) + } + current_ex_bank.update_attributes(ex_params) + # question_bank = QuestionBank.ques_by_container(current_ex_bank.id,current_ex_bank.container_type).first #该习题库是否存在于问题库里 + # ques_params = { + # :name => current_ex_bank.name, + # :course_list_id => current_ex_bank.course_list_id + # } + # question_bank.update_attributes(ques_params) if question_bank.present? + current_ex_bank.exercise_bank_questions.destroy_all # 更新后,习题库的问题全部删除,后续重新再建 + else + ex_params = { + :name => exercise.exercise_name, + :description => exercise.exercise_description, + :user_id => current_user.id, + :is_public => 0, + :course_list_id => exercise.course.try(:course_list_id), + :container_id => exercise.id, + :container_type => "Exercise", + :quotes => 1 + } + current_ex_bank= ExerciseBank.new ex_params + current_ex_bank.save! #如果习题库保存成功,则会创建问题库question_bank + # if current_ex_bank.save + # ques_params = { + # :name => current_ex_bank.name, + # :container_id => current_ex_bank.id, + # :container_type => current_ex_bank.container_type, + # :quotes => current_ex_bank.quotes, + # :user_id => current_ex_bank.user_id, + # :is_public => current_ex_bank.is_public, + # :course_list_id => current_ex_bank.course_list_id + # } + # question_bank = QuestionBank.new ques_params + # question_bank.save + # end + end + # 试卷的问题的输入 + exercise.exercise_questions.each do |q| + option = { + :question_title => q.question_title, + :question_type => q.question_type, + :question_number => q.question_number, + :question_score => q.question_score, + :shixun_id => q.shixun_id, + :shixun_name => q.shixun_name + } + exercise_bank_question = current_ex_bank.exercise_bank_questions.new option + exercise_bank_question.save + ## 试卷选项的输入 + if q.question_type != 5 #不为实训题时,试卷选项加入试题答案库 + ex_choices = q.exercise_choices + ex_standard = q.exercise_standard_answers + ex_choices.each do |c| + choice_option = { + :choice_position => c.choice_position, + :choice_text =>c.choice_text + } + ex_bank_choice = exercise_bank_question.exercise_bank_choices.new choice_option + ex_bank_choice.save + end + ex_standard.each do |s| + ex_stand = { + :exercise_bank_choice_id => s.exercise_choice_id, + :answer_text => s.answer_text + } + ex_stand_bank = exercise_bank_question.exercise_bank_standard_answers.new ex_stand + ex_stand_bank.save + end + else #当为实训题时 + shixun_challenges = q.exercise_shixun_challenges + shixun_challenges.each do |c| + challenge_option = { + :position => c.position, + :challenge_id => c.challenge_id, + :shixun_id => q.shixun_id, + :question_score => q.question_score + } + shixun_challenge_bank = exercise_bank_question.exercise_bank_shixun_challenges.new challenge_option + shixun_challenge_bank.save + end + end + end + current_ex_bank.save + end + normal_status(0, "题库更新成功!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("题库更新失败!") + raise ActiveRecord::Rollback + end + end + end + + #试卷的设置页面 + def exercise_setting + ActiveRecord::Base.transaction do + begin + @user_permission = 2 + @user_course_groups = @course.teacher_group(current_user.id) #当前老师的分班 + @being_setting_course_ids = @exercise.common_published_ids(current_user.id) #当前用户已发布的班级的id + @user_published_setting = @exercise.exercise_group_settings.find_in_exercise_group("course_group_id",@being_setting_course_ids) #当前用户已发布班级的试卷设置 + exercise_ids = [@exercise.id] + @exercise_publish_count = get_user_permission_course(exercise_ids,2).count #判断当前用户是否有试卷已发布的分班,用于显示立即截止/撤销发布 + @exercise_unpublish_count = get_user_permission_course(exercise_ids,1).count #判断当前用户是否有试卷未发布的分班,用户显示立即发布 + @exercise_users_count = @exercise.exercise_users.commit_exercise_by_status(1).count #判断当前试卷是否有已提交的 + # ## 需添加发送消息的接口,稍后添加 + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + #试卷的提交设置 + def commit_setting + ActiveRecord::Base.transaction do + begin + error_count = 0 # 判断循环里是否有已发布/已截止的,且时间更改了的分班。 + course_group_ids = @course.teacher_course_group_ids(current_user.id) #当前老师的班级id数组 + exercise_status = @exercise.get_exercise_status(current_user.id) + + if exercise_status == 1 && (course_group_ids - [0]).count > 0 # 试卷未发布,且老师的分班大于1 ,才可以修改统一设置,否则按试卷默认的来处理 + unified_setting = params[:unified_setting] + else + unified_setting = @exercise.unified_setting + end + + show_statistic = params[:show_statistic] ? true :false + exercise_time = params[:time].blank? ? -1 : params[:time] + question_random = params[:question_random] ? true :false #问题是否随机,0为不随机,1为随机 + choice_random = params[:choice_random] ? true :false + score_open = params[:score_open] ? true : false #分数是否公开 + answer_open = params[:answer_open] ? true : false #答案是否公开 + + # 统一设置或者分班为0,则更新试卷,并删除试卷分组 + if unified_setting || (course_group_ids.count == 0) + params_publish_time = params[:publish_time].blank? ? nil : params[:publish_time].to_time + params_end_time = nil + if params[:end_time].blank? + if params_publish_time.present? + params_end_time = params_publish_time + 30.days + end + else + params_end_time = params[:end_time].to_time + end + + if exercise_status == 2 && @exercise.publish_time != params_publish_time + normal_status(-1,"已发布,不允许修改发布时间") + elsif exercise_status == 3 && (@exercise.end_time != params_end_time || @exercise.publish_time != params_publish_time) + normal_status(-1,"已截止,不允许修改时间") + elsif params_publish_time.present? && params_end_time.present? && params_end_time < params_publish_time + normal_status(-1,"截止时间不能小于发布时间") + else + #发布时间小于当前时间,则试卷显示为未发布,当截止时间大于当前时间,则显示为已截止 + exercise_status_n = set_exercise_status(params_publish_time,params_end_time) + exercise_params = { + :unified_setting => unified_setting, + :show_statistic => show_statistic, + :time => exercise_time, + :question_random => question_random, + :choice_random => choice_random, + :score_open => score_open, + :answer_open => answer_open, + :exercise_status => exercise_status_n, + :publish_time => params_publish_time, + :end_time => params_end_time + } + @exercise.update_attributes(exercise_params) + @exercise.exercise_group_settings.destroy_all + normal_status(0, "试卷设置成功!") + end + else + params_times = params[:publish_time_groups] #分班返回的json数组{"publish_time_groups":[{"course_group_id":"1","publish_time":"xx","end_time":"xxx"}]} + exercise_groups = @exercise.exercise_group_settings.find_in_exercise_group("course_id",@course.id) #试卷的全部分班信息 + exercise_groups_ids = exercise_groups.pluck(:course_group_id) #问卷的全部分班id + total_common = params_times.map{|k| k[:course_group_id]}.sum.uniq #传入的所有分组的分班id + total_common_group = exercise_groups_ids & total_common #传入的分班与问卷已存在的分班的交集 + old_exercise_groups = exercise_groups_ids - total_common_group #后来传入的分班里,没有了的班级,即需要删除 + + params_times.each do |t| + course_id = t[:course_group_id] + exercise_publish_time = t[:publish_time].present? ? t[:publish_time].to_time : nil + exercise_end_time = nil + if t[:end_time].blank? + if exercise_publish_time.present? + exercise_end_time = exercise_publish_time + 30.days + end + else + exercise_end_time = t[:end_time].to_time + end + # exercise_end_time = t[:end_time].present? ? t[:end_time].to_time : nil + exercise_group = exercise_groups.find_in_exercise_group("course_group_id",course_id) #判断该分班是否存在 + if exercise_group.present? && exercise_group.first.end_time <= Time.now && (exercise_end_time != exercise_group.first.end_time || exercise_publish_time != exercise_group.first.publish_time) #已截止且时间改变的,则提示错误 + error_count += 1 + end + if exercise_group.present? && exercise_group.first.publish_time < Time.now && exercise_publish_time != exercise_group.first.publish_time + error_count += 1 + end + if error_count == 0 + common_group = exercise_groups_ids & course_id #传入的班级与问卷已存在的班级的交集,即表示已有分班的 + new_group_ids = course_id - common_group #新传入的班级id + if common_group.count > 0 #判断试卷的分班设置是否存在,存在则更新,负责则新建 + ex_group_params = { + :publish_time => exercise_publish_time, + :end_time => exercise_end_time + } + exercise_group_sets = exercise_groups.find_in_exercise_group("course_group_id",common_group) + the_group_setting = exercise_group_sets.first + if the_group_setting.present? + the_group_setting_status = set_exercise_status(the_group_setting.publish_time,the_group_setting.end_time) + if the_group_setting_status == 2 + ex_group_params = { + :publish_time => the_group_setting.publish_time, + :end_time => exercise_end_time + } + elsif the_group_setting_status == 3 + ex_group_params = { + :publish_time => the_group_setting.publish_time, + :end_time => the_group_setting.end_time + } + end + end + exercise_group_sets.update_all(ex_group_params) + end + if new_group_ids.size > 0 + new_group_ids.each do |c| + exercise_group_params = { + :exercise_id => @exercise.id, + :course_group_id => c, + :course_id => @course.id, + :publish_time => exercise_publish_time, + :end_time => exercise_end_time + } + new_exercise_group = ExerciseGroupSetting.new(exercise_group_params) + new_exercise_group.save + end + end + end + end + + if error_count > 0 + error_count == 0 + normal_status(-1,"已发布/已截止的试卷不允许修改时间") + else + if old_exercise_groups.size > 0 + old_all_ex_groups = exercise_groups.find_in_exercise_group("course_group_id",old_exercise_groups) + old_all_ex_groups.destroy_all + end + #试卷更新为exercise_group_setting的发布时间最小,截止时间最大 + e_time_present = exercise_groups.end_time_no_null.map(&:end_time) + p_time_present = exercise_groups.publish_time_no_null.map(&:publish_time) + e_time = e_time_present.size > 0 ? e_time_present.max : nil + p_time = p_time_present.size > 0 ? p_time_present.min : nil + exercise_status = 1 + if p_time.nil? #发布时间为空,则表示问卷未发布 + exercise_status = 1 + elsif p_time.present? && e_time.present? + exercise_status = set_exercise_status(p_time,e_time) + end + exercise_params = { + :unified_setting => unified_setting, + :show_statistic => show_statistic, + :time => exercise_time, + :question_random => question_random, + :choice_random => choice_random, + :score_open => score_open, + :answer_open => answer_open, + :exercise_status => exercise_status, + :publish_time => p_time, + :end_time => e_time + } + @exercise.update_attributes(exercise_params) + if @exercise.exercise_status == 2 + if @exercise.course_acts.size == 0 + @exercise.course_acts << CourseActivity.new(:user_id => @exercise.user_id,:course_id => @exercise.course_id) + end + end + normal_status(0, "试卷设置成功!") + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("提交出现错误!") + raise ActiveRecord::Rollback + end + end + end + + #我的题库 + def my_exercises + ActiveRecord::Base.transaction do + begin + ## 我的试卷题库 + @current_user_exercises = current_user.exercise_banks.find_by_c_type("Exercise") + if @current_user_exercises.present? + + if params[:search].present? + search_type = params[:search].to_s.strip + @current_user_exercises = @current_user_exercises.exercise_bank_search(search_type) + end + page = params[:page] || 1 + limit = params[:limit] || 15 + @my_exercises_count = @current_user_exercises.size + @current_user_exercises = @current_user_exercises.page(page).per(limit) + else + @current_user_exercises = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + # 公共题库 + def public_exercises + ActiveRecord::Base.transaction do + begin + if current_user.is_certification_teacher + @user_certification = 1 #用户已通过认证 + @public_exercises = ExerciseBank.find_by_c_type("Exercise").public_exercises + if @public_exercises.present? + if params[:search].present? + search_type = params[:search].to_s.strip + @public_exercises = @public_exercises.exercise_bank_search(search_type) + end + page = params[:page] || 1 + limit = params[:limit] || 15 + @public_exercises_count = @public_exercises.size + @public_exercises = @public_exercises.page(page).per(limit) + else + @public_exercises_count = 0 + @public_exercises = [] + end + else + @user_certification = 0 #用户未通过认证 + @public_exercises_count = 0 + @public_exercises = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("题库调用失败!") + raise ActiveRecord::Rollback + end + end + end + + #立即发布的弹窗内容 + def publish_modal + ActiveRecord::Base.transaction do + begin + exercise_ids = params[:check_ids] + if exercise_ids.count > 0 + @course_groups = get_user_permission_course(exercise_ids,1) + else + @course_groups = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + #首页批量或单独 立即发布,应是跳出弹窗,设置开始时间和截止时间。 + def publish + ActiveRecord::Base.transaction do + begin + check_ids = Exercise.where(id: params[:check_ids]) + ex_end_time = params[:end_time] || Time.at(((1.month.since.to_i)/3600.0).ceil * 3600) + check_ids.each do |exercise| + if exercise.present? + if exercise.unified_setting + ex_status = exercise.exercise_status #则为试卷的状态 + else + ex_status = exercise.exercise_group_settings.find_in_exercise_group("course_group_id",params[:group_ids]).exercise_group_not_published.present? ? 1 : 0 + end + if ex_status == 1 #如果试卷存在已发布的,或者是已截止的,那么则直接跳过 + g_course = params[:group_ids] #表示是否传入分班参数,如果传入分班的参数,那么试卷的统一设置需修改 + if g_course + course_groups = @course.teacher_course_groups.get_user_groups(current_user.id) + + if course_groups.blank? + user_course_groups = @course.course_groups.present? ? @course.course_groups.pluck(:id) : [] + else + user_course_groups = course_groups.pluck(:course_group_id).reject(&:blank?).uniq + end + + if g_course.map(&:to_i).sort == user_course_groups.sort # 如果是设置为全部班级,则试卷不用分组,且试卷设定为统一设置,否则则分组设置 + exercise.exercise_group_settings.destroy_all + ex_unified = true + notify_receiver_ids = @course.students.pluck(:user_id) + else + ex_unified = false + g_course.each do |i| + exercise_group_setting = exercise.exercise_group_settings.find_in_exercise_group("course_group_id",i).first #根据课堂分班的id,寻找试卷所在的班级 + if exercise_group_setting #如果该试卷分组存在,则更新,否则新建 + exercise_group_setting.update_attributes(publish_time:Time.now,end_time:ex_end_time) + else + p_course_group = { + :exercise_id => exercise.id, + :course_group_id => i, + :course_id => exercise.course.id, + :publish_time => Time.now, + :end_time => ex_end_time, + } + new_exercise_group = exercise.exercise_group_settings.new p_course_group + new_exercise_group.save + end + end + + notify_receiver_ids = @course.students.where(course_group_id: params[:group_ids]).pluck(:user_id) + end + else + exercise.exercise_group_settings.destroy_all + ex_unified = true + notify_receiver_ids = @course.students.pluck(:user_id) + end + if exercise.end_time.blank? + e_time = ex_end_time + elsif exercise.exercise_group_settings.end_time_no_null.count > 0 # 该试卷分组有结束时间为空的 + e_time = exercise.exercise_group_settings.end_time_no_null.map(&:end_time).max + else + e_time = exercise.end_time + end + ex_status = set_exercise_status(Time.now,e_time) + exercise_params = { + :publish_time => Time.now, + :end_time => e_time, + :exercise_status => ex_status, + :unified_setting => ex_unified + } + exercise.update_attributes(exercise_params) + + if exercise.course_acts.size == 0 + exercise.course_acts << CourseActivity.new(:user_id => exercise.user_id,:course_id => exercise.course_id) + end + ExercisePublishNotifyJob.perform_later(exercise.id, notify_receiver_ids) + end + end + end + normal_status(0, "试卷发布成功!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷发布失败") + raise ActiveRecord::Rollback + end + end + end + + #立即截止的弹窗内容 + def end_modal + ActiveRecord::Base.transaction do + begin + exercise_ids = params[:check_ids] + if exercise_ids.count > 0 + @course_groups = get_user_permission_course(exercise_ids,3) + else + @course_groups = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + # 首页批量或单独 立即截止,截止时间为当前时间 + def end_exercise + ActiveRecord::Base.transaction do + begin + check_ids = Exercise.where(id:params[:check_ids]) + course_students = @course.students #课堂的全部学生数 + check_ids.each do |exercise| + exercise_status= exercise.get_exercise_status(current_user.id) + if exercise_status == 2 #跳过已截止的或未发布的 + g_course = params[:group_ids] + if g_course.present? + user_course_groups= @course.teacher_course_groups.get_user_groups(current_user.id) + if user_course_groups.present? + teacher_course_group_ids = user_course_groups.pluck(:course_group_id) + else + teacher_course_group_ids = @course.course_groups.pluck(:id) + end + if g_course.map(&:to_i).sort == teacher_course_group_ids.sort #开始为统一设置 + exercise.exercise_group_settings.destroy_all + new_ex_status = set_exercise_status(exercise.publish_time,Time.now) + exercise.update_attributes(:end_time => Time.now,:unified_setting => true,:exercise_status => new_ex_status) + exercise_users = exercise.exercise_users + else + course_members_ids = course_students.course_find_by_ids("course_group_id",g_course).pluck(:user_id).uniq #该班级的全部学生 + exercise_users = exercise.exercise_users.exercise_commit_users(course_members_ids) #参与答题的学生数 + ex_group_setting = exercise.exercise_group_settings + old_exercise_groups = ex_group_setting.find_in_exercise_group("course_group_id",g_course) #试卷的分组设置 + left_course_groups = teacher_course_group_ids - g_course + left_exercise_groups = ex_group_setting.find_in_exercise_group("course_group_id",left_course_groups) + if left_exercise_groups.blank? && exercise.unified_setting + if left_course_groups.size > 0 #开始为统一设置,但是立即截止为分班。则创建没有立即截止的班级的exercise_group_setting + left_course_groups.each do |g| + ex_group_options = { + :exercise_id => exercise.id, + :course_group_id => g, + :course_id => @course.id, + :publish_time => exercise.publish_time, + :end_time => exercise.end_time + } + ExerciseGroupSetting.create(ex_group_options) + end + end + end + if old_exercise_groups.present? + old_exercise_groups.update_all(:end_time => Time.now) + else + g_course.each do |g| + ex_group_options = { + :exercise_id => exercise.id, + :course_group_id => g, + :course_id => @course.id, + :publish_time => exercise.publish_time, + :end_time => Time.now + } + ExerciseGroupSetting.create(ex_group_options) + end + end + new_end_time = exercise.exercise_group_settings.end_time_no_null.map(&:end_time) # 试卷结束时间不为空的 + new_end_time_s = new_end_time.count > 0 ? new_end_time.max : Time.now + new_ex_status = set_exercise_status(exercise.publish_time,new_end_time_s) + exercise.update_attributes(:end_time => new_end_time_s,:exercise_status => new_ex_status,:unified_setting => false) + end + else + exercise_users = exercise.exercise_users + exercise.update_attributes(:exercise_status => 3, :end_time => Time.now,:unified_setting => true) + end + exercise_users.each do |user| + if user.commit_status == 0 && user.start_at.present? + objective_score = calculate_student_score(exercise,user.user)[:total_score] + user_sub_score = user.subjective_score + subjective_score = user_sub_score < 0.0 ? 0.0 : user_sub_score + total_score = objective_score + subjective_score + commit_option = { + :status => 1, + :commit_status => 1, + :end_at => Time.now, + :objective_score => objective_score, + :score => total_score, + :subjective_score => user_sub_score + } + user.update_attributes(commit_option) + end + end + end + end + normal_status(0, "试卷截止成功!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("立即截止失败!") + raise ActiveRecord::Rollback + end + end + end + + #学生撤销回答 + def cancel_exercise + ActiveRecord::Base.transaction do + begin + ex_question_ids = @exercise.exercise_questions.pluck(:id) + exercise_user = @exercise.exercise_users.exercise_commit_users(current_user.id).first + if exercise_user.present? + if exercise_user.commit_status == 1 && @exercise.get_exercise_status(current_user.id) == 2 #用户已提交且试卷提交中 + if @exercise.time == -1 || ((Time.now.to_i - exercise_user.start_at.to_i) < @exercise.time.to_i * 60) + exercise_user.update_attributes(:score => nil, :end_at => nil, :status => nil, :commit_status => 0, :objective_score => 0.0, :subjective_score => -1.0) + exercise_user.user.exercise_shixun_answers.search_shixun_answers("exercise_question_id",ex_question_ids).destroy_all + exercise_answers = exercise_user.user.exercise_answers.search_answer_users("exercise_question_id",ex_question_ids) + exercise_answers.update_all(:score => -1.0) + all_answer_comment = ExerciseAnswerComment.search_answer_comments("exercise_question_id",ex_question_ids).search_answer_comments("exercise_answer_id",exercise_answers.pluck(:id)) + all_answer_comment.destroy_all + normal_status(0,"撤销回答成功") + else + normal_status(-1,"用户答题时间已到") + end + else + normal_status(-1,"用户未提交/试卷不是提交中") + end + else + normal_status(-1,"当前用户未答题") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败") + raise ActiveRecord::Rollback + end + end + end + + #打回重做modal + def redo_modal + ActiveRecord::Base.transaction do + begin + #搜索 + if params[:realname].present? + search_name = params[:realname] + #搜索用户的nickname,如果存在则返回,否则继续查询用户的真实姓名或学生号 + @exercise_users = @exercise_users.includes(:user).where("LOWER(concat(users.lastname, users.firstname)) like ?","%#{search_name}%") + end + if params[:student_id].present? + search_st_id = params[:student_id].to_i + @exercise_users = @exercise_users.includes(user: [:user_extension]).where('user_extensions.student_id like ?',"%#{search_st_id}%") + end + sort = params[:sort] ? params[:sort] : "asc" + @exercise_users = @exercise_users.order("score #{sort}") + @exercise_users_size = @exercise_users.size + # 分页 + page = params[:page] || 1 + limit = params[:limit] || 15 + @exercise_users = @exercise_users.page(page).per(limit) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + #打回重做确认 + def redo_exercise + ActiveRecord::Base.transaction do + begin + user_ids = params[:user_ids] + if user_ids.present? + redo_option = { + :score => 0.0, + :start_at => nil, + :end_at => nil, + :status => nil, + :commit_status => 0, + :objective_score => 0.0, + :subjective_score => -1.0 + } + redo_exercise_users = @exercise_users.exercise_commit_users(user_ids) + redo_exercise_users.update_all(redo_option) + exercise_question_ids = @exercise.exercise_questions.pluck(:id).uniq + ExerciseAnswer.search_answer_users("user_id",user_ids).search_answer_users("exercise_question_id",exercise_question_ids).destroy_all + ExerciseShixunAnswer.search_shixun_answers("user_id",user_ids).search_shixun_answers("exercise_question_id",exercise_question_ids).destroy_all + + normal_status(0,"已成功打回重做!") + else + normal_status(-1,"请选择学生!") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + #学生开始答题页面 + def start_answer + ActiveRecord::Base.transaction do + begin + if @exercise_user_current.blank? + if @user_course_identity > Course::ASSISTANT_PROFESSOR #当为老师的时候,不创建exercise_user表,理论上老师是不能进入答题的 + exercise_user_params = { + :user_id => @exercise_current_user_id, + :exercise_id => @exercise.id, + :start_at => Time.now + } + exercise_user_current = ExerciseUser.new(exercise_user_params) + exercise_user_current.save + end + else + if @exercise_user_current.start_at.blank? + @exercise_user_current.update_attribute("start_at",Time.now) + end + end + if @exercise.time > 0 + exercise_user_start = @exercise_user_current.present? ? @exercise_user_current.start_at.to_i : 0 + exercise_user_left_time = Time.now.to_i - exercise_user_start + time_mill = @exercise.time * 60 #转为毫秒 + @user_left_time = (time_mill < exercise_user_left_time) ? nil : (time_mill - exercise_user_left_time) #当前用户对试卷的回答剩余时间 + end + + @t_user_exercise_status = @exercise.get_exercise_status(current_user.id) + + if @user_course_identity < Course::STUDENT || (@t_user_exercise_status == 3) || (@exercise_user_current.present? && @exercise_user_current.commit_status == 1) + @user_exercise_status = 1 #当前用户为老师/试卷已截止/试卷已提交不可编辑 + else + @user_exercise_status = 0 #可编辑 + end + + @exercise_questions = @exercise.exercise_questions.includes(:exercise_shixun_challenges,:exercise_shixun_answers,:exercise_answers,:exercise_standard_answers) + + if @exercise.question_random + @exercise_questions = @exercise_questions.order("RAND()") + else + @exercise_questions = @exercise_questions.order("question_number ASC") + end + # 判断问题是否已回答还是未回答 + + if @t_user_exercise_status == 3 + get_each_student_exercise(@exercise.id,@exercise_questions,@exercise_current_user_id) + end + get_user_answer_status(@exercise_questions,@exercise_current_user_id) + + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + #提交试卷前的弹窗 + def begin_commit + ActiveRecord::Base.transaction do + begin + if @user_course_identity > Course::ASSISTANT_PROFESSOR #为学生时 + @exercise_questions = @exercise.exercise_questions + @shixun_undo = 0 + @ques_undo = 0 + ex_answer_time = @exercise.time.to_i + @ex_end_time = @exercise.get_exercise_end_time(current_user.id) + if ex_answer_time > 0 + exercise_end_time = @exercise.exercise_users.exercise_commit_users(current_user.id) + if exercise_end_time.present? + ex_end_times = exercise_end_time.first.start_at.nil? ? Time.now : exercise_end_time.first.start_at + @ex_end_time = ex_end_times + ex_answer_time.minutes + end + end + @exercise_questions.each do |q| + if q.question_type == 5 #当为实训题时 + user_myshixun = q.shixun.myshixuns.search_myshixun_user(current_user.id) + if user_myshixun.blank? || user_myshixun.first.status != 1 #当前用户的实训是否做完 + @shixun_undo += 1 + end + else + ques_vote = q.exercise_answers.search_exercise_answer("user_id",current_user.id) + if ques_vote.blank? + @ques_undo += 1 + end + end + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷提交失败!") + raise ActiveRecord::Rollback + end + end + end + + # 学生提交试卷 + def commit_exercise + ActiveRecord::Base.transaction do + begin + if @user_course_identity > Course::ASSISTANT_PROFESSOR #为学生时 + objective_score = calculate_student_score(@exercise,current_user)[:total_score] + subjective_score = @answer_committed_user.subjective_score + total_score_subjective_score = subjective_score < 0.0 ? 0.0 : subjective_score + total_score = objective_score + total_score_subjective_score + commit_option = { + :status => 1, + :commit_status => 1, + :end_at => Time.now, + :objective_score => objective_score, + :score => total_score, + :subjective_score => subjective_score + } + @answer_committed_user.update_attributes(commit_option) + normal_status(0,"试卷提交成功!") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("试卷提交失败!") + raise ActiveRecord::Rollback + end + end + end + + #教师评阅试卷 及学生查看试卷 + def review_exercise + ActiveRecord::Base.transaction do + begin + # 1 老师权限,0 学生权限 + @is_teacher_or = @user_course_identity < Course::STUDENT ? 1 : 0 + @student_status = 2 + # @exercise_answerer = User.find_by(id:@exercise_current_user_id) #试卷回答者 + @exercise_questions = @exercise.exercise_questions.order("question_number ASC") + @question_status = [] + get_exercise_status = @exercise.get_exercise_status(current_user.id) + if @ex_user.present? && @is_teacher_or == 0 + if get_exercise_status == 2 #当前用户已提交,且试卷未截止 + if @ex_user.commit_status == 0 #学生未提交,且当前为学生 + @student_status = 0 + else + @student_status = 1 + get_user_answer_status(@exercise_questions,@exercise_current_user_id) + end + end + end + if @student_status == 2 + get_each_student_exercise(@exercise.id,@exercise_questions,@exercise_current_user_id) + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + #答题列表 + def exercise_lists + ActiveRecord::Base.transaction do + begin + @current_user_id = current_user.id + exercise_ids = [@exercise.id] + @exercise_status = @exercise.get_exercise_status(current_user.id) + @course_all_members = @course.students + question_types = @exercise.exercise_questions.pluck(:question_type) + @exercise_publish_count = get_user_permission_course(exercise_ids,2).count #判断是否有已发布的分班 + @exercise_unpublish_count = get_user_permission_course(exercise_ids,1).count #判断是否有未发布的分班 + + if question_types.include?(4) #是否包含主观题 + @subjective_type = 1 + else + @subjective_type = 0 + end + if @user_course_identity < Course::STUDENT #当前为老师,而且老师只能查看自己班级的/课堂的试卷 + @exercise_current_user_status = 0 + if @exercise_status == 1 + @exercise_users_list = [] + @exercise_course_groups = [] + @exercise_unanswers = 0 + @exercise_answers = 0 + else + ex_common_ids = @exercise.common_published_ids(current_user.id) + @exercise_course_groups = @course.get_ex_published_course(ex_common_ids) + @exercise_users_list = @exercise.all_exercise_users(current_user.id) #当前老师所在班级的全部学生 + get_exercise_answers(@exercise_users_list) + end + elsif @user_course_identity > Course::ASSISTANT_PROFESSOR #当前为学生或者有过答题的(提交/未提交) + @ex_user_end_time = @exercise.get_exercise_end_time(current_user.id) #当前用户所看到的剩余时间 + @exercise_all_users = @exercise.get_stu_exercise_users + get_exercise_answers(@exercise_all_users) # 未答和已答的 + exercise_current_user = @exercise_all_users.exercise_commit_users(current_user.id) #当前用户是否开始做试卷(提交/未提交/没做) + if exercise_current_user.present? + @exercise_current_user_status = 1 #当前用户的状态,为学生 + if @exercise.score_open && @exercise_status == 3 && exercise_current_user.present? #勾选了成绩公开且试卷已截止的 + all_user_ids = @exercise_all_users.pluck(:user_id) + all_user_ids.delete(current_user.id) #删除了当前用户的ID + @exercise_users_list = @exercise_all_users.exercise_commit_users(all_user_ids).distinct + @current_user_ex_answers = exercise_current_user #当前用户的回答 + else + @exercise_users_list = exercise_current_user.present? ? exercise_current_user.distinct : [] + end + else + @exercise_all_users = @exercise.get_stu_exercise_users + get_exercise_answers(@exercise_all_users) # 未答和已答的 + @exercise_current_user_status = 2 #当前用户非课堂成员 + @exercise_users_list = [] + # @exercise_unanswers = 0 + # @exercise_answers = 0 + end + end + + if @exercise_users_list.present? && @exercise_users_list.count > 0 + @exercise_users_count = @exercise_users_list.count #当前显示的全部成员数量 + else + @exercise_users_count = 0 + end + if @exercise_unanswers < 0 + @exercise_unanswers = 0 + end + + @teacher_review_count = 0 + @teacher_unreview_count = 0 + #筛选/分类,排序 + order = params[:order] + if @exercise_users_list.present? && @exercise_users_list.count > 0 + teacher_reviews = @exercise_users_list.exercise_review + teacher_unreviews = @exercise_users_list.exercise_unreview + @teacher_review_count = teacher_reviews.count #已评阅 + @teacher_unreview_count = teacher_unreviews.count #未评阅 + + #是否评阅 + if params[:review].present? + review_type = params[:review].first.to_i #已评,则数据为1,未评,则数据为0,前端传过来的为数组 + if review_type == 1 + @exercise_users_list = teacher_reviews + else + @exercise_users_list = teacher_unreviews + end + end + + if order == "student_id" + @exercise_users_list = @exercise_users_list.joins(user: [:user_extension]).order("user_extensions.student_id DESC") + elsif order == "score" + @exercise_users_list = @exercise_users_list.order("#{order} DESC") + else + @exercise_users_list = @exercise_users_list.order("end_at DESC, start_at DESC") + end + + #答题状态的选择 + if params[:commit_status].present? + choose_type = params[:commit_status] + @exercise_users_list = @exercise_users_list.commit_exercise_by_status(choose_type) + end + + #班级的选择 + if params[:exercise_group_id].present? + group_id = params[:exercise_group_id] + exercise_students = @course_all_members.course_find_by_ids("course_group_id",group_id) #试卷所分班的全部人数 + user_ids = exercise_students.pluck(:user_id).reject(&:blank?) + @exercise_users_list = @exercise_users_list.exercise_commit_users(user_ids) + end + + #搜索 + if params[:search].present? + search_content = params[:search] + #搜索用户的nickname,如果存在则返回,否则继续查询用户的真实姓名或学生号 + nick_name_search = @exercise_users_list.where(user_id: User.where('CONCAT(users.lastname, users.firstname) like ?',"%#{search_content}%")) + if nick_name_search.present? + @exercise_users_list = nick_name_search + else + @exercise_users_list = @exercise_users_list.joins(user: [:user_extension]).where('user_extensions.student_id like ? OR user_extensions.student_realname like ?',"%#{search_content}%","%#{search_content}%") + end + end + + @export_ex_users = @exercise_users_list + + @exercise_users_size = @exercise_users_list.count + + # 分页 + @page = params[:page] || 1 + @limit = params[:limit] || 20 + @exercise_users_list = @exercise_users_list.page(@page).per(@limit) + respond_to do |format| + format.json + format.xlsx{ + if @user_course_identity > Course::ASSISTANT_PROFESSOR + tip_exception(403,"无权限操作") + else + get_export_users(@exercise,@course,@export_ex_users) + exercise_export_name = current_user.real_name + "_" + @course.name + "_" + @exercise.exercise_name + "_" + Time.now.strftime('%Y%m%d_%H%M%S') + render xlsx: "#{exercise_export_name.strip.first(30)}",template: "exercises/exercise_lists.xlsx.axlsx",locals: {table_columns:@table_columns,exercise_users:@user_columns} + end + } + end + else + @exercise_users_list = [] + @exercise_users_size = 0 + respond_to do |format| + format.json + format.xlsx{ + normal_status(-1,"暂无用户提交") + } + format.zip{ + normal_status(-1,"暂无用户提交") + } + end + end + + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + #导出空白试卷 + def export_exercise + @exercise_questions = @exercise.exercise_questions.order("question_number ASC") + filename = "#{current_user.real_name}_#{@course.name}_#{@exercise.exercise_name}_#{Time.current.strftime('%Y%m%d%H%M%S')}.pdf" + stylesheets = "#{Rails.root}/app/templates/exercise_export/exercise_export.css" + render pdf: 'exercise_export/blank_exercise', filename: filename, stylesheets: stylesheets + end + + #空白试卷预览页面,仅供测试使用,无其他任何用途 + # def blank_exercise + # ActiveRecord::Base.transaction do + # begin + # @exercise_questions = @exercise.exercise_questions.order("question_number ASC") + # challenge_ids = @exercise_questions.joins(:exercise_shixun_challenges).pluck("exercise_shixun_challenges.challenge_id") + # get_each_student_exercise(@exercise.id,@exercise_questions,31798) + # @games = @exercise_user.user.games.ch_games(challenge_ids) + # respond_to do |format| + # format.html + # end + # rescue Exception => e + # uid_logger_error(e.message) + # tip_exception("没有权限") + # raise ActiveRecord::Rollback + # end + # end + # end + + #学生的统计结果 + def exercise_result + ActiveRecord::Base.transaction do + begin + exercise_ids = [@exercise.id] + @exercise_publish_count = get_user_permission_course(exercise_ids,2).count #判断是否有已发布的分班 + @exercise_unpublish_count = get_user_permission_course(exercise_ids,1).count #判断是否有未发布的分班 + @course_all_members = @course.students #课堂的全部学生 + @exercise_all_users = @exercise.exercise_users + ex_common_ids = @exercise.common_published_ids(current_user.id) + @exercise_course_groups = @course.get_ex_published_course(ex_common_ids) + # @exercise_course_groups = @exercise.get_ex_published_course(current_user.id) + @exercise_users_list = @exercise.all_exercise_users(current_user.id) + @course_all_members_count = @exercise_users_list.size + + #班级的选择 + if params[:exercise_group_id].present? + group_id = params[:exercise_group_id] + exercise_students = @course_all_members.course_find_by_ids("course_group_id",group_id) # 试卷所分班的全部人数 + user_ids = exercise_students.pluck(:user_id).reject(&:blank?) + @exercise_all_users = @exercise.exercise_users.exercise_commit_users(user_ids) + end + @exercise_commit_users = @exercise_all_users.commit_exercise_by_status(1) #试卷的已提交用户 + @exercise_commit_user_ids = @exercise_commit_users.pluck(:user_id).uniq #已提交试卷的全部用户id + @exercise_commit_user_counts = @exercise_commit_users.count #试卷的已提交用户人数 + @exercise_status = @exercise.get_exercise_status(current_user.id) + + #提交率 + if @course_all_members_count == 0 + commit_percent = 0.00 + min_score = 0.0 + max_score = 0.0 + average_score = 0.0 + fail_counts = 0 + pass_counts = 0 + good_counts = 0 + best_counts = 0 + else + commit_percent = (@exercise_commit_user_counts / @course_all_members_count.to_f).round(3) + exercise_scores = @exercise_commit_users.pluck(:score).reject(&:blank?) + min_score = exercise_scores.min.present? ? exercise_scores.min : 0.0 + max_score = exercise_scores.max.present? ? exercise_scores.max : 0.0 + total_score = exercise_scores.sum.present? ? exercise_scores.sum : 0.0 + average_score = @exercise_commit_user_counts > 0 ? (total_score / @exercise_commit_user_counts).round(1) : 0.0 + fail_counts = exercise_scores.count{|a| a < 60.0} + pass_counts = exercise_scores.count{|a| a < 70.0 && a >= 60.0} + good_counts = exercise_scores.count{|a| a < 90.0 && a >= 70.0} + best_counts = exercise_scores.count{|a| a >= 90.0 && a <= 100.0} + end + @counts_array = { + :commit_percent => commit_percent, + :min_score => min_score.to_s, + :max_score => max_score.to_s, + :average_score => average_score.to_s, + :fail_counts => fail_counts, + :pass_counts => pass_counts, + :good_counts => good_counts, + :best_counts => best_counts, + } + + @exercise_questions = @exercise.exercise_questions + + @paging_type = "percent" + # 按题型排序 + if params[:sort].present? + @paging_type = params[:sort].to_s + end + + ques_result_all = exercise_commit_result(@exercise_questions,@exercise_commit_user_ids) + + if @paging_type == "percent" + @question_result_hash = ques_result_all.sort_by{|s| s[:percent]} + else + @question_result_hash = ques_result_all.sort_by{|s| s["#{@paging_type}"]} + end + + @exercise_questions_count = @exercise_questions.count + @page = params[:page] || 1 + @limit = params[:limit] || 10 + @question_result_hash = Kaminari.paginate_array(@question_result_hash).page(@page).per(@limit) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + private + + def exercise_params + params.require(:exercise).permit(:exercise_name, :exercise_description, :course_id, :exercise_status, :user_id, :time, + :publish_time, :end_time, :show_result, :question_random, :choice_random, :is_public, + :score_open, :answer_open, :exercise_bank_id, :unified_setting, :show_statistic) + end + + def is_course_teacher + unless @user_course_identity < Course::STUDENT #为老师/助教/管理员 + normal_status(403, "...") + end + end + + #检查传入的参数内容是否符合 + def validates_exercise_params + normal_status(-1, "试卷标题不能为空!") if params[:exercise_name].blank? + normal_status(-1, "试卷标题不能超过60个字符") if (params[:exercise_name].length > 60) + normal_status(-1, "试卷须知不能超过100个字符") if (params[:exercise_description].present? && params[:exercise_description].length > 100) + end + + #判断设置的时间是否合理 + def validate_publish_time + # 截止时间存在,且截止时间必须大于当前时间或发布时间 + unified_setting = params[:unified_setting] + publish_course = params[:publish_time_groups] + if @course.is_end + normal_status(-1,"课堂已结束不能再修改") + elsif unified_setting + ex_group_settings = @exercise.exercise_group_settings + if ex_group_settings.present? + p_time_present = ex_group_settings.publish_time_no_null.map(&:publish_time).min + if p_time_present < Time.now + normal_status(-1,"设置失败,存在已发布的分班") + end + elsif params[:publish_time].blank? + normal_status(-1,"发布时间不允许为空") + end + elsif unified_setting.present? && !unified_setting #非统一设置,分班不能为空 + if publish_course.present? + course_ids = publish_course.map{|a| a[:course_group_id]}.sum + publish_t = publish_course.map{|a| a[:publish_time]} + if course_ids.include?(nil) || course_ids.count == 0 + normal_status(-1,"请选择分班") + elsif publish_t.include?(nil) || publish_t.count == 0 + normal_status(-1,"发布时间不允许为空") + end + else + normal_status(-1,"请选择分班") + end + end + end + + def get_exercise + @exercise = Exercise.find_by(id:params[:id]) + if @exercise.blank? + normal_status(404,"试卷不存在") + else + @course = @exercise.course + normal_status(404,"课堂不存在") if @course.blank? + end + end + + def get_exercise_question_counts #获取试卷的问题数及总分数 + exercise_questions = @exercise.exercise_questions.all + @exercise_ques_count = exercise_questions.count # 全部的题目数 + @exercise_ques_scores = exercise_questions.pluck(:question_score).sum + + #单选题的数量及分数 + exercise_single_ques = exercise_questions.find_by_custom("question_type",0) + @exercise_single_ques_count = exercise_single_ques.all.count + @exercise_single_ques_scores = exercise_single_ques.pluck(:question_score).sum + + #多选题的数量及分数 + exercise_double_ques = exercise_questions.find_by_custom("question_type",1) + @exercise_double_ques_count = exercise_double_ques.all.count + @exercise_double_ques_scores = exercise_double_ques.pluck(:question_score).sum + + # 判断题数量及分数 + exercise_ques_judge = exercise_questions.find_by_custom("question_type",2) + @exercise_ques_judge_count = exercise_ques_judge.all.count + @exercise_ques_judge_scores = exercise_ques_judge.pluck(:question_score).sum + + #填空题数量及分数 + exercise_ques_null = exercise_questions.find_by_custom("question_type",3) + @exercise_ques_null_count = exercise_ques_null.all.count + @exercise_ques_null_scores = exercise_ques_null.pluck(:question_score).sum + + #简答题数量及分数 + exercise_ques_main = exercise_questions.find_by_custom("question_type",4) + @exercise_ques_main_count = exercise_ques_main.all.count + @exercise_ques_main_scores = exercise_ques_main.pluck(:question_score).sum + + #实训题数量及分数 + exercise_ques_shixun = exercise_questions.find_by_custom("question_type",5) + @exercise_ques_shixun_count = exercise_ques_shixun.all.count + @exercise_ques_shixun_scores = exercise_ques_shixun.pluck(:question_score).sum + end + + #获取用户有权限的分班 + def get_user_permission_course(exercise_ids,status) + exercise_status = status.to_i #传入的试卷发布状态 + unpublish_group = [] + g_course_ids = @course.teacher_course_groups.get_user_groups(current_user.id).pluck(:course_group_id).reject(&:blank?).uniq #当前用户有权限的分班 + #用户的班级,理论上用户的班级要大于等于试卷设置的班级 + if g_course_ids.blank? || g_course_ids.include?(0) + user_groups_id = @course.course_groups.pluck(:id) + else + user_groups_id = g_course_ids + end + exercises_all = Exercise.where(id:exercise_ids) + exercises_all.each do |exercise| + if exercise.present? + if exercise.unified_setting #统一设置只有两种情况,全部发布,全部截止 + exercise_user_status = exercise.get_exercise_status(current_user.id) #当前用户的能看到的试卷 + if exercise_user_status == exercise_status || exercise_status == 3 #未发布的情况 + unpublish_group = unpublish_group + user_groups_id + else + unpublish_group = [] + end + # unpublish_group = unpublish_group + user_groups_id + else + ex_all_group_settings = exercise.exercise_group_settings + ex_group_settings = ex_all_group_settings.exercise_group_published.pluck(:course_group_id).uniq #问卷设置的班级 + if exercise_status == 1 + unpublish_group = user_groups_id - ex_group_settings + elsif exercise_status == 3 + ex_ended_groups = ex_all_group_settings.exercise_group_ended.pluck(:course_group_id).uniq + ex_and_user = user_groups_id & ex_group_settings #用户已设置的分班 + unpublish_group = unpublish_group + ex_and_user - ex_ended_groups #已发布的全部班级减去截止的全部班级 + else + ex_and_user = user_groups_id & ex_group_settings #用户已设置的分班 + unpublish_group = unpublish_group + ex_and_user + end + end + end + end + unpublish_group = unpublish_group.uniq + if unpublish_group.count > 0 + course_groups = CourseGroup.by_group_ids(unpublish_group) + else + course_groups = [] + end + course_groups + end + + def set_exercise_status(publish_time,end_time) + time_now_i = Time.now + if publish_time.present? && publish_time <= time_now_i && end_time > time_now_i + 2 + elsif publish_time.nil? || (publish_time.present? && publish_time > time_now_i) + 1 + elsif end_time.present? && end_time <= time_now_i + 3 + elsif end_time.present? && publish_time.present? && end_time < publish_time + normal_status(-1,"时间设置错误!") + else + 1 + end + end + + def check_course_public + unless @course.is_public == 1 # 0为私有,1为公开 + normal_status(403,"...") + end + end + + def check_user_id_start_answer #判断用户在开始答题时,是否有用户id传入,如果为老师,则id必需,否则为当前用户的id + user_login = params[:login] + # exercise_current_user_id = params[:user_id] + if user_login.blank? && @user_course_identity < Course::STUDENT #id不存在,且当前为老师/管理员等 + normal_status(-1,"请输入学生登陆名!") + else + @ex_answerer = User.find_by(login: user_login) #回答者 + if @ex_answerer.blank? + normal_status(404,"答题用户不存在") + else + @exercise_current_user_id = @ex_answerer.id || current_user.id + end + end + end + + ## 判断开始答题页面的用户权限 + def check_user_on_answer + if @user_course_identity == Course::STUDENT && @exercise.get_exercise_status(current_user.id) == 1 #试卷未发布,且当前用户不为老师/管理员 + normal_status(-1, "未发布试卷!") + elsif @user_course_identity > Course::STUDENT && (!@exercise.is_public || (@exercise.is_public && !@exercise.unified_setting)) ##不为课堂成员,且试卷不为公开的,或试卷公开,但不是统一设置的 + normal_status(-1, "试卷暂未公开!") + end + end + + def check_exercise_time + @answer_committed_user = @exercise.exercise_users.exercise_commit_users(current_user.id).first + if @answer_committed_user.blank? + normal_status(404,"答题用户不存在") + elsif @exercise.get_exercise_status(current_user.id) != 2 || @answer_committed_user.commit_status == 1 # + normal_status(-1,"提交错误,试卷已截止/用户已提交!") + # elsif @exercise.time > 0 + # user_start_at = @answer_committed_user.start_at + # exercise_time = @exercise.time.to_i + # if (user_start_at + exercise_time.minutes) < Time.now + # normal_status(-1,"限时试卷已结束,已自动提交!") + # end + end + end + + def commit_user_exercise + @exercise_user_current = @exercise.exercise_users.exercise_commit_users(@exercise_current_user_id).first #查找当前用户是否有过答题 + if @user_course_identity == Course::STUDENT + if @exercise_user_current.present? + if @exercise.time > 0 && @exercise_user_current.start_at.present? && (@exercise_user_current.commit_status == 0) && ((@exercise_user_current.start_at + (@exercise.time.to_i + 1).minutes) < Time.now) + #当前用户存在,且已回答,且试卷时间已过,且未提交,则自动提交。最好是前端控制 + objective_score = calculate_student_score(@exercise,current_user)[:total_score] + subjective_score = @exercise_user_current.subjective_score < 0.0 ? 0.0 : @exercise_user_current.subjective_score + total_score = objective_score + subjective_score + commit_option = { + :status => 1, + :commit_status => 1, + :end_at => Time.now, + :objective_score => objective_score, + :score => total_score, + :subjective_score => subjective_score + } + @exercise_user_current.update_attributes(commit_option) + normal_status(0,"已交卷成功!") + end + end + end + end + + #打回重做时的初步判断 + def check_exercise_status + @exercise_users = @exercise.all_exercise_users(current_user.id).commit_exercise_by_status(1) #当前教师所在分班的全部已提交的学生数 + if @exercise.get_exercise_status(current_user.id) != 2 + normal_status(-1,"非提交中的试卷不允许打回重做!") + elsif @exercise_users.count < 1 + normal_status(-1,"暂无人提交试卷!") + end + end + + + #查看试题页面,当为学生时,除非试卷已截止,或已提交才可以查看 + def check_exercise_is_end + ex_status = @exercise.get_exercise_status(current_user.id) + @ex_user = @exercise.exercise_users.find_by(user_id:@exercise_current_user_id) #该试卷的回答者 + if @user_course_identity > Course::ASSISTANT_PROFESSOR + if ex_status == 1 + normal_status(-1,"试卷未发布") + elsif @ex_user.present? && @ex_user.commit_status == 0 + normal_status(-1,"试卷未提交") + elsif params[:user_id].present? && current_user.id != params[:user_id] + normal_status(-1,"不能查看他人的试卷") + end + end + end + + #查看试卷是否选择为公开统计 + def check_exercise_public + if @user_course_identity > Course::ASSISTANT_PROFESSOR #当前为学生,试卷公开统计,且已截止,且已提交 + ex_user = @exercise.exercise_users.exercise_commit_users(current_user.id).first + unless @exercise.get_exercise_status(current_user.id) == 3 && ex_user.present? && ex_user.commit_status == 1 && @exercise.show_statistic + normal_status(-1,"学生暂不能查看") + end + end + end + + def get_left_banner_id + left_banner_content = @course.course_modules.search_by_module_type("exercise") + if left_banner_content.present? + @left_banner_id = left_banner_content.first.id + @left_banner_name = left_banner_content.first.module_name + else + normal_status(404,"左侧导航不存在") + end + end + + def get_user_answer_status(exercise_questions,user_id) + @question_status = [] + @exercise_all_questions = [] + question_answered = 0 + exercise_questions.each_with_index do |q,index| + if q.question_type != 5 + ques_vote = q.exercise_answers.search_exercise_answer("user_id",user_id) + else + ques_vote = q.exercise_shixun_answers.search_shixun_answers("user_id",user_id) + end + ques_status = 0 + if ques_vote.present? + if q.question_type == 5 + if ques_vote.pluck(:exercise_shixun_challenge_id).sort == q.exercise_shixun_challenges.pluck(:id).sort #用户的总得分等于问题的分数 + ques_status = 1 #全部回答了,才算已答 + question_answered += 1 + end + else #其他题目,需回答的有内容,才会为已答,否则如内容为空,视为未答 + vote_answer_id = ques_vote.pluck(:exercise_choice_id).reject(&:blank?) + vote_text_count = ques_vote.pluck(:answer_text).reject(&:blank?).size + if q.question_type <= 2 #选择题和判断题的时候,需要有选项,才算回答 + if vote_answer_id.size > 0 + ques_status = 1 + question_answered += 1 + end + elsif q.question_type == 3 #填空题的时候,需要有选项和内容,才算回答 + if vote_answer_id.uniq.sort == q.exercise_standard_answers.pluck(:exercise_choice_id).uniq.sort + ques_status = 1 + question_answered += 1 + end + else + if vote_text_count > 0 #主观题,必选有内容,才算回答 + ques_status = 1 + question_answered += 1 + end + end + end + end + question_status = { + :ques_id => q.id, + :ques_number => index+1, #仅问题的显示位置变化,但是问题的question_number 不会变化,与之相关的choice/standard_answer/answer不会变化 + :ques_status => ques_status, + } + question_options = { + :question => q, + :ques_number => index+1, + } + @question_status = @question_status.push(question_status).sort_by {|k| k[:ques_number]} + @exercise_all_questions = @exercise_all_questions.push(question_options).sort_by {|k| k[:ques_number]} + end + end + #下一步也有check_on_users再进行判断 + def only_student_in + if @user_course_identity < Course::STUDENT + normal_status(-1,"老师身份不允许进入") + end + end + + #判断实训是否已选择 + def commit_shixun_present + question_shixun_ids = @exercise.exercise_questions.pluck(:shixun_id).reject(&:blank?) + shixun_id = params[:shixun_id] + @shixun = Shixun.find_by(id: shixun_id) + if shixun_id.present? && question_shixun_ids.include?(shixun_id) + normal_status(-1,"该实训已选择!") + elsif @shixun.blank? + normal_status(-1,"该实训不存在!") + end + end + +end diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb new file mode 100644 index 000000000..0e00dcc66 --- /dev/null +++ b/app/controllers/files_controller.rb @@ -0,0 +1,301 @@ +class FilesController < ApplicationController + include MessagesHelper + + before_action :require_login, except: %i[index] + before_action :find_course, except: %i[public_with_course_and_project mine_with_course_and_project] + before_action :find_ids, only: %i[bulk_delete bulk_send bulk_move bulk_public] + before_action :file_validate_sort_type, only: :index + before_action :validate_send_message_to_course_params, only: :bulk_send + before_action :set_pagination, only: %i[index public_with_course_and_project mine_with_course_and_project] + before_action :validate_upload_params, only: %i[upload import] + before_action :find_file, only: %i[show setting update] + + SORT_TYPE = %w[created_on downloads quotes] + + def index + sort = params[:sort] || 0 # 0: 降序;1: 升序 + sort_type = params[:sort_type] || 'created_on' # created_on:时间排序, downloads:下载次数排序; quotes: 引用次数排序 + course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id + @user = current_user || nil + @attachments = @course.attachments.by_keywords(params[:search]) + .includes(attachment_group_settings: :course_group, author: [:user_extension, :course_members]) + .by_course_second_category_id(course_second_category_id) + .ordered(sort: sort.to_i, sort_type: sort_type.strip) + get_category(@course, course_second_category_id) + + case @user.course_identity(@course) + when 5 + # 课程学生 + @attachments = @attachments.published + when 6 || 7 + # 非课堂成员 + @attachments = @attachments.publiced.published + end + + @total_count = @attachments.size + @public_count = @attachments.publiced.size + @private_count = @total_count - @public_count + + @attachments = @attachments.page(@page).per(@page_size) + end + + def bulk_delete + ActiveRecord::Base.transaction do + begin + @course.attachments.by_ids(@attachment_ids).destroy_all + rescue Exception => e + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def bulk_send + return normal_status(403, "您没有权限进行该操作") unless current_user.teacher_of_course?(@course) + course_ids = params[:to_course_ids] + + begin + @attachment_ids.each do |id| + @attachment = @course.attachments.find_by_id id + course_ids.each do |course_id| + course = Course.find_by_id course_id + unless @attachment.nil? || course.nil? + course.attachments << course.attachments.build(@attachment.attributes.except("id").merge( + quotes: 0, + downloads: 0, + author_id: current_user.id, + created_on: Time.now, + course_second_category_id: 0 # TODO 暂时只支持发送到其他课堂的主目录 + )) + end + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def bulk_move + return normal_status(403, "您没有权限进行该操作") unless current_user.teacher_of_course?(@course) + + to_category_id = params[:to_category_id] || 0 # 默认移动到主目录 + unless to_category_id == 0 + course_second_category = @course.course_second_categories.find_by_id to_category_id + return normal_status(2, "参数to_category_id有误,该目录不存在") if course_second_category.nil? + end + + begin + @course.attachments.by_ids(@attachment_ids).update_all(course_second_category_id: to_category_id) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def bulk_public + @user = current_user + return normal_status(403, "您没有权限进行该操作") unless @user.teacher_of_course?(@course) + + @course.attachments.by_ids(@attachment_ids).update_all(is_public: 1) + end + + def public_with_course_and_project + @attachments = Attachment.publiced.simple_columns + .contains_course_and_project + .includes(:author => :user_extension) + .by_filename_or_user_name(params[:search]) + .ordered(sort: 0, sort_type: 'created_on') + + + @total_count = @attachments.size + @attachments = @attachments.page(@page).per(@page_size) + end + + def mine_with_course_and_project + @current_user = current_user + @attachments = Attachment.mine(current_user) + .simple_columns + .contains_course_and_project + .by_keywords(params[:search]) + .ordered(sort: 0, sort_type: 'created_on') + + @total_count = @attachments.size + @attachments = @attachments.page(@page).per(@page_size) + end + + # 上传资源 + def upload + attachment_ids = params[:attachment_ids] + course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id + is_unified_setting = params.has_key?(:is_unified_setting) ? params[:is_unified_setting] : true + publish_time = params[:publish_time] + course_group_publish_times = params[:course_group_publish_times] || [] + + begin + attachment_ids.each do |attchment_id| + attachment = Attachment.find_by_id attchment_id + unless attachment.nil? + attachment.container = @course + attachment.course_second_category_id = course_second_category_id + attachment.description = params[:description] + attachment.is_public = params[:is_public] ? 1 : 0 + attachment.set_publish_time(publish_time) if is_unified_setting + attachment.set_course_group_publish_time(@course, course_group_publish_times) if @course.course_groups.size > 0 && !is_unified_setting && publish_time.blank? + attachment.save! + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + # 选用资源 & 导入资源 + def import + return normal_status(403, "您没有权限进行该操作") unless current_user.teacher_of_course?(@course) || current_user.student_of_course?(@course) + + attachment_ids = params[:attachment_ids] + course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id + + begin + attachment_ids.each do |attachment_id| + ori = Attachment.find_by_id(attachment_id) + @course.attachments.each do |att| + @exist = false + if att.id == ori.id || (!att.copy_from.nil? && !ori.copy_from.nil? && att.copy_from == ori.copy_from) || att.copy_from == ori.id || att.id == ori.copy_from + att.created_on = Time.now + att.save + @exist = true + break + end + end + + next if @exist + attach_copied_obj = ori.copy + attach_copied_obj.container = @course + attach_copied_obj.created_on = Time.now + attach_copied_obj.author = current_user + attach_copied_obj.is_public = 0 + attach_copied_obj.course_second_category_id = course_second_category_id + attach_copied_obj.copy_from = ori.copy_from.nil? ? ori.id : ori.copy_from + if attach_copied_obj.attachtype == nil + attach_copied_obj.attachtype = 4 + end + attach_copied_obj.save + ori.update_columns(quotes: ori.quotes.to_i + 1) + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + # 资源设置 + def update + return normal_status(403, "您没有权限进行该操作") unless current_user.teacher_or_admin?(@course) || @file.author == current_user + + is_unified_setting = params[:is_unified_setting] + publish_time = params[:publish_time] + is_public = params[:is_public] + course_group_publish_times = params[:course_group_publish_times] || [] + + @old_attachment = @file + @new_attachment = Attachment.find_by_id params[:new_attachment_id] + + begin + unless @new_attachment.nil? + @new_attachment_history = @old_attachment.become_history + @new_attachment_history.save! + + @old_attachment.copy_attributes_from_new_attachment(@new_attachment) + @old_attachment.is_public = is_public == true ? 1 : 0 if is_public + @old_attachment.save! + @new_attachment.delete + end + if params[:description] && !params[:description].strip.blank? && params[:description] != @old_attachment.description + @old_attachment.description = params[:description] + end + + @old_attachment.set_public(is_public) + + if is_unified_setting + @old_attachment.set_publish_time(publish_time) + @old_attachment.attachment_group_settings.destroy_all + end + + if publish_time.blank? && @course.course_groups.size > 0 && !is_unified_setting + @old_attachment.set_course_group_publish_time(@course, course_group_publish_times) + end + + @old_attachment.save! + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def show + return normal_status(403, "您没有权限进行该操作") if !current_user.teacher_of_course?(@course) && current_user != @file.author + @attachment_histories = @file.attachment_histories + end + + def histories + @user = current_user + @file = @course.attachments.find_by_id params[:id] + + return normal_status(-2, "该课程下没有id为 #{params[:id]}的资源") if @file.nil? + return normal_status(403, "您没有权限进行该操作") if @user != @file.author && !@user.teacher_of_course?(@course) && !@file.public? + + @attachment_histories = @file.attachment_histories + end + + def get_category(course, category_id) + if category_id == 0 + category = course.attachment_course_modules.first + @category_id = category.try(:id) + @category_name = category.try(:module_name) + else + category = CourseSecondCategory.find category_id + @category_id = category.try(:id) + @category_name = category.try(:name) + end + end + + private + def find_file + @file = Attachment.find params[:id] + end + + def find_attachment_ids(attachment_ids = params[:attachment_ids]) + return normal_status(-2, "参数attachment_ids不能为空!") if attachment_ids.blank? + return normal_status(-2, "参数attachment_ids格式错误!") if !attachment_ids.is_a? Array + end + + def find_course_second_category_id + course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id + if course_second_category_id != 0 + course_second_category = CourseSecondCategory.find_by(id: course_second_category_id, category_type: "attachment") + return normal_status(-2, "未来找到course_second_category为 #{course_second_category_id} 的目录") if course_second_category.nil? + end + end + + def find_ids + @attachment_ids = params[:ids] || [] + find_attachment_ids(@attachment_ids) + end + + def file_validate_sort_type + normal_status(-2, "参数sort_tyope暂时只支持 'created_on', 'quotes', 'downloads'") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) + end + + def validate_upload_params + find_attachment_ids + find_course_second_category_id + end +end diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb new file mode 100644 index 000000000..4aa0b13b8 --- /dev/null +++ b/app/controllers/games_controller.rb @@ -0,0 +1,889 @@ +class GamesController < ApplicationController + before_action :require_login + before_action :find_game + before_action :find_shixun, only: [:show, :answer, :rep_content, :choose_build, :game_build, :game_status] + + before_action :allowed + + #require 'iconv' + + include GamesHelper + include ApplicationHelper + + def show + uid_logger("--games show start") + # 防止评测中途ajaxE被取消;3改成0是为了处理首次进入下一关的问题 + @game.update_attribute(:status, 0) if @game.status == 1 + @game.update_attributes(status: 0, open_time: Time.now) if @game.status == 3 + game_challenge = Challenge.base_attrs.find(@game.challenge_id) + + # 选择题类型的实训关卡总分 + @st = game_challenge.st + if @st == 1 + game_challenge.score = game_challenge.choose_score.to_i + end + + game_count = Game.where(myshixun_id: @game.myshixun_id).count + + discusses = @shixun.discusses + discusses = discusses.where('hidden = false OR user_id = :user_id', user_id: current_user.id) unless current_user.admin? + discusses_count = discusses.count + + @user = @game.owner + is_teacher = @user.is_teacher? + + # 实训超时设置 + time_limit = @shixun.exec_time + + # 上一关、下一关 + prev_game = @game.prev_of_current_game(@shixun.id, @game.myshixun_id, game_challenge.position) + next_game = @game.next_of_current_game(@shixun.id, @game.myshixun_id, game_challenge.position) + + # 关卡点赞数, praise_or_tread = 1则表示赞过 + praise_count = PraiseTread.where(praise_tread_object_id: game_challenge.id, praise_tread_object_type: "Challenge", + praise_or_tread: 1).count + user_praise = PraiseTread.where(praise_tread_object_id: game_challenge.id, praise_tread_object_type: "Challenge", + user_id: current_user.id, praise_or_tread: 1).present? ? true : false + + # 实训的最大评测次数,这个值是为了优化查询,每次只取最新的最新一次评测的结果集 + max_query_index = @game.query_index.to_i + + # 统计评测时间 + record_onsume_time = EvaluateRecord.where(game_id: @game.id).first.try(:consume_time) + + # power判断用户是否有权限查看隐藏测试集(TPM管理员;平台认证的老师;花费金币查看者) + # myshixun_manager + myshixun_manager = current_user.manager_of_shixun?(@shixun) || (current_user.is_teacher? && current_user.pro_certification?) + + # 选择题和编程题公共部分 + @base_date = {st: @st, discusses_count: discusses_count, game_count: game_count, myshixun: @myshixun, + challenge: game_challenge.attributes.except("answer"), game: @game.try(:attributes), shixun: @shixun.try(:attributes), + record_onsume_time: record_onsume_time, prev_game: prev_game, next_game: next_game, + praise_count: praise_count, user_praise: user_praise, time_limit: time_limit, + tomcat_url: edu_setting('cloud_tomcat_php'), is_teacher: is_teacher, + myshixun_manager: myshixun_manager} + + # 区分选择题和编程题,st:0编程题; + if @st == 0 + has_answer = game_challenge.challenge_answers.size == 0 ? false : true + game_challenge.answer = nil + mirror_name = @shixun.mirror_name + + # 判断tpm是否修改了 + begin + tpm_modified = @myshixun.repository_is_modified(@shixun.repo_path) # 判断TPM和TPI的版本库是否被改了 + rescue + uid_logger("实训平台繁忙,繁忙等级(81)") + end + tpm_cases_modified = (game_challenge.modify_time != @game.modify_time ? true : false) # modify_time 决定TPM测试集是否有更新 + + @task_result = {tpm_modified: tpm_modified, tpm_cases_modified: tpm_cases_modified, mirror_name: mirror_name, has_answer: has_answer} + + testset_detail max_query_index, game_challenge + else # 选择题类型的 + # 该方法多个地方调用,比如show、评测 + # 最后一个字段true表示只显示数据,false表示可能有添加数据 + choose_container(game_challenge, @game, max_query_index) + end + end + + # 查看效果 + # todo : 这块代码有很大的改进空间 + # todo : 中文排序问题 + def picture_display + myshixun = Myshixun.find(@game.myshixun_id) + if myshixun.main_mirror.try(:type_name) == "Android" + @type = "qrcode" + workspace = @game.try(:picture_path) + game_challenge = @game.challenge + qr = RQRCode::QRCode.new("#{edu_setting('host_name')}/api/shixuns/download_file?file_name=#{workspace}/#{game_challenge.picture_path}/manual-ok.apk", :size => 12, :level => :h) + @qrcode_str = Base64.encode64( qr.to_img.resize(400,400).to_s ) + + else + @type = "image" + #conv = Iconv.new("GBK", "utf-8") + @game_challenge = @game.challenge + type = @game_challenge.show_type + workspace_path = @game.try(:picture_path) + @answer_path = "#{Rails.root}/#{workspace_path}/#{@game_challenge.expect_picture_path}" + @user_path = "#{Rails.root}/#{workspace_path}/#{@game_challenge.picture_path}" + @original_path = "#{Rails.root}/#{workspace_path}/#{@game_challenge.original_picture_path}" + + @answer_picture = @game_challenge.expect_picture_path.nil? ? [] : get_dir_filename(@answer_path, type, @game.id) + #@answer_picture = @answer_picture.sort {|x, y| conv.iconv(x) <=> conv.iconv(y)} if @answer_picture.present? + + @user_picture = @game_challenge.picture_path.nil? ? [] : get_dir_filename(@user_path, type, @game.id) + #@user_picture = @user_picture.sort {|x, y| conv.iconv(x) <=> conv.iconv(y)} + if @game_challenge.original_picture_path.blank? + @orignal_picture = nil + else + @orignal_picture = @game_challenge.original_picture_path.nil? ? [] : get_dir_filename(@original_path, type, @game.id) + #@orignal_picture = @orignal_picture.sort {|x, y| conv.iconv(x) <=> conv.iconv(y)} + end + end + end + + # 同步更新最新代码 + # 同步完成后,需要更新myshixun的commit_id为实训的commit最新值 + # -------------------------- + # 新思路,有冲突则则重置,没有冲突直接pull + # identifier为password--- + # -------------------------- + # todo: TPI弹框的立即更新 + def sync_codes + shixun_tomcat = edu_setting('cloud_bridge') + begin + git_myshixun_url = repo_ip_url @myshixun.repo_path + git_shixun_url = repo_ip_url @myshixun.shixun.try(:repo_path) + git_myshixun_url = Base64.urlsafe_encode64(git_myshixun_url) + git_shixun_url = Base64.urlsafe_encode64(git_shixun_url) + # todo: identifier 是以前的密码,用来验证的,新版如果不需要,和中间层协调更改. + params = {tpiID: "#{@myshixun.try(:id)}", tpiGitURL: "#{git_myshixun_url}", tpmGitURL: "#{git_shixun_url}", + identifier: "xinhu1ji2qu3"} + uri = "#{shixun_tomcat}/bridge/game/resetTpmRepository" + res = uri_post uri, params + if (res && res['code'] != 0) + tip_exception("实训云平台繁忙(繁忙等级:95)") + end + shixun_new_commit = GitService.commits(repo_path: @myshixun.shixun.repo_path).first["id"] + @myshixun.update_attributes!(commit_id: shixun_new_commit, reset_time: @myshixun.shixun.try(:reset_time)) + if @game.challenge.st == 0 && @game.challenge.path.present? + paths = @game.challenge.path.split(";") + paths.each do |path| + game_code_init @game.id, path.try(:strip) + end + end + @path = @game.challenge.path + # 更新完成后,弹框则隐藏不再提示 + @myshixun.update_column(:system_tip, false) + rescue Exception => e + tip_exception("立即更新代码失败!#{e.message}") + end + end + + ## 给关卡打星星 + def star + shixun = Shixun.select([:id, :averge_star, :status]).where(id: params[:shixun_id]).first + grades = Grade.where(user_id: current_user.id, container_id: @game.id, container_type: 'Star') + if grades.exists? + tip_exception("您已经评价过该实训") + else + @game.update_column(:star, params[:star].to_i) + # 更新实训平均星星数值 + averge_star = Game.find_by_sql("select ifnull(sum(g.star),0)/ifnull(count(*),1) as averge_star from (games g left join + (myshixuns m join shixuns s on s.id = m.shixun_id) on m.id = g.myshixun_id) + where star != 0 and s.id = #{shixun.id}").first.try(:averge_star) + averge_star = averge_star.to_f || 5 + shixun.update_column(:averge_star, averge_star.round(1)) + # 随机生成10-100金币作为奖励 + @gold = 0 + # 加积分只针对已发布的实训 + if shixun.status >= 2 + @gold = rand(10..100) + + RewardGradeService.call(current_user, container_id: @game.id, container_type: 'Star', score: @gold) + end + end + end + + ## 代码文件目录结构 + def git_entries + gpid = params[:gpid] + @path = params[:path].try(:strip) + rev = params[:rev] ? params[:rev] : "master" + @trees = @g.trees(gpid, path: @path, rev: rev) + unless @trees.count + tip_exception("版本库异常") + end + end + + ## 是否可以查看答案,如果是管理员或者系统认证的老师则直接查看,不需要弹框 + def answer + challenge = Challenge.select([:answer, :id, :score, :st]).find(@game.challenge_id) + # 这几种情况可以直接查看答案的:实训未发布;当前用户为实训管理员;已经查看过答案;平台认证的老师; + @allowed = @shixun.status < 2 || @game.answer_open == 1 || current_user.shixun_identity(@shixun) <= User::EDU_CERTIFICATION_TEACHER + uid_logger("-- is manager #{current_user.manager_of_shixun?(@shixun)}") + + @result = challenge.st == 0 ? challenge.try(:answer) : challenge.choose_answer + end + + # 获取答案 + # GET: /tasks/:identifier/get_answer_info + # 0 直接查看答案, 1 查看答案弹框, 2 答案详情弹框 + def get_answer_info + challenge = @game.challenge + @challenge_answers = challenge.challenge_answers + # 平台已认证的老师需要控制 + @power = (@identity < User::EDU_GAME_MANAGER) + if !@power + if @challenge_answers.size == 0 + tip_exception("无答案可以查看") + elsif @challenge_answers.size == 1 + # 未看答案,提示弹框 + if @game.answer_open == 0 + tip_exception(1, {answer_id: @challenge_answers.first.id, answer_score:@challenge_answers.first.score}) + end + else + if @game.answer_open == 0 + tip_exception(2, @challenge_answers.map{|a| {answer_id: a.id, answer_name: a.name, answer_score:a.score}}) + end + end + end + + end + + # 解锁答案 + # GET: /tasks/:identifier/get_answer_info?answer_id=? + def unlock_answer + @answer = ChallengeAnswer.find(params[:answer_id]) + challenge = @answer.challenge + # 解锁需要本层级的答案是否需要扣分 + points = challenge.challenge_answers.where(level: @game.answer_open+1..@answer.level).sum(:score) + deduct_score = ((points / 100.0) * challenge.score).to_i + uid_logger("############金币数目: #{current_user.grade}") + unless current_user.grade.to_i - deduct_score > 0 + tip_exception("您没有足够的金币") + end + + ActiveRecord::Base.transaction do + begin + # 积分消耗情况记录 + score = challenge.st.zero? ? -deduct_score : -challenge.choose_score.to_i + RewardGradeService.call(current_user, container_id: @answer.id, container_type: 'Answer', score: score) + + # 通关查看答案 不扣 得分 + if @game.status == 2 + @game.update_attributes!(:answer_open => @answer.level) + else + @game.update_attributes!(:answer_open => @answer.level, :answer_deduction => deduct_score) + end + + rescue Exception => e + uid_logger_error("#######金币扣除异常: #{e.message}") + raise ActiveRecord::Rollback + end + end + + end + + # 查看答案需要扣取金币 + # 必须保证用户的金币数大于关卡的金币数 + def answer_grade + challenge = Challenge.select([:answer, :id, :score, :st]).find(@game.challenge_id) + challenge_score = challenge.try(:score) + final_score = @game.final_score + @allowed_viewed = current_user.grade.to_i - challenge_score > 0 + unless @allowed_viewed + tip_exception("您没有足够的金币") + end + ActiveRecord::Base.transaction do + begin + if @game.answer_open == 0 # 如果这是第一次查看答案 + if challenge.st == 0 + @final_score = final_score - challenge_score + # 积分消耗情况记录 + RewardGradeService.call( + current_user, + container_id: @game.id, + container_type: 'Answer', + score: -challenge_score + ) + else + @final_score = final_score - challenge.choose_score.to_i + # 之所以不用final_score是因为过关后查看答案的final_score为0,但是记录需要记录扣除的分数 + RewardGradeService.call( + current_user, + container_id: @game.id, + container_type: 'Answer', + score: -challenge.choose_score.to_i) + end + @game.update_attributes!(:answer_open => true, :final_score => final_score) + end + if challenge.st == 0 + @answer = challenge.try(:answer) + else + @answer = challenge.choose_answer + end + @answer = + # 更新当前用户的总金币数 + @grade = User.where(:id => @game.user_id).pluck(:grade).first + rescue Exception => e + uid_logger_error("#######奖励金币异常: #{e.message}") + raise ActiveRecord::Rollback + end + end + + end + + # 查看隐藏测试集 + # REDO:有漏洞,通过game详情可以看到隐藏的测试集 + def check_test_sets + challenge = Challenge.select([:id, :score]).find(@game.challenge_id) + user_grade = current_user.grade + @minus_grade = challenge.score * 5 + @allowed_viewed = user_grade >= @minus_grade + if @allowed_viewed + current_user.update_attribute(:grade, user_grade - @minus_grade) + @game.update_attribute(:test_sets_view, true) + # 扣分记录 + Grade.create(:user_id => current_user.id, :container_id => @game.id, :score => -@minus_grade, :container_type => "testSet") + @status = 0 + @message = "解锁成功!" + else + @status = -1 + @message = "本操作需要扣除#{ @minus_grade }金币,您的金币不够了" + end + end + + # # 文件更新;数据评测记录 + # # 生成重新评测认证码 + # # content_modified:0 表示文件没有更新;content_modified:1 表示文件有更新 + # def file_update + # path = params[:path].strip unless params[:path].blank? + # myshixun = @game.myshixun + # rev = params[:rev] ? params[:rev] : "master" + # @content_modified = 0 + # # params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过 + # # 自动保存的时候evaluate为0;点评测的时候为1 + # if params[:evaluate] == 1 + # record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => myshixun.shixun_id, :game_id => @game.id) + # uid_logger("-- game is #{@game.id}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + # student_work_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f + # record.update_attributes!(:student_work => student_work_time) + # end + # # 远程版本库文件内容 + # last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] + # last_content = tran_base64_decode64(last_content) + # + # content = if @myshixun.mirror_name.select{|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present? + # params[:content].gsub(/\t/, ' ') + # else + # params[:content] + # end + # if content != last_content + # @content_modified = 1 + # code_file = @g.edit_file(myshixun.gpid, current_user.login, :content => content, :file_path => path, + # :branch_name => rev, :commit_message => params[:evaluate] == 0 ? "auto commit" : "task commit") + # uid_logger("-- file update #{code_file}") + # # REDO:更新失败的处理 + # raise("文件更新失败") unless code_file + # end + # + # if record.present? + # consume_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f + # record.update_attributes!(:file_update => consume_time) + # end + # + # # status为2说明是重新评测 + # if @game.status == 2 + # code = CODES.sample(8).join + # @resubmit = "#{code}_#{@myshixun.id}" + # end + # + # if content != last_content && code_file.blank? + # raise("实训平台繁忙(繁忙等级:81),请稍后刷新并重试") + # end + # rescue Exception => e + # uid_logger("-- file update failed #{e.message}") + # raise Educoder::TipException.new("#{e.message}") + # end + + # 恢复初始代码 + # 注意path为当前打开文件的path + def reset_original_code + path = params[:path] + # 恢复初始代码应该找tpm的版本库 + repo_path = @myshixun.shixun.repo_path + + @content = git_fle_content(repo_path, path) + tip_exception("初始代码为空,代码重置失败") if @content.nil? + + # 将tpm的代码内容同步更新到tpi + update_file_content(@content, @myshixun.repo_path, path, current_user.mail, current_user.full_name, "reset_original_code") + rescue Exception => e + uid_logger_error("#{e.message}") + tip_exception("初始化代码失败") + end + + # 加载上次通过的代码 + def reset_passed_code + path = params[:path] + game_code = GameCode.where(:game_id => @game.try(:id), :path => path).first + if game_code.present? + content = game_code.try(:new_code) + @content = if @myshixun.mirror_name.select{|a| a.include?("MachineLearning") || a.include?("Python")}.present? && content.present? + content.gsub(/\t/, ' ') + else + content + end + update_file_content(@content, @myshixun.repo_path, path, current_user.mail, current_user.full_name, "game passed reset") + else + tip_exception("代码重置失败,代码为空") + end + end + + # 获取版本库文件内容 + # 注:如果本身path传错,内容肯定也为空;fork成功后,可能短时间内也获取不到版本库内容 + # params[:status] 1: 目录树点击的请求 0:正常自动加载 + # 返回参数status : -3 需要重试,带retry参数;-1 给出提示 + def rep_content + challenge_path = @game.challenge.try(:path) + if challenge_path.blank? + tip_exception("代码获取异常,请检查实训模板的评测设置是否正确") + end + path = @game.challenge.try(:path).split(";")[0].strip() + path = params[:path] || path + status = params[:status].to_i + path = path.try(:strip) + uid_logger("--rep_content: path is #{path}") + begin + @content = git_fle_content(@myshixun.repo_path, path) || "" + rescue + if params[:retry].present? + begin + begin + # 检测TPM对应的路径代码是否正常 + git_fle_content(@myshixun.shixun.repo_path, path) + rescue Exception => e + uid_logger_error("#{e.message}") + if @myshixun.shixun.try(:status) < 2 + tip_exception("代码获取异常,请检查实训模板的评测设置是否正确") + else + tip_exception("代码获取异常,请联系系统管理员") + end + end + + # 如果模板没有问题,则通过中间层检测实训仓库是否异常 + # 监测版本库HEAD是否存在,不存在则取最新的HEAD + gitUrl = repo_url @myshixun.repo_path + gitUrl = Base64.urlsafe_encode64(gitUrl) + shixun_tomcat = edu_setting('cloud_bridge') + rep_params = {:tpiID => "#{@myshixun.id}", :tpiGitURL => "#{gitUrl}"} + # 监测版本库HEAD是否存在,不存在则取最新的HEAD + uri = "#{shixun_tomcat}/bridge/game/check" + res = uri_post uri, rep_params + # res值:0 表示正常;-1表示有错误;-2表示代码版本库没了 + if status == 0 && res && (res['code'] == -2 || res['code'] == -1) + # 删除不需要的仓库 + begin + GitService.delete_repository(repo_path: @myshixun.repo_path) + rescue Exception => e + uid_logger_error("#{e.message}") + end + # fork一个新的仓库 + project_fork(@myshixun, @shixun.repo_path, current_user.login) + end + rescue Exception => e + uid_logger_error(e.message) + # 报错继续retry + tip_exception(-3, "#{e.message}") + end + end + tip_exception(-3, "#{e.message}") + end + end + + # 编程题评测 + def game_build + game_challenge = Challenge.select([:id, :position, :picture_path]).find(@game.challenge_id) + + # 更新评测次数 + @game.update_column(:evaluate_count, (@game.evaluate_count.to_i + 1)) + # 清空代码评测信息 + msg = @game.run_code_message + msg.update_attributes(:status => 0, :message => nil) if msg.present? + + # 更新时间是为了TPM端显示的更新,退出实训及访问实训的时候会更新 + @myshixun.update_column(:updated_at, Time.now) + + gitUrl = repo_ip_url @myshixun.repo_path + logger.info("#############giturl: ##{gitUrl}") + gitUrl = Base64.urlsafe_encode64(gitUrl) + + shixun_tomcat = edu_setting('cloud_bridge') + step = game_challenge.try(:position) + mirror_repository_limit = @shixun.mirror_repositories.where(main_type: 1).select(:resource_limit).try(:first).try(:resource_limit) + # mirror表中很很大的脚本字段,所以单独查询一个字段效果更好 + resource_limit = "echo 'ulimit -f #{mirror_repository_limit}' >> /root/.bashrc ; source /root/.bashrc\n" + tpmScript = @shixun.evaluate_script.nil? ? "" : Base64.urlsafe_encode64((resource_limit + @shixun.evaluate_script).gsub("\r\n", "\n")) + + # status为2已经通过关,是重新评测 + if @game.status == 2 + resubmit = params[:resubmit] + else + # 重新评测不影响已通关的实训状态;first为第一次评测,通过前端JS轮询获取 + @game.update_attributes!(status: 1) if params[:first].to_i == 1 + end + + testSet = [] + game_challenge.test_sets.each do |test_set| + input = test_set.input.nil? ? "" : test_set.input.gsub("\r\n", "\n") + output = test_set.output.nil? ? "" : test_set.output.gsub("\r\n", "\n") + test_cases = {:input => input, :output => output} + testSet << test_cases + end + + testCases = Base64.urlsafe_encode64(testSet.to_json) unless testSet.blank? + + + # 注意:这个地方的参数写的时候不能换行 + content_modified = params[:content_modified] # 决定文件内容是否有修改,有修改如果中间层pull没有更新,则轮询等待更新 + br_params = {:tpiID => "#{@myshixun.id}", :tpiGitURL => "#{gitUrl}", :buildID => "#{@game.id}", + :instanceChallenge => "#{step}", :testCases => "#{testCases}", :resubmit => "#{resubmit}", + :times => params[:first].to_i, :podType => @shixun.webssh, :content_modified => content_modified, + :containers => "#{Base64.urlsafe_encode64(container_limit(@shixun.mirror_repositories))}", + :persistenceName => @shixun.identifier, :tpmScript => "#{tpmScript}", + :timeLimit => "#{@shixun.exec_time}", :isPublished => (@shixun.status < 2 ? 0 : 1) } + + # 评测有文件输出的需要特殊传字段 path:表示文件存储的位置 + br_params['file'] = Base64.urlsafe_encode64({path: "#{game_challenge.picture_path}"}.to_json) if game_challenge.picture_path.present? + + # needPortMapping: web类型需要pod端口映射 + br_params[:needPortMapping] = 8080 if @myshixun.mirror_name.include?("Web") + + # 中间层交互 + uri = "#{shixun_tomcat}/bridge/game/gameEvaluate" + res = interface_post uri, br_params, 502, "gameEvaluate failed" + + @result = {status: 1, resubmit: resubmit, position: game_challenge.position, port: res['port'], had_done: @game.had_done} + rescue Exception => e + uid_logger("评测出错,详情:" + e.message) + @result = {status: -1, message: "实训云平台繁忙(繁忙等级:502),请稍后刷新并重试", position: game_challenge.position, + had_done: @game.had_done} + end + + # 选择题评测 + def choose_build + Rails.logger.error("#################{params}") + # 选择题如果通关了,则不让再评测 + if @game.status == 2 + raise Educoder::TipException.new("您已通过该关卡") + end + # 更新评测次数 + @game.update_column(:evaluate_count, (@game.evaluate_count.to_i + 1)) + + game_challenge = Challenge.select([:id, :position]).find(@game.challenge_id) + user_answer = params[:answer] + challenge_chooses_count = user_answer.length + + choose_correct_num = 0 + score = 0 + had_passed = true + test_sets = [] + str = "" + game_challenge.challenge_chooses.includes(:challenge_tags).each_with_index do |choose, index| + # user_answer虽然是传的数组,但是可能存在多选择提的情况. + user_answer_tran = user_answer[index].size > 1 ? user_answer[index].split("").sort.join("") : user_answer[index] + standard_answer_tran = choose.standard_answer.size > 1 ? choose.standard_answer.split("").sort.join("") : choose.standard_answer + correct = (user_answer_tran == standard_answer_tran) ? true : false + if str.present? + str += "," + end + str += "('#{@game.id}', '#{choose.position}', '#{user_answer_tran}', '#{correct ? 1 : 0}', '#{@game.next_query_index}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + # 只要有一题错误就不能通关 + had_passed = false if !correct + choose_correct_num += 1 if correct + + # 全部通关的时候,需要对所得的总分记录 + # 总分的记录应该是根据每一题累加,如果该题正确,则加分 + score += choose.score if correct + + standard_answer = correct ? standard_answer_tran : -1 + sin_test_set = {:result => correct, + :actual_output => user_answer_tran, + :standard_answer => standard_answer, + :position => choose.position} + test_sets << sin_test_set + end + + # 批量插入评测结果 + uid_logger("choose_build") + sql = "INSERT INTO outputs (game_id, test_set_position, actual_output, result, query_index, created_at, updated_at) VALUES" + str + ActiveRecord::Base.connection.execute sql + + had_done = @game.had_done + @myshixun.update_attribute(:status, 1) if had_done == 1 + + # 没通关或者查看了答案通关的时候经验为0 + # 通关但是查看了答案,评测的时候金币显示0(避免用户以为重复扣除),但是在关卡列表中金币显示负数 + experience = 0 + final_score = 0 + # 如果本次答题全部正确,并且之前没有通关,则进行相应的奖励,每关只要有错题,则不进行任何奖励 + # 注:扣除分数是在查看答案的时候扣除的 + if had_passed && !@game.had_passed? + @game.update_attributes(:status => 2, :end_time => Time.now) + # TPM实训已发布并且没有查看答案 + if @shixun.is_published? && !@game.answer_open + # 查看答案的时候处理final_scor和扣分记录 + experience = score + reward_attrs = { container_id: @game.id, container_type: 'Game', score: score } + RewardGradeService.call(@myshixun.owner, reward_attrs) + @game.update_attribute(:final_score, score) + final_score = score + RewardExperienceService.call(@myshixun.owner, reward_attrs) + end + end + + grade = @myshixun.owner.try(:grade) + + # 更新实训关联的作品分数 TODO: 更新作业需要等作业模块开了再打开 + # update_myshixun_work_score myshixun + + # 高性能取上一关、下一关 + prev_game = @game.prev_of_current_game(@shixun.id, @game.myshixun_id, game_challenge.position) + next_game = @game.next_of_current_game(@shixun.id, @game.myshixun_id, game_challenge.position) if had_passed + + # 高性能取上一关、下一关 + #prev_game = Game.prev_identifier(@shixun.id, @game.myshixun_id, game_challenge.position) + #next_game = Game.next_game(@shixun.id, @game.myshixun_id, game_challenge.position) + + @result = {grade: grade, + gold: final_score, + experience: experience, + challenge_chooses_count: challenge_chooses_count, + choose_correct_num: choose_correct_num, + test_sets: test_sets, + prev_game: prev_game, + next_game: next_game} + rescue Exception => e + uid_logger("choose build failed #{e.message}") + @result = [status: -1, contents: "#{e.message}"] + end + + # 轮询获取状态 + # resubmit是在file_update中生成的,从game_build中传入的 + def game_status + resubmit_identifier = @game.resubmit_identifier + # 如果没有超时并且正在评测中 + # 判断评测中的状态有两种:1、如果之前没有通关的,只需判断status为1即可;如果通过关,则判断game的resubmit_identifier是否更新 + uid_logger("################game_status: #{@game.status}") + uid_logger("################params[:resubmit]: #{params[:resubmit]}") + uid_logger("################resubmit_identifier: #{resubmit_identifier}") + uid_logger("################time_out: #{params[:time_out]}") + if (params[:time_out] == "false") && ((params[:resubmit].blank? && @game.status == 1) || (params[:resubmit].present? && + (params[:resubmit] != resubmit_identifier))) + # 代码评测的信息 + running_code_status = @game.run_code_message.try(:status) + running_code_message = @game.run_code_message.try(:message) + render :json => { running_code_status: running_code_status, running_code_message: running_code_message } + end + + uid_logger("##### resubmit_identifier is #{resubmit_identifier}") + port = params[:port] + score = 0 + experience = 0 + game_status = @game.status + had_done = @game.had_done + game_challenge = Challenge.select([:id, :score, :position, :shixun_id, :web_route]).find(@game.challenge_id) + + if params[:resubmit].blank? # 非重新评测 + if game_status == 2 # 通关 + if @shixun.status > 1 + score = @game.final_score # 查看答案的时候有对最终获得金币进行处理 + experience = @game.final_score + else + score = 0 + experience = 0 + end + end + else # 重新评测 + # 如果满足前面的条件,进入此处只可能是结果已返回并存入了数据库 + if params[:resubmit] == resubmit_identifier # 本次重新评测结果已经返回并存入数据库 + game_status = (@game.retry_status == 2 ? 2 : 0) # retry_status是判断重新评测的通关情况。2表示通关 + end + end + + # 实训的最大评测次数,这个值是为了优化查询,每次只取最新的最新一次评测的结果集 + max_query_index = @game.query_index + #max_query_index = @game.outputs.first.try(:query_index) + # 区分评测过未评测过,未评测过按需求取数据 + testset_detail max_query_index.to_i, game_challenge + + # 处理生成图片类型文件 + picture = (@game.picture_path.nil? ? 0 : @game.id) + # 针对web类型的实训 + web_route = game_challenge.try(:web_route) + mirror_name = @shixun.mirror_name + + # 轮询结束,更新评测统计耗时 + if game_status == 0 || game_status == 2 + e_record = EvaluateRecord.where(:game_id => @game.id).first + if e_record + front_js = format("%.3f", (Time.now.to_f - e_record.try(:updated_at).to_f)).to_f + consume_time = format("%.3f", (Time.now - e_record.created_at)).to_f + e_record.update_attributes(:consume_time => consume_time, :front_js => front_js) + end + end + + uid_logger("game is is #{@game.id}, record id is #{e_record.try(:id)}, time is**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + # 记录前端总耗时 + record_consume_time = EvaluateRecord.where(:game_id => @game.id).first.try(:consume_time) + # 实训制作者当前拥有的金币 + grade = User.where(:id => @game.user_id).pluck(:grade).first + + # 高性能取上一关、下一关 + # 上一关、下一关 + prev_game = @game.prev_of_current_game(@shixun.id, @game.myshixun_id, game_challenge.position) + next_game = @game.next_of_current_game(@shixun.id, @game.myshixun_id, game_challenge.position) if game_status == 2 + @base_date = {grade: grade, gold: score, experience: experience, status: game_status, had_done: had_done, + position: game_challenge.position, port: port, record_consume_time: record_consume_time, + mirror_name: mirror_name, picture: picture, web_route: web_route, star: @game.star, + next_game: next_game, prev_game: prev_game} + end + + # 记录实训花费的时间 + # REDO:需要添加详细的说明 + def cost_time + cost_time = params[:time].to_i + @game.update_attribute(:cost_time, cost_time) + end + + # 同步challenge的更新时间 + def sync_modify_time + modify_time = Challenge.where(:id => @game.challenge_id).pluck(:modify_time).first + @game.update_column(:modify_time, modify_time) + sucess_status + end + + # tpi弹框状态更新;true则不再显示;false每次刷新显示 + def system_update + myshixun = Myshixun.find(params[:myshixun_id]) + myshixun.update_attribute(:system_tip, true) + sucess_status + end + + # 关闭webssh + def close_webssh + myshixun_id = @game.myshixun_id + digest = @game.identifier + edu_setting('bridge_secret_key') + digest_key = Digest::SHA1.hexdigest("#{digest}") + begin + shixun_tomcat = edu_setting('cloud_bridge') + uri = "#{shixun_tomcat}/bridge/webssh/delete" + Rails.logger.info("#{current_user} => cloese_webssh digest is #{digest}") + params = {:tpiID => myshixun_id, :digestKey => digest_key, :identifier => @game.identifier} + res = uri_post uri, params + if res && res['code'].to_i != 0 + raise("实训云平台繁忙(繁忙等级:110)") + end + rescue Exception => e + Rails.logger.error(e) + tip_exception("实训云平台繁忙, 关闭失败!") + end + end + + # tpi对于实训关卡的点赞或取消点赞 + def plus_or_cancel_praise + challenge = @game.challenge + pt = PraiseTread.where(:praise_tread_object_id => challenge.id, :praise_tread_object_type => 'Challenge', + :user_id => current_user, :praise_or_tread => 1).first + # 如果当前用户已赞过,则不能重复赞 + if pt.blank? + PraiseTread.create!(:praise_tread_object_id => challenge.id, :praise_tread_object_type => 'Challenge', + :user_id => current_user.id, :praise_or_tread => 1) if pt.blank? + @praise = true + else + pt.destroy if pt.present? # 如果已赞过,则删掉这条赞(取消);如果没赞过,则为非法请求不处理 + @praise = false + end + + @praise_count = PraiseTread.where(:praise_tread_object_id => challenge.id, :praise_tread_object_type => 'Challenge', + :praise_or_tread => 1).count + end + + private + + # 评测测试机封装 + def testset_detail max_query_index, challenge + # 是否允许查看隐藏的测试集,以前的power + @allowed_hidden_testset = @identity < User::EDU_GAME_MANAGER + + if max_query_index > 0 + uid_logger("max_query_index is #{max_query_index} game id is #{@game.id}, challenge_id is #{challenge.id}") + @qurey_test_sets = TestSet.find_by_sql("SELECT o.code, o.actual_output, o.out_put, o.result, o.test_set_position, + o.query_index, t.is_public, t.input, t.output, o.compile_success FROM outputs o, games g, challenges c, + test_sets t where g.id=#{@game.id} and c.id=#{challenge.id} and o.query_index=#{max_query_index} + and g.id = o.game_id and c.id= g.challenge_id and t.challenge_id = c.id and + t.position =o.test_set_position order by o.query_index + ") + @test_sets_count = @qurey_test_sets.count + # 错误的测试集总数 + @sets_error_count = 0 + @qurey_test_sets.each do |set| + @sets_error_count += 1 unless set.result + end + @last_compile_output = @qurey_test_sets.first['out_put'].gsub(/\n/, '
').gsub(/\t/, " \; \; \; \; \; \; \; \;") if @qurey_test_sets.first['out_put'].present? + else + @qurey_test_sets = TestSet.find_by_sql("SELECT t.is_public, t.input, t.output, t.position + FROM test_sets t where t.challenge_id = #{challenge.id}") + end + end + + # 实训选择题需要局部刷新或者显示的部分 + def choose_container game_challenge, game, max_query_index + # category 1: 单选题,其它的多选题(目前只有两种) + challenge_chooses = game_challenge.challenge_chooses.includes(:challenge_questions) + test_sets = [] + @chooses = [] + + # 选择题测试集统计 + challenge_chooses_count = challenge_chooses.count + choose_correct_num = game.choose_correct_num(max_query_index) + game_outputs = game.outputs.where(:query_index => max_query_index) + + # 判断用户是否有提交 + had_submmit = game_outputs.present? + + # 判断选择题是否写了标准答案 + has_answer = [] + challenge_chooses.each do |choose| + challenge_question = [] + output = game_outputs.select{|game_output| game_output.test_set_position == choose.position}[0] unless game_outputs.blank? + + category = choose.category + subject = choose.subject + choose.challenge_questions.each do |question| + position = question.position + option_name = question.option_name + challenge_question << {:positon => position, :option_name => option_name} + end + # actual_output为空表示暂时没有评测答题,不允许查看 + actual_output = output.try(:actual_output).try(:strip) + has_answer << choose.answer if choose.answer.present? + # 标准答案处理,错误的不让用户查看,用-1替代 + standard_answer = (actual_output.blank? || !output.try(:result)) ? -1 : choose.standard_answer + result = output.try(:result) + sin_test_set = {:result => result, :actual_output => actual_output, :standard_answer => standard_answer, + :position => choose.position} + + sin_choose = {:category => category, :subject => subject, :challenge_question => challenge_question} + @chooses << sin_choose + test_sets << sin_test_set + end + @has_answer = has_answer.present? + @choose_test_cases = {:had_submmit => had_submmit, :challenge_chooses_count => challenge_chooses_count, + :choose_correct_num => choose_correct_num, :test_sets => test_sets} + end + + + def find_game + @game = Game.find_by_identifier(params[:identifier]) + if @game.blank? + normal_status(404, "...") + return + end + + @myshixun = @game.myshixun + end + + def find_shixun + @shixun = Shixun.find(@myshixun.shixun_id) + end + + # http://localhost:3000/tasks/hcie39pw2bjn + # 可以访问条件:学员本身;管理员;TPM制作者 + def allowed + @identity = current_user.game_identity(@game) + raise Educoder::TipException.new(403, "..") if @identity > User::EDU_GAME_MANAGER + end +end diff --git a/app/controllers/gits_controller.rb b/app/controllers/gits_controller.rb new file mode 100644 index 000000000..778963f6e --- /dev/null +++ b/app/controllers/gits_controller.rb @@ -0,0 +1,62 @@ +class GitsController < ApplicationController + + #供git-workhorse反向调用认证 + def auth + # HTTP_AUTHORIZATION: "Basic 这里base64编码的的密码(user:passwd)" + logger.info("11111112222223333#{request.env["HTTP_AUTHORIZATION"]}") + #logger.info("#########-----request_env: #{request.env}") + # {"service"=>"git-receive-pack", "controller"=>"gits", "action"=>"auth", + # "url"=>"forge01/cermyt39.git/info/refs"} + # + gituser = edu_setting('git_username') + gitpassword = edu_setting('git_password') + + result = false + if request.env["HTTP_AUTHORIZATION"] && request.env["HTTP_AUTHORIZATION"].split(" ").length == 2 + username_password = Base64.decode64(request.env["HTTP_AUTHORIZATION"].split(" ")[1]) + input_username = username_password.split(":")[0].strip() + input_password = username_password.split(":")[1].strip() + uid_logger("git start auth: input_username is #{input_username}") + + # Git 超级权限用户 + if input_username == gituser && input_password == gitpassword + result = true + else + # 用户是否对对象拥有权限 + system_user = User.find_by_login(input_username) || User.find_by_mail(input_username) || User.find_by_phone(input_username) + + # 如果用户名密码错误 + if !system_user.check_password?(input_password) + uid_logger_error("git start: password is wrong") + result = false + else + git_url = params["url"] + username = git_url.split("/")[0] + shixunname = git_url.split("/")[1].split(".")[0] + repo_name = username + "/" + shixunname + uid_logger("git start: repo_name is #{repo_name}") + shixun = Shixun.select([:id, :user_id, :repo_name, :identifier]).where(repo_name: repo_name).first + uid_logger("git start auth: shixun identifier is #{shixun.try(:identifier)}") + uid_logger("git start auth: systemuser is #{system_user.try(:login)}") + + if shixun.present? + if system_user.present? && system_user.manager_of_shixun?(shixun) + result = true + else + logger.info("git411 start") + result = false + end + else + render :json => { :status => 404 } + result = false + end + end + end + end + + authenticate_or_request_with_http_basic do |username, password| + result + end + end + +end \ No newline at end of file diff --git a/app/controllers/graduation_tasks_controller.rb b/app/controllers/graduation_tasks_controller.rb new file mode 100644 index 000000000..d95716c9b --- /dev/null +++ b/app/controllers/graduation_tasks_controller.rb @@ -0,0 +1,580 @@ +class GraduationTasksController < ApplicationController + before_action :require_login, except: [:index] + before_action :find_course, except: [:edit, :update, :settings, :update_settings, :tasks_list, :show, :show_comment] + before_action :find_task, only: [:edit, :update, :settings, :update_settings, :tasks_list, :show, :show_comment] + before_action :user_course_identity + before_action :task_publish, only: [:show, :show_comment, :tasks_list, :settings] + before_action :teacher_allowed, only: [:new, :create, :edit, :update, :set_public,:multi_destroy, :publish_task, :end_task, + :update_settings, :add_to_bank] + before_action :require_id_params, only: [:set_public ,:multi_destroy, :publish_task, :end_task, :add_to_bank] + before_action :valid_params, only: [:update_settings] + include ExportHelper + + def index + search = "#{params[:search].to_s.strip.downcase}" + order = params[:order] + page = params[:page] ? params[:page].to_i : 1 + + default_order = "IF(ISNULL(graduation_tasks.publish_time),0,1), graduation_tasks.publish_time DESC, graduation_tasks.created_at DESC" + @identity = current_user.course_identity(@course) + if @identity < Course::STUDENT + @tasks = @course.graduation_tasks.where("graduation_tasks.name like ?", "%#{search}%") + else + @tasks = @course.graduation_tasks.where("graduation_tasks.name like ? and publish_time <= '#{Time.now}'", "%#{search}%") + end + + if order.present? && order != "all" + if @course.is_end + @tasks = @tasks.none + elsif order.to_i == 4 # 补交 + @tasks = @tasks.where("status > 1 and allow_late = 1 and (late_time is null or late_time > '#{Time.now}')") + else + @tasks = @tasks.where(status: order) + end + end + + @member = @course.course_members.find_by(user_id: current_user.id, is_active: 1) + @all_count = @course.graduation_tasks.size + @published_count = @course.graduation_tasks.where("publish_time <= '#{Time.now}'").size + @task_count = @tasks.size + @tasks = @tasks.reorder("#{default_order}").page(page).per(15).includes(:graduation_works, course: [course_members: :teacher_course_groups]) + end + + # 任务问答 + def show + @attachments = @task.attachments + @current_user = current_user + end + + # 毕设任务列表 + def tasks_list + # 搜索栏数据 + @current_user = current_user + + # 分页参数 + page = params[:page] || 1 + limit = params[:limit] || 20 + @work = @task.graduation_works.where(user_id: current_user.id) + #end_time @task.allow_late ? @task.late_time : @task.end_time + # 任务发布的情况下: 是老师身份或者任务已截止的情况下公开任务了作品设置的学生也能查看其他人的作品 + if @task.published? && (@user_course_identity < Course::STUDENT || + (@user_course_identity == Course::STUDENT && @work.present? && @work.take.work_status > 0 && + @task.status > 1 && @task.open_work)) + # 如有有分班则看分班内的学生,否则看所有学生的作品 + user_ids = + if @user_course_identity < Course::STUDENT + @course.teacher_group_user_ids(current_user.id) + else + course_group_id = @course.course_member(current_user.id).course_group_id + @course.course_members.where(course_group_id: course_group_id).pluck(:user_id) + end + + @work_list = @task.graduation_works.where(user_id: user_ids).includes(user: [:user_extension]) + @all_work_count = @work_list.count + @teachers = @course.teachers + # 教师评阅搜索 0: 未评, 1 已评 + unless params[:teacher_comment].blank? + graduation_work_ids = GraduationWorkScore.where(graduation_work_id: @work_list.map(&:id)).pluck(:graduation_work_id) + if params[:teacher_comment] == 0 + @work_list = @work_list.where.not(id: graduation_work_ids) + elsif params[:teacher_comment] == 1 + @work_list = @work_list.where(id: graduation_work_ids).where.not(work_status: 0) + end + end + + # 作品状态 0: 未提交, 1 按时提交, 2 延迟提交 + unless params[:task_status].blank? + @work_list = @work_list.where(work_status: params[:task_status]) + end + + # 分班情况 + unless params[:course_group].blank? + group_user_ids = @course.course_members.where(course_group_id: params[:course_group]).pluck(:user_id) + # 有分组只可能是老师身份查看列表 + @work_list = @work_list.where(user_id: group_user_ids) + end + + # 只看我的交叉评阅 + unless params[:cross_comment].blank? + graduation_work_id = @task.graduation_work_comment_assignations.where(:user_id =>current_user.id) + .pluck(:graduation_work_id).uniq if @task.graduation_work_comment_assignations + @work_list = @work_list.where(id: graduation_work_id) + end + + # 输入姓名和学号搜索 + # TODO user_extension 如果修改 请调整 + unless params[:search].blank? + @work_list = @work_list.joins(user: :user_extension).where("concat(lastname, firstname) like ? + or student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%") + end + + # 排序 + rorder = params[:order] || "updated_at" + b_order = params[:b_order] || "desc" + if rorder == "created_at" || rorder == "work_score" + @work_list = @work_list.order("graduation_works.#{rorder} #{b_order}") + elsif rorder == "student_id" + @work_list = @work_list.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}") + end + + + @work_count = @work_list.count + @work_excel = @work_list + @work_list = @work_list.page(page).limit(limit) + respond_to do |format| + format.json + format.xlsx{ + if @user_course_identity >= Course::STUDENT + tip_exception(403, "无权限操作") + else + graduation_work_to_xlsx(@work_excel,@task,current_user) + exercise_export_name = current_user.real_name + "_" + @course.name + "_" + @task.name + "_" + Time.now.strftime('%Y%m%d_%H%M%S') + render xlsx: "#{exercise_export_name.strip.first(30)}",template: "graduation_tasks/tasks_list.xlsx.axlsx",locals: {table_columns:@head_cells_column, task_users:@task_cells_column} + end + } + format.zip{ + if @user_course_identity >= Course::STUDENT + tip_exception(403, "无权限操作") + else + zip_works = @work_excel.where("work_status > 0") + status = checkfileSize(zip_works) + if status == 0 + zipfile = zip_homework_common @task, zip_works + file = decode64(zipfile[0][:base64file]) + send_file "#{OUTPUT_FOLDER}/#{file}", filename: filename_for_content_disposition(file), type: 'application/zip' + else + tip_exception(status == -1 ? "文件大小超过500M,请通过微信或者QQ联系管理员辅助您打包下载" : "无附件可下载") + end + end + } + end + else + @work_list = @work + @work_count = @work_list.count + @all_work_count = @work_list.count + respond_to do |format| + format.json + format.xlsx{ + normal_status(-1,"作业未发布") + } + format.zip{ + normal_status(-1,"作业未发布") + } + end + end + end + + + # 评论列表接口、 包含一级和二级评论的获取 + def show_comment + @page = params[:page] || 1 + @limit = params[:limit] || 10 + @parent = params[:parent_id] + @current_user = current_user + + @messages = @task.journals_for_messages + @messages_count = @messages.count + if @parent + @messages = @messages.where(m_parent_id: @parent).order("created_on asc") + else + @messages = @messages.parent_comment.order("created_on desc") + end + + @messages = @messages.page(@page).per(@limit) + end + + def create + ActiveRecord::Base.transaction do + begin + @graduation_task = GraduationTask.new(graduation_task_params) + @graduation_task.course_id = @course.id + @graduation_task.user_id = current_user.id + @graduation_task.base_on_project = @graduation_task.task_type == 2 ? 1 : 0 + if @graduation_task.save! + # 为学生创建作品 + @graduation_task.create_work_list + + Attachment.associate_container(params[:attachment_ids], @graduation_task.id, @graduation_task.class) if params[:attachment_ids] + end + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def new + left_banner_content = @course.course_modules.search_by_module_type("graduation") + if left_banner_content.present? + banner = left_banner_content.first.course_second_categories.last + @left_banner_id = banner.id + @left_banner_name = banner.name + else + normal_status(-1,"左侧导航不存在!") + end + end + + def edit + left_banner_content = @course.course_modules.search_by_module_type("graduation") + if left_banner_content.present? + banner = left_banner_content.first.course_second_categories.last + @left_banner_id = banner.id + @left_banner_name = banner.name + end + end + + def update + ActiveRecord::Base.transaction do + begin + @task.update_attributes(graduation_task_params) + Attachment.associate_container(params[:attachment_ids], @task.id, @task.class) if params[:attachment_ids] + normal_status(0, "更新成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 设为公开 + def set_public + tip_exception("仅公开课堂才能公开毕设任务") if @course.is_public == 0 + tasks = @course.graduation_tasks.where(id: params[:task_ids]) + tasks.update_all(is_public: 1) + normal_status(0, "更新成功") + end + + # 删除多个任务 + def multi_destroy + ActiveRecord::Base.transaction do + begin + tasks = @course.graduation_tasks.where(id: params[:task_ids]) + + tasks.destroy_all + + # 这些写是因为model中的关联删除无法删除is_delete=0的作品 + GraduationWork.where(graduation_work_id: tasks.pluck(:id)).destroy_all + normal_status(0, "删除成功") + + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 加入题库 + def add_to_bank + ActiveRecord::Base.transaction do + begin + tasks = @course.graduation_tasks.where(id: params[:task_ids]) + + tasks.each do |task| + task_bank = current_user.gtask_banks.find_by(graduation_task_id: task.id) + + # 已加入的更新,未加入的新建 + if task_bank.present? + task_bank.update_attributes(name: task.name, description: task.description, course_list_id: @course.course_list_id, + min_num: task.min_num, max_num: task.max_num, base_on_project: task.base_on_project) + task_bank.attachments.destroy_all + else + task_bank = GtaskBank.new(name: task.name, description: task.description, user_id: current_user.id, + task_type: task.task_type, quotes: 1, graduation_task_id: task.id, + min_num: task.min_num, max_num: task.max_num, base_on_project: task.base_on_project, + course_list_id: @course.course_list_id) + + task_bank.save! + end + task.attachments.each do |attachment| + att = attachment.copy + att.author_id = task_bank.user_id + att.copy_from = attachment.id + task_bank.attachments << att + end + end + + normal_status(0,"加入题库成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def publish_task + tip_exception("缺少截止时间参数") if params[:end_time].blank? + tip_exception("截止时间必须晚于当前时间") if params[:end_time] <= strf_time(Time.now) + + ActiveRecord::Base.transaction do + begin + tasks = @course.graduation_tasks.where(id: params[:task_ids], status: 0). + where("publish_time is null or publish_time > '#{Time.now}'") + + tasks.each do |task| + task.publish_time = Time.now + task.status = 1 + + task.end_time = params[:end_time] + + # 补交结束时间 + task.late_time = Time.at(task.end_time.to_i + 30*24*3600) if task.allow_late && task.late_time.nil? + + task.save! + GraduationTaskPublishNotifyJob.perform_later(task.id) + task.act_as_course_activity + end + normal_status(0, "发布成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def end_task + ActiveRecord::Base.transaction do + begin + tasks = @course.graduation_tasks.where(id: params[:task_ids], status: 1) + + tasks.each do |task| + task.end_time = Time.now + task.status = task.allow_late ? 2 : 3 + task.save! + end + normal_status(0, "更新成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def settings + @current_user = current_user + end + + def update_settings + ActiveRecord::Base.transaction do + begin + unless @course.is_end + + # 分组设置 已有提交作品或关联项目的,则“基于项目实施”不能修改, 已有提交作品的人数限制的范围只能扩大,不能缩小 + if @task.task_type == 2 + @task.min_num = @task.student_commit_works ? (params[:min_num].to_i > @task.min_num ? @task.min_num : params[:min_num]) + : params[:min_num] + @task.max_num = @task.student_commit_works ? (params[:max_num].to_i < @task.max_num ? @task.max_num : params[:max_num]) + : params[:max_num] + unless @task.student_relate_projects + tip_exception("base_on_project参数不能为空") if params[:base_on_project].blank? + @task.base_on_project = params[:base_on_project].to_i + end + end + + # 发布设置 + if @task.status == 0 + tip_exception("发布时间不能为空") if params[:publish_time].blank? + tip_exception("截止时间不能为空") if params[:end_time].blank? + tip_exception("发布时间不能早于当前时间") if params[:publish_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") + tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") + tip_exception("截止时间不能早于发布时间") if params[:publish_time] > params[:end_time] + tip_exception("截止时间不能早于课堂结束时间") if @course.end_date.present? && + params[:end_time] > @course.end_date.end_of_day + + @task.publish_time = params[:publish_time] + @task.end_time = params[:end_time] + if @task.publish_time <= Time.now + @task.status = 1 + send_tiding = true + end + + elsif @task.status < 2 + tip_exception("截止时间不能为空") if params[:end_time].blank? + tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") + tip_exception("截止时间不能早于课堂结束时间") if @course.end_date.present? && params[:end_time] > @course.end_date.end_of_day + @task.end_time = params[:end_time] + end + + # 补交设置 + # @task.allow_late = params[:allow_late] + # @task.late_penalty = params[:allow_late].to_i == 1 ? params[:late_penalty] : 0 + current_late_penalty = @task.late_penalty + if params[:allow_late].to_i == 1 + tip_exception("补交结束时间不能为空") if params[:late_time].blank? + tip_exception("补交结束时间不能早于截止时间") if params[:late_time] <= @task.end_time + tip_exception("补交结束时间不能晚于课堂结束时间") if @course.end_date.present? && params[:late_time] > + @course.end_date.end_of_day + tip_exception("迟交扣分应为正整数") if params[:late_penalty] && params[:late_penalty].to_i < 0 + + @task.allow_late = true + @task.late_time = params[:late_time] + @task.late_penalty = params[:late_penalty].to_i + else + @task.allow_late = false + @task.late_penalty = 0 + end + + # 迟交扣分有变动则更新迟交学生的成绩 + if @task.late_penalty != current_late_penalty + @task.graduation_works.where(work_status: 2).each do |work| + work.late_penalty = @task.late_penalty + work.save! + end + end + + # 评分设置 + unless @task.cross_comment && @task.comment_time && @task.comment_time < Time.now + @task.cross_comment = params[:cross_comment].to_i + + tip_exception("评阅时间不能为空") if @task.cross_comment && params[:comment_time].blank? + tip_exception("评阅时间应当大于截止时间") if @task.cross_comment && params[:comment_time] <= @task.end_time + + @task.comment_time = @task.cross_comment ? params[:comment_time] : nil + @task.comment_num = @task.cross_comment ? params[:comment_num].to_i : 3 + @task.comment_status = @task.cross_comment ? params[:comment_status] : 0 + if @task.cross_comment && params[:comment_status].to_i == 4 + tip_exception("评阅数不能为空") if params[:comment_num].blank? + tip_exception("评阅数应大于0") if params[:comment_num].to_i < 1 + + @course.graduation_groups.each_with_index do |group, index| + ass_group = @task.graduation_task_group_assignations.find_by(graduation_group_id: group.id) + if ass_group.present? && params[:comment_group][index].present? && params[:comment_group][index] != "0" + ass_group.update_attributes(assign_graduation_group_id: params[:comment_group][index]) + else + @task.graduation_task_group_assignations << GraduationTaskGroupAssignation.new(graduation_group_id: group.id, + assign_graduation_group_id: params[:comment_group][index]) + end + end + end + end + + # 公开设置 + @task.open_work = params[:open_work] ? params[:open_work].to_i : 0 + @task.open_score = params[:open_score] ? params[:open_score].to_i : 0 + @task.save! + + if send_tiding + GraduationTaskPublishNotifyJob.perform_later(@task.id) + @task.act_as_course_activity + end + + normal_status(0, "更新成功") + else + tip_exception("课堂已结束不能再更新") + end + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + private + def find_task + begin + @task = GraduationTask.find(params[:id]) + @course = @task.course + rescue Exception => e + uid_logger(e.message) + tip_exception("id不存在") + end + end + + # 未发布时非老师角色不能访问,发布后非课堂成员不能访问未公开的任务 + def task_publish + if (@user_course_identity >= Course::STUDENT && @task.status < 1) || + (@user_course_identity > Course::STUDENT && (@course.is_public == 0 || !@task.is_public)) + tip_exception(-1,"任务还未发布,无法查看") + end + end + + def graduation_task_params + tip_exception("task_type参数不能为空") if params[:task_type].blank? + tip_exception("name参数不能为空") if params[:name].blank? + tip_exception("name参数不能超过60个字符") if params[:name].length > 60 #6.11 -hs + tip_exception("description参数不能为空") if params[:description].blank? + params.require(:graduation_task).permit(:task_type, :name, :description) + end + + def require_id_params + tip_exception("请至少选择一个毕设任务") if params[:task_ids].blank? + tip_exception("批量设置不能超过15个") if params[:task_ids].length > 15 + end + + def valid_params + if @task.task_type == 2 + tip_exception("最小人数不能为空") if params[:min_num].blank? + tip_exception("最大人数不能为空") if params[:max_num].blank? + tip_exception("最小人数不能少于1") if params[:min_num].to_i <= 0 + tip_exception("最大人数不能小于最小人数要求") if params[:min_num].to_i > params[:max_num].to_i + end + end + # + # def graduation_work_to_xls items + # xls_report = StringIO.new + # book = Spreadsheet::Workbook.new + # sheet1 = book.create_worksheet :name => "学生成绩" + # blue = Spreadsheet::Format.new :color => :blue, :weight => :bold, :size => 10 + # sheet1.row(0).default_format = blue + # course = @task.course + # count_row = 1 + # list = 0 + # if @task.task_type == 1 + # if @task.cross_comment + # sheet1.row(0).concat(["学生id","真实姓名", "登录名", "学号", "电子邮箱", "分班", "作品描述", "教师评分","交叉评分", "迟交扣分", + # "成绩", "更新时间"]) + # else + # sheet1.row(0).concat(["学生id", "真实姓名", "登录名", "学号", "电子邮箱", "分班", "作品描述", "教师评分", "迟交扣分", + # "成绩", "更新时间"]) + # end + # items.each do |work| + # sheet1[count_row,list] = work.user.id + # sheet1[count_row,list+=1] = work.user.full_name + # sheet1[count_row,list+=1] = work.user.login + # sheet1[count_row,list+=1] = work.user.student_id + # sheet1[count_row,list+=1] = work.user.mail + # sheet1[count_row,list+=1] = work.class_grouping_name + # sheet1[count_row,list+=1] = strip_html work.description if work.description + # sheet1[count_row,list+=1] = work.teacher_score.nil? ? "未评分" : work.teacher_score.round(1) + # if @task.cross_comment + # sheet1[count_row,list+=1] = work.cross_score.nil? ? "未评分" : work.cross_score.round(1) + # end + # sheet1[count_row,list+=1] = work.late_penalty + # sheet1[count_row,list+=1] = work.respond_to?("work_score") ? work.work_score.nil? ? "未评分" : work.work_score.round(1) : "未评分" + # sheet1[count_row,list+=1] = format_time(work.update_time) + # count_row += 1 + # list = 0 + # end + # elsif @task.task_type == 2 + # if @task.cross_comment + # sheet1.row(0).concat(["分组", "组员","分班", "作品描述", "教师评分","交叉评分","迟交扣分", "成绩", "更新时间"]) + # else + # sheet1.row(0).concat(["分组", "组员","分班", "作品描述", "教师评分", "迟交扣分", "成绩", "更新时间"]) + # end + # items.each do |work| + # sheet1[count_row,list] = work.group_id + # sheet1[count_row,list+=1] = work.user.full_name + # sheet1[count_row,list+=1] = work.class_grouping_name + # sheet1[count_row,list+=1] = strip_html work.description if work.description + # sheet1[count_row,list+=1] = work.teacher_score.nil? ? "未评分" : work.teacher_score.round(1) + # if @task.cross_comment + # sheet1[count_row,list+=1] = work.cross_score.nil? ? "未评分" : work.cross_score.round(1) + # end + # sheet1[count_row,list+=1] = work.late_penalty + # sheet1[count_row,list+=1] = work.respond_to?("work_score") ? work.work_score.nil? ? "未评分" : work.work_score.round(1) : "未评分" + # sheet1[count_row,list+=1] = format_time(work.update_time) + # count_row += 1 + # list = 0 + # end + # end + # book.write xls_report + # xls_report.string + # end + +end diff --git a/app/controllers/graduation_topics_controller.rb b/app/controllers/graduation_topics_controller.rb new file mode 100644 index 000000000..6bc3a4c2a --- /dev/null +++ b/app/controllers/graduation_topics_controller.rb @@ -0,0 +1,312 @@ +class GraduationTopicsController < ApplicationController + before_action :require_login, except: [:index] + before_action :find_course + before_action :teacher_allowed, only: [:new, :create, :update, :edit, :destroys, :set_public, + :refuse_student_topic, :accept_student_topic, :export] + before_action :find_graduation_topic, except: [:index, :create, :new, :set_public, :destroys, :export] + before_action :find_course_teachers, only: [:new, :edit] + before_action :user_course_identity, only: [:index, :show, :show_detail, :show_comment] + + include ExportHelper + + + # 毕设选题列表 + def index + @graduation_topic = @course.graduation_topics + @current_user = current_user + # 搜索 + if params[:search] + @graduation_topic = @graduation_topic.search_by_name(params[:search]) + end + + if params[:status] + @graduation_topic = @graduation_topic.search_by_status(params[:status]) + end + + # 当前用户是否已经选过题 + # @user_selected = StudentGraduationTopic.where(graduation_topic_id: @graduation_topic, user_id: current_user.id).count > 0 + user_graduation_topics = @course.student_graduation_topics.where(user_id: current_user.id, status: [0, 1], graduation_topic_id: @graduation_topic.pluck(:id)) #6.12 -hs + @user_selected = user_graduation_topics.size > 0 + ## 分页参数 + page = params[:page] || 1 + limit = params[:limit] || 15 + @graduation_topic_count = @graduation_topic.count + @graduation_topic = @graduation_topic.order("created_at desc").page(page).per(limit) + end + + # 课题列表 + def show + @student_graduation_topics = + if @user_course_identity > Course::STUDENT && !@graduation_topic.is_public + StudentGraduationTopic.none + else + @graduation_topic.student_graduation_topics.includes(:user, :course_member => [:course_group]) + .order("student_graduation_topics.created_at desc") + end + ## 分页参数 + @current_user = current_user + course_group_ids = @course.course_members.where(user_id: current_user.id, role: [1,2,3]).pluck(:course_group_id).uniq + #6.11 -hs + if course_group_ids.present? + if course_group_ids.include?(0) + course_group_ids = @course.course_groups.pluck(:id) + end + end + + @group_list = CourseGroup.where(id: course_group_ids) + + page = params[:page] || 1 + limit = params[:limit] || 50 + @users_count = @student_graduation_topics.try(:count).to_i + @student_graduation_topics = @student_graduation_topics.page(page).per(limit) + end + + # 课题详情 + def show_detail + @attachments = @graduation_topic.attachments + end + + # 课题详情回复接口 + def show_comment + @page = params[:page] || 1 + @limit = params[:limit] || 10 + @parent = params[:parent_id] + @current_user = current_user + @messages = @graduation_topic.journals_for_messages + if @parent + @messages = @messages.where(m_parent_id: @parent).order("created_on desc") + else + @messages = @messages.parent_comment.order("created_on asc") + end + + @messages_count = @messages.count + + @messages = @messages.page(@page).per(@limit) + end + + + # 新建课题 + def new + #6.11 新增,-hs + left_banner_content = @course.course_modules.search_by_module_type("graduation") + if left_banner_content.present? + @left_banner_id = left_banner_content.first.course_second_categories.first.id + @left_banner_name = left_banner_content.first.course_second_categories.first.name + else + normal_status(-1,"左侧导航不存在!") + end + end + + # 创建课题 + # POST: /graduation_topics + def create + @graduation_topic = GraduationTopic.new(graduation_topic_params) + @graduation_topic.course_id = @course.id + @graduation_topic.user_id = current_user.id + @graduation_topic.save! + Attachment.associate_container(params[:attachment_ids], @graduation_topic.id, @graduation_topic.class) if params[:attachment_ids] + + end + + # 更新课程 + def update + @graduation_topic.update_attributes(graduation_topic_params) + Attachment.associate_container(params[:attachment_ids], @graduation_topic.id, @graduation_topic.class) if params[:attachment_ids] + end + + def edit + @attachments = @graduation_topic.attachments + left_banner_content = @course.course_modules.search_by_module_type("graduation") + if left_banner_content.present? + @left_banner_id = left_banner_content.first.course_second_categories.first.id + @left_banner_name = left_banner_content.first.course_second_categories.first.name + end + end + + def destroys + tip_exception(-1, "graduation_topic_ids不能为空") if params[:graduation_topic_ids].nil? + @graduation_topics = GraduationTopic.where(:id => params[:graduation_topic_ids]) + @graduation_topics.destroy_all + normal_status("删除成功") + end + + def set_public + tip_exception(-1, "私有课程不能设置毕设选题为公开") if @course.is_public == 0 + tip_exception(-1, "graduation_topic_ids不能为空") if params[:graduation_topic_ids].nil? + @graduation_topics = GraduationTopic.where(id: params[:graduation_topic_ids]) + @graduation_topics.update_all(is_public: true) + normal_status("设置成功") + end + + # 拒绝课题 + def refuse_student_topic + begin + student_graduation_topic = @graduation_topic.student_graduation_topics + .find_by(id: params[:student_graduation_topic]) + if student_graduation_topic.present? + # 更新学生选题和老师选题的状态 + student_graduation_topic.update_attributes(:status => 2) + update_graduation_topic_status + + # 拒绝后将该学生移动到未分班中 + student_member = @course.course_members.where(:user_id => student_graduation_topic.user_id).first + student_member.update_attributes(:course_group_id => 0) if student_member.present? + + student_graduation_topic.tidings.update_all(:status => 1) + Tiding.create(:user_id => student_graduation_topic.user_id, :trigger_user_id => current_user.id, + :container_id => student_graduation_topic.id, :container_type => "DealStudentTopicSelect", + :parent_container_id => @graduation_topic.id, :parent_container_type => "GraduationTopic", + :belong_container_id => @graduation_topic.course_id, :belong_container_type => "Course", + :viewed => 0, :tiding_type => "GraduationTopic", :status => 2) + end + normal_status("拒绝成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(-1, "操作失败") + end + end + + # 接受课题 + def accept_student_topic + student_graduation_topic = @graduation_topic.student_graduation_topics + .where(:id => params[:student_graduation_topic_id]).first + if student_graduation_topic.present? + # 更新学生选题和老师选题的状态 + student_graduation_topic.update_attributes(:status => 1) + update_graduation_topic_status + + # 将学生加入到老师的第一个具有管理权限的分班(没有则创建一个“XXX老师组”分班并弹框提醒) + teacher_group = @course.teacher_course_groups.where(:user_id => @graduation_topic.tea_id, :id => params[:group_id]).first + unless teacher_group.present? + member = @course.course_members.where(:user_id => @graduation_topic.tea_id).first + tip_exception("分班名称不能为空") if params[:course_group_name].blank? + course_group = CourseGroup.create(:name => params[:course_group_name], :course_id => @course.id) + teacher_group = TeacherCourseGroup.create(:course_id => @course.id, :member_id => member.try(:id), + :user_id => @graduation_topic.tea_id, + :course_group_id => course_group.try(:id)) + end + student_member = @course.course_members.where(:user_id => student_graduation_topic.user_id).first + student_member.update_attributes(:course_group_id => teacher_group.course_group_id) if student_member.present? + + student_graduation_topic.tidings.update_all(:status => 1) + Tiding.create(:user_id => student_graduation_topic.user_id, :trigger_user_id => current_user.id, + :container_id => student_graduation_topic.id, :container_type => "DealStudentTopicSelect", + :parent_container_id => @graduation_topic.id, :parent_container_type => "GraduationTopic", + :belong_container_id => @graduation_topic.course_id, :belong_container_type => "Course", + :viewed => 0, :tiding_type => "GraduationTopic", :status => 1) + end + normal_status("同意成功") + end + + # 学生选题 + def student_select_topic + user_unaccept_topics = @course.student_graduation_topics.where(user_id: current_user.id, status: [0, 1]) + if user_unaccept_topics.size == 0 + member_id = @course.course_members.find_by_user_id(current_user.id) + StudentGraduationTopic.create(course_id: @course.id, user_id: current_user.id, member_id: member_id, + graduation_topic_id: @graduation_topic.id) + @graduation_topic.update_attribute(:status, 1) + normal_status("选题成功") + else + normal_status("已经选过题,无法重复选题") + end + end + + # 学生取消选题 + def student_cancel_topic + user_unaccept_topics = @course.student_graduation_topics.where(user_id: current_user.id, status: [0, 1]) + user_unaccept_topics.destroy_all + update_graduation_topic_status + normal_status(0,"取消成功") + end + + # 加入题库 + def add_to_bank + ActiveRecord::Base.transaction do + begin + topics = @course.graduation_topics.where(id: params[:topic_ids]) + + topics.each do |topic| + topic_bank = current_user.gtopic_banks.find_by(graduation_topic_id: topic.id) + + # 已加入的更新,未加入的新建 + if topic_bank.present? + topic_bank.update_attributes(name: topic, description: topic.description, + topic_source: topic.topic_source, + topic_property_first: topic.topic_property_first, + topic_property_second: topic.topic_property_second, + source_unit: topic.source_unit, + topic_repeat: topic.topic_repeat, + province: topic.province, + city: topic.city, + course_list_id: @course.course_list_id) + topic_bank.attachments.destroy_all + else + topic_bank = GtopicBank.new(name: topic, description: topic.description, + topic_source: topic.topic_source, + topic_property_first: topic.topic_property_first, + topic_property_second: topic.topic_property_second, + source_unit: topic.source_unit, + topic_repeat: topic.topic_repeat, + province: topic.province, + city: topic.city, + course_list_id: @course.course_list_id, + user_id: current_user.id, + graduation_topic_id: topic.id) + + topic_bank.save! + end + topic.attachments.each do |attachment| + att = attachment.copy + att.author_id = topic_bank.user_id + att.copy_from = attachment.id + topic_bank.attachments << att + end + end + + normal_status(0,"加入题库成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 导出功能 + def export + course = @course + students = course.students.joins(user: :user_extension).order("user_extensions.student_id") + graduation_topic_to_xlsx(students,course) + exercise_export_name = current_user.real_name + "_" + course.name + "_毕设选题" + "_" + Time.now.strftime('%Y%m%d_%H%M%S') + render xlsx: "#{exercise_export_name.strip.first(30)}",template: "graduation_topics/export.xlsx.axlsx",locals: {table_columns:@topic_head_cells,topic_users:@topic_body_cells} + end + + private + def find_graduation_topic + begin + @graduation_topic = GraduationTopic.find params[:id] + rescue Exception => e + uid_logger(e.message) + missing_template + end + end + + def find_course_teachers + @teachers = @course.teachers.joins(:user).order("users.id = #{current_user.id} desc, + CONVERT(users.lastname USING gbk) COLLATE gbk_chinese_ci asc") + end + + # 创建允许参数 + def graduation_topic_params + params.require(:graduation_topic).permit(:tea_id, :name, :topic_type, :topic_source, :topic_property_first, + :description, :topic_property_second, :status, :source_unit, :topic_repeat, + :province, :city, :is_public) + end + + # 更新选题的状态 + def update_graduation_topic_status + status = @graduation_topic.student_graduation_topic_status + @graduation_topic.update_attribute(:status, status) + end +end diff --git a/app/controllers/graduation_works_controller.rb b/app/controllers/graduation_works_controller.rb new file mode 100644 index 000000000..9117112d3 --- /dev/null +++ b/app/controllers/graduation_works_controller.rb @@ -0,0 +1,534 @@ +class GraduationWorksController < ApplicationController + before_action :require_login + before_action :find_task, only: [:new, :create, :search_member_list, :check_project, :relate_project, + :cancel_relate_project] + before_action :find_work, only: [:show, :edit, :update, :revise_attachment, :supply_attachments, :comment_list, + :add_score, :delete_score, :adjust_score, :assign_teacher] + before_action :user_course_identity + before_action :task_public + before_action :teacher_allowed, only: [:add_score, :adjust_score, :assign_teacher] + before_action :course_student, only: [:new, :create, :edit, :update, :search_member_list, :relate_project, + :cancel_relate_project] + before_action :my_work, only: [:edit, :update, :revise_attachment] + before_action :published_task, only: [:new, :create, :edit, :update, :search_member_list, :relate_project, + :cancel_relate_project, :revise_attachment] + before_action :edit_duration, only: [:edit, :update] + + def new + if @task.task_type == 2 && @task.base_on_project + work = @task.graduation_works.where(user_id: current_user.id).first + if work.present? && (work.work_status != 0 || work.project_id == 0) + normal_status(403, "") + end + end + @user = current_user + end + + # 搜索课堂学生 + def search_member_list + unless params[:search].blank? + # 有搜索条件时搜索课堂所有学生包括已提交的 + users = User.joins(:graduation_works).where("concat(users.lastname, users.firstname) like ? and + graduation_task_id = #{@task.id}", "%#{params[:search]}%") + user_ids = users.pluck(:id) - [current_user.id] + @members = @course.students.where(user_id: user_ids) + else + + # 没有搜索条件时搜索课堂所有未提交的学生 + user_ids = @task.graduation_works.where("work_status = 0").pluck(:user_id) - [current_user.id] + @members = @course.students.where(user_id: user_ids) + end + + page = params[:page] ? params[:page].to_i : 1 + limit = params[:limit] ? params[:limit].to_i : 10 + + # todo user_extension + @members = @members.page(page).per(limit).includes(:course_group, user: :user_extension) + end + + # 判断项目是否已有其他作品关联上了 + def check_project + tip_exception("项目id不能为空") if params[:project_id].blank? + work = @task.graduation_works.where(project_id: params[:project_id]).first + @is_relate = work.present? + @relate_user = work.present? ? work.user.real_name : "" + end + + def relate_project + tip_exception("项目id不能为空") if params[:project_id].blank? + + ActiveRecord::Base.transaction do + begin + # 判断项目是否存在且当前用户是项目管理员 + project = Project.where(id: params[:project_id]).first + member = Member.where(project_id: project.try(:id), user_id: current_user.id).first + + if project.present? && member.present? && member.member_roles.first.try(:role_id) == 3 + + + work = @task.graduation_works.where("user_id = #{current_user.id}").first || + GraduationWork.create(user_id: current_user.id, graduation_task_id: @task.id, course_id: @task.course_id) + + if work.work_status == 0 && work.project_id == 0 + work.update_attributes(project_id: project.id, update_time: Time.now) + + # 将老师加入项目 + project_member = project.members.where(user_id: @task.user_id).first + if project_member.present? + project_member.member_roles.first.update_attributes(role_id: 3) if project_member.member_roles.first.present? + else + member = Member.create(user_id: @task.user_id, project_id: project.id) + member.member_roles << MemberRole.new(role_id: 3) + Tiding.create(user_id: @task.user_id, trigger_user_id: current_user.id, container_id: project.id, + container_type: 'ManagerJoinProject', belong_container_id: project.id, + belong_container_type: "Project", tiding_type: "System", extra: 3) + end + normal_status("关联成功") + else + tip_exception("不能重复关联项目") + end + else + tip_exception("该项目不存在") + end + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def cancel_relate_project + work = @task.graduation_works.where(user_id: current_user.id, work_status: 0).first + if work.present? && work.project.present? + ActiveRecord::Base.transaction do + begin + member = work.project.members.where(user_id: @task.user_id).first + member.destroy if member.present? + Tiding.where(user_id: @task.user_id, trigger_user_id: current_user.id, container_id: work.project.id, + container_type: 'ManagerJoinProject').destroy_all + + work.update_attributes(project_id: 0) + normal_status("取消关联成功") + + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + else + tip_exception("无法取消关联") + end + end + + def create + graduation_work = @task.graduation_works.where(user_id: current_user.id).first || + GraduationWork.create(user_id: current_user.id, graduation_task_id: @task.id, course_id: @task.course_id) + + update_check graduation_work + + tip_exception("作业不可重复提交") if graduation_work.work_status != 0 + tip_exception("已过了提交时间") if @course.is_end || (@task.end_time < Time.now && (!@task.allow_late || + (@task.late_time.present? && @task.late_time < Time.now))) + + student_ids = [current_user.id] + ActiveRecord::Base.transaction do + begin + # work.update_attributes(graduation_work_params) + + graduation_work.description = params[:description] + graduation_work.commit_time = Time.now + graduation_work.update_time = Time.now + graduation_work.commit_user_id = current_user.id + graduation_work.course_id = @course.id + graduation_work.group_id = @task.task_type == 2 ? @task.graduation_works.where("work_status != 0").map(&:group_id).max.to_i + 1 : 0 + + #提交作品时,计算是否迟交 + graduation_work.late_penalty = @task.end_time < Time.now.to_s ? @task.late_penalty : 0 + graduation_work.work_status = @task.end_time < Time.now.to_s ? 2 : 1 + + if graduation_work.save! + Attachment.associate_container(params[:attachment_ids], graduation_work.id, graduation_work.class) + + if @task.task_type == 2 + members = (params[:user_ids] || []).collect(&:to_i) - [current_user.id] + members = @course.students.pluck(:user_id) & members + student_ids += members + for i in 0 .. members.count-1 + stu_work = @task.graduation_works.where(user_id: members[i].to_i).first || GraduationWork.new + stu_work.update_attributes(user_id: members[i].to_i, description: graduation_work.description, + graduation_task_id: @task.id, project_id: graduation_work.project_id, + late_penalty: graduation_work.late_penalty, work_status: graduation_work.work_status, + commit_time: Time.now, update_time: Time.now, group_id: graduation_work.group_id, + commit_user_id: current_user.id) + stu_work.save! + graduation_work.attachments.each do |attachment| + att = attachment.copy + att.author_id = attachment.author_id + stu_work.attachments << att + end + end + end + @task.update_column(:updated_at, Time.now) + # todo 更新对应的毕设任务课堂动态 + # update_course_activity(@taskhomework.class,@task.id) + @work_id = graduation_work.id + end + + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + + SubmitGraduationWorkNotifyJob.perform_later(@task.id, student_ids) + end + end + + def edit + @task_user = current_user + if @task.task_type == 2 + @work_members = @course.students.where(user_id: @task.graduation_works.where(group_id: @work.group_id).pluck(:user_id)). + order("course_members.id=#{@work.user_id} desc").includes(:course_group, user: :user_extension) + end + end + + def update + update_check @work + + student_ids = [] + ActiveRecord::Base.transaction do + begin + @work.description = params[:description] + @work.update_time = Time.now + @work.commit_user_id = current_user.id + if @work.save! + Attachment.associate_container(params[:attachment_ids], @work.id, @work.class) + + #如果学生作品被打分后修改,应该给老师提示 + student_ids << @work.user_id if @work.scored? + if @task.task_type == 2 + graduation_works = @task.graduation_works.where("group_id = #{@work.group_id} and user_id != #{@work.user_id}") + work_user_ids = graduation_works.pluck(:user_id) + params_user_ids = (params[:user_ids] || []).collect(&:to_i) - [@work.user_id] + params_user_ids = @course.students.pluck(:user_id) & params_user_ids + + # 原成员更新描述、更新时间以及附件 + @task.graduation_works.where(group_id: @work.group_id, user_id: (work_user_ids & params_user_ids)).each do |work| + work.update_attributes(update_time: Time.now, description: @work.description, commit_user_id: current_user.id) + work.attachments.destroy_all + @work.attachments.each do |attachment| + att = attachment.copy + att.author_id = attachment.author_id + work.attachments << att + end + student_ids << work.user_id if work.scored? + end + + # 删除的成员 + delete_user_ids = work_user_ids - params_user_ids + @task.graduation_works.where(group_id: @work.group_id, user_id: delete_user_ids).each do |work| + work.attachments.destroy_all + # work.student_works_scores.destroy_all + work.tidings.destroy_all + end + @task.graduation_works.where(group_id: @work.group_id, user_id: delete_user_ids). + update_all(work_status: 0, description: nil, late_penalty: 0, commit_time: nil, update_time: nil, + final_score: nil, teacher_score: nil, work_score: nil, project_id: 0, group_id: 0, + commit_user_id: nil) + + # 新增加的成员 + (params_user_ids - work_user_ids).each do |user_id| + stu_work = @task.graduation_works.where(user_id: user_id).empty? ? GraduationWork.new : + @task.graduation_works.where(user_id: user_id).first + stu_work.update_attributes(user_id: user_id, description: @work.description, graduation_task_id: @task.id, + project_id: @work.project_id, late_penalty: @work.late_penalty, + work_status: @work.work_status, commit_time: Time.now, update_time: Time.now, + group_id: @work.group_id, commit_user_id: current_user.id) + @work.attachments.each do |attachment| + att = attachment.copy + att.author_id = attachment.author_id + stu_work.attachments << att + end + + student_ids << user_id + end + end + + normal_status("更新成功") + end + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + + SubmitGraduationWorkNotifyJob.perform_later(@task.id, student_ids) if student_ids.present? + end + end + + def show + @current_user = current_user + @is_author = @work.user_id == current_user.id + @work_members = @task.task_type == 1 ? [] : @task.graduation_works.where.not(user_id: @work.user_id). + where(group_id: @work.group_id).includes(:user) + @attachments = @work.attachments.where.not(attachtype: 7) + end + + def comment_list + @current_user = current_user + @last_comment = @work.graduation_work_scores.where(user_id: @current_user.id).last + @comment_scores = @work.graduation_work_scores.reorder("created_at desc").includes(:user) + end + + # 给作品评分 + def add_score + tip_exception("该学生的分数已经过调整,不能再评阅") if @work.ultimate_score + tip_exception("分数和评语不能都为空") if params[:score].blank? && params[:comment].blank? + tip_exception("分数不能超过0-100") if params[:score] && (params[:score].to_f < 0 || params[:score].to_f > 100) + + ActiveRecord::Base.transaction do + begin + # 没传score则取上次评分成绩 + score = GraduationWorkScore.where(user_id: current_user.id, graduation_work_id: @work.id).last + new_score = GraduationWorkScore.new + new_score.score = params[:score].blank? ? score.try(:score) : params[:score].to_f + new_score.comment = params[:comment] if params[:comment] && params[:comment].strip != "" + new_score.user_id = current_user.id + new_score.graduation_work_id = @work.id + new_score.graduation_task_id = @task.id + + # 如果作品是未提交的状态则更新为已提交 + if !new_score.score.nil? && @work.work_status == 0 + @work.update_attributes(work_status: 1, commit_time: Time.now) + if @task.task_type == 2 + @work.update_attributes(group_id: @task.graduation_works.where("work_status != 0").select("distinct group_id").count + 1) + end + end + + if @task.status == 3 && @task.graduation_work_comment_assignations.where(graduation_work_id: @work.id, user_id: current_user.id).count > 0 + new_score.reviewer_role = 2 + else + new_score.reviewer_role = 1 + end + + if new_score.save! + Attachment.associate_container(params[:attachment_ids], new_score.id, new_score.class) + + # 该用户的历史评阅无效 + score.update_column('is_invalid', true) if score.present? && score.score.present? + + Tiding.create(user_id: @work.user_id, trigger_user_id: User.current.id, container_id: new_score.id, + container_type: "GraduationWorkScore", parent_container_id: @work.id, + parent_container_type: "GraduationWork", belong_container_id: @task.course_id, + belong_container_type: "Course", viewed: 0, tiding_type: "GraduationTask", extra: new_score.reviewer_role) + + case new_score.reviewer_role + when 1 #教师评分取平均分 + ts_score = GraduationWorkScore.find_by_sql("SELECT AVG(score) AS score FROM graduation_work_scores WHERE + graduation_work_id = #{@work.id} AND reviewer_role = 1 AND score IS NOT NULL AND is_invalid = 0") + + @work.teacher_score = ts_score.first.score.nil? ? nil : ts_score.first.score.try(:round, 2).to_f + + # 分组作业整组同评 + if @task.task_type == 2 && params[:same_score] + add_graduation_score_to_member @work, @task, new_score + end + + when 2 #交叉评分显示平均分 + ts_score = GraduationWorkScore.find_by_sql("SELECT AVG(score) AS score FROM graduation_work_scores WHERE + graduation_work_id = #{@work.id} AND reviewer_role = 2 AND score IS NOT NULL AND is_invalid = 0") + @work.cross_score = ts_score.first.score.nil? ? nil : ts_score.first.score.try(:round, 2).to_f + end + + @task.update_column('updated_at', Time.now) + # update_course_activity(@task.class, @task.id) + @work.save! + + normal_status("提交成功") + end + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def adjust_score + tip_exception("分数不能为空") if params[:score].blank? + tip_exception("分数不能超过0-100") if params[:score].to_f < 0 || params[:score].to_f > 100 + ActiveRecord::Base.transaction do + begin + # 分数不为空的历史评阅都置为失效 + @work.graduation_work_scores.where.not(score: nil).update_all(is_invalid: 1) + + new_score = GraduationWorkScore.new(graduation_work_id: @work.id, score: params[:score].to_f, + graduation_task_id: @task.id, comment: "使用调分功能调整了作业最终成绩:#{params[:comment]}", + user_id: User.current.id, reviewer_role: 1, is_ultimate: 1) + new_score.save! + @work.update_attributes(ultimate_score: 1, work_score: params[:score].to_f) + + normal_status("调分成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 删除教师/教辅的评分记录 + def delete_score + score = @work.graduation_work_scores.where(id: params[:comment_id]).first + if score.present? && (score.is_invalid || score.score.nil?) && (score.user == current_user || current_user.admin?) + begin + score.destroy + normal_status("删除成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + else + tip_exception("无法删除") + end + end + + def supply_attachments + @revise_attachments = @work.attachments.where(attachtype: 7) + @last_atta = @revise_attachments.last + end + + def revise_attachment + tip_exception("不在补交阶段内") if @course.is_end || @task.end_time > Time.now || !@task.allow_late || + (@task.late_time && @task.late_time < Time.now) + tip_exception("附件参数有误") if params[:attachment_ids].blank? || !params[:attachment_ids].is_a?(Array) + tip_exception("补交附件原因不能为空") if params[:description].blank? + + ActiveRecord::Base.transaction do + begin + revise_attachment = @work.attachments.where(attachtype: 7).reorder("created_on desc").last + if revise_attachment.present? && @work.graduation_work_scores.where("created_at > '#{revise_attachment.created_on}' + and score is not null").count == 0 + revise_attachment.destroy + end + Attachment.associate_container(params[:attachment_ids], @work.id, @work.class, 7) + revise_attachment = Attachment.where(attachtype: 7, container_id: @work.id, container_type: "GraduationWork").last + revise_attachment.update_attributes(description: params[:description]) if revise_attachment.present? + + @work.update_attributes(update_time: Time.now) + + normal_status("提交成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 交叉评阅分配老师 + def assign_teacher + tip_exception(-1, "user_id不能为空") if params[:user_id].nil? + @work_assign_teacher = @work.graduation_work_comment_assignations.first + + if @work_assign_teacher + # graduation_group_id: 已经是答辩组的需要 将答辩组清空 + @work_assign_teacher.update_attributes(user_id: params[:user_id], graduation_group_id: 0) + else + @work.graduation_work_comment_assignations << GraduationWorkCommentAssignation.new(graduation_task_id: @task.id, + user_id: params[:user_id], + graduation_group_id: 0) + end + normal_status("分配成功") + end + + private + def find_task + begin + @task = GraduationTask.find(params[:graduation_task_id]) + @course = @task.course + rescue Exception => e + uid_logger(e.message) + tip_exception("id不存在") + end + end + + def find_work + begin + @work = GraduationWork.find(params[:id]) + @task = @work.graduation_task + @course = @task.course + rescue Exception => e + uid_logger(e.message) + tip_exception("id不存在") + end + end + + def task_public + tip_exception(403,"没有操作权限") if @user_course_identity > Course::STUDENT && (@course.is_public == 0 || + (@course.is_public == 1 && !@task.is_public)) + end + + def course_student + tip_exception(403,"没有操作权限") if @user_course_identity != Course::STUDENT + end + + def my_work + tip_exception(403,"没有操作权限") if @work.user_id != current_user.id || @work.work_status == 0 + end + + def published_task + tip_exception("不能在非提交时间内操作") if @task.status == 0 || (!@task.allow_late && @task.status > 1) || + (@task.allow_late && @task.late_time && @task.late_time < Time.now) + end + + def edit_duration + tip_exception("已过了修改时间") if @task.end_time && @task.end_time < Time.now + end + + def update_check work + tip_exception("作品描述不能为空") if params[:description].blank? + if @task.task_type == 2 + tip_exception("小组成员不能为空") if params[:user_ids].blank? + tip_exception("小组成员人数不合要求") if params[:user_ids].length > @task.max_num || params[:user_ids].length < @task.min_num + tip_exception("请先关联项目") if @task.base_on_project && work.project_id == 0 + end + end + + def graduation_work_params + params.require(:graduation_work).permit(:description) + end + + def add_graduation_score_to_member work, task, new_score + graduation_works = task.graduation_works.where("group_id = #{work.group_id} and id != #{work.id} and ultimate_score = 0") + graduation_works.each do |st_work| + st_score = GraduationWorkScore.new(user_id: new_score.user_id, score: new_score.score, + reviewer_role: new_score.reviewer_role, comment: new_score.comment) + st_work.graduation_work_scores << st_score + + score = GraduationWorkScore.where(user_id: new_score.user_id, graduation_work_id: st_work.id).last + # 该用户的历史评阅无效 + score.update_column('is_invalid', true) if score.present? && score.score.present? + + teacher_score = GraduationWorkScore.find_by_sql("SELECT AVG(score) AS score FROM graduation_work_scores WHERE + graduation_work_id = #{work.id} AND reviewer_role = 1 AND score IS NOT NULL AND is_invalid = 0") + + st_work.teacher_score = teacher_score.first.score.nil? ? nil : teacher_score.first.score.try(:round, 2).to_f + st_work.save! + + Tiding.create(user_id: st_work.user_id, trigger_user_id: User.current.id, container_id: st_score.id, + container_type: "GraduationWorkScore", parent_container_id: st_work.id, + parent_container_type: "GraduationWork", belong_container_id: task.course_id, + belong_container_type: "Course", viewed: 0, tiding_type: "GraduationTask", extra: st_score.reviewer_role) + # 评阅附件的复制 + new_score.attachments.each do |attachment| + att = attachment.copy + att.author_id = st_score.user_id + st_score.attachments << att + end + end + end +end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb new file mode 100644 index 000000000..37cfed3fb --- /dev/null +++ b/app/controllers/home_controller.rb @@ -0,0 +1,40 @@ +class HomeController < ApplicationController + + def index + # banner图 + images = PortalImage.where(status: true).order("position asc") + @images_url = [] + images.each do |image| + @images_url << {path: image.link, image_url: "/images/avatars/PortalImage/#{image.id}"} + end + + # 目录分级 + repertoires = Repertoire.includes(sub_repertoires: :tag_repertoires).order("updated_at asc") + @rep_list = [] + repertoires.each do |rep| + + sub_rep_list = [] + rep.sub_repertoires.each do |sub_rep| + tag_rep_list = [] + sub_rep.tag_repertoires.each do |tag_rep| + tag_rep_list << {tag_id: tag_rep.id, tag_name: tag_rep.name} + end + sub_rep_list << {sub_rep_id: sub_rep.id, sub_rep_name: sub_rep.name, tag_rep_list: tag_rep_list} + end + @rep_list << {rep_id: rep.id, rep_name: rep.name, sub_rep_list: sub_rep_list} + end + + @shixuns = Shixun.where(homepage_show: 1).includes(:tag_repertoires, :challenges).limit(8) + + @subjects = Subject.where(homepage_show: 1).includes(:shixuns, :repertoire).limit(8) + + @tea_users = User.where(homepage_teacher: 1).includes(:user_extension).limit(10).order("experience desc") + @stu_users = User.includes(:user_extension).where(user_extensions: {identity: 1}).limit(10).order("experience desc") + end + + def search + @fuzzy_searchs = params[:keyword].split(" ").join("%") + @shixuns = Shixun.where("name like ?", "%#{@fuzzy_searchs}%") + @total_count = @shixuns.count + end +end diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb new file mode 100644 index 000000000..d3ece9feb --- /dev/null +++ b/app/controllers/homework_commons_controller.rb @@ -0,0 +1,1461 @@ +class HomeworkCommonsController < ApplicationController + include HomeworkCommonsHelper + include ApplicationHelper + include ExportHelper + + before_action :require_login, except: [:index, :choose_category] + + before_action :find_course, only: [:index, :create, :new, :shixuns, :subjects, :create_shixun_homework, :publish_homework, + :end_homework, :set_public, :choose_category, :move_to_category, :choose_category, + :create_subject_homework, :multi_destroy, :add_to_homework_bank] + before_action :find_homework, only: [:edit, :show, :update, :group_list, :homework_code_repeat, :code_review_results, + :code_review_detail, :show_comment, :settings, :works_list, :update_settings, + :reference_answer, :publish_groups, :end_groups, :alter_name, :update_explanation] + before_action :user_course_identity + before_action :homework_publish, only: [:show, :works_list, :code_review_results, :show_comment, :settings, :reference_answer] + before_action :teacher_allowed, only: [:new, :edit, :create, :update, :shixuns, :subjects, :create_shixun_homework, + :publish_homework, :end_homework, :set_public, :choose_category, :move_to_category, + :choose_category, :create_subject_homework, :multi_destroy, :group_list, :homework_code_repeat, + :code_review_results, :code_review_detail, :update_explanation, :update_settings, + :add_to_homework_bank, :publish_groups, :end_groups] + before_action :require_id_params, only: [:set_public, :multi_destroy, :publish_homework, :end_homework, :move_to_category, + :add_to_homework_bank] + before_action :course_manager, only: [:alter_name] + + def index + tip_exception("type参数有误") if params[:type] && ![1, 3, 4].include?(params[:type].to_i) + @user = current_user + search = "#{params[:search].to_s.strip.downcase}" if params[:search] + order = params[:order] + page = params[:page] ? params[:page].to_i : 1 + @homework_type = params[:type] ? params[:type].to_i : 4 + module_type = @homework_type == 4 ? "shixun_homework" : @homework_type == 1 ? "common_homework" : "group_homework" + @homework_commons = @course.homework_commons.where(homework_type: @homework_type) + @main_category = @course.course_modules.find_by(module_type: module_type) + if @homework_type == 4 && !params[:category].blank? + @category = @main_category.course_second_categories.find_by(id: params[:category]) + tip_exception("子目录id有误") if !@category.present? + @homework_commons = @homework_commons.where(course_second_category_id: params[:category]) + elsif @homework_type == 4 + @homework_commons = @homework_commons.where(course_second_category_id: 0) + end + @all_count = @homework_commons.size + + @member = @course.course_members.find_by(user_id: current_user.id, is_active: 1) + # 老师显示所有的作业、未分班学生显示统一设置的且已发布、否则对学生所在分班已发布的作业 + if @user_course_identity < Course::STUDENT + @homework_commons = @homework_commons + elsif @user_course_identity == Course::STUDENT + if @member.try(:course_group_id).to_i == 0 + @homework_commons = @homework_commons.homework_published.unified_setting + else + not_homework_ids = @course.homework_group_settings.none_published.where("course_group_id = #{@member.try(:course_group_id)}").pluck(:homework_common_id) + + @homework_commons = @homework_commons.where.not(id: not_homework_ids).homework_published + end + else + @homework_commons = @homework_commons.homework_published.unified_setting + end + + @published_count = @user_course_identity < Course::STUDENT ? @homework_commons.homework_published.size : + @homework_commons.size + + unless search.blank? + @homework_commons = @homework_commons.where("homework_commons.name like ?", "%#{search}%") + end + + unless order.blank? + case order + when '1' + sql_str = %Q(homework_detail_manuals.comment_status = #{order} and homework_commons.end_time > '#{Time.now}') + when '2' + sql_str = %Q(allow_late = 1 and homework_commons.end_time < '#{Time.now}' and (late_time is null or late_time > '#{Time.now}')) + when '3' + sql_str = %Q(homework_detail_manuals.comment_status = #{order} and homework_detail_manuals.evaluation_end > '#{Time.now}') + when '4' + sql_str = %Q((homework_detail_manuals.comment_status = #{order} and homework_detail_manuals.appeal_time > '#{Time.now}')) + when '5' + sql_str = %Q((homework_detail_manuals.comment_status = #{order} or (anonymous_comment = 0 and homework_commons.end_time <= '#{Time.now}'))) + else + sql_str = %Q(homework_detail_manuals.comment_status = #{order}) + end + @homework_commons = @homework_commons.joins(:homework_detail_manual).where(sql_str) + end + @homework_commons = @homework_commons.order("IF(ISNULL(homework_commons.publish_time),0,1), homework_commons.publish_time DESC, + homework_commons.created_at DESC") + + @task_count = @homework_commons.size + + @homework_commons = @homework_commons.page(page).per(15) + + if @homework_type == 4 + if @user_course_identity == Course::STUDENT + @homework_commons = @homework_commons.includes(:homework_detail_manual, :homework_group_settings, :shixuns, + student_works: [myshixun: [:games]]) + else + @homework_commons = @homework_commons.includes(:homework_detail_manual, :homework_group_settings, :shixuns, :student_works) + end + else + @homework_commons = @homework_commons.includes(:homework_detail_manual, :homework_group_settings, :homework_detail_group, + :student_works) + end + end + + def works_list + @current_user = current_user + @member = @course.course_member(@current_user.id) + + @shixun = @homework.shixuns.take if @homework.homework_type == "practice" + + student_works = @homework.all_works + @all_member_count = student_works.count + if @homework.publish_time.nil? || @homework.publish_time > Time.now + @student_works = [] + respond_to do |format| + format.json + format.xlsx{ + normal_status(-1,"作业未发布") + } + format.zip{ + normal_status(-1,"作业未发布") + } + end + else + if @user_course_identity == Course::STUDENT + @work = @homework.user_work(current_user.id) + + # 学生已提交作品且补交(提交)已截止、作品公开、非匿评阶段 + if @work.work_status > 0 && @homework.work_public && + ((!@homework.anonymous_comment && @homework.end_or_late) || @homework_detail_manual.comment_status > 4) + @student_works = student_works.where("user_id != #{@work.id}") + + # 匿评、申诉阶段只能看到分配给自己的匿评作品 + elsif @work.work_status > 0 && @homework.anonymous_comment && @homework_detail_manual.comment_status > 2 + @is_evaluation = true + @student_works = student_works.joins(:student_works_evaluation_distributions).where( + "student_works_evaluation_distributions.user_id = #{@current_user.id}") + else + @student_works = [] + end + elsif @user_course_identity < Course::STUDENT + @student_works = @homework.teacher_works(@current_user.id) + @all_member_count = @student_works.count + elsif @user_course_identity > Course::STUDENT && @homework.work_public + @student_works = student_works + else + @student_works = [] + end + + unless @student_works.size == 0 + # 教师评阅搜索 0: 未评, 1 已评 + unless params[:teacher_comment].blank? + student_work_ids = StudentWorksScore.where(student_work_id: @student_works.map(&:id)).pluck(:student_work_id) + if params[:teacher_comment].to_i == 0 + @student_works = @student_works.where.not(id: student_work_ids) + elsif params[:teacher_comment].to_i == 1 + @student_works = @student_works.where(id: student_work_ids) + end + end + + # 作品状态 0: 未提交, 1 按时提交, 2 延迟提交 + unless params[:work_status].blank? + @student_works = @student_works.where(work_status: params[:work_status]) + end + + # 分班情况 + unless params[:course_group].blank? + group_user_ids = @course.students.where(course_group_id: params[:course_group]).pluck(:user_id) + # 有分组只可能是老师身份查看列表 + @student_works = @student_works.where(user_id: group_user_ids) + end + + # 输入姓名和学号搜索 + # TODO user_extension 如果修改 请调整 + unless params[:search].blank? + @student_works = @student_works.joins(user: :user_extension).where("concat(lastname, firstname) like ? + or student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%") + end + + # 排序 + rorder = params[:order] || "update_time" + b_order = params[:b_order] || "desc" + if rorder == "update_time" || rorder == "work_score" + @student_works = @student_works.order("student_works.#{rorder} #{b_order}") + elsif rorder == "student_id" + @student_works = @student_works.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}") + end + + @work_count = @student_works.size + @work_excel = @student_works + + # 分页参数 + page = params[:page] || 1 + limit = params[:limit] || 20 + @student_works = @student_works.page(page).per(limit).includes(:student_works_scores) + if @homework.homework_type == "practice" + @student_works = @student_works.includes(user: :user_extension, myshixun: :games) + else + @student_works = @student_works.includes(:student_works_scores, :project, user: :user_extension) + end + end + respond_to do |format| + format.json + format.xlsx{ + if @user_course_identity >= Course::STUDENT + tip_exception(403, "无权限操作") + else + student_work_to_xlsx(@work_excel,@homework) + exercise_export_name = current_user.real_name + "_" + @course.name + "_" + @homework.name + "_" + Time.now.strftime('%Y%m%d_%H%M%S') + render xlsx: "#{exercise_export_name.strip.first(30)}",template: "homework_commons/works_list.xlsx.axlsx",locals: + {table_columns: @work_head_cells,task_users: @work_cells_column} + end + } + format.zip{ + if @user_course_identity >= Course::STUDENT + tip_exception(403, "无权限操作") + else + zip_works = @work_excel.where("work_status > 0") + status = checkfileSize(zip_works) + if status == 0 + zipfile = zip_homework_common @homework, zip_works + file = decode64(zipfile[0][:base64file]) + send_file "#{OUTPUT_FOLDER}/#{file}", filename: filename_for_content_disposition(file), type: 'application/zip' + else + tip_exception(status == -1 ? "文件大小超过500M,请通过微信或者QQ联系管理员辅助您打包下载" : "无附件可下载") + end + end + } + end + end + end + + def alter_name + tip_exception("作业名称不能为空") if params[:name].blank? + @homework.update_attributes(name: params[:name].strip) + normal_status("更新成功") + end + + def show + @user = current_user + @attachments = @homework.attachments.where(attachtype: 1) + @work = @homework.user_work(current_user.id) if @user_course_identity == Course::STUDENT + end + + # 评论列表接口、 包含一级和二级评论的获取 + def show_comment + @page = params[:page] || 1 + @limit = params[:limit] || 10 + @parent = params[:parent_id] + @current_user = current_user + + @messages = @homework.journals_for_messages + @messages_count = @messages.size + @parent_messages_count = @messages.parent_comment.size + + if @parent + @messages = @messages.where(m_parent_id: @parent) + else + @messages = @messages.parent_comment + end + + @messages = @messages.page(@page).per(@limit).order("created_on desc") + end + + def reference_answer + # 只有课堂老师 或 作业设置了“公开答案”,则在作业截止时间后(若开启了补交,则补交截止后),提交了作品的学生 才能访问 + if @homework.view_answer(@user_course_identity, current_user.id) + @attachments = @homework.attachments.where(attachtype: 2) + else + normal_status(403, "无权限访问") + end + @current_user = current_user + @work = @homework.user_work(current_user.id) if @user_course_identity == Course::STUDENT + end + + def update_explanation + @homework.update_attributes(explanation: params[:explanation]) + normal_status(0, "更新成功") + end + + def new + tip_exception("type参数有误") if params[:type].blank? || ![1, 3].include?(params[:type].to_i) + @homework_type = params[:type].to_i + end + + def create + tip_exception("type参数有误") if params[:type].blank? || ![1, 3].include?(params[:type].to_i) + @homework_type = params[:type].to_i + if @homework_type == 3 + validate_min_max_num + tip_exception("base_on_project参数不能为空") if params[:base_on_project].nil? + end + + ActiveRecord::Base.transaction do + begin + @homework = HomeworkCommon.new(homework_params) + @homework.homework_type = @homework_type + @homework.user_id = current_user.id + @homework.course_id = @course.id + + homework_detail_manual = HomeworkDetailManual.new + @homework.homework_detail_manual = homework_detail_manual + homework_detail_manual.te_proportion = 0.7 + homework_detail_manual.ta_proportion = 0.3 + + if @homework_type == 3 + homework_detail_group = HomeworkDetailGroup.new(min_num: params[:min_num].to_i, max_num: params[:max_num].to_i, + base_on_project: params[:base_on_project]) + @homework.homework_detail_group = homework_detail_group + end + + if @homework.save! + homework_detail_manual.save! if homework_detail_manual + homework_detail_group.save! if homework_detail_group + + # 作业描述的附件 + Attachment.associate_container(params[:attachment_ids], @homework.id, @homework.class) if params[:attachment_ids] + # 作业参考答案的附件 + Attachment.associate_container(params[:reference_attachment_ids], @homework.id, @homework.class, 2) if params[:reference_attachment_ids] + + HomeworksService.new.create_works_list(@homework, @course) + else + tip_exception("创建失败") + end + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def edit + + end + + def update + if @homework.homework_type == "group" + validate_min_max_num + tip_exception("base_on_project参数不能为空") if !@homework.has_relate_project && params[:base_on_project].nil? + end + + ActiveRecord::Base.transaction do + begin + @homework.update_attributes(homework_params) + + if @homework.homework_type == "group" + homework_detail_group = @homework.homework_detail_group + param_min = params[:min_num].to_i + param_max = params[:max_num].to_i + homework_detail_group.min_num = @homework.has_commit_work ? (param_min > homework_detail_group.min_num ? homework_detail_group.min_num : + param_min) : param_min + homework_detail_group.max_num = @homework.has_commit_work ? (param_max < homework_detail_group.max_num ? homework_detail_group.max_num : + param_max) : param_max + homework_detail_group.base_on_project = params[:base_on_project] unless @homework.has_relate_project + homework_detail_group.save! + end + # 作业描述的附件 + Attachment.associate_container(params[:attachment_ids], @homework.id, @homework.class) if params[:attachment_ids] + # 作业参考答案的附件 + Attachment.associate_container(params[:reference_attachment_ids], @homework.id, @homework.class, 2) if params[:reference_attachment_ids] + + normal_status(0, "更新成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def settings + @user = current_user + @work = @homework.user_work(current_user.id) if @user_course_identity == Course::STUDENT + end + + def update_settings + begin + # 课堂结束后不能再更新 + unless @course.is_end + + # 作业未发布时,unified_setting参数不能为空 + if @homework.publish_time.nil? || @homework.publish_time > Time.now + tip_exception("缺少统一设置的参数") if params[:unified_setting].nil? + if params[:unified_setting] || @course.course_groups_count == 0 + tip_exception("发布时间不能为空") if params[:publish_time].blank? + tip_exception("截止时间不能为空") if params[:end_time].blank? + tip_exception("发布时间不能早于当前时间") if params[:publish_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") + tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") + tip_exception("截止时间不能早于发布时间") if params[:publish_time] > params[:end_time] + tip_exception("截止时间不能早于课堂结束时间") if @course.end_date.present? && params[:end_time] > @course.end_date.end_of_day + + @homework.unified_setting = 1 + @homework.homework_group_settings.destroy_all + @homework.publish_time = params[:publish_time] + # 截止时间为空时取发布时间后一个月 + @homework.end_time = params[:end_time] + + else + tip_exception("分班发布设置不能为空") if params[:group_settings].blank? + # 创建作业的分班设置 + create_homework_group_settings @homework + + setting_group_ids = [] + + params[:group_settings].each do |setting| + tip_exception("分班id不能为空") if setting[:group_id].length == 0 + tip_exception("发布时间不能为空") if setting[:publish_time].blank? + tip_exception("截止时间不能为空") if setting[:end_time].blank? + tip_exception("发布时间不能早于当前时间") if setting[:publish_time] <= strf_time(Time.now) + tip_exception("截止时间不能早于当前时间") if setting[:end_time] <= strf_time(Time.now) + tip_exception("截止时间不能早于发布时间") if setting[:publish_time] > setting[:end_time] + tip_exception("截止时间不能早于课堂结束时间") if @course.end_date.present? && setting[:end_time] > @course.end_date.end_of_day + + + publish_time = setting[:publish_time] == "" ? Time.now : setting[:publish_time] + # 截止时间为空时取发布时间后一个月 + end_time = setting[:end_time] == "" ? Time.at(publish_time.to_time.to_i+30*24*3600) : setting[:end_time] + HomeworkGroupSetting.where(homework_common_id: @homework.id, course_group_id: setting[:group_id]). + update_all(publish_time: publish_time, end_time: end_time) + setting_group_ids << setting[:group_id] + end + + # 未设置的分班:发布时间和截止时间都为nil + HomeworkGroupSetting.where.not(course_group_id: setting_group_ids).where(homework_common_id: @homework.id). + update_all(publish_time: nil, end_time: nil) + + # 记录已发布需要发消息的分班 + publish_group_ids = HomeworkGroupSetting.where(homework_common_id: @homework.id).group_published.pluck(:course_group_id) + + @homework.unified_setting = 0 + @homework.publish_time = @homework.min_group_publish_time + @homework.end_time = @homework.max_group_end_time + end + + # 如果作业立即发布则更新状态、发消息 + if @homework.publish_time <= Time.now and @homework_detail_manual.comment_status == 0 + @homework_detail_manual.comment_status = 1 + send_tiding = true + end + + # 作业在"提交中"状态时 + else + if @homework.end_time > Time.now && @homework.unified_setting + tip_exception("截止时间不能为空") if params[:end_time].blank? + tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) + tip_exception("截止时间不能早于课堂结束时间") if @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) + + @homework.end_time = params[:end_time] + + elsif !@homework.unified_setting + create_homework_group_settings @homework + tip_exception("分班发布设置不能为空") if params[:group_settings].blank? + params[:group_settings].each do |setting| + group_settings = HomeworkGroupSetting.where(homework_common_id: @homework.id, course_group_id: setting[:group_id]) + + tip_exception("分班id不能为空") if setting[:group_id].length == 0 + tip_exception("发布时间不能为空") if setting[:publish_time].blank? + tip_exception("截止时间不能为空") if setting[:end_time].blank? + # 如果该发布规则 没有已发布的分班则需判断发布时间 + tip_exception("发布时间不能早于当前时间") if setting[:publish_time] <= strf_time(Time.now) && group_settings.group_published.count == 0 + + tip_exception("截止时间不能早于当前时间") if setting[:end_time] <= strf_time(Time.now) + tip_exception("截止时间不能早于发布时间") if setting[:publish_time] > setting[:end_time] + tip_exception("截止时间不能早于课堂结束时间") if setting[:end_time] > strf_time(@course.end_date.end_of_day) + + group_settings.none_published.update_all(publish_time: setting[:publish_time]) + group_settings.none_end.update_all(end_time: setting[:end_time]) + end + + @homework.end_time = @homework.max_group_end_time + end + end + + # 补交设置 + tip_exception("缺少allow_late参数") if params[:allow_late].nil? + tip_exception("缺少late_penalty参数") if params[:allow_late] && params[:late_penalty].blank? + tip_exception("缺少late_time参数") if params[:allow_late] && params[:late_time].blank? + + current_late_penalty = @homework.late_penalty + if params[:allow_late] + tip_exception("补交结束时间必须晚于截止时间") if params[:late_time] <= strf_time(@homework.end_time) + tip_exception("补交结束时间不能晚于课堂结束时间") if @course.end_date.present? && params[:late_time] > + strf_time(@course.end_date.end_of_day) + tip_exception("迟交扣分应为正整数") if params[:late_penalty] && params[:late_penalty].to_i < 0 + + @homework.allow_late = true + @homework.late_time = params[:late_time] + @homework.late_penalty = params[:late_penalty].to_i + else + @homework.allow_late = false + @homework.late_penalty = 0 + @homework.late_time = nil + end + + # 迟交扣分有变动则更新迟交学生的成绩 + late_penalty_change = @homework.late_penalty != current_late_penalty + + if @homework.homework_type == "practice" + + # 实训作业的评分设置 + tip_exception("缺少answer_open_evaluation参数") if params[:answer_open_evaluation].nil? + tip_exception("缺少work_efficiency参数") if params[:work_efficiency].nil? + tip_exception("缺少eff_score参数") if params[:work_efficiency] && params[:eff_score].blank? + tip_exception("效率分应为正整数") if params[:eff_score] && params[:eff_score].to_i < 0 + tip_exception("缺少shixun_evaluation参数") if params[:shixun_evaluation].blank? + tip_exception("缺少challenge_settings参数") if params[:challenge_settings].blank? + # tip_exception("缺少challenge_id参数") if params[:challenge_settings][:challenge_id].blank? + # tip_exception("缺少challenge_score参数") if params[:challenge_settings][:challenge_score].blank? + # tip_exception("challenge_id参数的长度与challenge_score参数的长度不匹配") if + # params[:challenge_settings][:challenge_score].length != params[:challenge_settings][:challenge_id].length + + current_eff_score = @homework.eff_score + @homework.work_efficiency = params[:work_efficiency] + @homework.eff_score = params[:work_efficiency] ? params[:eff_score].to_i : 0 + + update_eff_score = current_eff_score != @homework.eff_score + + if @homework_detail_manual.answer_open_evaluation != params[:answer_open_evaluation] + @homework_detail_manual.answer_open_evaluation = params[:answer_open_evaluation] + score_change = true + end + + @homework_detail_manual.shixun_evaluation = params[:shixun_evaluation].to_i + + if params[:challenge_settings] + params[:challenge_settings].each do |challenge| + setting = @homework.homework_challenge_settings.find_by(challenge_id: challenge[:challenge_id]) + score = challenge[:challenge_score] + if setting && setting.score != score + score_change = true + setting.update_attributes(score: score) + else + score_change = true + HomeworkChallengeSetting.create!(homework_common_id: @homework.id, challenge_id: challenge[:challenge_id], + shixun_id: @homework.homework_commons_shixun.try(:shixun_id), score: score) + end + end + + if @homework.homework_challenge_settings.where.not(challenge_id: params[:challenge_settings].pluck(:challenge_id)).count > 0 + score_change = true + @homework.homework_challenge_settings.where.not(challenge_id: params[:challenge_settings].pluck(:challenge_id)).destroy_all + end + end + + # 公开设置 + tip_exception("缺少score_open参数") if params[:score_open].nil? + @homework.score_open = params[:score_open] + + @homework.save! + if score_change + @homework.student_works.has_committed.each do |student_work| + HomeworksService.new.set_shixun_final_score student_work + end + end + + # 更新所有学生的效率分(作业允许补交且补交已截止 或者 作业不允许补交且提交已截止) + if (score_change || update_eff_score) && @homework.end_or_late + HomeworksService.new.update_student_eff_score HomeworkCommon.find_by(id: @homework.id) + end + + # 更新迟交扣分 + if !(score_change || update_eff_score) && late_penalty_change + @homework.student_works.where(work_status: 2).each do |work| + work.late_penalty = @homework.late_penalty + work.save! + end + end + + unless @homework.allow_late + @homework.student_works.where(work_status: 2).update_all(work_status: 1) + end + + @homework_detail_manual.save! + @homework.save! + else + + # 普通和分组作业的匿评设置 + current_absence_penalty = @homework_detail_manual.absence_penalty + current_appeal_penalty = @homework_detail_manual.appeal_penalty + + # 匿评未开启前可以更新:是否开启匿评、匿评开始时间、匿评数 + if @homework_detail_manual.comment_status < 3 + tip_exception("缺少anonymous_comment参数") if params[:anonymous_comment].nil? + # anonymous_comment :true 是启用,false 是不启用 + if params[:anonymous_comment] + tip_exception("匿评开启时间不能为空") if params[:evaluation_start].blank? + tip_exception("匿评开启时间不能早于截止时间") if params[:evaluation_start] <= strf_time(@homework.end_time) + tip_exception("匿评结束时间不能为空") if params[:evaluation_end].blank? + tip_exception("匿评截止时间不能早于匿评开启时间") if params[:evaluation_end] <= params[:evaluation_start] + tip_exception("匿评截止时间不能晚于课堂结束时间") if @course.end_date.present? && params[:evaluation_end] > + strf_time(@course.end_date.end_of_day) + tip_exception("匿评数必须为正整数") if params[:evaluation_num].blank? || params[:evaluation_num].to_i < 1 + tip_exception("缺评扣分不能为空") if params[:absence_penalty].blank? + tip_exception("缺评扣分不能小于0") if params[:absence_penalty].to_i < 0 + tip_exception("缺评扣分不能大于100") if params[:absence_penalty].to_i > 100 + end + + @homework.anonymous_comment = params[:anonymous_comment] + @homework_detail_manual.evaluation_start = !@homework.anonymous_comment ? nil : params[:evaluation_start] + @homework_detail_manual.evaluation_num = !@homework.anonymous_comment ? 0 : params[:evaluation_num] + + # 不启用匿评时还原申诉设置和教师、助教的评分比例 + unless @homework.anonymous_comment + @homework.anonymous_appeal = false + @homework_detail_manual.appeal_time = nil + @homework_detail_manual.appeal_penalty = 0 + @homework_detail_manual.te_proportion = 1 + @homework_detail_manual.ta_proportion = 0 + end + + end + + # 匿评未截止时可以更新匿评结束时间 + if @homework_detail_manual.comment_status < 4 + tip_exception("匿评结束时间不能为空") if @homework.anonymous_comment && params[:evaluation_end].blank? + tip_exception("匿评截止时间不能早于匿评开启时间") if @homework.anonymous_comment && + params[:evaluation_end] <= params[:evaluation_start] + tip_exception("匿评截止时间不能晚于课堂结束时间") if @homework.anonymous_comment && + @course.end_date.present? && params[:evaluation_end] > strf_time(@course.end_date.end_of_day) + + @homework_detail_manual.evaluation_end = !@homework.anonymous_comment ? nil : params[:evaluation_end] + end + + # 作业未结束可以更新缺评扣分 + tip_exception("缺评扣分不能为空") if @homework.anonymous_comment && params[:absence_penalty].blank? + tip_exception("缺评扣分不能小于0") if @homework.anonymous_comment && params[:absence_penalty].to_i < 0 + tip_exception("缺评扣分不能大于100") if @homework.anonymous_comment && params[:absence_penalty].to_i > 100 + @homework_detail_manual.absence_penalty = !@homework.anonymous_comment ? 0 : params[:absence_penalty].to_i + + + # 匿评申诉设置 + # 匿评申诉未开启前可以更新:是否启用匿评申诉 + if @homework_detail_manual.comment_status < 4 && @homework.anonymous_comment + tip_exception("缺少anonymous_appeal参数") if params[:anonymous_appeal].nil? + @homework.anonymous_appeal = params[:anonymous_appeal] + end + + + # 匿评申诉未结束前可以更新:匿评申诉结束时间 + if @homework_detail_manual.comment_status < 5 + tip_exception("匿评申诉结束时间不能为空") if @homework.anonymous_appeal && params[:appeal_time].blank? + tip_exception("匿评开启时间不能早于匿评截止时间") if @homework.anonymous_appeal && + params[:appeal_time] <= strf_time(@homework_detail_manual.evaluation_end) + tip_exception("匿评申诉结束不能晚于课堂结束时间") if @homework.anonymous_appeal && + @course.end_date.present? && params[:appeal_time] > strf_time(@course.end_date.end_of_day) + + @homework_detail_manual.appeal_time = @homework.anonymous_appeal ? params[:appeal_time] : nil + end + + # 作业未结束可以更新违规匿评扣分 + tip_exception("违规匿评扣分不能为空") if @homework.anonymous_appeal && params[:appeal_penalty].blank? + tip_exception("违规匿评扣分不能小于0") if @homework.anonymous_appeal && params[:appeal_penalty].to_i < 0 + tip_exception("违规匿评扣分不能大于100") if @homework.anonymous_appeal && params[:appeal_penalty].to_i > 100 + @homework_detail_manual.appeal_penalty = @homework.anonymous_appeal ? params[:appeal_penalty].to_i : 0 + + # 如果缺评扣分的设置有变更且匿评已截止 + absence_penalty_change = current_absence_penalty != @homework_detail_manual.absence_penalty && + @homework_detail_manual.comment_status >= 4 + # 如果违规匿评扣分的设置有变更且匿评已截止 + appeal_penalty_change = current_appeal_penalty != @homework_detail_manual.appeal_penalty && + @homework_detail_manual.comment_status >= 4 + + # 评分设置 + tip_exception("助教评分模式不能为空") if params[:ta_mode].blank? + + # 助教评分模式的变更 + ta_mode_change = @homework_detail_manual.ta_mode != params[:ta_mode].to_i + @homework_detail_manual.ta_mode = params[:ta_mode].to_i + + # 最终成绩组成 + tip_exception("最终成绩组成模式不能为空") if params[:final_mode].nil? + + final_mode_change = @homework_detail_manual.final_mode != params[:final_mode] + @homework_detail_manual.final_mode = params[:final_mode] + if !@homework_detail_manual.final_mode + tip_exception("教师评分比例不能为空") if params[:te_proportion].blank? + te_proportion = params[:te_proportion].to_f.round(2) + tip_exception("教师评分比例不能小于零") if te_proportion < 0 + tip_exception("助教评分比例不能为空") if params[:ta_proportion].blank? + ta_proportion = params[:ta_proportion].to_f.round(2) + tip_exception("助教评分比例不能小于零") if ta_proportion < 0 + if !@homework.anonymous_comment + tip_exception("评分比例之和不能大于100") if (te_proportion + ta_proportion) > 1.0 + else + tip_exception("学生评分比例不能为空") if params[:st_proportion].blank? + st_proportion = params[:st_proportion].to_f.round(2) + tip_exception("学生评分比例不能小于零") if st_proportion < 0 + tip_exception("评分比例之和不能大于100") if (te_proportion + ta_proportion + st_proportion) > 1.0 + end + + proportion_change = @homework_detail_manual.te_proportion.round(2) != te_proportion || + @homework_detail_manual.ta_proportion.round(2) != ta_proportion + @homework_detail_manual.te_proportion = te_proportion + @homework_detail_manual.ta_proportion = ta_proportion + else + @homework_detail_manual.te_proportion = 1 + @homework_detail_manual.ta_proportion = 0 + end + + # 公开属性设置 + tip_exception("缺少work_public参数") if params[:work_public].nil? + tip_exception("缺少score_open参数") if params[:score_open].nil? + tip_exception("缺少answer_public参数") if params[:answer_public].nil? + @homework.work_public = params[:work_public] + @homework.score_open = params[:score_open] + @homework.answer_public = params[:answer_public] + + @homework_detail_manual.save! + @homework.save! + + # 迟交扣分、缺评扣分、违规匿评扣分、助教评分模式变更、最终成绩组成、评分比例变更都需要更新学生成绩 + if late_penalty_change || absence_penalty_change || appeal_penalty_change || ta_mode_change || + final_mode_change || proportion_change + + student_works = @homework.student_works.has_committed + work_ids = student_works.pluck(:id) + + student_works.each do |student_work| + # 迟交扣分 + student_work.late_penalty = student_work.work_status == 1 ? 0 : @homework.late_penalty + + # 缺评扣分的更新 如果之前的作业缺评扣分为0,则需重新计算缺评次数 + if absence_penalty_change + absence_penalty_count = current_absence_penalty == 0 ? student_work.absence_count : + (student_work.absence_penalty / current_absence_penalty).to_i + student_work.absence_penalty = absence_penalty_count * @homework_detail_manual.absence_penalty + end + + # 违规匿评扣分 如果之前的作业违规扣分为0,则需重新计算违规匿评次数 + if appeal_penalty_change + appeal_penalty_count = current_appeal_penalty == 0 ? student_work.appeal_count : + (student_work.appeal_penalty / current_appeal_penalty).to_i + student_work.appeal_penalty = appeal_penalty_count * @homework_detail_manual.appeal_penalty + end + + # 助教模式变更且有助教评分记录时才更新 + if ta_mode_change && student_work.student_works_scores.where("reviewer_role = 2 AND score IS NOT NULL").count > 0 + student_work.teaching_asistant_score = student_work.ta_score @homework_detail_manual.ta_mode + end + + student_work.save! + end + end + + end + + HomeworkCommonPushNotifyJob.perform_later(@homework.id, publish_group_ids) if send_tiding + normal_status(0, "更新成功") + else + tip_exception("课堂已结束不能再更新") + end + rescue Exception => e + uid_logger(e.backtrace) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + # 选用实训 + def shixuns + search = params[:search] + type = params[:type] + # 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭) + if current_user.admin? + @shixuns = Shixun.unhidden + else + none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id) + + @shixuns = Shixun.where.not(id: none_shixun_ids).unhidden + end + + # 实训的所有标签 + @tags = TagRepertoire.select([:id, :name]).joins(:shixuns).where(shixuns: {id: @shixuns}).distinct + + if params[:search] && params[:search].strip != "" + @shixuns = @shixuns.joins(:user).where("shixuns.name like ? or concat(users.lastname, users.firstname) like ?", + "%#{search}%", "%#{search}%").distinct + end + + unless type.blank? || type == "all" + @shixuns = @shixuns.joins(:shixun_tag_repertoires).where(shixun_tag_repertoires: {tag_repertoire_id: type}).distinct + end + + @shixuns = @shixuns.select([:id, :name, :status, :myshixuns_count, :identifier]).reorder("shixuns.created_at desc") + @shixuns_count = @shixuns.size + + ## 分页参数 + page = params[:page] || 1 + @shixuns = @shixuns.page(page).per(10) + + @main_catrgory = @course.course_modules.where(module_type: "shixun_homework") + @homework_category = @main_catrgory.take.course_second_categories + end + + def create_shixun_homework + tip_exception("请至少选择一个实训") if params[:shixun_ids].blank? + shixuns = Shixun.where(id: params[:shixun_ids]).reorder("id desc") + @homework_ids = [] + unless params[:category_id].blank? + @category = @course.course_second_categories.find_by(id: params[:category_id], category_type: "shixun_homework") + end + ActiveRecord::Base.transaction do + begin + shixuns.each do |shixun| + homework = HomeworksService.new.create_homework shixun, @course, @category, current_user + @homework_ids << homework.id + end + rescue Exception => e + uid_logger(e.message) + tip_exception("创建失败") + raise ActiveRecord::Rollback + end + end + end + + # 选用实训课程 + def subjects + search = params[:search] + type = params[:type] + # 显示所有未隐藏的、已发布的实训课程 + @subjects = Subject.select([:id, :name, :status, :repertoire_id]).visible.unhidden + + @tags = Repertoire.select([:id, :name]).where(id: @subjects.pluck(:repertoire_id).uniq).order("updated_at desc") + + if params[:search] && params[:search].strip != "" + @subjects = @subjects.joins(:user).where("subjects.name like ? or concat(users.lastname, users.firstname) like ?", + "%#{search}%", "%#{search}%") + end + + unless type.blank? || type == "all" + @subjects = @subjects.where(repertoire_id: type) + end + + @subjects = @subjects.reorder("subjects.created_at desc") + @subjects_count = @subjects.size + + ## 分页参数 + page = params[:page] || 1 + @subjects = @subjects.page(page).per(10) + + @subjects = @subjects.includes(:shixuns) + end + + def create_subject_homework + tip_exception("请至少选择一个实训课程") if params[:subject_ids].blank? + subjects = Subject.where(id: params[:subject_ids], status: 2).includes(stages: :shixuns).reorder("id desc") + @homework_ids = [] + + none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id) + + course_module = @course.course_modules.find_by(module_type: "shixun_homework") + ActiveRecord::Base.transaction do + begin + subjects.each do |subject| + + subject.stages.each do |stage| + + # 为实训作业创建与stage同名的子目录 + category = CourseSecondCategory.find_by(name: stage.name, course_id: @course.id, category_type: "shixun_homework") || + CourseSecondCategory.create!(name: stage.name, course_id: @course.id, category_type: "shixun_homework", + course_module_id: course_module.id, position: course_module.course_second_categories.count + 1) + + # 去掉不对当前用户的单位公开的实训,已发布的实训 + stage.shixuns.where.not(shixuns: {id: none_shixun_ids}).unhidden.each do |shixun| + homework = HomeworksService.new.create_homework shixun, @course, category, current_user + @homework_ids << homework.id + end + end + end + rescue Exception => e + uid_logger(e.message) + tip_exception("创建失败") + raise ActiveRecord::Rollback + end + end + end + + def publish_groups + @current_user = current_user + if @homework.publish_immediately @current_user + # 可立即发布的分班:当前用户管理的分班去除已发布的分班 + group_ids = @course.charge_group_ids(@current_user) - @homework.homework_group_settings.group_published.pluck(:course_group_id) + @course_groups = @course.course_groups.where(id: group_ids) + else + tip_exception("没有可发布的分班") + end + end + + def publish_homework + tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0 + tip_exception("缺少截止时间参数") if params[:end_time].blank? + tip_exception("截止时间必须晚于当前时间") if params[:end_time] <= strf_time(Time.now) + + homeworks = @course.homework_commons.where(id: params[:homework_ids]) + homeworks = homeworks.includes(:homework_group_settings, :homework_detail_manual) + + charge_group_ids = @course.charge_group_ids(current_user) + publish_groups = charge_group_ids & params[:group_ids] if params[:group_ids] + + ActiveRecord::Base.transaction do + begin + homeworks.each do |homework| + # 作业未发布时 + if homework.homework_detail_manual.try(:comment_status) == 0 + if !params[:group_ids].blank? + + # 全选即统一设置,unified_setting为true + if @course.course_groups.where(id: publish_groups).size == @course.course_groups.size + homework.homework_group_settings.destroy_all + homework.unified_setting = true + else + homework.unified_setting = false + # 创建作业分班设置:homework_group_setting + create_homework_group_settings(homework) + + # 选中的分班设置的发布时间改为当前时间,截止时间不为空的保持原状,为空的改为一个月后 + homework.homework_group_settings.where(course_group_id: publish_groups).update_all(publish_time: Time.now) + homework.homework_group_settings.where(course_group_id: publish_groups, end_time: nil). + update_all(end_time: params[:end_time]) + # 发消息 + tiding_group_ids = publish_groups + end + else + homework.homework_group_settings.destroy_all + # students = @course.students + end + + homework.publish_time = Time.now + + # 截止时间不为空的保持原状,为空的改为一个月后, 非统一设置的更新为最大分班截止时间 + if homework.end_time.nil? + homework.end_time = params[:end_time] + elsif homework.max_group_end_time + homework.end_time = homework.max_group_end_time + end + homework.homework_detail_manual.update_attribute('comment_status', 1) + + if homework.course_acts.size == 0 + homework.course_acts << CourseActivity.new(user_id: homework.user_id, course_id: homework.course_id) + end + + HomeworkCommonPushNotifyJob.perform_later(homework.id, tiding_group_ids) + else + create_homework_group_settings(homework) + + none_publish_settings = homework.homework_group_settings.where(course_group_id: publish_groups).none_published + none_publish_settings.update_all(publish_time: Time.now) + none_publish_settings.where(end_time: nil).update_all(end_time: params[:end_time]) + if homework.max_group_end_time + homework.end_time = homework.max_group_end_time + end + HomeworkCommonPushNotifyJob.perform_later(homework.id, none_publish_settings.pluck(:course_group_id)) + end + if homework.end_time > Time.now && homework.homework_detail_manual.try(:comment_status) > 1 + homework.homework_detail_manual.update_attribute("comment_status", 1) + end + + # 补交结束时间 + homework.late_time = Time.at(homework.end_time.to_i + 30*24*3600) if homework.allow_late && homework.late_time.nil? + + homework.save! + + HomeworkPublishUpdateWorkStatusJob.perform_later(tiding_group_ids, homework.id) + end + normal_status(0, "发布成功") + rescue Exception => e + uid_logger(e.message) + tip_exception("发布失败") + raise ActiveRecord::Rollback + end + end + end + + def end_groups + @current_user = current_user + if @homework.end_immediately @current_user + # 可立即截止的分班:统一设置则是用户管理的所有分班,否则是当前用户管理的分班中已发布且未截止的 + charge_group_ids = @course.charge_group_ids(@current_user) # 当前用户管理的分班 + group_ids = @homework.unified_setting ? charge_group_ids : + @homework.homework_group_settings.where(course_group_id: charge_group_ids).none_end.pluck(:course_group_id) + @course_groups = @course.course_groups.where(id: group_ids) + else + tip_exception("没有可截止的分班") + end + end + + def end_homework + tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0 + + time = Time.now.strftime("%Y-%m-%d %H:%M:%S") + + # 已发布且未截止的作业才能立即截止 + + homeworks = @course.homework_commons.where(id: params[:homework_ids]) + homeworks = homeworks.published_no_end.includes(:homework_group_settings, :homework_detail_manual, :homework_challenge_settings) + course_students = @course.students + charge_group_ids = @course.charge_group_ids(current_user) + end_groups = charge_group_ids & params[:group_ids] if params[:group_ids] + + ActiveRecord::Base.transaction do + begin + homeworks.each do |homework| + homework_detail_manual = homework.homework_detail_manual + + # 分组设置 + if !params[:group_ids].blank? + # 确保之前是统一设置或者有新创建的分班的数据一致性 + create_homework_group_settings(homework) + + homework.unified_setting = false if homework.unified_setting && end_groups.length != @course.course_groups_count + + # 已发布且未截止的分班 + none_end_settings = homework.homework_group_settings.where(course_group_id: end_groups).published_no_end + + none_end_settings.update_all(end_time: time) + student_works = homework.student_works.where(user_id: course_students.where(course_group_id: none_end_settings. + pluck(:course_group_id)).pluck(:user_id)).has_committed if homework.homework_type == "practice" + + homework.end_time = homework.max_group_end_time + if homework.end_time > time && homework_detail_manual.try(:comment_status) > 1 + homework_detail_manual.update_attribute("comment_status", 1) + end + + # 统一设置 + elsif homework.unified_setting + student_works = homework.student_works.has_committed if homework.homework_type == "practice" + homework.end_time = time + end + + homework_detail_manual.update_attribute("comment_status", 2) if homework.end_time <= time + + # 实训作业的作品需要计算是否迟交 + if homework.homework_type == "practice" + # shixun = homework.shixuns.first + # homework_challenge_settings = homework.homework_challenge_settings + unless student_works.blank? + student_works.joins(:myshixun).where("myshixuns.status != 1").update_all(late_penalty: homework.late_penalty) if homework.allow_late + +=begin + student_works.where("work_status != 0").includes(:myshixun).each do |student_work| + unless student_work.myshixun.is_complete? + student_work.update_attributes(work_status: 2, late_penalty: homework.late_penalty) + student_work.late_penalty = homework.late_penalty + end + HomeworksService.new.set_shixun_final_score student_work, student_work.myshixun, homework_detail_manual.answer_open_evaluation, + homework_challenge_settings + end + + student_works.where("work_status = 0").each do |student_work| + myshixun = Myshixun.where(shixun_id: shixun.id, user_id: student_work.user_id).first + if myshixun.present? + student_work.update_attributes(work_status: (myshixun.is_complete? ? 1 : 2), + late_penalty: myshixun.is_complete? ? 0 : homework.late_penalty, + commit_time: myshixun.created_at, myshixun_id: myshixun.id) + student_work.late_penalty = myshixun.is_complete? ? 0 : homework.late_penalty + HomeworksService.new.set_shixun_final_score student_work, myshixun, homework_detail_manual.answer_open_evaluation, + homework_challenge_settings + end + end +=end + + # 更新所有学生的效率分(重新取homework确保是更新后的) + HomeworksService.new.update_student_eff_score HomeworkCommon.find_by(id: homework.id) if !homework.allow_late && homework.end_time <= time + end + end + homework.save! + end + normal_status(0, "更新成功") + rescue Exception => e + uid_logger(e.message) + tip_exception("操作失败") + raise ActiveRecord::Rollback + end + end + end + + def set_public + tip_exception("仅公开课堂才能公开作业") if @course.is_public == 0 + homeworks = @course.homework_commons.where(id: params[:homework_ids]) + homeworks.update_all(is_public: 1) + normal_status(0, "更新成功") + end + + def choose_category + @main_catrgory = @course.course_modules.where(module_type: "shixun_homework") + @homework_category = @main_catrgory.take.course_second_categories + end + + # 实训作业移动到目录 + def move_to_category + tip_exception("请选择要移动的目录") if params[:new_category_id].blank? + + category = @course.course_second_categories.find_by(id: params[:new_category_id]) + if params[:new_category_id].to_i == 0 || category.present? + homeworks = @course.homework_commons.where(id: params[:homework_ids]) + + homeworks.update_all(course_second_category_id: params[:new_category_id]) + normal_status(0, "更新成功") + else + normal_status(-1, "目录不存在") + end + end + + # 删除多个作业 + def multi_destroy + ActiveRecord::Base.transaction do + begin + homeworks = @course.homework_commons.where(id: params[:homework_ids]) + homeworks.destroy_all + + # 这些写是因为model中的关联删除无法删除is_delete=0的作品 + StudentWork.where(homework_common_id: homeworks.pluck(:id)).destroy_all + normal_status(0, "删除成功") + + rescue Exception => e + uid_logger(e.message) + tip_exception("删除失败") + raise ActiveRecord::Rollback + end + end + end + + #加入到题库 + def add_to_homework_bank + homeworks = @course.homework_commons.where(id: params[:homework_ids]) + + homeworks.each do |homework| + ActiveRecord::Base.transaction do + begin + homework_bank = current_user.homework_banks.find_by(homework_common_id: homework.id) + if homework_bank.present? + # 如果作业加入过题库则更新参数 + if homework_bank.homework_type == 1 + homework_bank.update_attributes(name: homework.name, description: homework.description, + reference_answer: homework.reference_answer, course_list_id: @course.course_list_id) + elsif homework_bank.homework_type == 3 + homework_detail_group = homework.homework_detail_group + homework_bank.update_attributes(name: homework.name, description: homework.description, + reference_answer: homework.reference_answer, course_list_id: @course.course_list_id, + min_num: homework_detail_group.min_num, max_num: homework_detail_group.max_num, + base_on_project: homework_detail_group.base_on_project) + end + + # 附件的更新 + homework_bank.attachments.destroy_all + homework.attachments.each do |attachment| + att = attachment.copy + att.author_id = homework_bank.user_id + att.copy_from = attachment.id + homework_bank.attachments << att + end + else + new_homework_bank = add_to_homework_bank_f homework + new_homework_bank.save! + end + + rescue Exception => e + uid_logger(e.message) + tip_exception("删除失败") + raise ActiveRecord::Rollback + end + end + end + normal_status(0, "加入成功") + end + + # 代码查重分班列表 + def group_list + @page = params[:page] || 1 + @limit = params[:limit] || 10 + @course_groups = @course.course_groups.page(@page).per(@limit) + @ungroup_user_ids = @course.course_members.ungroup_students.pluck(:user_id) + end + + # 班级作品查重 + def homework_code_repeat + tip_exception(-1,"分班id不能为空!") if params[:group_ids].nil? + shixun = @homework.shixuns.take + # 通过代码文件来判断语言 + language = shixun.challenges.practice_type.pluck(:path).first + language = language.split(";")[0].split(".")[1].downcase if language.present? + user_lists = [] + if language.present? && (language == "java" || language == "py") + user_ids = @course.course_members.where(course_group_id: params[:group_ids]).distinct(:user_id).pluck(:user_id) + challenge_ids = @homework.homework_challenge_settings.pluck(:challenge_id) + challenge_ids = challenge_ids.size == 0 ? "(-1)" : "(#{challenge_ids.join(",")})" + user_ids.each do |user_id| + code_infos = [] + games = Game.find_by_sql("select games.* from games right join myshixuns ms on games.myshixun_id = ms.id where + games.user_id = #{user_id} and games.status = 2 and ms.shixun_id = #{shixun.id} and + games.challenge_id in #{challenge_ids}") + games.each do |game| + game.game_codes.each do |game_code| + code_infos << { + path: game_code.path, + content: Base64.urlsafe_encode64(game_code.new_code.to_s, padding: false), + passed_time: game.end_time.try(:strftime, '%Y-%m-%d %H:%M:%S') + } + end + end + if code_infos.size != 0 + user_lists << { + user_id: user_id, + code_info: code_infos + } + end + end + result = ReviewService.check(user_lists, language == "py" ? "python" : "java") + if result.status == 0 + params[:group_ids].each do |group_id| + @homework.homework_group_reviews << HomeworkGroupReview.new(:course_group_id => group_id, + :user_id => current_user.id, + :query_id => result.query_id) + end + normal_status("代码查重成功") + else + if result.status == 1 + tip_exception(-4,"代码查重异常,请稍后重试") + else + tip_exception(-3,"正在查重,请在几分钟后刷新页面查看结果") + end + end + else + tip_exception(-2,"平台目前支持java、python语言的查重
其他语言正在规划中,敬请期待") + end + end + + + # 代码查重届结果 + def code_review_results + # 如果有未获取结果的查重操作 则先读取结果 + get_new_code_reviews_result @homework + @current_user = current_user + + # 列表数据 + rorder = params[:order] || "code_rate" + sort = params[:sort] || "desc" + page = params[:page] || 1 + limit = params[:limit] || 15 + student_works = @homework.student_works.where("work_status > 0") + # 按分班id搜索 + user_ids = + if params[:group_ids] + # 筛选了分班 + group_student_ids = @course.course_members.where(course_group_id: params[:group_ids]).pluck(:user_id) + student_works.where(:user_id => group_student_ids).pluck(:user_id) + else + # 如果当前用户有分班 显示分班内的学生,没有则显示全部 + user_ids = @course.user_group_students(current_user.id).pluck(:user_id) + if user_ids.present? + student_works.where(:user_id => user_ids).pluck(:user_id) + else + student_works.pluck(:user_id) + end + end + # 查询作品数总数 + @all_reviews_count = user_ids.count + @users_reviews = @homework.homework_review_results.where("code_rate >= 50.0") + .where(:user_id => user_ids).joins(user: :user_extension) + # 按学号和姓名搜索 + if params[:search] + @users_reviews = @users_reviews.where("concat(lastname, firstname) like ? or student_id like ?", params[:search], params[:search]) + end + # 抄袭作品数 + @copy_reviews_count = @users_reviews.count + # 排序搜索 + @users_reviews = @users_reviews.order("#{rorder} #{sort}").page(page).per(limit) + # 获取所有查重过的分班 + @course_groups = @course.course_groups.where(id: @homework.homework_group_reviews.pluck(:course_group_id).uniq) + + # 如果未分班被查重过,则显示未分班列 + @non_course_group = + if @homework.homework_group_reviews.where(course_group_id: 0).count > 0 + @course.course_members.where(role: 4, course_group_id: 0).count + end + + # 最新一次的查重时间 + @last_review_time = format_time @homework.homework_group_reviews.last.try(:created_at) + + end + + # 代码查重详情 + def code_review_detail + @student_work = @homework.student_works.find_by(user_id: params[:user_id]) + @user = @student_work.user + tip_exception("当前用户无作品可以显示") if @student_work.nil? + # 查询最新一次的查重标识query_id + group_id = @course.course_members.where(user_id: params[:user_id]).pluck(:course_group_id).first + query_id = @homework.homework_group_reviews.where(:course_group_id => group_id).last.try(:query_id) + results = ReviewService.query_result({user_id: params[:user_id], query_id: query_id}) + @shixun = @homework.shixuns.take + if results.status == 0 + code_info = results.code_info + homework_challenge_settings = @homework.homework_challenge_settings + @challenges = @shixun.challenges.where(id: homework_challenge_settings.pluck(:challenge_id), st: 0).includes(:games) + @challenges = + @challenges.map do |challenge| + code_rate = 0 + game_codes = results.code_info.select {|info| challenge.path.split(";").include?(info.origin_path)} + # 先判断用户该关卡是否查重了 取多个待补充文件的平均值 + if game_codes.count > 0 + code_rate += game_codes.map(&:rate).sum / challenge.path.split(";").length + end + target = game_codes.count > 0 ? game_codes[0].target_user_id : nil + # 作品完成时间 + game = challenge.games.find_by(user_id: @user.id) + end_time = game.end_time + # 用户关卡的得分 + all_score = homework_challenge_settings.find_by(challenge_id: challenge.id).try(:score) + final_score = + if @student_work.challenge_work_scores.where(challenge_id: challenge.id).last.present? + @student_work.challenge_work_scores.where(:challenge_id => game.challenge_id).last.score + else + if game.status == 2 && ((game.end_time && game.end_time < @homework.end_time) || + (@homework.allow_late && (@course.end_date.nil? || + (game.end_time && game.end_time < @course.end_date.end_of_day)))) + answer_open_evaluation = @homework.homework_detail_manual.answer_open_evaluation + # 设置了查看答案也获得满分的话就取总分。否则取关卡的百分比分支 + if answer_open_evaluation.present? + all_score + else + # 关卡的百分比 * 作业设置的分数 = 总得分 + ((game.final_score) / challenge.score) * all_score + end + end + end + # 抄袭用户 + copy_user = User.find_by_id(game_codes[0].target_user_id) + copy_end_time = copy_user.games.find_by(challenge_id: challenge.id).try(:end_time) if copy_user.present? + # 代码部分 + code_list = [] + challenge.path.split(";").each do |path| + if code_info.select{|info| path == info.origin_path}.size > 0 + info = code_info.select{|info| path == info.origin_path}[0] + code_list << {path: path, origin_content: info.origin_content, target_content: info.target_content} + end + end + + {code_rate: code_rate, copy_user_id: copy_user.try(:id), end_time: end_time, final_score: final_score, + all_score: all_score, copy_end_time: copy_end_time, copy_username: copy_user.try(:full_name), + username: game.user.full_name, code_list: code_list, subject: challenge.subject, position: challenge.position, + id: challenge.id} + end + + else + if results.status == 1 + tip_exception(-1, "代码查重异常,请稍后重试") + else + tip_exception(-2, "代码查重正在执行中,请稍后") + + end + end + + end + + private + + def find_homework + begin + @homework = HomeworkCommon.find(params[:id]) + @course = @homework.course + @homework_detail_manual = @homework.homework_detail_manual + rescue Exception => e + uid_logger(e.message) + tip_exception("id不存在") + end + end + + def homework_params + tip_exception("name参数不能为空") if params[:name].blank? + tip_exception("description参数不能为空") if params[:description].blank? + params.require(:homework_common).permit(:name, :description, :reference_answer) + end + + def require_id_params + tip_exception("请至少选择一个作业") if params[:homework_ids].blank? + tip_exception("批量设置不能超过15个") if params[:homework_ids].length > 15 + end + + def validate_min_max_num + tip_exception("min_num参数不能为空") if params[:min_num].blank? + tip_exception("max_num参数不能为空") if params[:max_num].blank? + tip_exception("最小人数不能小于1") if params[:min_num].to_i < 1 + tip_exception("最大人数不能小于最小人数") if params[:max_num].to_i < params[:min_num].to_i + end + + def validate_absence_penalty + + end + + def create_homework_group_settings homework + if homework.homework_group_settings.size != @course.course_groups.size + @course.course_groups.where.not(id: homework.homework_group_settings.pluck(:course_group_id)).each do |group| + homework.homework_group_settings << HomeworkGroupSetting.new(course_group_id: group.id, course_id: @course.id, + publish_time: homework.publish_time, end_time: homework.end_time) + end + end + end + + def get_new_code_reviews_result homework + if homework.code_reviews_new_results? + # 获取最新的查询id + query_id = homework.homework_group_reviews.where(status: 0).last.try(:query_id) + results = ReviewService.query_result({query_id: query_id}) + if results.status == 0 + shixun = homework.shixuns.take + challenges = shixun.challenges.where(id: homework.homework_challenge_settings.pluck(:challenge_id), st: 0) + challenge_count = challenges.count + Rails.logger.info("#####results_user_list: #{results.user_lists.to_json}") + results.user_lists.map(&:user_id).uniq.each do |user| + user_rate = 0 + # 计算每个关卡的相似度 + challenges.each do |challenge| + game_codes = results.user_lists.select{|user_list| user_list.user_id == user && + challenge.path.split(";").include?(user_list.origin_path)} + # 先判断用户该关卡是否查重了 取多个待补充文件的平均值 + if game_codes.count > 0 + user_rate += game_codes.map(&:rate).sum / challenge.path.split(";").length + end + end + user_rate = challenge_count == 0 ? 0 : user_rate / challenge_count + + # 如果用户已有查重记录则更新相似度 否则新建一条记录 + user_review = homework.homework_review_results.find_by(:user_id => user) + if user_review.present? + user_review.update_attributes(:code_rate => user_rate) + else + homework.homework_review_results.create(:user_id => user, :code_rate => user_rate) + end + end + nuser_ids = results.user_lists.map(&:user_id).uniq + homework.homework_review_results.where.not(user_id: nuser_ids).destroy_all + homework.homework_group_reviews.where(status: 0).update_all(status: 1) + elsif results.status == 2 + tip_exception(-2, "代码查重正在执行中,请稍后") + else + tip_exception(-1, "代码查重异常,请稍后重试") + end + end + end + + def add_to_homework_bank_f homework + homework_bank = HomeworkBank.new(name: homework.name, description: homework.description, user_id: current_user.id, + homework_type: homework.homework_type == "normal" ? 1 : 3, quotes: 1, is_public: 0, + homework_common_id: homework.id, reference_answer: homework.reference_answer, + course_list_id: @course.course_list_id) + if homework.homework_type == "group" && homework.homework_detail_group + homework_bank.min_num = homework.homework_detail_group.min_num + homework_bank.max_num = homework.homework_detail_group.max_num + homework_bank.base_on_project = homework.homework_detail_group.base_on_project + end + homework.attachments.each do |attachment| + att = attachment.copy + att.author_id = homework_bank.user_id + att.copy_from = attachment.id + homework_bank.attachments << att + end + homework_bank + end + +end diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb new file mode 100644 index 000000000..0e2628c3e --- /dev/null +++ b/app/controllers/main_controller.rb @@ -0,0 +1,5 @@ +class MainController < ApplicationController + def index + render file: 'public/react/build/index.html', :layout => false + end +end \ No newline at end of file diff --git a/app/controllers/memos_controller.rb b/app/controllers/memos_controller.rb new file mode 100644 index 000000000..723f2e9a4 --- /dev/null +++ b/app/controllers/memos_controller.rb @@ -0,0 +1,138 @@ +class MemosController < ApplicationController + before_action :set_memo, only: [:show, :edit, :update, :destroy] + + include ApplicationHelper + # GET /memos + # GET /memos.json + def index + @user = current_user + @memos = Memo.all + s_order = (params[:order] == "replies_count" ? "all_replies_count" : params[:order]) || "updated_at" + #@tidding_count = unviewed_tiddings(current_user) if current_user.present? + page = params[:page].to_i + search = params[:search] + offset = page * 15 + forum_id = params[:forum] + user_id = params[:user_id] + if user_id == -1 + user_id = current_user.try(:id) + end + tag_repertoire_id = params[:tag_repertoire_id] + + sql = + if forum_id + search ? "forum_id = #{forum_id} and root_id is null and subject like '%#{search}%'" : + "forum_id = #{forum_id} and root_id is null" + elsif search + user_id ? "author_id = #{user_id.to_i} and forum_id in(3, 5) and root_id is null and subject like '%#{search}%'" : + "forum_id in(3, 5) and root_id is null and subject like '%#{search}%'" + else + user_id ? "author_id = #{user_id.to_i} and forum_id in(3, 5) and root_id is null" : + "forum_id in(3, 5) and root_id is null" + end + + if tag_repertoire_id + memo_ids = MemoTagRepertoire.where(tag_repertoire_id: tag_repertoire_id).pluck(:memo_id) + memo_ids = memo_ids ? memo_ids.join(",") : -1 + sql += " and #{Memo.table_name}.id in(#{memo_ids})" + end + + if params[:order] == "updated_at" + sql += " and all_replies_count != 0" + end + + memos = Memo.field_for_list.includes(:praise_tread, :author).where("#{sql}") + @memos_count = memos.length + @memos = memos.order("sticky = 1 desc, #{Memo.table_name}.#{s_order} desc").offset(offset).limit(15) + @my_memos_count = Memo.user_posts(current_user.try(:id)).count + @tags_info = MemoTagRepertoire.find_by_sql("SELECT tag_repertoire_id, tr.name, count(*) cnt + FROM memo_tag_repertoires mtr join tag_repertoires tr on + tr.id = mtr.tag_repertoire_id group by tag_repertoire_id order by cnt desc, + tag_repertoire_id desc limit 9") + @hot_memos = Memo.field_for_recommend.posts.hot.limit(4) + end + + # GET /memos/1 + # GET /memos/1.json + def show + # tidding_count = unviewed_tiddings(current_user) if current_user + @user = current_user + # TODO 附件最后再做 + # attachments_list = + @memo.update_column(:viewed_count, @memo.viewed_count+1) + @memos = @memo.reply_for_memo.includes(:praise_tread, :author).order("created_at desc").limit(10) + + end + + # GET /memos/new + def new + @csrf_token = session[:_csrf_toke] ||= SecureRandom.base64(32) + @tag_list = TagRepertoire.field_for_list.order("name asc") + + end + + # GET /memos/1/edit + def edit + end + + # POST /memos + # POST /memos.json + def create + ActiveRecord::Base.transaction do + begin + @memo = Memo.new(memo_params) + @memo.author = current_user + # TODO 保存附件 + # @memo.save_attachments(params[:attachments]) if params[:attachments] + @memo.save! + params[:tags].each do |tag| + MemoTagRepertoire.create(:memo_id => @memo.id, :tag_repertoire_id => tag) + end + @status = 0 + @message = "帖子创建成功!" + rescue Exception => e + @status = -1 + @message = "帖子创建失败,原因:#{e}" + raise ActiveRecord::Rollback + end + end + + + end + + # PATCH/PUT /memos/1 + # PATCH/PUT /memos/1.json + def update + respond_to do |format| + if @memo.update(memo_params) + format.html { redirect_to @memo, notice: 'Memo was successfully updated.' } + format.json { render :show, status: :ok, location: @memo } + else + format.html { render :edit } + format.json { render json: @memo.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /memos/1 + # DELETE /memos/1.json + def destroy + @memo.destroy + respond_to do |format| + format.html { redirect_to memos_url, notice: 'Memo was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_memo + @memo = Memo.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def memo_params + params.fetch(:memo, {}) + end + +end diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb new file mode 100644 index 000000000..8e340da73 --- /dev/null +++ b/app/controllers/messages_controller.rb @@ -0,0 +1,206 @@ +class MessagesController < ApplicationController + include MessagesHelper + + SORT_TYPE = %w[time hot] + + before_action :require_login, only: %i[create update sticky_top bulk_delete create destroy bulk_send bulk_move bulk_public] + before_action :find_board, only: [:create, :index, :bulk_delete, :bulk_move, :bulk_send, :bulk_public] + before_action :find_message, only: [:update, :destroy, :sticky_top, :reply_list, :destroy, :reply] + before_action :validate_delete_params, only: %i[bulk_delete bulk_public] + before_action :message_validate_create_params, only: :create + before_action :validate_update_params, only: :update + before_action :validate_sort_type, only: :index + before_action :validate_send_message_to_course_params, only: :bulk_send + before_action :validate_move_params, only: :bulk_move + + def index + @page = params[:page] || 1 + @page_size = params[:page_size] || 15 + + sort = params[:sort] || 0 + sort_type = params[:sort_type] || 'time' + sort = sort.to_i + sort_type = sort_type.strip + + @messages = @board.messages.root_nodes.by_keywords(params[:search]).includes(:praise_treads, :author, :children) + @messages = @messages.ordered(sort: sort, sort_type: sort_type) + @messages = sort_by_all_replies(sort, sort_type, @messages) + + @messages = sort_by_sticky(@messages) + @messages = Kaminari.paginate_array(@messages).page(@page).per(@page_size) + end + + def reply_list + @page = params[:page] || 1 + @page_size = params[:page_size] || 10 + @current_user = current_user || nil + + @messages = @message.children.preload_messages + @messages = @messages.ordered(sort: 1) unless @message.parent_id.nil? + + @messages = @messages.page(@page).per(@page_size) + end + + def reply + return normal_status(2, "回复内容不能为空") if params[:content].blank? + begin + @reply = Message.create!(board: @message.board, + author: current_user, + parent: @message, + message_detail_attributes: { + content: params[:content] + } + ) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def sticky_top + return normal_status(403, "您没有权限进行该操作") unless current_user.teacher_of_course?(@message.board.course) + + ActiveRecord::Base.transaction do + begin + @message.update_attributes(:sticky => @message.sticky == 1 ? 0 : 1) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def bulk_delete + ActiveRecord::Base.transaction do + begin + @messages = @board.messages.by_ids(params[:ids]) + @messages.destroy_all + rescue Exception => e + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def new + @message = Message.new + end + + def show + @message = Message.includes(:attachments, :message_detail, :children, :author => :user_extension, :board => [{course: :board_course_modules}]).find_by_id params[:id] + return normal_status(-2, "ID为#{params[:id]}的帖子不存在") if @message.nil? + + @attachment_size = @message.attachments.size + @message.update_visits + @current_user = current_user + end + + def update + return normal_status(403, "您没有权限进行该操作") if current_user != @message.author && !current_user.teacher_of_course?(@message.board.course) + + begin + @message.update_attributes(message_params) + Attachment.associate_container(params[:attachment_ids], @message.id, @message.class.name) + @message.update_content(params[:content]) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("修改失败") + raise ActiveRecord::Rollback + end + end + + def create + return normal_status(403, "您没有权限进行该操作") unless current_user.admin? || current_user.member_of_course?(@board.course) + + begin + @message = Message.new(message_params) + @message.author = current_user + @message.board_id = params[:select_board_id] + @message.message_detail_attributes = {content: params[:content]} + @message.save! + Attachment.associate_container(params[:attachment_ids], @message.id, @message.class.name) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def destroy + begin + return normal_status(403, "您没有权限进行该操作") unless @message.author == current_user || current_user.teacher_of_course?(@message.board.course) + @message.destroy! + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def bulk_send + return normal_status(403) unless current_user.teacher_or_admin?(@board.course) + ids = params[:ids] + course_ids = params[:to_course_ids] + + begin + ids.each do |id| + @message = Message.find_by_id id + if @message.try(:parent_id).nil? # TODO 暂时只支持目录下的跟节点发送 + course_ids.each do |course_id| + course = Course.find course_id + new_message = Message.create!(board: course.course_board, + subject: @message.subject, + author: current_user, + message_detail_attributes: { + content: @message.try(:message_detail).try(:content) + } + ) + @message.copy_attachments_to_new_message(new_message, current_user) + end + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def bulk_move + # 课堂的目录之间移动,有子栏目的才显示此项 + return normal_status(403) unless current_user.teacher_of_course?(@board.course) + + begin + Message.bulk_move_to_other_board(params[:ids], params[:to_board_id], current_user.id) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def bulk_public + @messages = @board.messages.root_nodes.by_ids Array(params[:ids]) + @messages.update_all(is_public: true) + end + + private + def validate_sort_type + normal_status(2, "参数sort_tyope暂时只支持 'time', 'hot'两种") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) + end + + def find_message + begin + @message = Message.find params[:id] + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + end + + def message_params + params.require(:message).permit(:subject, :sticky) + end +end diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb new file mode 100644 index 000000000..042945b6e --- /dev/null +++ b/app/controllers/myshixuns_controller.rb @@ -0,0 +1,362 @@ +class MyshixunsController < ApplicationController + before_action :require_login, :except => [:training_task_status, :code_runinng_message] + before_action :find_myshixun, :except => [:training_task_status] + before_action :find_repo_name, :except => [:training_task_status] + skip_before_action :verify_authenticity_token, :only => [:html_content] + + ## TPI关卡列表 + def challenges + # @challenges = Challenge.where(shixun_id: params[:shixun_id]) + + @shixun_status = @myshixun.shixun.status + @games = @myshixun.games.includes(:challenge).reorder("challenges.position") + end + + + # For Admin + # 强制重置实训 + # REDO等删除是否可以做成异步 + # 前段需要按照操作过程提示 + def reset_my_game + unless (current_user.admin? || current_user.id == @myshixun.user_id) + tip_exception("403", "") + end + + ActiveRecord::Base.transaction do + begin + @shixun = Shixun.select(:id, :identifier).find(@myshixun.shixun_id) + @myshixun.destroy + + # 刪除版本庫 + begin + GitService.delete_repository(repo_path: @repo_path) + rescue Exception => e + uid_logger_error("版本库删除异常,详情:#{e.message}") + end + + StudentWork.where(:myshixun_id => @myshixun.id).update_all(:myshixun_id => nil, :work_status => 0) + + rescue Exception => e + uid_logger_error("myshixun reset failed #{e}") + raise ActiveRecord::Rollback + end + end + end + + # 代码运行中的信息接口 + def code_runinng_message + begin + jsonTestDetails = JSON.parse(params[:jsonTestDetails]) + game_id = jsonTestDetails['buildID'] + message = jsonTestDetails['textMsg'] + if game_id.present? && message.present? + game = Game.find game_id + msg = game.run_code_message + # 只有评测中的game才会创建和更新代码评测中的信息 + if game.status == 1 || game.status == 2 + if msg.blank? + RunCodeMessage.create!(:game_id => game_id, :status => 1, :message => message) + else + msg.update_attributes(:status => (msg.status + 1), :message => message) + end + end + render :json => {:data => "success"} + end + rescue Exception => e + render :json => {:data => "failed, exception_message: #{e}"} + end + end + + # 中间层评测接口 + # taskId 即返回的game id + # 返回结果:params [:stauts] 0 表示成功,其它则失败 + # msg 错误信息 + # output 为测试用户编译输出结果 + # myshixun:status 1为完成实训 + # @jenkins: caseId对应test_set的position,passed: 1表示成功,0表示失败 + # resubmit 1:表示已通关后重新评测;0:表示非重新评测 + # retry_status 0:初始值;1:重新评测失败;2:重新评测成功 + # tpiRepoPath 中间层图片的workspace路径 + # params[:jsonTestDetails] = '{"buildID":"19284","compileSuccess":"1", + # "msg":[{"caseId":"1","expectedOutput":"MSAyIDMNCg","input":"MiAzIDE","output":"MSAyIDMNCg","passed":"1"}, + # {"caseId":"2","expectedOutput":"LTMgMSA2DQo","input":"LTMgNiAx","output":"LTMgMSA2DQo","passed":"1"}, + # {"caseId":"3","expectedOutput":"LTcgLTUgLTMNCg","input":"LTcgLTMgLTU","output":"LTcgLTUgLTMNCg","passed":"1"}], + # "outPut":"Y29tcGlsZSBzdWNjZXNzZnVsbHk","resubmit":"","status":"0"}' + # params[:timeCost] = '{"evaluateEnd":"2017-11-24 11:04:37","pull":"0.086", + # "createPod":"1.610","evaluateAllTime":2820,"evaluateStart":"2017-11-24 11:04:35","execute":"0.294"}' + # params[:pics] = "a.png,b.png,c.png" + def training_task_status + logger.info("123################{params[:jsonTestDetails]}") + logger.info("456################{params[:timeCost]}") + logger.info("666###############{params}") + + ActiveRecord::Base.transaction do + begin + t1 = Time.now + jsonTestDetails = JSON.parse(params[:jsonTestDetails]) + timeCost = JSON.parse(params[:timeCost]) + brige_end_time = Time.parse(timeCost['evaluateEnd']) if timeCost['evaluateEnd'].present? + return_back_time = format("%.3f", ( t1.to_f - brige_end_time.to_f)).to_f + status = jsonTestDetails['status'] + game_id = jsonTestDetails['buildID'] + logger.info("training_task_status start#1**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + resubmit = jsonTestDetails['resubmit'] + outPut = tran_base64_decode64(jsonTestDetails['outPut']) + jenkins_testsets = jsonTestDetails['msg'] + compile_success = jsonTestDetails['compileSuccess'] + # message = Base64.decode64(params[:msg]) unless params[:msg].blank? + logger.info(outPut) + game = Game.find(game_id) + myshixun = game.myshixun + challenge = game.challenge + # test_sets = challenge.test_sets + if challenge.picture_path.present? + #pics = params[:files] + pics = params[:tpiRepoPath] + game.update_column(:picture_path, pics) + end + logger.info("training_task_status start#2**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + max_query_index = game.outputs ? (game.outputs.first.try(:query_index).to_i + 1) : 1 + test_set_score = 0 + unless jenkins_testsets.blank? + jenkins_testsets.each_with_index do |j_test_set, i| + logger.info("j_test_set: ############## #{j_test_set}") + actual_output = tran_base64_decode64(j_test_set['output']) + # is_public = test_sets.where(:position => j_test_set['caseId']).first.try(:is_public) + logger.info "actual_output:################################################# #{actual_output}" + Output.create!(:code => status, :game_id => game_id, :out_put => outPut, :test_set_position => j_test_set['caseId'], + :actual_output => actual_output, :result => j_test_set['passed'].to_i, :query_index => max_query_index, + :compile_success => compile_success.to_i) + # 如果设置了按测试集给分,则需要统计测试集的分值 + if challenge.test_set_score && j_test_set['passed'].to_i == 1 + test_set_score += challenge.test_sets.where(:position => j_test_set['caseId']).pluck(:score).first + end + end + end + uid_logger("#############status: #{status}") + uid_logger("#############resubmit: #{resubmit}") + record = EvaluateRecord.where(:game_id => game_id).first + logger.info("training_task_status start#3**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + answer_deduction_percentage = (100 - game.answer_deduction) / 100.to_f # 查看答案后剩余分数的百分比. + # answer_deduction是查看答案的扣分比例 + # status:0表示评测成功 + if status == "0" + if resubmit.present? + game.update_attributes!(:retry_status => 2, :resubmit_identifier => resubmit) + challenge.path.split(";").each do |path| + game_passed_code(path.try(:strip), myshixun, game_id) + end + else + game.update_attributes!(:status => 2, + :end_time => Time.now, + :accuracy => format("%.4f", 1.0 / game.query_index)) + myshixun.update_attributes!(:status => 1) if game.had_done == 1 + challenge.path.split(";").each do |path| + game_passed_code(path.try(:strip), myshixun, game_id) + end + # 如果是已经发布的实训,则需要给出相应的奖励 + if challenge.shixun.try(:status) > 1 + score = (challenge.score * answer_deduction_percentage).to_i + if score > 0 + reward_attrs = { container_id: game.id, container_type: 'Game', score: score } + RewardGradeService.call(game.user, reward_attrs) + RewardExperienceService.call(game.user, reward_attrs) + end + # 需要扣除查看答案的分数 + game.update_attributes!(:final_score => score) + end + + # 更新实训关联的作品分数 TODO: 更新作品分数 + HomeworksService.new.update_myshixun_work_score myshixun + end + # 如果过关了,下一关的状态是3(为开启),则需要把状态改成1(已开启) + # next_game = game.next_game + next_game = game.next_game(myshixun.shixun_id, game.myshixun_id, challenge.position) + next_game.update_column(:status, 0) if next_game.present? && next_game.status == 3 + # status == "-1" 表示返回结果错误 + else + if resubmit.present? + game.update_attributes!(:retry_status => 1, :resubmit_identifier => resubmit) + else + # 评测没通关则,测试集对的个数给分,并且还要扣除用户是否查看答案的值 + test_set_percentage = test_set_score / 100.to_f # 测试集得分比 + score = (challenge.score * test_set_percentage * answer_deduction_percentage).to_i + # 如果分数比上次多,则更新成绩 + game.update_attributes!(:status => 0, :final_score => score) if game.final_score < score + end + end + test_cases_time = format("%.3f", (Time.now.to_f - t1.to_f)).to_f + if record.present? + consume_time = format("%.3f", (Time.now - record.created_at)).to_f + record.update_attributes!(:consume_time => consume_time, :git_pull => timeCost['pull'] , + :create_pod => timeCost['createPod'], :pod_execute => timeCost['execute'], :test_cases => test_cases_time, + :brige => timeCost['evaluateAllTime'], :return_back => return_back_time) + end + uid_logger("training_task_status start#4**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + sucess_status + rescue Exception => e + tip_exception(e.message) + uid_logger_error("training_task_status error: #{e}") + raise ActiveRecord::Rollback + end + end + end + + # 连接webssh + def open_webssh + username = edu_setting('webssh_username') + password = edu_setting('webssh_password') + old_time = Time.now.to_i + begin + shixun_tomcat = edu_setting('tomcat_webssh') + uri = "#{shixun_tomcat}/bridge/webssh/getConnectInfo" + params = {tpiID:@myshixun.id, podType:@myshixun.shixun.try(:webssh), + containers:(Base64.urlsafe_encode64(container_limit @myshixun.shixun.mirror_repositories))} + res = uri_post uri, params + if res && res['code'].to_i != 0 + tip_exception("实训云平台繁忙(繁忙等级:92)") + end + render :json => {:host => res['address'], + :port => res['port'], + :ws_url => res['ws_address'], + :username => username, + :password => password, + :game_id => @myshixun.id, + :webssh_url => "#{shixun_tomcat}/bridge"} + rescue Exception => e + logger.error(e) + render :json => {:error => e.try(:message)} + ensure + use_time = Time.now.to_i - old_time + logger.info "open_webssh tpiID #{@myshixun.id} use time #{use_time}" + end + end + + include GitCommon + + # -----Repository + # TODO: 之类需要一个resubmit参数,但是是关于games. + def update_file + @hide_code = Shixun.where(id: @myshixun.shixun_id).pluck(:hide_code).first + tip_exception("技术平台为空!") if @myshixun.mirror_name.blank? + path = params[:path].strip unless params[:path].blank? + game_id = params[:game_id] + game = Game.find(game_id) + @content_modified = 0 + # params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过 + # 自动保存的时候evaluate为0;点评测的时候为1 + if params[:evaluate] == 1 + record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => @myshixun.shixun_id, :game_id => game_id) + uid_logger("-- game is #{game_id}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + student_work_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f + record.update_attributes!(:student_work => student_work_time) + end + unless @hide_code + # 远程版本库文件内容 + last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] + + content = if @myshixun.mirror_name.select{|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present? + params[:content].gsub(/\t/, ' ') + else + params[:content] + end + if content != last_content + @content_modified = 1 + + author_name = current_user.full_name + author_email = current_user.mail + message = params[:evaluate] == 0 ? "auto commit" : "task commit" + @content = GitService.update_file(repo_path: @repo_path, + file_path: path, + message: message, + content: content, + author_name: author_name, + author_email: author_email) + + uid_logger("-- file update #{@content}") + end + end + + + if game.status == 2 + @resubmit = Time.now.to_i + end + + # 评测时间记录 + if record.present? + consume_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f + record.update_attributes!(:file_update => consume_time) + end + end + + # 渲染实训代码 + # educodercss: 字符串以 ‘,’分隔,存储的是版本库css的路径 + # educoderscript: 字符串以 ‘,’分隔,存储的是版本库js的路径 + # contents: html实训的整体内容 + def html_content + @contents = params[:contents] || "" + edu_css = params[:educodercss] + edu_js = params[:educoderscript] + if @contents.present? + @contents = @contents.gsub("w3equalsign", "=").gsub("w3scrw3ipttag", "script").gsub("edulink", "link").html_safe + end + # css + if edu_css.present? + css_path = edu_css.split(",") + css_path.each do |path| + file_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] + file_content = tran_base64_decode64(file_content) unless file_content.blank? + @contents = @contents.sub(/EDUCODERCSS/, "") + end + end + # js + if edu_js.present? + js_path = edu_js.split(",") + js_path.each do |path| + file_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] + file_content = tran_base64_decode64(file_content) unless file_content.blank? + @contents = @contents.sub(/EDUCODERJS/, "") + end + end + respond_to do |format| + format.json + format.html{render :layout => false} + end + end + + # 最新可以用的并发测试接口 + def sigle_mul_test + codes = %W(1 2 3 4 5 6 7 8 9 A B C D E F G H J K L N M O P Q R S T U V W X Y Z) + begin + identifiers = Myshixun.where(:shixun_id => params[:shixun_id].split(",")).pluck(:identifier) + ide = identifiers[rand(identifiers.length)] + myshixun = Myshixun.where(:identifier => ide).first + + game = myshixun.games.last + logger.warn("###2mul test game_build start ") + identifier = game.try(:identifier) + if game.status == 2 + code = codes.sample(8).join + resubmit = "#{code}_#{myshixun.id}" + end + logger.warn("###3mul test game_build start ...") + EvaluateRecord.create!(:user_id => myshixun.user_id, :shixun_id => myshixun.shixun.id, :game_id => game.id) + redirect_to "/api/games/#{identifier}/game_build?resubmit=#{resubmit}&content_modified=0&first=1" + rescue Exception => e + logger.error("mul test failed ===> #{e.message}") + end + end + + + # -----End + + private + def find_myshixun + @myshixun = Myshixun.find_by!(identifier: params[:identifier]) + end + + def find_repo_name + @repo_path = @myshixun.try(:repo_path) + @path = params[:path] + end +end diff --git a/app/controllers/oauth_controller.rb b/app/controllers/oauth_controller.rb new file mode 100644 index 000000000..ff5908cd0 --- /dev/null +++ b/app/controllers/oauth_controller.rb @@ -0,0 +1,54 @@ +class OauthController < ApplicationController + DEFAULT_PASSWORD = "a12345678" + TOKEN_CALL_BACK = "/oauth/get_token_callback" + USER_INFO = "/oauth/userinfo" + + def get_code + identity_site = edu_setting('openi_domain') + root_url = edu_setting('educoder_domain') + + # 从OpenI发过来的回调中获取授权码 + code = params[:code] + + # 利用授权码从OpenI这里获取access_token + client = get_client(identity_site) + redirect_uri = "#{root_url}#{TOKEN_CALL_BACK}" + access_token_hash = client.auth_code.get_token(code, redirect_uri: redirect_uri).to_hash + + # 利用access_token获取OpenI的用户信息 + access_token = access_token_hash[:access_token] + get_info_url = "#{identity_site}#{USER_INFO}?access_token=#{access_token}" + response = HTTParty.get(get_info_url) + body_json = JSON.parse response.body + + openi_user_id = body_json['token'] + avatar_url = body_json['avatar_url'] + login = body_json['login'] + name = body_json['name'] + email = body_json['email'] + + # 根据获取的用户信息来查询数据库,如已经存在对应的Educoder用户,则直接访问用户要访问的实训页面,否则为其创建用户后再访问实训页面 + openi = Openi.find_by_login(login) + unless openi + ActiveRecord::Base.transaction do + user = User.new(lastname: name, mail: email, mail_notification: email) + user.login = login + user.password = DEFAULT_PASSWORD + user.save! + + UserExtensions.create!(user_id: user.id, school_id: School.first.id, identity: 4, gender: 0) + + UserDayCertification.create!(user_id: user.id, status: 1) + + openi = Openi.create!(user_id: user.id, openi_user_id: openi_user_id, avatar_url: avatar_url, login: login, name: name, email: email) + end + end + + self.logged_user = openi.user + original_url = params[:original_url] + redirect_to original_url + end + + def get_token_callback + end +end diff --git a/app/controllers/poll_questions_controller.rb b/app/controllers/poll_questions_controller.rb new file mode 100644 index 000000000..69aef41c0 --- /dev/null +++ b/app/controllers/poll_questions_controller.rb @@ -0,0 +1,314 @@ +class PollQuestionsController < ApplicationController + before_action :require_login + before_action :get_poll,only:[:new,:create] + before_action :get_poll_question,except: [:new,:create] + before_action :is_course_teacher + before_action :get_poll_questions_count,only:[:create] + before_action :get_poll_question_answers,only:[:edit,:update] + before_action :check_poll_status,only: [:new,:create,:delete_answer,:destroy] + before_action :validates_params,only:[:create,:update] + before_action :validates_update_params,only: [:update] + + + def new + ActiveRecord::Base.transaction do + begin + @poll_question = @poll.poll_questions.new + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + # 创建题目和选择的答案 + def create + ActiveRecord::Base.transaction do + begin + poll_options = { + :question_title => params[:question_title], + :question_type => params[:question_type], + :is_necessary => params[:is_necessary].to_i, + :question_number => @poll_ques_count + 1, + :max_choices => params[:max_choices] || nil, + :min_choices => params[:min_choices] || nil + } + @poll_question = @poll.poll_questions.new(poll_options) + + if params[:insert_id].present? #插入问题时,那么从插入的这个id以后的question_num都将要+1 + insert_poll = @poll.poll_questions.find_by(id: params[:insert_id]) + if insert_poll.present? #如果该问题存在的话,意思是如果是第一题,那么就不存在插入 + ques_num = insert_poll.question_number.to_i + @poll_question.question_number = ques_num + 1 #更新了问题的位置 + @poll.poll_questions.insert_question(ques_num).update_all("question_number = question_number + 1") + end + end + if @poll_question.save + if params[:question_type] != 3 + p_answer = params[:question_answers] + p_other_answer = params[:question_other_answer] + # 新增选择题答案选择的选项 + (1..p_answer.count).each do |i| + answer = p_answer[i-1] # 传入的答案的内容 + question_option = { + :answer_position => i, + :answer_text => answer + } + poll_answers = @poll_question.poll_answers.new question_option + poll_answers.save + end + # 新增答案的其他选项 + if p_other_answer + question_option = { + :answer_position => p_answer.count + 1, + :answer_text => '' + } + poll_answers = @poll_question.poll_answers.new question_option + poll_answers.save + end + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问卷的问题创建失败!") + raise ActiveRecord::Rollback + end + end + end + + def show + ActiveRecord::Base.transaction do + begin + @poll_answers = @poll_question.poll_answers + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + def edit + ActiveRecord::Base.transaction do + begin + @poll_answers = @poll_question.poll_answers + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + def update + ActiveRecord::Base.transaction do + begin + if @poll_question.question_type < 3 #当为单选题或多选题时 + p_answer = params[:question_answers] + p_other_answer = params[:question_other_answer] + p_answer_count = p_answer.count + @poll_question.poll_answers.each do |an| + if (p_answer_count < @poll_current_answers) && (p_answer_count..@poll_current_answers).to_a.include?(an.answer_position) + an.destroy + end + end + (1..p_answer_count).each do |i| + answer = @poll_question.poll_answers.find_answer_by_custom("answer_position",i).first + if answer # 判断该位置的answer是否存在,存在则更新.不存在则跳到下一步 + answer.answer_text = p_answer[i-1] + answer.answer_position = i + answer.save + else + answer_options = { + :answer_position => i, + :answer_text => p_answer[i-1] + } + @poll_question.poll_answers.new answer_options + end + end + if p_other_answer #判断答案的其他选项是否存在 + other_answer = @poll_question.poll_answers.find_answer_by_custom("answer_text","").first + if other_answer.blank? + question_option = { + :answer_position => p_answer_count + 1, + :answer_text => '' + } + @poll_question.poll_answers.new question_option + else + other_answer.answer_position = p_answer_count + 1 + other_answer.save + end + end + end + + @poll_question.update_attributes(poll_questions_params) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("更新失败") + raise ActiveRecord::Rollback + end + end + end + + def delete_answer + ActiveRecord::Base.transaction do + begin + answer_d_id = params[:answer_no].to_i # 答案的当前位置 + poll_answers = @poll_question.poll_answers + delete_answer = poll_answers.find_answer_by_custom("answer_position",answer_d_id).first + left_answer = poll_answers.left_answer_choose("answer_position",answer_d_id) + if left_answer.present? + left_answer.each do |p| + p.answer_position -= 1 + p.save + end + end + if delete_answer.destroy + normal_status(0, "答案删除成功!") + else + normal_status(-1, "答案删除失败!") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("答案删除失败!") + end + end + end + + def destroy + ActiveRecord::Base.transaction do + begin + question_d_id = @poll_question.question_number.to_i #问题的当前位置 + poll_questions = @poll.poll_questions + left_questions = poll_questions.insert_question(question_d_id) + left_questions.update_all("question_number = question_number - 1") if left_questions + @poll_question.destroy! + normal_status("删除成功") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问题删除失败!") + end + end + end + + def up_down + ActiveRecord::Base.transaction do + begin + opr = params[:opr] + current_q_p = @poll_question.question_number.to_i #问题的当前位置 + last_q_p = @poll.poll_questions.last_poll(current_q_p) #当前问题的前一个问题 + next_q_p = @poll.poll_questions.next_poll(current_q_p) # 当前问题的后一个问题 + if @poll.polls_status.to_i == 1 + if opr.present? + if opr.to_s == "up" + if last_q_p.present? + @poll_question.update_attribute(:question_number, (current_q_p - 1)) + last_q_p.update_attribute(:question_number, (@poll_question.question_number.to_i + 1)) # 重新获取当前问题的位置 + normal_status(0, "问题上移成功!") + else + normal_status(-1, "移动失败,已经是第一个问题了!") + end + elsif opr.to_s == "down" + if next_q_p.present? + @poll_question.update_attribute(:question_number, (current_q_p + 1)) + next_q_p.update_attribute(:question_number, (@poll_question.question_number.to_i - 1)) + normal_status(0, "问题下移成功!") + else + normal_status(-1, "移动失败,已经是最后一个问题了!") + end + end + else + normal_status(-1, "移动失败,请输入参数") + end + else + normal_status(-1,"已发布的不能移动问题") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问题移动失败!") + end + end + end + + private + + def poll_questions_params + params.require(:poll_question).permit(:question_title,:question_type,:is_necessary,:question_number,:max_choices,:min_choices) + end + + def validates_params + normal_status(-1, "问题标题不能为空!") if params[:question_title].blank? + normal_status(-1, "是否要求必答的值不能为空!") if params[:is_necessary].blank? + normal_status(-1, "问题类型不能为空!") if params[:question_type].blank? + if params[:min_choices].present? && params[:max_choices].present? && (params[:min_choices].to_i > params[:max_choices].to_i) + normal_status(-1, "最小可选不能大于最大可选!") + elsif params[:question_answers].present? && (params[:max_choices].to_i > params[:question_answers].count) + normal_status(-1, "选择题的最大可选项不能大于答案数!") + elsif [1,3].include?(params[:question_type]) && (params[:max_choices].to_i > 0 || params[:min_choices].to_i > 0) + normal_status(-1, "单选题或主观题不能有最大或最小选择数!") + elsif params[:question_type] == 3 && (params[:question_answers] || params[:question_other_answer]) + normal_status(-1, "主观问题不需要可选答案!") + elsif params[:question_type] != 3 + if params[:question_answers].present? && params[:question_answers].include?("") + normal_status(-1, "选择题不能有空值!") + elsif params[:question_other_answer].present? && params[:question_other_answer].length > 0 + normal_status(-1, "其他选项不能有值!") + elsif params[:question_type] == 1 && params[:question_answers].count < 2 + normal_status(-1, "单选题选项不能小于2!") + elsif params[:question_type] == 2 && params[:question_answers].count < 3 + normal_status(-1, "多选题选项不能小于3!") + end + end + end + + def validates_update_params + question_a_count = params[:question_answers].present? ? params[:question_answers].count : 0 + question_o_count = params[:question_other_answer].present? ? params[:question_other_answer].count : 0 + normal_status(-1, "已发布的问卷不允许增删答案!") if (((question_a_count+question_o_count) != @poll_current_answers) && (@poll.polls_status.to_i != 1)) + end + + def get_poll + @poll = Poll.find_by(id:params[:poll_id]) + if @poll.blank? + tip_exception(404) + end + end + + def get_poll_questions_count + if @poll.poll_questions.count > 0 + @poll_ques_count = @poll.poll_questions.count + else + @poll_ques_count = 0 + end + end + + def get_poll_question + @poll_question = PollQuestion.find_by(id: params[:id]) + if @poll_question.present? + @poll = Poll.find_by(id:@poll_question.poll_id) + else + tip_exception(404) + end + end + + #获取问题的答案数量 + def get_poll_question_answers + @poll_current_answers = @poll_question.poll_answers.count + end + + # 已发布的问卷不能新增题目 + def check_poll_status + normal_status(-1, "问卷已发布,不能更改问卷题目") if @poll.polls_status.to_i != 1 + end + + def is_course_teacher + @course = @poll.course + if @course.blank? + tip_exception(404) + else + @identity = current_user.course_identity(@course) + normal_status(-1, "权限不够") unless(@course.present? && @identity < Course::STUDENT) #课堂存在,且当前用户为教师/管理员 + end + end +end diff --git a/app/controllers/poll_votes_controller.rb b/app/controllers/poll_votes_controller.rb new file mode 100644 index 000000000..eef953d5e --- /dev/null +++ b/app/controllers/poll_votes_controller.rb @@ -0,0 +1,157 @@ +class PollVotesController < ApplicationController + #在开始回答和提交问卷的时候,已经做了判断用户的身份权限 + before_action :require_login + before_action :get_poll_question + before_action :check_answer_in_question,only: [:create] + before_action :check_multi_answers + + + def create #每一次答案的点击,请求一次 + ActiveRecord::Base.transaction do + begin + question_votes = @poll_question.poll_votes + question_type = @poll_question.question_type + question_answer_id = params[:poll_answer_id] ? params[:poll_answer_id] : nil #该答案的id + question_answer_text = params[:vote_text].present? ? params[:vote_text] : nil #其他选项的内容 + user_votes = question_votes.find_current_vote("user_id",current_user.id) #当前用户的答案,可能有多个 + # 当前用户的当前答案,如果已存在,当再次点击的时候,取消答案,即删除该答案 + current_vote_text = nil + + if user_votes.find_vote_text.present? + current_vote_text = user_votes.find_vote_text.first + end + + vote_answer_params = { + :user_id => current_user.id, + :poll_question_id => @poll_question.id, + :poll_answer_id => question_answer_id, + :vote_text => question_answer_text + } + #begin + if question_type == 1 + if user_votes.present? #用户曾经回答过的,答案选择不一样,否则新建 + current_user_answer = user_votes.first + if current_user_answer.poll_answer_id != question_answer_id #如果说更换了答案,则以前的答案删除,并新建记录 + current_user_answer.destroy + PollVote.create(vote_answer_params) + else + if question_answer_text.present? + current_user_answer.update_attribute("vote_text", question_answer_text) + end + end + else + PollVote.create(vote_answer_params) + end + elsif question_type == 2 #多选题的话,答案应该是1个以上 + question_answer_ids = params[:poll_answer_id] ? params[:poll_answer_id] : [] #该答案的id + if question_answer_ids.present? + if question_answer_text.present? #有文字输入,但是不存在其他选项的 + ques_vote_id = question_answer_ids.map(&:to_i).max + if current_vote_text.present? #已有其他输入文字的选项 + current_vote_text.update_attribute("vote_text", question_answer_text) + else + answer_option = { + :user_id => current_user.id, + :poll_question_id => @poll_question.id, + :poll_answer_id => ques_vote_id, + :vote_text => question_answer_text + } + PollVote.create(answer_option) + end + end + + ea_ids = user_votes.pluck(:poll_answer_id) + common_answer_ids = question_answer_ids & ea_ids #已经存在的试卷选项id + new_ids = question_answer_ids - common_answer_ids # 新增的id + old_ids = ea_ids - common_answer_ids #没有选择的,则删掉 + if new_ids.size > 0 + new_ids.each do |e| + answer_option = { + :user_id => current_user.id, + :poll_question_id => @poll_question.id, + :poll_answer_id => e, + :vote_text => nil + } + ex_a = PollVote.new(answer_option) + ex_a.save! + end + end + if old_ids.size > 0 + ea_answer = user_votes.find_current_vote("poll_answer_id",old_ids) + ea_answer.destroy_all + end + else + user_votes.destroy_all + end + else #主观题的输入 + if current_vote_text.present? + if question_answer_text.present? + user_votes.first.update_attribute("vote_text", question_answer_text) + else + user_votes.destroy_all + end + else + PollVote.create(vote_answer_params) + end + end + @current_question_number = @poll_question.question_number + @current_question_necessary = @poll_question.is_necessary + #问答记录存在,且有值,才会有返回值。 + @current_question_status = 0 + if user_votes.present? + vote_answer_id = user_votes.pluck(:poll_answer_id).reject(&:blank?).size + vote_text_count = user_votes.pluck(:vote_text).reject(&:blank?).size + if vote_text_count > 0 || vote_answer_id > 0 + @current_question_status = 1 + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + + private + + def get_poll_question + @poll_question = PollQuestion.find_by_id(params[:poll_question_id]) + if @poll_question.blank? + normal_status(-1,"问卷试题不存在!") + else + @poll = @poll_question.poll + @course = @poll.course + if @poll.blank? + normal_status(-1,"问卷不存在!") + elsif @course.blank? + normal_status(-1,"课堂不存在!") + end + end + + end + + def check_answer_in_question + poll_answer_ids = @poll_question.poll_answers.pluck(:id) + if @poll_question.question_type == 1 #单选题/多选题 + unless (params[:poll_answer_id].present? && poll_answer_ids.include?(params[:poll_answer_id].to_i)) || (params[:poll_answer_id].blank? && params[:vote_text].present?) + normal_status(-1, "答案ID错误!") + end + end + end + + def check_multi_answers + if @poll_question.question_type == 2 + user_vote_count = params[:poll_answer_id].size + if @poll_question.max_choices.present? + question_max_choices = @poll_question.max_choices + else + question_max_choices = 0 + end + if question_max_choices > 0 && user_vote_count > question_max_choices + normal_status(-1,"多选题答案超过最大限制!") + end + end + end +end diff --git a/app/controllers/polls_controller.rb b/app/controllers/polls_controller.rb new file mode 100644 index 000000000..751b725e6 --- /dev/null +++ b/app/controllers/polls_controller.rb @@ -0,0 +1,1300 @@ +class PollsController < ApplicationController + # before_action :check_poll_status 问卷的发消息和定时任务没有做 + before_action :require_login,except: [:index] + before_action :find_course, except: [:show,:poll_setting,:commit_setting,:edit,:update,:start_answer,:commit_poll, + :commit_result,:poll_lists,:cancel_publish,:cancel_publish_modal,:common_header] + before_action :get_poll_and_course, only: [:show,:poll_setting,:commit_setting,:edit,:update,:start_answer, + :commit_poll,:commit_result,:poll_lists,:cancel_publish, + :cancel_publish_modal,:common_header] + before_action :user_course_identity + before_action :is_course_teacher, except: [:index,:start_answer,:poll_setting,:commit_poll,:commit_result,:poll_lists,:common_header] #判断是否为课堂老师 + before_action :check_user_status + before_action :is_course_public, only: [:set_public] + before_action :check_user_on_answer, only: [:show,:start_answer,:commit_poll,:poll_lists] #判断当前用户在问卷的权限/老师是否属于分班的权限 + before_action :validate_params, only: [:create,:update] + before_action :validates_multi_ids, only: [:publish,:end_poll,:destroys,:set_public,:join_poll_banks] + before_action :check_poll_setting_status,only: [:commit_setting] + before_action :get_questions_count ,only: [:start_answer,:show,:commit_result,:edit] + before_action :check_user_id_start_answer,only: [:start_answer] + before_action :check_poll_question_complete,only: [:commit_poll] #问卷提交前来判断问题是否完成 + before_action :check_poll_commit_result,only: [:commit_result] + before_action :get_all_polls_commit, only: [:commit_result] #该问卷全部的用户 + before_action :get_left_banner_id, only:[:common_header,:start_answer,:new,:edit,:index] + include PollsHelper + + def index + ActiveRecord::Base.transaction do + begin + # 按发布时间或创建时间排序 + @polls_all = @course.polls + member_show_polls = @polls_all.publish_or_not # 已发布的或已截止的问卷 + @current_user_ = current_user + @course_status = @course.is_end ? 0 : 1 # 课堂是否结束 + @course_is_public = @course.is_public + @polls_count = @polls_all.count # 全部页面,需返回 + @polls_unpublish_counts = @polls_all.poll_by_status(1).count #未发布的问卷数 + @polls_published_counts = @polls_all.poll_by_status([2, 3]).count # 已发布的问卷数 + + # 课堂的学生人数 + @course_all_members = @course.students #当前课堂的全部学生 + @course_all_members_count = @course_all_members.count #当前课堂的学生数 + @current_student = @course_all_members.find_by(user_id: current_user.id) #当前用户是否为课堂的学生 + + # polls的不同用户群体的显示 + if @user_course_identity < Course::STUDENT # @is_teacher_or 1为老师/管理员/助教 + @is_teacher_or = 1 + @teacher_groups_ids = @course.teacher_course_groups.get_user_groups(current_user.id).pluck(:course_group_id).reject(&:blank?) + @polls = @polls_all #老师能看到全部的问卷,不管是已发布的/未发布的/已截止的/统一设置的/私有设置的(看到内容不同) + elsif @user_course_identity == Course::STUDENT # 2为课堂成员,能看到统一设置的和自己班级的 + @is_teacher_or = 2 + member_group_id = @current_student.try(:course_group_id).to_i # 成员的分班id,默认为0 + if member_group_id == 0 #表示是课堂的未分班成员,只能查看统一设置的试卷(已发布的/已截止的) + @polls = member_show_polls.size > 0 ? member_show_polls.public_or_unset : [] + else #已分班级的成员,可以查看统一设置和单独设置(试卷是发布在该班级)试卷 + # 已发布 当前用户班级分组的 试卷id + poll_settings_ids = @course.poll_group_settings.where(course_group_id: member_group_id).poll_group_published.pluck(:poll_id).uniq # 选择成员的班级id等于课堂问卷设置的班级id + @polls = member_show_polls.present? ? member_show_polls.public_or_unset.or(member_show_polls.where(id: poll_settings_ids)) : [] + end + else #用户未登陆或不是该课堂成员,仅显示统一设置的(已发布的/已截止的),如有公开,则不显示锁,不公开,则显示锁 + @is_teacher_or = 0 + @polls = member_show_polls.size > 0 ? member_show_polls.public_or_unset : [] + end + if @polls.count > 0 + if params[:type].present? + choose_type = params[:type] + member_group_id = @current_student.try(:course_group_id).to_i # 成员的分班id,默认为0 + if @is_teacher_or == 2 && member_group_id > 0 + poll_groups_sets = @course.poll_group_settings.where(course_group_id: member_group_id).poll_group_published + poll_settings_ids = poll_groups_sets.pluck(:poll_id) + poll_ended_ids = poll_groups_sets.poll_group_ended.pluck(:poll_id).uniq + # poll_settings_ids = @course.poll_group_settings.where(course_group_id: member_group_id).poll_group_ended.pluck(:poll_id).uniq + if choose_type.to_i == 2 + @polls = @polls_all.present? ? @polls_all.poll_by_status(2).public_or_unset.or(@polls_all.where(id:(poll_settings_ids - poll_ended_ids).uniq)).distinct : [] + elsif choose_type.to_i == 3 + @polls = @polls_all.present? ? @polls_all.poll_by_status(3).public_or_unset.or(@polls_all.where(id: poll_ended_ids)).distinct : [] + end + else + @polls = @polls.poll_by_status(choose_type) + end + end + + if params[:search].present? + search_type = params[:search].to_s.strip + @polls = @polls.poll_search(search_type) + end + + # 分页 + @polls_select_count = @polls.size + @polls = @polls.order( "IF(ISNULL(publish_time),0,1), publish_time DESC,created_at DESC") + @page = params[:page] || 1 + @limit = params[:limit] || 15 + + @polls = @polls.page(@page).per(@limit) + @polls = @polls.includes(:poll_users,:poll_questions,:poll_group_settings) + + else + @polls = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def new + ActiveRecord::Base.transaction do + begin + @poll = Poll.new + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问卷创建失败!") + raise ActiveRecord::Rollback + end + end + end + + # polls_status 问卷状态,1为创建成功,但未发布;2为已发布;3表示已截止 + # show_result true则在截止时间之后对课堂成员公开答题统计,0则不公开,默认为true + # is_public true 为公开/ false为私有,默认为false + # exercise_bank_id 试卷的id + # unified_setting true 统一设置 / false为分班设置,默认为true + # un_anonymous 是否实名,默认为false,即不公开 + def create + ActiveRecord::Base.transaction do + begin + poll_name = params[:polls_name] + poll_desc = params[:polls_description] + poll_options = { + :polls_name => poll_name, + :polls_description => poll_desc, + :user_id => current_user.id, + :course_id => @course.id, + :polls_status => 1, + :polls_type => "Course", + } + @poll = Poll.create(poll_options) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问卷创建失败!") + raise ActiveRecord::Rollback + end + end + end + + def edit + ActiveRecord::Base.transaction do + begin + @poll_questions = @poll.poll_questions.order("question_number ASC") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面请求失败!") + raise ActiveRecord::Rollback + end + end + end + + def update + ActiveRecord::Base.transaction do + begin + poll_name = params[:polls_name] + poll_des = params[:polls_description] + poll_params = { + :polls_name => poll_name, + :polls_description => poll_des + } + @poll.update_attributes(poll_params) + normal_status(0,"问卷更新成功!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + #show页面应该是老师的题型预览页面及问题/答案的编辑,老师页面的 + def show + ActiveRecord::Base.transaction do + begin + if @user_course_identity < Course::STUDENT + @is_teacher_or = 1 + else + @is_teacher_or = 0 + end + @poll_questions = @poll.poll_questions.order("question_number ASC") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + def common_header + ActiveRecord::Base.transaction do + begin + if @user_course_identity > Course::ASSISTANT_PROFESSOR + @is_teacher_or = 0 + @user_poll_answer = @poll.check_user_votes_status(current_user) + else + @is_teacher_or = 1 + @user_poll_answer = 3 #教师页面 + end + poll_status = @poll.get_poll_status(current_user.id) + poll_id_array = [@poll.id] + @poll_publish_count = get_user_permission_course(poll_id_array,2).count #是否存在已发布的 + @poll_unpublish_count = get_user_permission_course(poll_id_array,1).count #是否存在未发布的 + + if (@poll_publish_count == 0) && (@poll_unpublish_count == 0) #即表示没有分班 + if poll_status == 1 + @poll_unpublish_count = 1 #试卷未发布,且课堂没有分班的时候 + elsif poll_status == 2 + @poll_publish_count = 1 #试卷未发布,且课堂没有分班的时候 + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + #立即发布的弹窗内容 + def publish_modal + ActiveRecord::Base.transaction do + begin + poll_ids = params[:check_ids] + if poll_ids.count > 0 + @course_groups = get_user_permission_course(poll_ids,1) + else + @course_groups = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + #首页批量或单独 立即发布,应是跳出弹窗,设置开始时间和截止时间。 + def publish + ActiveRecord::Base.transaction do + begin + check_ids = Poll.where(id: params[:check_ids]) + ex_end_time = params[:end_time] || Time.at(((1.month.since.to_i)/3600.0).ceil * 3600) + check_ids.each do |poll| + if poll.unified_setting + pl_status = poll.polls_status #则为试卷的状态 + else + pl_status = poll.poll_group_settings.find_in_poll_group("course_group_id",params[:group_ids]).poll_group_not_published.present? ? 1 : 0 #立即发布针对分组设置的全部未发布的班级才生效 + end + if pl_status == 1 #如果问卷存在已发布的,或者是已截止的,那么则直接跳过 + g_course = params[:group_ids] #表示是否传入分班参数,如果传入分班的参数,那么poll的统一设置需修改 + if g_course + course_groups = @course.teacher_course_groups.get_user_groups(current_user.id) + if course_groups.blank? + user_course_groups = @course.course_groups.present? ? @course.course_groups.pluck(:id) : [] + else + user_course_groups = course_groups.pluck(:course_group_id) + end + if g_course.map(&:to_i).sort == user_course_groups.sort # 如果是设置为全部班级,则问卷不用分组,且问卷设定为统一设置,否则则分组设置 + poll.poll_group_settings.destroy_all + poll_unified = true + notify_student_ids = @course.students.pluck(:user_id) + else + poll_unified = false + g_course.each do |i| + poll_group_setting = poll.poll_group_settings.find_in_poll_group("course_group_id",i).first #根据课堂分班的id,寻找问卷所在的班级 + if poll_group_setting #如果该问卷分组存在,则更新,否则新建 + poll_group_setting.update_attributes(publish_time:Time.now,end_time:ex_end_time) + else + p_course_group = { + :poll_id => poll.id, + :course_group_id => i, + :course_id => poll.course.id, + :publish_time => Time.now, + :end_time => ex_end_time, + } + new_poll_group = poll.poll_group_settings.new p_course_group + new_poll_group.save + end + end + + notify_student_ids = @course.students.where(course_group_id: params[:group_ids]).pluck(:user_id) + end + else + poll.poll_group_settings.destroy_all + poll_unified = true + notify_student_ids = @course.students.pluck(:user_id) + end + if poll.end_time.blank? + e_time = ex_end_time + elsif poll.poll_group_settings.end_time_present.count > 0 # 该问卷分组有结束时间为空的 + e_time = poll.poll_group_settings.end_time_present.map(&:end_time).max + else + e_time = poll.end_time + end + poll_status = set_poll_status(Time.now,e_time) + + poll_params = { + :publish_time => Time.now, + :end_time => e_time, + :polls_status => poll_status, + :unified_setting => poll_unified + } + poll.update_attributes(poll_params) + if poll.course_acts.size == 0 + poll.course_acts << CourseActivity.new(:user_id => poll.user_id,:course_id => poll.course_id) + end + PollPublishNotifyJob.perform_later(poll.id, notify_student_ids) + end + end + normal_status(0, "问卷发布成功!") + + ## 需添加发送消息的接口,稍后添加 + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问卷发布失败") + raise ActiveRecord::Rollback + end + end + end + + #立即截止的弹窗内容 + def end_poll_modal + ActiveRecord::Base.transaction do + begin + poll_ids = params[:check_ids] + if poll_ids.count > 0 + @course_groups = get_user_permission_course(poll_ids,3) + else + @course_groups = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + # 首页批量或单独 立即截止,截止时间为当前时间 + def end_poll + ActiveRecord::Base.transaction do + begin + check_ids = Poll.where(id: params[:check_ids]) + check_ids.each do |poll| + poll_status = poll.get_poll_status(current_user.id) + if poll_status == 2 #跳过已截止的或未发布的 + g_course = params[:group_ids] #表示是否传入分班参数,如果传入分班的参数,那么poll的统一设置需修改,poll_group_settings + if g_course + # 如果问卷之前是统一设置且分班参数与课堂的分班数不一致,则变为非统一设置,同时创建poll_group_settings + if poll.unified_setting && g_course.length != @course.course_groups_count + poll.poll_group_settings.destroy_all + @course.course_groups.each do |group| + poll.poll_group_settings << PollGroupSetting.new(poll_id: poll.id, course_group_id: group.id, course_id: @course.id, + publish_time: poll.publish_time, end_time: poll.end_time) + end + else + poll_unified = poll.unified_setting #这个作为初始化的值是否要好点呢?-hs + end + poll_users = poll_unified ? poll.poll_users : + poll.poll_users.joins("join course_members on poll_users.user_id = course_members.user_id").where(course_members: {course_group_id: g_course, role: 4}) + poll_group_setting = poll.poll_group_settings + old_poll_groups = poll_group_setting.find_in_poll_group("course_group_id",g_course) #问卷分组的截止时间更改 + old_poll_groups.update_all(:end_time => Time.now) + new_end_time = poll_group_setting.end_time_present.map(&:end_time) # 问卷结束时间不为空的 + new_end_time_s = new_end_time.size > 0 ? new_end_time.max : Time.now + new_poll_status = set_poll_status(poll.publish_time,new_end_time_s) + poll.update_attributes(:end_time => new_end_time_s,:polls_status => new_poll_status,:unified_setting => poll_unified) + elsif poll.unified_setting + poll_users = poll.poll_users + poll.update_attributes(:polls_status => 3, :end_time => Time.now) + end + poll_users = poll_users.where("commit_status = 0 and start_at is not null") + poll_users.update_all(:commit_status => 1, :end_at => Time.now) + end + end + normal_status(0, "问卷截止成功!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("立即截止失败!") + raise ActiveRecord::Rollback + end + end + end + + #撤销发布的弹窗内容 + def cancel_publish_modal + ActiveRecord::Base.transaction do + begin + poll_ids = [@poll.id] + if poll_ids.count > 0 + @course_groups = get_user_permission_course(poll_ids,2) + else + @course_groups = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("没有权限") + raise ActiveRecord::Rollback + end + end + end + + # 撤销发布,仅指当前的问卷 + def cancel_publish + ActiveRecord::Base.transaction do + begin + g_course = params[:group_ids] + if !@poll.unified_setting #如果问卷为分班设置,且传入的班级id存在 + if g_course.present? + course_group_ids = @course.course_members.course_find_by_ids("course_group_id",g_course).pluck(:user_id).uniq #传入班级的全部学生人数 + all_poll_settings = @poll.poll_group_settings.find_in_poll_group("course_group_id",g_course) #根据传入的班级id来获取问卷的分组设置 + all_poll_settings.destroy_all #问卷的设置文件全部删除 + # @poll.poll_users.find_by_group_ids(course_group_ids).destroy_all #问卷的提交信息 + poll_question_ids = @poll.poll_questions.pluck(:id) #问卷的全部问卷 + PollVote.find_current_vote("user_id",course_group_ids).find_current_vote("poll_question_id",poll_question_ids).destroy_all + poll_user_options = { + :commit_status => 0, + :start_at => nil, + :end_at => nil + } + @poll.poll_users.find_by_group_ids(course_group_ids).update_all(poll_user_options) #试卷的用户全部更新为未答题状态 + poll_groups = @poll.poll_group_settings + if poll_groups.present? #是否还有问卷的发布分组,如果有的话,则是根据发布规则取最大和最小值 + unified_setting = false + e_time_present = poll_groups.end_time_present.map(&:end_time) + p_time_present = poll_groups.publish_time_present.map(&:publish_time) + e_time = e_time_present.size > 0 ? e_time_present.max : nil + p_time = p_time_present.size > 0 ? p_time_present.min : nil + poll_status = 1 + if p_time.nil? #发布时间为空,则表示问卷未发布 + poll_status = 1 + elsif p_time.present? && e_time.present? + poll_status = set_poll_status(p_time,e_time) + end + else + unified_setting = true + p_time = nil + e_time = nil + poll_status = 1 + end + poll_options = { + :unified_setting => unified_setting, + :polls_status => poll_status, + :publish_time => p_time, + :end_time => e_time + } + @poll.update_attributes(poll_options) + normal_status(0,"分班问卷撤销发布成功!") + else + normal_status(-1,"请选择撤销发布班级!") + end + else + poll_user_options = { + :commit_status => 0, + :start_at => nil, + :end_at => nil + } + @poll.poll_users.update_all(poll_user_options) + poll_question_ids = @poll.poll_questions.pluck(:id) + PollVote.find_current_vote("poll_question_id",poll_question_ids).destroy_all + poll_new_params = { + :polls_status => 1, + :publish_time => nil, + :end_time => nil, + :unified_setting => true + } + @poll.update_attributes(poll_new_params) + @poll.poll_group_settings.destroy_all + normal_status(0,"问卷撤销发布成功!") + + ## @poll.tidings.destroy_all 用户的发送消息全部删除,因接口未定,所以先注释 + + ## 需添加发送消息的接口,稍后添加 + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问卷撤销发布失败!") + raise ActiveRecord::Rollback + end + end + end + + # 首页批量或单独删除 + def destroys + ActiveRecord::Base.transaction do + begin + check_ids = Poll.where(id:params[:check_ids]) + check_ids.each do |poll| + if poll.present? + poll.destroy + end + end + normal_status(0, "问卷已删除成功!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问卷删除失败!") + raise ActiveRecord::Rollback + end + end + end + + # 设为公开 + def set_public + ActiveRecord::Base.transaction do + begin + check_ids = Poll.where(id:params[:check_ids]) + check_ids.each do |poll| + poll.update_attribute('is_public', true) + end + normal_status(0, "问卷已设为公开!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("问卷设为公开失败!") + raise ActiveRecord::Rollback + end + end + end + + ## 加入题库 + def join_poll_banks + ActiveRecord::Base.transaction do + begin + check_ids = Poll.where(id: params[:check_ids]) + check_ids.each do |poll| + current_ex_bank = current_user.exercise_banks.find_by_container(poll.id,"Poll").first + if current_ex_bank.present? #当前用户的选择问卷是否已加入习题库,存在则更新习题库和问题库,否则新建习题库和问题库 + ex_params = { + :name => poll.polls_name, + :description => poll.polls_description, + :course_list_id => poll.course.try(:course_list_id) + } + current_ex_bank.update_attributes(ex_params) + question_bank = QuestionBank.ques_by_container(current_ex_bank.id,current_ex_bank.container_type) #该习题库是否存在于问题库里 + ques_params = { + :name => current_ex_bank.name, + :course_list_id => current_ex_bank.course_list_id + } + question_bank.first.update_attributes(ques_params) if question_bank.present? + current_ex_bank.exercise_bank_questions.destroy_all # 更新后,习题库的问题全部删除,后续重新再建 + else + ex_params = { + :name => poll.polls_name, + :description => poll.polls_description, + :user_id => current_user.id, + :is_public => 0, + :course_list_id => poll.course.try(:course_list_id), + :container_id => poll.id, + :container_type => "Poll", + :quotes => 1 + } + current_ex_bank= ExerciseBank.new ex_params + if current_ex_bank.save #如果习题库保存成功,则会创建问题库question_bank + ques_params = { + :name => current_ex_bank.name, + :container_id => current_ex_bank.id, + :container_type => current_ex_bank.container_type, + :quotes => current_ex_bank.quotes, + :user_id => current_ex_bank.user_id, + :is_public => current_ex_bank.is_public, + :course_list_id => current_ex_bank.course_list_id + } + question_bank = QuestionBank.new ques_params + question_bank.save + end + end + # 问卷的问题的输入 + poll.poll_questions.each do |f| + option = { + :question_title => f.question_title, + :question_type => f.question_type, + :is_necessary => f.is_necessary, + :question_number => f.question_number, + :max_choices => f.max_choices, + :min_choices => f.min_choices + } + exercise_bank_question = current_ex_bank.exercise_bank_questions.new option + exercise_bank_question.save + ## 问卷答案的输入 + f.poll_answers.each do |a| + choice_option = { + :choice_position => a.answer_position, + :choice_text => a.answer_text + } + exercise_bank_c = exercise_bank_question.exercise_bank_choices.new choice_option + exercise_bank_c.save + end + end + end + normal_status(0, "题库更新成功!") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("题库更新失败!") + raise ActiveRecord::Rollback + end + end + end + + # 我的问卷题库 + def my_polls + ActiveRecord::Base.transaction do + begin + ## 我的问卷题库 + @current_user_exercises = current_user.exercise_banks.find_by_c_type("Poll") + if @current_user_exercises.present? + + if params[:search].present? + search_type = params[:search].to_s.strip + @current_user_exercises = @current_user_exercises.exercise_bank_search(search_type) + end + page = params[:page] || 1 + limit = params[:limit] || 15 + @my_exercises_count = @current_user_exercises.size + @current_user_exercises = @current_user_exercises.page(page).per(limit) + else + @current_user_exercises = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("题库调用失败!") + raise ActiveRecord::Rollback + end + end + end + + # 公共的问卷题库 + def public_polls + ActiveRecord::Base.transaction do + begin + if current_user.is_certification_teacher + @user_certification = 1 #用户已通过认证 + @public_exercises = ExerciseBank.find_by_c_type("Poll").public_exercises + if @public_exercises.present? + + if params[:search].present? + search_type = params[:search].to_s.strip + @public_exercises = @public_exercises.exercise_bank_search(search_type) + end + + page = params[:page] || 1 + limit = params[:limit] || 15 + + @public_exercises_count = @public_exercises.size + @public_exercises = @public_exercises.page(page).per(limit) + else + @public_exercises_count = 0 + @public_exercises = [] + end + else + @user_certification = 0 #用户未通过认证 + @public_exercises_count = 0 + @public_exercises = [] + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("题库调用失败!") + raise ActiveRecord::Rollback + end + end + end + + # 设置页面,先返回问卷的状态 + def poll_setting + ActiveRecord::Base.transaction do + begin + @user_permission = 2 + @user_course_groups = @course.teacher_group(current_user.id) #当前老师的分班 + @being_setting_course_ids = @poll.poll_published_ids(current_user.id) #当前用户已发布的班级的id + @user_published_setting = @poll.poll_group_settings.find_in_poll_group("course_group_id",@being_setting_course_ids) + poll_ids = [@poll.id] + @poll_publish_count = get_user_permission_course(poll_ids,2).count + ## 需添加发送消息的接口,稍后添加 + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + #问卷设置提交 + def commit_setting + ActiveRecord::Base.transaction do + begin + error_count = 0 # 判断循环里是否有已发布/已截止的,且时间更改了的分班。 + + course_group_ids = @course.teacher_course_group_ids(current_user.id) #当前老师的班级id数组 + + poll_status = @poll.get_poll_status(current_user.id) + if poll_status == 1 && (course_group_ids - [0]).count > 0 # 问卷未发布,且老师的分班大于1 ,才可以修改统一设置,否则按poll默认的来处理 + unified_setting = params[:unified_setting] + else + unified_setting = @poll.unified_setting + end + show_result = params[:show_result] ? 1 : 0 + un_anonymous = params[:un_anonymous] ? true : false + # 统一设置或者分班为0,则更新问卷,并删除问卷分组 + if unified_setting || (course_group_ids.size == 0) + params_publish_time = params[:publish_time].present? ? params[:publish_time].to_time : nil + params_end_time = nil + if params[:end_time].blank? + if params_publish_time.present? + params_end_time = params_publish_time + 30.days + end + else + params_end_time = params[:end_time].to_time + end + # params_end_time = params[:end_time].present? ? params[:end_time].to_time : nil + if poll_status == 2 && @poll.publish_time != params_publish_time + normal_status(-1,"不允许修改发布时间") + elsif poll_status == 3 && (@poll.end_time != params_end_time || @poll.publish_time != params_publish_time) + normal_status(-1,"不允许修改发布时间") + elsif params_publish_time.present? && params_end_time.present? && params_end_time < params_publish_time + normal_status(-1,"截止时间不能小于发布时间") + else + #发布时间小于当前时间,则poll显示为未发布,当截止时间大于当前时间,则显示为已截止 + poll_status_n = set_poll_status(params_publish_time,params_end_time) + poll_params = { + :unified_setting => unified_setting, + :show_result => show_result, + :un_anonymous => un_anonymous, + :polls_status => poll_status_n, + :publish_time => params_publish_time, + :end_time => params_end_time + } + @poll.update_attributes(poll_params) + @poll.poll_group_settings.destroy_all + normal_status(0, "问卷设置成功!") + end + else + params_times = params[:publish_time_groups] #分班返回的json数组{"publish_time_groups":[{"course_group_id":["1","2"],"publish_time":"xx","end_time":"xxx"}]} + poll_groups = @poll.poll_group_settings.find_in_poll_group("course_id",@course.id) #当前课堂问卷的班级全部分班信息 + poll_groups_ids = poll_groups.pluck(:course_group_id) #问卷的全部分班id + total_common = params_times.map{|k| k[:course_group_id]}.sum #传入的所有分组的分班id + total_common_group = poll_groups_ids & total_common #传入的分班与问卷已存在的分班的交集 + old_poll_groups = poll_groups_ids - total_common_group #后来传入的分班里,没有了的班级,即需要删除 + params_times.each do |t| + course_id = t[:course_group_id] #为数组,可能会设置分班为各个班级id的数组 + poll_publish_time = t[:publish_time].present? ? t[:publish_time].to_time : nil + # poll_end_time = t[:end_time].present? ? t[:end_time].to_time : nil + poll_end_time = nil + if t[:end_time].blank? + if poll_publish_time.present? + poll_end_time = poll_publish_time + 30.days + end + else + poll_end_time = t[:end_time].to_time + end + poll_group = poll_groups.find_in_poll_group("course_group_id",course_id) #判断该分班是否存在 + if poll_group.present? && poll_group.first.end_time <= Time.now && (poll_end_time != poll_group.first.end_time || poll_publish_time != poll_group.first.publish_time) #已截止且时间改变的,则提示错误 + error_count += 1 + end + if poll_group.present? && poll_group.first.publish_time < Time.now && poll_publish_time != poll_group.first.publish_time + error_count += 1 + end + if error_count == 0 + common_group = poll_groups_ids & course_id #传入的班级与问卷已存在的班级的交集,即表示已有分班的 + new_group_ids = course_id - common_group #新传入的班级id + if common_group.size > 0 #传入的参数存在已发布的分班 + poll_group_params = { + :publish_time => poll_publish_time, + :end_time => poll_end_time + } + poll_group = poll_groups.find_in_poll_group("course_group_id",common_group) + the_group_setting = poll_group.first + if the_group_setting.present? + the_group_setting_status = set_poll_status(the_group_setting.publish_time,the_group_setting.end_time) + if the_group_setting_status == 2 + poll_group_params = { + :publish_time => the_group_setting.publish_time, + :end_time => poll_end_time + } + elsif the_group_setting_status == 3 + poll_group_params = { + :publish_time => the_group_setting.publish_time, + :end_time => the_group_setting.end_time + } + end + end + poll_group.update_all(poll_group_params) + end + if new_group_ids.size > 0 + new_group_ids.each do |c| + poll_group_params = { + :poll_id => @poll.id, + :course_group_id => c, + :course_id => @course.id, + :publish_time => poll_publish_time, + :end_time => poll_end_time + } + new_poll_group = PollGroupSetting.new(poll_group_params) + new_poll_group.save + end + end + end + end + + if error_count > 0 + error_count == 0 + normal_status(-1,"已发布/已截止的问卷不允许修改时间") + else + if old_poll_groups.size > 0 + old_all_poll_groups = poll_groups.find_in_poll_group("course_group_id",old_poll_groups) + old_all_poll_groups.destroy_all + end + #问卷更新为poll_group_setting的发布时间最小,截止时间最大 + e_time_present = poll_groups.end_time_present.map(&:end_time) + p_time_present = poll_groups.publish_time_present.map(&:publish_time) + e_time = e_time_present.size > 0 ? e_time_present.max : nil + p_time = p_time_present.size > 0 ? p_time_present.min : nil + poll_status = 1 + if p_time.nil? #发布时间为空,则表示问卷未发布 + poll_status = 1 + elsif p_time.present? && e_time.present? + poll_status = set_poll_status(p_time,e_time) + end + + poll_params = { + :unified_setting => unified_setting, + :show_result => show_result, + :un_anonymous => un_anonymous, + :polls_status => poll_status, + :publish_time => p_time, + :end_time => e_time + } + @poll.update_attributes(poll_params) + if @poll.polls_status == 2 + if @poll.course_acts.size == 0 + @poll.course_acts << CourseActivity.new(:user_id => @poll.user_id,:course_id => @poll.course_id) + end + end + normal_status(0, "问卷设置成功!") + end + + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("提交出现错误!") + raise ActiveRecord::Rollback + end + end + end + + # 开始答题,如答案提交后则不可再修改, 问卷截止后或提交后,该页面不可再次点击 + def start_answer + ActiveRecord::Base.transaction do + begin + poll_user_current = @poll.poll_users.find_by_group_ids(@poll_current_user_id).first #查找当前用户是否有过答题 + @poll_status = @poll.get_poll_status(current_user.id) + if poll_user_current.blank? + if @user_course_identity > Course::ASSISTANT_PROFESSOR #当为老师的时候,不创建poll_user表,理论上老师是不能进入答题的 + poll_user_params = { + :user_id => @poll_current_user_id, + :poll_id => @poll.id, + :start_at => Time.now, + :commit_status => 0 + } + PollUser.create(poll_user_params) + end + elsif poll_user_current.start_at.nil? + poll_user_current.update_attributes(:start_at => Time.now) + end + + if @user_course_identity < Course::STUDENT || (@poll_status == 3) || (poll_user_current.present? && poll_user_current.commit_status == 1) + @user_poll_status = 1 #当前用户为老师/问卷已截止/问卷已提交不可编辑 + else + @user_poll_status = 0 #可编辑 + end + + # @answer_user = User.find_by(id:@poll_current_user_id) + @answer_status = [] + question_answered = 0 + + # 判断是否已经回答还是新建的回答 + @poll_questions.each do |q| + ques_vote = q.poll_votes.find_current_vote("user_id",@poll_current_user_id) + if ques_vote.present? + ques_status = 1 + question_answered += 1 + else + ques_status = 0 + end + answer_status = { + :ques_id => q.id, + :ques_number => q.question_number, + :ques_status => ques_status + } + @answer_status = @answer_status.push(answer_status) + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + # 用户提交问卷 + def commit_poll + ActiveRecord::Base.transaction do + begin + poll_user_current = @poll.poll_users.find_by_group_ids(current_user.id).first + poll_user_params = { + :commit_status => 1, + :end_at => Time.now + } + poll_user_current.update_attributes(poll_user_params) + normal_status(0, "问卷提交成功!") + ## 需添加发送消息的接口,稍后添加 + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + #问卷的统计结果 + def commit_result + ActiveRecord::Base.transaction do + begin + # 分页 + @page = params[:page] || 1 + @limit = params[:limit] || 10 + @poll_export_questions = @poll_questions.order("question_number ASC") + @poll_questions = @poll_questions.page(@page).per(@limit) + respond_to do |format| + format.json + format.xlsx{ + if @user_course_identity > Course::ASSISTANT_PROFESSOR + tip_exception(403,"无权限操作") + else + polls_export_name = current_user.real_name + "_" + @course.name + "_" + @poll.polls_name + "_" + Time.now.strftime('%Y%m%d_%H%M%S') + render xlsx: "#{polls_export_name.strip.first(30)}",template: "polls/commit_result.xlsx.axlsx",locals: {poll_questions:@poll_export_questions} + end + } + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + #问卷的答题列表 + def poll_lists + ActiveRecord::Base.transaction do + begin + logger.info("########___________@course.teacher_course_groups)________________####################{@course.teacher_course_groups.where(user_id:current_user.id).pluck(:course_group_id)}") + poll_ids = [@poll.id] + @poll_list_status = @poll.get_poll_status(current_user.id) + @poll_publish_count = get_user_permission_course(poll_ids,2).count + @poll_unpublish_count = get_user_permission_course(poll_ids,1).count + @course_all_members = @course.students + if @user_course_identity < Course::STUDENT #当前为老师,而且老师只能查看自己班级的/课堂的问卷 + @poll_current_user_status = 0 + @poll_users_list = @poll.all_poll_users(current_user.id).distinct #该老师分班的全部学生 + get_poll_answers(@poll_users_list) + + if @poll_list_status == 1 + @poll_course_groups =[] + else + poll_common_ids = @poll.poll_published_ids(current_user.id) + @poll_course_groups = @course.get_ex_published_course(poll_common_ids) + end + if @poll_list_status == 1 + @poll_users_list = [] + end + elsif @user_course_identity > Course::ASSISTANT_PROFESSOR + @poll_all_users = @poll.get_poll_exercise_users + get_poll_answers(@poll_all_users) # 未答和已答的 + @poll_course_groups = [] #当为学生的时候,不显示分班情况 + @poll_current_user_status = 1 #当前用户的状态,为学生 + poll_current_user = @poll_all_users.find_by_group_ids(current_user.id) #当前用户是否开始做问卷(提交/未提交/没做) + if poll_current_user.present? && @poll_list_status != 1 #当前为学生或者有过答题的(提交/未提交),且问卷已发布的 + @poll_users_list = poll_current_user.distinct + else + @poll_users_list = [] + end + else + @poll_all_users = @poll.get_poll_exercise_users + get_poll_answers(@poll_all_users) # 未答和已答的 + @poll_current_user_status = 2 #当前用户非课堂成员 + @poll_users_list = [] + end + + if @poll_users_list.present? && @poll_users_list.count > 0 + @poll_users_count = @poll_users_list.count #当前显示的全部成员数量 + else + @poll_users_count = 0 + end + + if @poll_unanswers < 0 + @poll_unanswers = 0 + end + + #筛选/分类,排序 + order = params[:order] + # b_sort = params[:sort] || "desc" + choose_type = params[:commit_status] + group_id = params[:poll_group_id] + search_content = params[:search] + + if @poll_users_list.present? && @poll_users_list.count > 0 + + if order == "student_id" + @poll_users_list = @poll_users_list.joins(user: [:user_extension]).order("user_extensions.student_id DESC") + else + @poll_users_list = @poll_users_list.order("end_at DESC") + end + + #答题状态的选择 + if choose_type.present? + @poll_users_list = @poll_users_list.commit_by_status(choose_type) + end + + #班级的选择 + if group_id.present? + poll_students = @course_all_members.course_find_by_ids("course_group_id",group_id) # 问卷所分班的全部人数 + user_ids = poll_students.pluck(:user_id).reject(&:blank?) + @poll_users_list = @poll_users_list.find_by_group_ids(user_ids) + end + + #搜索 + if search_content.present? + #搜索用户的nickname,如果存在则返回,否则继续查询用户的真实姓名或学生号 + nick_name_search = @poll_users_list.where(user_id: User.where('CONCAT(users.lastname, users.firstname) like ?',"%#{search_content}%")) + if nick_name_search.present? + @poll_users_list = nick_name_search + else + @poll_users_list = @poll_users_list.joins(user: [:user_extension]).where('user_extensions.student_id like ? OR user_extensions.student_realname like ?',"%#{search_content}%","%#{search_content}%") + end + end + + @poll_users_size = @poll_users_list.count + # 分页 + @page = params[:page] || 1 + @limit = params[:limit] || 20 + @poll_users_list = @poll_users_list.page(@page).per(@limit) + else + @poll_users_list = [] + @poll_users_size = 0 + end + + @current_user = current_user + rescue Exception => e + uid_logger_error(e.message) + tip_exception("页面调用失败!") + raise ActiveRecord::Rollback + end + end + end + + private + + def is_course_teacher + unless @user_course_identity < Course::STUDENT #为老师/助教/管理员 + tip_exception("403", "") + end + + end + + def validate_params + normal_status(-1, "问卷标题不能为空!") if params[:polls_name].blank? + normal_status(-1, "问卷标题不能超过60个字符") if (params[:polls_name].present? && params[:polls_name].length > 60) + normal_status(-1, "问卷描述不能超过100个字符") if (params[:polls_description].present? && params[:polls_description].length > 100) + end + + def poll_params + params.require(:poll).permit(:polls_name,:polls_status,:publish_time,:end_time,:polls_description, + :show_result,:exercise_bank_id,:is_public,:unified_setting,:un_anonymous) + end + + # 获得问卷及课堂 + def get_poll_and_course + @poll = Poll.find_by(id: params[:id]) + if @poll.blank? + tip_exception(404) + else + @course = @poll.course + tip_exception(404) if @course.blank? + end + end + + # 当前课堂及用户的判断 + def check_user_status + unless @course.is_public == 1 || (@course.is_public == 0 && @user_course_identity < Course::NORMAL) #课堂的成员/管理员才可以 + tip_exception(403) + end + end + + # 在设置问卷公开前,需判断课堂是否公开 + def is_course_public + unless @course.is_public == 1 # 0为私有,1为公开 + tip_exception(403) + end + end + + ## 判断开始答题页面的用户权限 + def check_user_on_answer + poll_status = @poll.get_poll_status(current_user.id) + if @user_course_identity == Course::STUDENT && poll_status == 1 #问卷未发布,且当前用户不为老师/管理员 + normal_status(-1, "未发布问卷!") + elsif @user_course_identity > Course::STUDENT && (!@poll.is_public || (@poll.is_public && !@poll.unified_setting)) ##不为课堂成员,且问卷不为公开的,或问卷公开,但是不是统一设置的 + normal_status(-1, "问卷暂未公开!") + end + end + + def check_unified_setting?(poll) #问卷是否统一设置,如为分班设置,当前用户是否在班级内 + if !poll.unified_setting #如果为分班设置,则需判断用户是否在班级内 + poll_group_settings = poll.poll_group_settings.pluck(:course_group_id) + member = @course.course_members.course_find_by_ids("user_id",current_user.id) + member_group_id = member.pluck(:course_group_id).uniq + if (member_group_id & poll_group_settings).size > 0 || @user_course_identity < Course::STUDENT + true + else + false + end + else + true + end + end + + def validates_multi_ids + if params[:check_ids].blank? || params[:check_ids].count <= 0 + normal_status(-1, "请选择问卷!") + elsif params[:check_ids].count > 15 + normal_status(-1, "最多只能选择15条数据!") + end + end + + def set_poll_status(publish_time,end_time) + time_now_i = Time.now + if publish_time.present? && end_time.present? && publish_time <= time_now_i && end_time > time_now_i + 2 + elsif publish_time.nil? || (publish_time.present? && publish_time > time_now_i) + 1 + elsif end_time.present? && end_time <= time_now_i + 3 + # elsif end_time.present? && publish_time.present? && end_time < publish_time + # normal_status(-1,"时间设置错误!") + else + 1 + end + end + + def get_questions_count + @poll_questions = @poll.poll_questions.order("question_number ASC") + @poll_questions_count = @poll_questions.count # 全部的题目数 + @poll_question_singles = @poll_questions.ques_count(1).all.count # 单选题 + @poll_question_doubles = @poll_questions.ques_count(2).all.count # 多选题 + @poll_question_mains = @poll_questions.ques_count(3).all.count #主观题 + end + + def check_poll_question_complete #commit_poll 的权限 + poll_user_current = @poll.poll_users.find_by_group_ids(current_user.id).first + poll_status = @poll.get_poll_status(current_user.id) + if @user_course_identity < Course::STUDENT || (poll_status == 3) || (poll_user_current.present? && poll_user_current.commit_status == 1) + normal_status(-1,"用户没有权限!") #老师/管理员在提交时没有权限 + else + necessary_answer = 0 + poll_questions = @poll.poll_questions + necessary_question = poll_questions.ques_necessary # 问卷必答的问题 + necessary_question.each do |q| + user_vote = q.poll_votes.find_current_vote("user_id",current_user.id) + vote_answer_id = user_vote.pluck(:poll_answer_id).reject(&:blank?).size + vote_text_count = user_vote.pluck(:vote_text).reject(&:blank?).size + if vote_answer_id == 0 && vote_text_count == 0 + necessary_answer += 1 + end + end + if necessary_answer > 0 + normal_status(-1,"问卷提交失败,有#{necessary_answer}个未答的必答题!") + end + end + end + + def check_poll_commit_result + poll_status = @poll.get_poll_status(current_user.id) + commit_poll_user = @poll.poll_users.find_by_group_ids(current_user.id).commit_by_status(1) #当前用户已提交问卷的 + unless @user_course_identity < Course::STUDENT || (@poll.show_result && poll_status == 3 && commit_poll_user.present?) + normal_status(-1,"没有权限!") #当前为老师/问卷公开统计,且问卷已截止,且用户有过回答的 + end + end + + def check_user_id_start_answer #判断用户在开始答题时,是否有用户id传入,如果为老师,则id必需,否则为当前用户的id + user_login = params[:login] + # @poll_current_user_id = params[:user_id] + if user_login.blank? && @user_course_identity < Course::STUDENT #id不存在,且当前为老师/管理员等 + normal_status(-1,"请输入学生登陆名!") + else + @answer_user = User.find_by(login:user_login) + if @answer_user.blank? + normal_status(404,"答题用户不存在") + else + @poll_current_user_id = @answer_user.id || current_user.id + end + end + end + + def get_all_polls_commit + @poll_questions = @poll.poll_questions.order("question_number ASC") + @poll_commit_ids = @poll.poll_users.commit_by_status(1).pluck(:user_id) #问卷提交用户的id + # 全部页面,需返回 + @poll_questions_count = @poll_questions.size + end + + def get_user_permission_course(poll_ids,status) #获取用户权限范围内的已发布/未发布 + poll_status = status.to_i + unpublish_group = [] + g_course_ids = @course.teacher_course_groups.get_user_groups(current_user.id).pluck(:course_group_id).reject(&:blank?).uniq + if g_course_ids.blank? || g_course_ids.include?(0) #当前用户的分班权限为空,即具体全部的分班权限 + user_groups_id = @course.course_groups.pluck(:id) + else + user_groups_id = g_course_ids + end + all_polls = Poll.where(id:poll_ids) + all_polls.each do |poll| + if poll.present? + if poll.unified_setting + poll_user_status = poll.get_poll_status(current_user.id) #当前用户的能看到的试卷 + if poll_user_status == poll_status || poll_status == 3 #未发布的情况 + unpublish_group = unpublish_group + user_groups_id + else + unpublish_group = [] + end + # unpublish_group = unpublish_group + user_groups_id + else + poll_all_group_settings = poll.poll_group_settings + poll_group_settings = poll_all_group_settings.poll_group_published.pluck(:course_group_id).uniq #问卷设置已发布的班级 + if poll_status == 1 + unpublish_group = user_groups_id - poll_group_settings + elsif poll_status == 3 + poll_ended_groups = poll_all_group_settings.poll_group_ended.pluck(:course_group_id).uniq + poll_and_user = user_groups_id & poll_group_settings #用户已设置的分班 + unpublish_group = unpublish_group + poll_and_user - poll_ended_groups #已发布的全部班级减去截止的全部班级 + else + poll_and_user = user_groups_id & poll_group_settings #用户已设置的分班 + unpublish_group = unpublish_group + poll_and_user + end + end + end + end + unpublish_group = unpublish_group.uniq + if unpublish_group.size > 0 + course_groups = CourseGroup.by_group_ids(unpublish_group) + else + course_groups = [] + end + course_groups + end + + def check_poll_setting_status + publish_course = params[:publish_time_groups] + unified_setting = params[:unified_setting] + if @course.is_end + normal_status(-1,"课堂已结束不能再修改!") + elsif unified_setting + poll_group_settings = @poll.poll_group_settings + if poll_group_settings.present? + p_time_present = poll_group_settings.publish_time_present.map(&:publish_time).min + if p_time_present < Time.now + normal_status(-1,"设置失败,存在已发布的分班!") + end + elsif params[:publish_time].blank? + normal_status(-1,"发布时间不允许为空") + end + elsif unified_setting.present? && !unified_setting #非统一设置,分班不能为空 + if publish_course.present? + course_ids = publish_course.map{|a| a[:course_group_id]}.sum + publish_t = publish_course.map{|a| a[:publish_time]} + if course_ids.include?(nil) || course_ids.count == 0 + normal_status(-1,"请选择分班!") + elsif publish_t.include?(nil) || publish_t.count == 0 + normal_status(-1,"发布时间不允许为空") + end + else + normal_status(-1,"请选择分班!") + end + # elsif (@poll.poll_status != 1) && (params[:publish_time].to_time != @poll.publish_time) && (@user_course_identity > Course::CREATOR) + # normal_status(-1,"已发布/已截止的不能修发布时间!") #课堂管理员和超级管理员才有权限 + end + end + + def get_left_banner_id + left_banner_content = @course.course_modules.search_by_module_type("poll") + if left_banner_content.present? + @left_banner_id = left_banner_content.first.id + @left_banner_name = left_banner_content.first.module_name + else + tip_exception(404) + end + end + +end diff --git a/app/controllers/praise_tread_controller.rb b/app/controllers/praise_tread_controller.rb new file mode 100644 index 000000000..bf814db77 --- /dev/null +++ b/app/controllers/praise_tread_controller.rb @@ -0,0 +1,46 @@ +class PraiseTreadController < ApplicationController + include MessagesHelper + before_action :require_login + before_action :validate_params, only: [:like, :unlike] + before_action :find_object + + def like + begin + return normal_status(2, "你已点过赞了") if by_user_liked?(@obj, current_user) + @praise_tread = @obj.praise_treads.build(user_id: current_user.id) + @praise_tread.save! + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + def unlike + begin + return normal_status(2, "你还没有点过赞噢") unless by_user_liked?(@obj, current_user) + @praise_treads = @obj.praise_treads.user_liker(current_user) + @praise_treads.last.destroy! if @praise_treads.present? + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + private + def find_object + begin + @obj = params[:object_type].strip.classify.constantize.find params[:object_id] + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + return + end + end + + def validate_params + return normal_status(2, "缺少参数:object_id") if params[:object_id].blank? + return normal_status(2, "缺少参数:object_type") if params[:object_type].blank? + end +end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb new file mode 100644 index 000000000..c9ed6c597 --- /dev/null +++ b/app/controllers/projects_controller.rb @@ -0,0 +1,10 @@ +class ProjectsController < ApplicationController + def search + query_params = { keyword: params[:keyword], category: 'manage' } + projects = Users::ProjectService.new(current_user, query_params).call + + params[:limit] = params[:per_page].to_i.zero? ? 20 : params[:per_page].to_i + @count = projects.count + @projects = paginate projects + end +end \ No newline at end of file diff --git a/app/controllers/question_banks_controller.rb b/app/controllers/question_banks_controller.rb new file mode 100644 index 000000000..f814822e8 --- /dev/null +++ b/app/controllers/question_banks_controller.rb @@ -0,0 +1,287 @@ +class QuestionBanksController < ApplicationController + before_action :require_login + before_action :params_filter + + # 题库选用列表 + # object_type: # normal 普通作业题库; group 分组作业题库; poll问卷题库; exercise试卷题库; gtask 毕设选题题库;gtopic 毕设任务 + # filter: 过滤条件 public公共题库, myself我的题库 + # search: 搜索条件 + def bank_list + page = params[:page] || 1 + limit = params[:limit] || 15 + @certification_teacher = current_user.is_certification_teacher || current_user.admin? + @objects = @object_type.classify.constantize.where(@object_filter) + @objects = + if params[:search] + if params[:filter] == 'public' + # 已认证才能获取题库 + if @certification_teacher + sql = %Q{ + #{@objects.table_name}.is_public = 1 and concat(#{@objects.table_name}.name, course_lists.name) like + '%#{params[:search]}%' + } + @objects.joins(:course_list).where(sql) + else + @objects.none + end + else + sql = %Q{ + #{@objects.table_name}.user_id = #{current_user.id} and concat(#{@objects.table_name}.name, course_lists.name) like + '%#{params[:search]}%' + } + @objects.joins(:course_list).where(sql) + end + else + if params[:filter] == 'public' + if @certification_teacher # 只用平台已认证的老师才能获取题库 + @objects.is_public + else + @objects.none + end + else + @objects.myself(current_user.id) + end + end + @objects = @objects.page(page).per(limit) + end + + # 保存题库 + def save_banks + tip_exception("bank_id不能为空") if params[:bank_id].blank? + tip_exception("一次最多只能选用15份题库") if params[:bank_id].count > 15 + tip_exception("course_id不能为空") if params[:course_id].blank? + begin + objects = @object_type.classify.constantize.where(id: params[:bank_id]) + course = Course.find params[:course_id] + new_object_ids = [] + objects.each do |object| + case @object_type + when 'HomeworkBank' # 作业 + new_object = quote_homework_bank object,course + when 'ExerciseBank' + if object.container_type == 'Exercise' # 试卷 + new_object = quote_exercise_bank object, course + else # 问卷 + new_object = quote_poll_bank object, course + end + when 'GtaskBank' + new_object = quote_gtask_bank object, course + when 'GtopicBank' + new_object = quote_gtopic_bank object, course + end + new_object_ids << new_object.id + end + render json: {status: 0, message: "选题成功", object_ids: new_object_ids} + rescue Exception => e + uid_logger_error(e.message) + tip_exception("题库选用失败") + raise ActiveRecord::Rollback + end + end + + def destroy + bank = current_bank + + unless user.admin? || bank.user_id == user.id + render_forbidden + return + end + + bank.destroy! + + render_ok + end + + def public + current_bank.update!(is_public: true) + render_ok + end + + private + + def current_bank + @_current_bank ||= @object_type.classify.constantize.where(@object_filter).find(params[:id]) + end + def params_filter + type = ["normal", "group", "poll", "exercise", "gtask", "gtopic"] + tip_exception("object_type类型不正确") unless type.include?(params[:object_type]) + # HomeworkBank 普通、分组作业题库;ExerciseBank试卷、问卷题库;GtaskBank毕设选题题库;GtopicBank毕设任务题库; + case params[:object_type] + when 'normal' + @object_type = "HomeworkBank" + @object_filter = "homework_type = 1" # 普通作业 + when 'group' + @object_type = "HomeworkBank" + @object_filter = "homework_type = 3" # 分组作业 + when 'poll' + @object_type = "ExerciseBank" + @object_filter = "container_type = 'Poll'" # 问卷 + when 'exercise' + @object_type = "ExerciseBank" + @object_filter = "container_type = 'Exercise'" # 试卷 + when 'gtask' + @object_type = "GtaskBank" + @object_filter = nil + when 'gtopic' + @object_type = "GtopicBank" + @object_filter = nil + end + end + + def quote_homework_bank homework, course + ActiveRecord::Base.transaction do + # 复制作业的基本信息 + new_homework = HomeworkCommon.new(name: homework.name, user_id: current_user.id, description: homework.description, + homework_type: homework.homework_type, course_id: course.id, homework_bank_id: homework.id, + reference_answer: homework.reference_answer) + + # 作业的基本设置复制 + new_homework.homework_detail_manual = HomeworkDetailManual.new + new_homework_detail_manual = new_homework.homework_detail_manual + + if new_homework.homework_type == "group" + # 分组作业表的复制 + new_homework.homework_detail_group = HomeworkDetailGroup.new + new_homework.homework_detail_group.min_num = homework.min_num + new_homework.homework_detail_group.max_num = homework.max_num + new_homework.homework_detail_group.base_on_project = homework.base_on_project + end + # 附件 + homework.attachments.try(:each) do |attachment| + att = attachment.copy + att.container_id = nil + att.container_type = nil + att.author_id = homework.user_id + att.copy_from = attachment.id + att.save + new_homework.attachments << att + end + + if new_homework.save + new_homework_detail_manual.save if new_homework_detail_manual + new_homework.homework_detail_group.save if new_homework.homework_detail_group + HomeworksService.new.create_works_list(new_homework, course) + homework.update_column(:quotes, homework.quotes+1) + end + new_homework + end + end + + def quote_exercise_bank exercise, course + ActiveRecord::Base.transaction do + new_exercise = Exercise.new(:exercise_name => exercise.name, :exercise_description => exercise.description, + :user_id => current_user.id, :course_id => course.id, :exercise_bank_id => exercise.id) + # 复制试卷基本信息 + exercise.exercise_bank_questions.each do |q| + option = { + :question_title => q.question_title, + :question_type => q.question_type || 1, + :question_number => q.question_number, + :question_score => q.question_score, + :shixun_id => q.shixun_id + } + exercise_question = new_exercise.exercise_questions.new option + # question_type:5实训题;其他是非实训题 + if q.question_type != 5 + # 复制选择题题目选项 + q.exercise_bank_choices.try(:each_with_index) do |choice, index| + exercise_question.exercise_choices.new({choice_position: index+1, choice_text: choice.choice_text}) + end + + # 复制标准答案(填空题和问答题) 多空填空题的话,应该是原标准答案的exercise_choice_id,即为题空的位置。 + q.exercise_bank_standard_answers.try(:each) do |answer| + exercise_question.exercise_standard_answers.new({exercise_choice_id: answer.exercise_bank_choice_id, answer_text: answer.answer_text}) + end + else + # 复制实训题 + q.exercise_bank_shixun_challenges.try(:each_with_index) do |sc, index| + exercise_question.exercise_shixun_challenges.new({position: index+1, challenge_id: sc.challenge_id, + shixun_id: sc.shixun_id, question_score: sc.question_score}) + end + end + end + # 添加学生 + # if new_exercise.save + # new_exercise.create_exercise_list + # exercise.update_column(:quotes, exercise.quotes+1) + # end + new_exercise if new_exercise.save! + end + end + + def quote_poll_bank poll, course + ActiveRecord::Base.transaction do + new_poll = Poll.new(:polls_name => poll.name, :polls_description => poll.description, :user_id => current_user.id, + :polls_type => 'Course', :course_id => course.id, :exercise_bank_id => poll.id) + + poll.exercise_bank_questions.try(:each) do |q| + option = { + :question_title => q.question_title, + :question_type => q.question_type || 1, + :is_necessary => q.is_necessary, + :question_number => q.question_number, + :max_choices => q.max_choices, + :min_choices => q.min_choices + } + poll_question = new_poll.poll_questions.new option + q.exercise_bank_choices.try(:each_with_index) do |choice, index| + poll_question.poll_answers.new({answer_position: index+1, answer_text: choice.choice_text}) + end + end + # if new_poll.save + # new_poll.create_polls_list + # poll.update_column(:quotes, poll.quotes+1) + # end + new_poll if new_poll.save! + end + end + + def quote_gtask_bank task, course + ActiveRecord::Base.transaction do + new_task = GraduationTask.new + new_task.attributes = task.attributes.dup.except("id", "course_id", "user_id", "quotes", "graduation_task_id", + "course_list_id") + new_task.course_id = course.id + new_task.user_id = current_user.id + if new_task.save! + new_task.create_work_list + end + # 复制附件内容 + task.attachments.try(:each) do |attachment| + att = attachment.copy + att.container_id = nil + att.container_type = nil + att.author_id = task.user_id + att.copy_from = attachment.id + att.save + new_task.attachments << att + end + task.update_column(:quotes, task.quotes+1) + new_task + end + end + + def quote_gtopic_bank topic, course + ActiveRecord::Base.transaction do + new_topic = GraduationTopic.new + new_topic.attributes = topic.attributes.dup.except("id", "course_id", "user_id", "graduation_topic_id", "course_list_id") + new_topic.course_id = course.id + new_topic.user_id = current_user.id + new_topic.save + + topic.attachments.each.try(:each) do |attachment| + att = attachment.copy + att.container_id = nil + att.container_type = nil + att.author_id = topic.user_id + att.copy_from = attachment.id + att.save + new_topic.attachments << att + end + topic.update_column(:quotes, topic.quotes+1) + new_topic + end + end + + +end diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb new file mode 100644 index 000000000..25c268bc7 --- /dev/null +++ b/app/controllers/repositories_controller.rb @@ -0,0 +1,16 @@ +class RepositoriesController < ApplicationController + before_action :git_base + + def show + repo_path = Shixun.find_by_identifier(params[:identifier]).try(:repo_name) + {repo_path: repo_path, path: params[:path]} + @entries = @git.file_tree(params) + end + + private + + def git_base + @shixun = Shixun.find_by_identifier(params[:shixun_identifier]) + @repo_namespace = @shixun.repo_path + end +end diff --git a/app/controllers/schools_controller.rb b/app/controllers/schools_controller.rb new file mode 100644 index 000000000..1551091aa --- /dev/null +++ b/app/controllers/schools_controller.rb @@ -0,0 +1,8 @@ +class SchoolsController < ApplicationController + + + def school_list + q = params[:search] ? params[:search].strip : "" + @schools = School.where("name like ?", "%#{q}%").pluck(:name) + end +end diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb new file mode 100644 index 000000000..00ae559b1 --- /dev/null +++ b/app/controllers/shixuns_controller.rb @@ -0,0 +1,746 @@ +class ShixunsController < ApplicationController + before_action :require_login, except: [:download_file, :index] + # before_action :check_auth, except: [:download_file, :index] + + before_action :find_shixun, except: [:index, :new, :create, :menus, :get_recommend_shixuns, :propaedeutics, + :departments, :apply_shixun_mirror, :get_mirror_script, :download_file] + before_action :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy] + + before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, + :shixun_members_added, :change_manager, :collaborators_delete, + :cancel_publish, :add_collaborators] + before_action :portion_allowed, only: [:copy] + + before_action :special_allowed, only: [:send_to_course, :search_user_courses] + + include ShixunsHelper + include ApplicationHelper + + ## 获取课程列表 + def index + ## 我的实训 + @shixuns = + if params[:order_by] == 'mine' + current_user.my_shixuns + else + Shixun.unhidden + end + + ## 方向 + if params[:tag_level].present? && params[:tag_id].present? + @shixuns = @shixuns.filter_tag(params[:tag_level].to_i, params[:tag_id].to_i) + case params[:tag_level].to_i + when 1 #大类 + @search_tags = Repertoire.find(params[:tag_id].to_i).name + when 2 #子类 + @search_tags = SubRepertoire.find(params[:tag_id].to_i).name + when 3 #tag + tag = TagRepertoire.find(params[:tag_id].to_i) + @search_tags = "#{tag.sub_repertoire.name} / #{tag.name}" + end + end + + ## 搜索关键字 匹配关卡名, 用户名, 实训名 和 空格多搜索 + if params[:keyword].present? + keyword = params[:keyword].strip + @shixuns = @shixuns.joins(:users, challenges: :challenge_tags). + where("challenge_tags.name like '%#{keyword}%' + or challenges.subject like '%#{keyword}%' + or concat(lastname, firstname) like '%#{keyword}%' + or shixuns.name like '%#{keyword.split(" ").join("%")}%'") + end + + ## 筛选 状态 + if params[:status].present? && params[:status].to_i != 0 + params[:status] = [0, 1] if params[:status].to_i == 1 + @shixuns = @shixuns.where(status: params[:status]) + end + + ## 筛选 难度 + if params[:diff].present? && params[:diff].to_i != 0 + @shixuns = @shixuns.where(trainee: params[:diff]) + end + + ## 排序参数 + bsort = params[:sort] || 'desc' + case params[:order_by] || 'publish_time' + when 'new' + @shixuns = @shixuns.order("shixuns.status = 2 desc, shixuns.created_at #{bsort}") + when 'hot' + @shixuns = @shixuns.order("shixuns.status = 2 desc, myshixuns_count #{bsort}") + when 'mine' + @shixuns = @shixuns.order("shixuns.created_at #{bsort}") + else + @shixuns = @shixuns.order("shixuns.status = 2 desc, publish_time #{bsort}") + end + + + @total_count = @shixuns.count + + ## 分页参数 + page = params[:page] || 1 + limit = params[:limit] || 16 + + @shixuns = @shixuns.includes(:tag_repertoires, :challenges).page(page).per(limit) + end + + ## 获取顶部菜单 + def menus + @repertoires = Repertoire.includes(sub_repertoires: [:tag_repertoires]).order("updated_at asc") + # respond_with @repertoires + + render_json + end + + ## 实训详情 + def show + # 当前用户开启的实训 + can_fork = current_user.is_certification_teacher || current_user.admin? + unless can_fork + @can_fork = {can_fork: "已经职业认证的教师才能fork实训", + certi_url: edu_setting('old_edu_host') + "/account/professional_certification"} + end + @current_myshixun = @shixun.current_myshixun(current_user) + if @shixun.fork_from + fork_shixun = Shixun.select(:id, :user_id, :name, :identifier).where(id: @shixun.fork_from).first + @fork_from = {name: fork_shixun.name, username: fork_shixun.owner.try(:full_name), + fork_identifier: fork_shixun.identifier} if fork_shixun + end + @power = current_user.manager_of_shixun?(@shixun) + # 更新是为了首页的排序,myshixun的动静需要在实训中展现出来 + if @current_myshixun && params[:exit] && !current_user.admin? + @current_myshixun.update_column(:updated_at, Time.now) + end + end + + def show_right + owner = @shixun.owner + #@fans_count = owner.followers.count + #@followed_count = owner.followed_users.count + @user_own_shixuns = owner.shixuns.published.count + end + + # 排行榜 + def ranking_list + if @shixun.status == 2 + sql = " + select m.user_id, u.login, u.lastname, m.updated_at, + (select sum(cost_time) from games g where g.myshixun_id = m.id) as time, + (select sum(final_score) from games g where g.myshixun_id = m.id) as score + from (myshixuns m join users u on m.user_id = u.id) where m.shixun_id = #{@shixun.id} and m.status = 1 + order by score desc, time asc limit 10 + " + @myshixuns = Myshixun.find_by_sql(sql) + + end + end + + #评论 + def discusses + new_params = params.merge(container_id: @shixun.id, container_type: 'Shixun') + discusses = ShixunsService.new.shixun_discuss new_params, current_user + + if discusses.present? + @children_list = discusses[:children_list] + else + @children_list = [] + end + end + + def copy + ActiveRecord::Base.transaction do + begin + @new_shixun = Shixun.new + @new_shixun.attributes = @shixun.attributes.dup.except("id","user_id","visits","gpid","status", "identifier", "averge_star", + "homepage_show","repo_name", "myshixuns_count", "challenges_count", + "can_copy") + @new_shixun.user_id = User.current.id + @new_shixun.averge_star = 5 + @new_shixun.identifier = generate_identifier Shixun, 8 + @new_shixun.fork_from = @shixun.id + @new_shixun.save! + + # 同步shixun_info的信息 + if @shixun.shixun_info.present? + ShixunInfo.create!(shixun_id: @new_shixun.id, + description: @shixun.description, + evaluate_script: @shixun.evaluate_script) + end + + # 同步镜像 + if @shixun.mirror_repositories.present? + @shixun.mirror_repositories.each do |mirror| + ShixunMirrorRepository.create!(:shixun_id => @new_shixun.id, :mirror_repository_id => mirror.id) + end + end + # 同步技术标签 + @shixun.shixun_tag_repertoires.each do |str| + ShixunTagRepertoire.create!(:tag_repertoire_id => str.tag_repertoire_id, :shixun_id => @new_shixun.id) + end + + # fork版本库 + logger.info("###########fork_repo_path: ######{@repo_path}") + project_fork(@new_shixun, @repo_path, current_user.login) + + ShixunMember.create!(:user_id => User.current.id, :shixun_id => @new_shixun.try(:id), :role => 1) + + # 同步复制关卡 + if @shixun.challenges.present? + @shixun.challenges.each do |challenge| + new_challenge = Challenge.new + new_challenge.attributes = challenge.attributes.dup.except("id","shixun_id","user_id", "challenge_tags_count") + new_challenge.user_id = User.current.id + new_challenge.shixun_id = @new_shixun.id + new_challenge.save! + if challenge.st == 0 # 评测题 + # 同步测试集 + if challenge.test_sets.present? + challenge.test_sets.each do |test_set| + new_test_set = TestSet.new + new_test_set.attributes = test_set.attributes.dup.except("id","challenge_id") + new_test_set.challenge_id = new_challenge.id + new_test_set.save! + end + end + # 同步关卡标签 + challenge_tags = ChallengeTag.where("challenge_id =? and challenge_choose_id is null", challenge.id) + if challenge_tags.present? + challenge_tags.each do |challenge_tag| + ChallengeTag.create!(:challenge_id => new_challenge.id, :name => challenge_tag.try(:name)) + end + end + elsif challenge.st == 1 # 选择题 + if challenge.challenge_chooses.present? + challenge.challenge_chooses.each do |challenge_choose| + new_challenge_choose = ChallengeChoose.new + new_challenge_choose.attributes = challenge_choose.attributes.dup.except("id","challenge_id") + new_challenge_choose.challenge_id = new_challenge.id + new_challenge_choose.save! + # 每一题的选项 + if challenge_choose.challenge_questions.present? + challenge_choose.challenge_questions.each do |challenge_question| + new_challenge_question = ChallengeQuestion.new + new_challenge_question.attributes = challenge_question.attributes.dup.except("id","challenge_choose_id") + new_challenge_question.challenge_choose_id = new_challenge_choose.id + new_challenge_question.save! + end + end + # 每一题的知识标签 + st_challenge_tags = ChallengeTag.where(:challenge_id => challenge.id, :challenge_choose_id => challenge_choose.id) + if st_challenge_tags.present? + st_challenge_tags.each do |st_challenge_tag| + ChallengeTag.create!(:challenge_id => new_challenge.id, :name => st_challenge_tag.try(:name), :challenge_choose_id => new_challenge_choose.id) + end + end + end + end + end + end + end + rescue Exception => e + uid_logger_error("copy shixun failed ##{e.message}") + g.delete_project(gshixungshixun.id) if gshixun.try(:id).present? # 异常后,如果已经创建了版本库需要删除该版本库 + tip_exception("实训Fork失败") + raise ActiveRecord::Rollback + end + end + end + + #合作者 + def collaborators + @user = current_user + @members = @shixun.shixun_members.includes(:user) + end + + def fork_list + @shixuns = Shixun.where(:fork_from => @shixun.id) + @shixuns_count = @shixuns.count + + ## 分页参数 + page = params[:page] || 1 + limit = params[:limit] || 20 + + @shixuns = @shixuns.page(page).per(limit) + end + + def new + @introduction_sample = PlatformSample.where(samples_type: ['introduction', 'knowledge']).pluck([:samples_type, :contents]) + @main_type = shixun_main_type + @small_type = shixun_small_type + end + + # 注意这里传参都应该使用params[:shixun]['name']这种格式 + def create + # 评测脚本的一些操作 + main_type, sub_type = params[:main_type], params[:small_type] + mirror = MirrorScript.where(:mirror_repository_id => main_type) + + identifier = generate_identifier Shixun, 8 + @shixun = Shixun.new(shixun_params) + @shixun.identifier = identifier + @shixun.user_id = current_user.id + @shixun.reset_time, @shixun.modify_time = Time.now, Time.now + + if sub_type.blank? + shixun_script = mirror.first.try(:script) + else + main_mirror = MirrorRepository.find(main_type).type_name + sub_mirror = MirrorRepository.where(id: sub_type).pluck(:type_name) + if main_mirror == "Java" && sub_mirror.include?("Mysql") + shixun_script = mirror.last.try(:script) + else + shixun_script = mirror.first.try(:script) + shixun_script = modify_shixun_script @shixun, shixun_script + end + end + + ActiveRecord::Base.transaction do + begin + @shixun.save! + # shixun_info关联ß + ShixunInfo.create!(shixun_id: @shixun.id, evaluate_script: shixun_script, description: params[:description]) + # 实训的公开范围 + if params[:scope_partment].present? + arr = [] + ids = School.where(:name => params[:scope_partment]).pluck(:id).uniq + ids.each do |id| + arr << { :school_id => id, :shixun_id => @shixun.id } + end + ShixunSchool.create!(arr) + end + + # 实训合作者 + @shixun.shixun_members.create!(user_id: current_user.id, role: 1) + + # 镜像-实训关联表 + ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => main_type.to_i) if main_type.present? + if sub_type.present? + sub_type.each do |mirror| + ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror) + end + end + + # 创建版本库 + repo_path = repo_namespace(User.current.login, @shixun.identifier) + GitService.add_repository(repo_path: repo_path) + # todo: 为什么保存的时候要去除后面的.git呢?? + @shixun.update_column(:repo_name, repo_path.split(".")[0]) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("实训创建失败") + raise ActiveRecord::Rollback + end + end + end + + def apply_shixun_mirror + form_params = params.permit(*%i[language runtime run_method attachment_id]) + form = ApplyShixunMirrorForm.new(form_params) + form.validate! + + tiding = Tiding.new( + user_id: 1, + trigger_user_id: current_user.id, + container_type: 'SendMessage', + viewed: 0, + tiding_type: 'Apply', + extra: form.to_json + ) + ActiveRecord::Base.transaction do + # TODO: 由于tiding是多态,而SendMessage却没有对应的model,因此,如果不跳过验证会报 container must exist的错. + tiding.save(validate: false) + + form.attachment.update!(container: tiding) + end + + sucess_status + rescue ActiveModel::ValidationError => ex + tip_exception(ex.message) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("申请失败") + end + + def update + h = {test_set_permission: params[:test_set_permission], code_hidden: params[:code_hidden], + task_pass: params[:task_pass], hide_code: params[:hide_code], forbid_copy: params[:forbid_copy]} + + s_params = shixun_params.merge(h) + + ActiveRecord::Base.transaction do + begin + @shixun.shixun_mirror_repositories.destroy_all + if params[:main_type].present? + ShixunMirrorRepository.create(:shixun_id => @shixun.id, :mirror_repository_id => params[:main_type].to_i) + end + if params[:small_type].present? + params[:small_type].each do |mirror| + ShixunMirrorRepository.create(:shixun_id => @shixun.id, :mirror_repository_id => mirror) + end + end + + @shixun.update_attributes(s_params) + @shixun.shixun_info.update_attributes(description: params[:description], evaluate_script: params[:evaluate_script]) + @shixun.shixun_schools.delete_all + if params[:scope_partment].present? && params[:user_scope].to_i == 1 + arr = [] + ids = School.where(:name => params[:scope_partment]).pluck(:id).uniq + ids.each do |id| + arr << { :school_id => id, :shixun_id => @shixun.id } + end + ShixunSchool.create!(arr) + use_scope = 1 + else + use_scope = 0 + end + @shixun.update_attributes!(:use_scope => use_scope) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("实训保存失败") + raise ActiveRecord::Rollback + end + end + end + + # 永久关闭实训 + def close + @shixun.update_attributes(status: 3, closer_id: current_user.id, end_time: Time.now) + sucess_status + end + + def propaedeutics + @content = Shixun.where(identifier: params[:identifier]).pluck(:propaedeutics) + end + + # 更新背景知识 + def update_propaedeutics + @shixun.update_column(:propaedeutics, params[:content]) + end + + # 获取推荐实训接口 2个热门实训 + 2个最新实训 + def get_recommend_shixuns + hot_shixuns = Shixun.field_for_recommend.published.order("myshixuns_count desc").limit(2) + newest_shixuns = Shixun.field_for_recommend.published.order("created_at desc").limit(2) + @recommend_shixuns = hot_shixuns + newest_shixuns + end + + def settings + @choice_main_type = @shixun.main_mirror_id + @choice_small_type = @shixun.small_mirror_id + @main_type = shixun_main_type + @small_type = shixun_small_type + #@mirror_script = MirrorScript.select([:id, :script_type]).find(@shixun.mirror_script_id).attributes if @shixun.mirror_script_id && @shixun.mirror_script_id != 0 + # @shixun_main_mirror = @shixun.show_shixun_mirror + # @script_type = @shixun.script_tag.try(:script_type) || "无" + # @evaluate_scirpt = @shixun.evaluate_script || "无" + end + + # 获取脚本内容 + def get_script_contents + mirrir_script = MirrorScript.find(params[:script_id]) + script = mirrir_script.try(:script) + @description = mirrir_script.try(:description) + @script = modify_shixun_script @shixun, script + end + + def get_custom_script + shixun_script = PlatformSample.where(:samples_type => "script").first.try(:contents) + compile = params[:compile] + execute = params[:executive] + if shixun_script + shixun_script = compile.blank? ? shixun_script.gsub("COMPILEFUNCTION", "").gsub("CHALLENGEFIELPATH", "") : + shixun_script.gsub("COMPILEFUNCTION", "#{compile_command}").gsub("COMPILECOMMAND", "#{compile}") + shixun_script = execute.blank? ? shixun_script.gsub("EXECUTEFUNCTION", "") : shixun_script.gsub("EXECUTECOMMAND", "#{execute}") + shixun_script = modify_shixun_script @shixun, shixun_script + end + @shixun_script = shixun_script + end + + def departments + @scope = [] + q = params[:q] + if q && q.strip.present? + @scope = School.where("name like ?", "%#{q.strip}%").pluck(:name) + end + + end + + def get_mirror_script + mirror = MirrorRepository.find(params[:mirror_id]) + @script = mirror.mirror_scripts + end + + # TODO: 目前实训只做软删除. + def destroy + # apply_records = ApplyAction.where(container_id: @shixun.id, container_type: "ApplyShixun") + # apply_records.delete_all if apply_records + # HomeworkCommonShixuns.where(shixun_id: @shixun).delete_all + # @shixun.destroy + @shixun.update_column(:status, -1) + end + + # 开启挑战 + # 以前在开启挑战的时候检测实训是否更新,更新则重置,觉得应该放在TPI更好 + # 中间需要一个过渡动画 + # TODO: 第一次开启实训都会去判断是否是纯选择题类型,感觉做成在创建关卡的时候就判断该实训是否是纯选择题更加合适 + def shixun_exec + current_myshixun = @shixun.current_myshixun(current_user.id) + + if @shixun.opening_time.present? && @shixun.opening_time > Time.now && current_user.shixun_identity(@shixun) > User::EDU_SHIXUN_MEMBER + tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}") + end + + if current_myshixun + # 如果TPM和TPI的管卡数不相等或者关卡顺序错了,说明实训被极大的改动,需要重置 + if current_myshixun.games.count != @shixun.challenges_count || current_myshixun.games.map(&:challenge_id).sort != Challenge.where(shixun_id: @shixun.id).pluck(:id).sort + # 这里页面弹框要收到 当前用户myshixun的identifier. + tip_show_exception("/myshixuns/#{current_myshixun.try(:identifier)}/reset_my_game") + end + + # 如果存在实训,则直接进入实训 + @current_task = current_myshixun.current_task + else + # 如果未创建关卡一定不能开启实训,否则TPI没法找到当前的关卡 + if @shixun.challenges_count == 0 + tip_exception("开启实战前请先创建实训关卡") + end + + # 判断实训是否全为选择题 + is_choice_type = @shixun.is_choice_type? + if !is_choice_type + commit = GitService.commits(repo_path: @repo_path).try(:first) + Rails.logger.info("First comit########{commit}") + tip_exception("开启实战前请先在版本库中提交代码") if commit.blank? + commit_id = commit["id"] + end + + ActiveRecord::Base.transaction do + begin + cloud_bridge = edu_setting('cloud_bridge') + myshixun_identifier = generate_identifier Myshixun, 10 + myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier, + modify_time: @shixun.modify_time, reset_time: @shixun.reset_time, + onclick_time: Time.now, commit_id: commit_id) + uid_logger("myshixun_id is #{myshixun.id}") + + # 如果实训是纯选择题,则不需要去fork仓库以及中间层的相关操作了 + unless is_choice_type + # fork仓库 + project_fork(myshixun, @repo_path, current_user.login) + + rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path ) + uid_logger("start openGameInstance") + uri = "#{cloud_bridge}/bridge/game/openGameInstance" + logger.info("end openGameInstance") + params = {tpiID: "#{myshixun.id}", tpmGitURL:rep_url, tpiRepoName: myshixun.repo_name.split("/").last} + uid_logger("openGameInstance params is #{params}") + # res = interface_post uri, params, 83, "实训云平台繁忙(繁忙等级:83)" + end + # 其它创建关卡等操作 + challenges = @shixun.challenges + # 之所以增加user_id是为了方便统计查询性能 + challenges.each_with_index do |challenge, index| + status = (index == 0 ? 0 : 3) + game_identifier = generate_identifier(Game, 12) + Game.create!(:challenge_id => challenge.id, :myshixun_id => myshixun.id, :status => status, :user_id => myshixun.user_id, + :open_time => Time.now, :identifier => game_identifier, :modify_time => challenge.modify_time) + end + + # REDO:开启实训时更新关联作品的状态 + HomeworksService.new.update_myshixun_work_status myshixun + + @current_task = myshixun.current_task + uid_logger("## shixun exec: myshixun id is #{myshixun.id}") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("实训云平台繁忙(繁忙等级:81)") + raise ActiveRecord::Rollback + end + end + end + + + + end + # gameID 及实训ID + # status: 0 , 1 申请过, 2,实训关卡路径未填, 3 实训标签未填, 4 实训未创建关卡 + def publish + @status = 0 + @position = [] + begin + if @shixun.challenges.count == 0 + @status = 4 + else + @shixun.challenges.each do |challenge| + if challenge.challenge_tags.count == 0 + @status = 3 + @position << challenge.position + end + end + unfinish_challenge = @shixun.challenges.where(:st => 0, :path => nil) + if unfinish_challenge.count > 0 && !@shixun.is_choice_type? + @status = 2 + @pos = [] + unfinish_challenge.each do |challenge| + @pos << challenge.position + end + end + end + if @status == 0 + @shixun.update_attributes!(:status => 1) + apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first + if apply && apply.status == 0 + @status = 0 + else + ApplyAction.create(:container_type => "ApplyShixun", :container_id => @shixun.id, :user_id => current_user.id, :status => 0) + #begin + # status = Trustie::Sms.send(mobile: '18711011226', send_type:'publish_shixun' , name: '管理员') + #rescue => e + # Rails.logger.error "发送验证码出错: #{e}" + #end + @status = 1 + end + end + rescue Exception => e + logger.error("pushlish game #{e}") + end + end + + include GitCommon + + def update_file + content = params[:content] + author_name = current_user.full_name + author_email = current_user.mail + @content = update_file_content content, @repo_path, @path, author_email, author_name, "Edit by browser" + end + + def add_collaborators + raise("搜索内容不能为空") unless params[:search] + member_ids = "(" + @shixun.shixun_members.map(&:user_id).join(',') + ")" + condition = "%#{params[:search].strip}%".gsub(" ","") + @users = User.where("id not in #{member_ids} and status = 1 and LOWER(concat(lastname, firstname, login, mail, nickname)) LIKE '#{condition}'") + end + + def shixun_members_added + raise("user_ids 不能为空!") if params[:user_ids].blank? + memberships = params[:user_ids] + memberships.each do |member| + ShixunMember.create!(:user_id => member, :shixun_id => @shixun.id, :role => 2) + end + end + + def change_manager + # 搜索成员 + if request.get? + @collaborators = @shixun.shixun_members.where("user_id != #{@shixun.user_id}") + else + if params[:user_id] + man_member = ShixunMember.where(:shixun_id => @shixun.id, :user_id => @shixun.user_id).first + cha_member = ShixunMember.where(:user_id => params[:user_id], :shixun_id => @shixun.id).first + if man_member && cha_member + man_member.update_attribute(:role, 2) + cha_member.update_attribute(:role, 1) + @shixun.update_attribute(:user_id, cha_member.user_id) + end + end + end + end + + # 刪除合作者 + def collaborators_delete + raise("user_id不能为空") if params[:user_id].blank? + shixun_member = ShixunMember.where(:user_id => params[:user_id], :shixun_id => @shixun.id, :role => 2).first + shixun_member.delete + end + + # 实训的发送至课堂:搜索课堂 + def search_user_courses + ## 分页参数 + page = params[:page] || 1 + limit = params[:limit] || 20 + if params[:search] + search = "%#{params[:search].to_s.strip.downcase}%" + course_ids = Course.find_by_sql("SELECT c.id FROM courses c, members m, member_roles mr + WHERE m.course_id = c.id AND m.id=mr.member_id AND mr.role_id in (3,7,9) + AND m.user_id=#{current_user.id} AND c.is_delete = 0 AND c.is_end = 0 + AND c.name like '#{search}' ").map(&:id) + + else + course_ids = Course.find_by_sql("SELECT c.id, c.name FROM courses c, members m, member_roles mr + WHERE m.course_id = c.id AND m.id=mr.member_id AND mr.role_id in (3,7,9) + AND m.user_id=#{current_user.id} AND c.is_delete = 0 AND c.is_end = 0").map(&:id) + + end + + @course_count = course_ids.length + @courses = Course.where(:id => course_ids).page(page).per(limit) + end + + # 将实训发送到课程 + def send_to_course + @course = Course.find(params[:course_id]) + homework = HomeworksService.new.create_homework shixun, @course, nil, current_user + end + + # 二维码扫描下载 + def download_file + file_path = params[:file_name] + send_file "#{Rails.root}/#{file_path}", :filename => "#{file_path}", + :type => 'shixun', + :disposition => 'attachment' #inline can open in browser + end + + # 撤销发布 + def cancel_publish + apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first + if apply && apply.status == 0 + apply.update_attribute(:status, 3) + apply.tidings.destroy_all + @shixun.update_column('status', 0) + end + end + +private + def shixun_params + raise("实训名称不能为空") if params[:name].blank? + params.require(:shixun).permit(:name, :trainee, :webssh, :can_copy, :use_scope, :vnc, :test_set_permission, + :task_pass, :repo_name, :multi_webssh, :opening_time, :mirror_script_id) + end + + def find_shixun + @shixun = Shixun.find_by_identifier(params[:identifier]) + shixun = Shixun.where(identifier: params[:identifier]).first + if @shixun.blank? + normal_status(404, "...") + return + end + + if !current_user.shixun_permission(@shixun) || (@shixun.status == -1 && !current_user.admin?) + tip_exception(403, "..") + end + end + + def find_repo_name + @repo_path = @shixun.try(:repo_path) + @path = params[:path] + end + + def allowed + unless current_user.manager_of_shixun?(@shixun) + tip_exception(403, "..") + end + end + + def portion_allowed + if current_user.shixun_identity(@shixun) > User::EDU_CERTIFICATION_TEACHER + raise Educoder::TipException.new(403, "..") + end + end + + def special_allowed + if @shixun.status != 2 + tip_exception(403, "..") + end + end +end diff --git a/app/controllers/stages_controller.rb b/app/controllers/stages_controller.rb new file mode 100644 index 000000000..3d0087981 --- /dev/null +++ b/app/controllers/stages_controller.rb @@ -0,0 +1,117 @@ +class StagesController < ApplicationController + before_action :require_login + before_action :find_subject, only: [:create, :index] + before_action :find_stage, only: [:update, :destroy, :edit, :up_position, :down_position] + before_action :allowed, except: [:index] + + def index + @user = current_user + @stages = @subject.stages + end + + def create + ActiveRecord::Base.transaction do + begin + @stage = Stage.new(stage_params) + @stage.subject_id = @subject.id + @stage.user_id = current_user.id + @stage.position = @subject.stages.count + 1 + @stage.save! + unless params[:shixun_id].blank? + shixuns = Shixun.where(id: params[:shixun_id]) + shixuns.each do |shixun| + StageShixun.create!(stage_id: @stage.id, subject_id: @subject.id, shixun_id: shixun.id, position: @stage.stage_shixuns.count + 1) + end + end + @subject.update_attributes(updated_at: Time.now) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("章节创建失败") + raise ActiveRecord::Rollback + end + end + end + + def edit + + end + + def update + ActiveRecord::Base.transaction do + begin + @stage.update_attributes(stage_params) + @stage.stage_shixuns.destroy_all + unless params[:shixun_id].blank? + params[:shixun_id].each do |shixun_id| + shixun = Shixun.where(id: shixun_id).first + @stage.stage_shixuns.create!(subject_id: @subject.id, shixun_id: shixun.id, position: @stage.stage_shixuns.count + 1) if shixun.present? + end + end + @subject.update_attributes(updated_at: Time.now) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("章节更新失败") + raise ActiveRecord::Rollback + end + end + end + + def destroy + ActiveRecord::Base.transaction do + @subject.stages.where("position > ?", @stage.position).update_all("position = position - 1") + @stage.destroy + @status = 1 + end + end + + def up_position + ActiveRecord::Base.transaction do + begin + position = @stage.position + tip_exception("第一章不能向上移动") if @stage.position == 1 + pre_stage = @subject.stages.where(position: position - 1).first + pre_stage.update_attributes(position: position) + @stage.update_attributes(position: position - 1) + rescue Exception => e + uid_logger("stage up failed: #{e.message}") + raise ActiveRecord::Rollback + end + end + end + + def down_position + ActiveRecord::Base.transaction do + begin + position = @stage.position + rails "最后一章不能向下移动" if @stage.position == @subject.stages.count + next_stage = @subject.stages.where(position: position + 1).first + next_stage.update_attributes(position: position) + @stage.update_attributes(position: position + 1) + rescue Exception => e + uid_logger("stage up failed: #{e.message}") + raise ActiveRecord::Rollback + end + end + end + + private + def stage_params + tip_exception("章节名称不能为空") if params[:name].blank? + params.require(:stage).permit(:name, :description) + end + + def find_subject + @subject = Subject.find_by!(id: params[:subject_id]) + end + + def find_stage + @stage = Stage.find_by!(id: params[:id]) + @subject = @stage.subject + end + + def allowed + unless current_user.manager_of_subject?(@subject) + tip_exception("403", "") + end + end +end diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb new file mode 100644 index 000000000..46e87e632 --- /dev/null +++ b/app/controllers/student_works_controller.rb @@ -0,0 +1,747 @@ +class StudentWorksController < ApplicationController + include HomeworkCommonsHelper + include StudentWorksHelper + + before_action :require_login + before_action :find_homework, only: [:new, :create, :search_member_list, :check_project, :relate_project, + :cancel_relate_project] + before_action :find_work, only: [:shixun_work_report, :adjust_review_score, :shixun_work, :commit_des, :update_des, + :adjust_score, :show, :adjust_score, :supply_attachments, :revise_attachment, + :comment_list, :add_score, :add_score_reply, :destroy_score, :appeal_anonymous_score, + :deal_appeal_score, :cancel_appeal, :edit, :update, :export_shixun_work_report] + before_action :user_course_identity + before_action :allow_add_score, only: [:add_score] + before_action :homework_publish + + before_action :teacher_allowed, only: [:adjust_score, :adjust_review_score, :deal_appeal_score] + before_action :course_student, only: [:new, :commit_des, :update_des, :create, :edit, :update, :search_member_list, :relate_project, + :cancel_relate_project, :relate_project] + + before_action :my_work, only: [:commit_des, :update_des, :edit, :update, :revise_attachment, :appeal_anonymous_score, + :cancel_appeal] + + before_action :edit_duration, only: [:edit, :update] + before_action :end_or_late, only: [:new, :create, :search_member_list, :commit_des, :update_des] + + before_action :require_score_id, only: [:destroy_score, :add_score_reply, :appeal_anonymous_score, :deal_appeal_score, :cancel_appeal] + + before_action :is_evaluation, only: [:show, :supply_attachments] + + def new + uid_logger("#######new current_user : 1111") + @current_user = current_user + uid_logger("#######new current_user : #{@current_user.id}") + if @homework.homework_type == "group" && @homework.homework_detail_group.try(:base_on_project) + work = @homework.student_works.find_by(user_id: @current_user.id) + if work.present? && (work.work_status != 0 || work.project_id == 0) + normal_status(403, "") + end + end + end + + # 搜索课堂学生 + def search_member_list + unless params[:search].blank? + @members = @course.students.joins(:user).where("user_id != #{current_user.id} and + concat(users.lastname, users.firstname) like ?", "%#{params[:search]}%") + else + + # 没有搜索条件时搜索课堂所有未提交的学生 + user_ids = @homework.student_works.where("work_status = 0").pluck(:user_id) - [current_user.id] + @members = @course.students.where(user_id: user_ids) + end + + page = params[:page] ? params[:page].to_i : 1 + limit = params[:limit] ? params[:limit].to_i : 10 + + # todo user_extension + @members = @members.page(page).per(limit).includes(:course_group, user: :user_extension) + end + + def create + student_work = @homework.student_works.find_or_create_by(user_id: current_user.id) + + tip_exception("作业不可重复提交") if student_work.work_status != 0 + update_check student_work + + student_ids = [current_user.id] + ActiveRecord::Base.transaction do + begin + student_work.description = params[:description] + student_work.commit_time = Time.now + student_work.update_time = Time.now + student_work.commit_user_id = current_user.id + student_work.group_id = @homework.homework_type == "group" ? @homework.max_group_id : 0 + + #提交作品时,计算是否迟交 + homework_setting = @homework.homework_group_setting(current_user.id) + student_work.late_penalty = homework_setting.end_time < Time.now ? @homework.late_penalty : 0 + student_work.work_status = homework_setting.end_time < Time.now ? 2 : 1 + + if student_work.save! + Attachment.associate_container(params[:attachment_ids], student_work.id, student_work.class) + + if @homework.homework_type == "group" + members = (params[:user_ids] || []).collect(&:to_i) - [current_user.id] + members = @course.students.pluck(:user_id) & members + student_ids += members + for i in 0 .. members.count-1 + stu_work = @homework.student_works.find_or_initialize_by(user_id: members[i].to_i) + stu_work.update_attributes(user_id: members[i].to_i, description: student_work.description, + homework_common_id: @homework.id, project_id: student_work.project_id, + late_penalty: student_work.late_penalty, work_status: student_work.work_status, + commit_time: Time.now, update_time: Time.now, group_id: student_work.group_id, + commit_user_id: current_user.id) + stu_work.save! + student_work.attachments.each do |attachment| + att = attachment.copy + att.author_id = attachment.author_id + stu_work.attachments << att + end + end + end + @homework.update_column(:updated_at, Time.now) + # todo 更新对应的作业课堂动态 + # update_course_activity(@taskhomework.class,@task.id) + + @work_id = student_work.id + end + + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + SubmitStudentWorkNotifyJob.perform_later(@homework.id, student_ids) + end + + def edit + @current_user = current_user + if @homework.homework_type == "group" + # todo user_extension + @work_members = @course.students.where(user_id: @homework.student_works.where(group_id: @work.group_id).pluck(:user_id)). + order("course_members.id=#{@work.user_id} desc").includes(:course_group, user: :user_extension) + end + end + + def update + update_check @work + + student_ids = [] + ActiveRecord::Base.transaction do + begin + @work.description = params[:description] + @work.update_time = Time.now + @work.commit_user_id = current_user.id + if @work.save! + Attachment.associate_container(params[:attachment_ids], @work.id, @work.class) + + #如果学生作品被打分后修改,应该给老师提示 + student_ids << @work.user_id if @work.scored? + + if @homework.homework_type == "group" + student_works = @homework.student_works.where("group_id = #{@work.group_id} and user_id != #{@work.user_id}") + work_user_ids = student_works.pluck(:user_id) + params_user_ids = (params[:user_ids] || []).collect(&:to_i) - [@work.user_id] + params_user_ids = @course.students.pluck(:user_id) & params_user_ids + + # 原成员更新描述、更新时间以及附件 + @homework.student_works.where(group_id: @work.group_id, user_id: (work_user_ids & params_user_ids)).each do |work| + work.update_attributes(update_time: Time.now, description: @work.description, commit_user_id: current_user.id) + work.attachments.destroy_all + @work.attachments.each do |attachment| + att = attachment.copy + att.author_id = attachment.author_id + work.attachments << att + end + student_ids << work.user_id if work.scored? + end + + # 删除的成员 + delete_user_ids = work_user_ids - params_user_ids + @homework.student_works.where(group_id: @work.group_id, user_id: delete_user_ids).each do |work| + work.attachments.destroy_all + # work.student_works_scores.destroy_all + work.tidings.destroy_all + end + @homework.student_works.where(group_id: @work.group_id, user_id: delete_user_ids). + update_all(work_status: 0, description: nil, late_penalty: 0, commit_time: nil, update_time: nil, + final_score: nil, teacher_score: nil, student_score: nil, teaching_asistant_score: nil, + work_score: nil, project_id: 0, group_id: 0, commit_user_id: nil) + + # 新增加的成员 + (params_user_ids - work_user_ids).each do |user_id| + stu_work = @homework.student_works.find_or_initialize_by(user_id: user_id) + stu_work.update_attributes(user_id: user_id, description: @work.description, homework_common_id: @homework.id, + project_id: @work.project_id, late_penalty: @work.late_penalty, + work_status: @work.work_status, commit_time: Time.now, update_time: Time.now, + group_id: @work.group_id, commit_user_id: current_user.id) + @work.attachments.each do |attachment| + att = attachment.copy + att.author_id = attachment.author_id + stu_work.attachments << att + end + + student_ids << user_id + end + end + + normal_status(0,"更新成功") + end + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + + SubmitStudentWorkNotifyJob.perform_later(@homework.id, student_ids) if student_ids.present? + end + end + + def show + @current_user = current_user + @work_members = @homework.homework_type != "group" ? [] : @homework.student_works.where.not(user_id: @work.user_id). + where(group_id: @work.group_id).includes(:user) + @attachments = @work.attachments.where.not(attachtype: 7) + end + + # 判断项目是否已有其他作品关联上了 + def check_project + tip_exception("项目id不能为空") if params[:project_id].blank? + work = @homework.student_works.find_by_project_id(params[:project_id]) + @is_relate = work.present? + @relate_user = work.present? ? work.user.real_name : "" + end + + def relate_project + tip_exception("项目id不能为空") if params[:project_id].blank? + + ActiveRecord::Base.transaction do + begin + # 判断项目是否存在且当前用户是项目管理员 + project = Project.find_by_id(params[:project_id]) + member = Member.find_by_project_id_and_user_id(project.try(:id), current_user.id) + + if project.present? && member.present? && member.member_roles.take.try(:role_id) == 3 + + work = @homework.student_works.find_or_create_by(user_id: current_user.id) + + if work.work_status == 0 && work.project_id == 0 + work.update_attributes(project_id: project.id, update_time: Time.now) + + # 将老师加入项目 + project_member = project.members.find_by_user_id(@homework.user_id) + if project_member.present? + project_member.member_roles.take.update_attributes(role_id: 3) if project_member.member_roles.take.present? + else + member = Member.create(user_id: @homework.user_id, project_id: project.id) + member.member_roles << MemberRole.new(role_id: 3) + Tiding.create(user_id: @homework.user_id, trigger_user_id: current_user.id, container_id: project.id, + container_type: 'ManagerJoinProject', belong_container_id: project.id, + belong_container_type: "Project", tiding_type: "System", extra: 3) + end + normal_status(0,"关联成功") + else + tip_exception("不能重复关联项目") + end + else + tip_exception("该项目不存在") + end + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def cancel_relate_project + work = @homework.student_works.find_by_user_id_and_work_status(current_user.id, 0) + if work.present? && work.project.present? + ActiveRecord::Base.transaction do + begin + member = work.project.members.find_by_user_id(@homework.user_id) + member.destroy if member.present? + Tiding.where(user_id: @homework.user_id, trigger_user_id: current_user.id, container_id: work.project.id, + container_type: 'ManagerJoinProject').destroy_all + + work.update_attributes(project_id: 0) + normal_status(0,"取消关联成功") + + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + else + tip_exception("无法取消关联") + end + end + + def supply_attachments + @revise_attachments = @work.attachments.where(attachtype: 7) + @last_atta = @revise_attachments.last + end + + def revise_attachment + tip_exception("不在补交阶段内") unless @homework.late_duration + tip_exception("附件参数有误") if params[:attachment_ids].blank? || !params[:attachment_ids].is_a?(Array) + tip_exception("补交附件原因不能为空") if params[:description].blank? + + ActiveRecord::Base.transaction do + begin + revise_attachment = @work.attachments.where(attachtype: 7).reorder("created_on desc").last + if revise_attachment.present? && @work.student_works_scores.where("created_at > '#{revise_attachment.created_on}' + and score is not null").count == 0 + revise_attachment.destroy + end + Attachment.associate_container(params[:attachment_ids], @work.id, @work.class, 7) + revise_attachment = Attachment.where(attachtype: 7, container_id: @work.id, container_type: "StudentWork").last + revise_attachment.update_attributes(description: params[:description]) if revise_attachment.present? + + @work.update_attributes(update_time: Time.now) + + normal_status(0, "提交成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def comment_list + @current_user = current_user + @last_comment = @work.student_works_scores.where(user_id: @current_user.id).last + # todo user_extension + @comment_scores = (@user_course_identity < Course::STUDENT || current_user == @work.user) ? + @work.student_works_scores.reorder("created_at desc") : + @work.student_works_scores.where(user_id: current_user.id).reorder("created_at desc") + @comment_scores = @comment_scores.includes(:student_works_scores_appeal, :attachments, journals_for_messages: :user, user: :user_extension) + end + + # 给作品评分 + def add_score + tip_exception("该学生的分数已经过调整,不能再评阅") if @work.ultimate_score + tip_exception("分数和评语不能都为空") if params[:score].blank? && params[:comment].blank? + tip_exception("分数不能超过0-100") if params[:score] && (params[:score].to_f < 0 || params[:score].to_f > 100) + + ActiveRecord::Base.transaction do + begin + # 没传score则取上次评分成绩 + score = StudentWorksScore.where(user_id: current_user.id, student_work_id: @work.id).last + new_score = StudentWorksScore.new + new_score.score = params[:score].blank? ? score.try(:score) : params[:score].to_f + new_score.comment = params[:comment] if params[:comment] && params[:comment].strip != "" + new_score.user_id = current_user.id + new_score.student_work_id = @work.id + + # 如果作品是未提交的状态则更新为已提交 + if @user_course_identity < Course::STUDENT && !new_score.score.nil? && @work.work_status == 0 + @work.update_attributes(work_status: 1, commit_time: Time.now) + # 分组作业更新分组id + @work.update_attributes(group_id: @homework.max_group_id) if @homework.homework_type == "group" + end + + new_score.reviewer_role = @user_course_identity == Course::STUDENT ? 3 : @user_course_identity == Course::ASSISTANT_PROFESSOR ? 2 : 1 + + if new_score.save! + Attachment.associate_container(params[:attachment_ids], new_score.id, new_score.class) + + # 该用户的历史评阅无效 + score.update_column('is_invalid', true) if score.present? && score.score.present? + + Tiding.create(user_id: @work.user_id, trigger_user_id: User.current.id, container_id: new_score.id, + container_type: "StudentWorksScore", parent_container_id: @work.id, + parent_container_type: "HomeworkCommon", belong_container_id: @homework.course_id, + belong_container_type: "Course", viewed: 0, tiding_type: "HomeworkCommon", extra: new_score.reviewer_role) + + case new_score.reviewer_role + when 1 #教师评分:最后一个教师评分为最终评分 + @work.teacher_score = new_score.score + if @homework.homework_type == "group" && params[:same_score] + add_score_to_member @work, @homework, new_score + end + when 2 #教辅评分 教辅评分显示平均分 + # 助教评分:普通模式则是平均分,复审模式则是最新评分 + if @homework.homework_detail_manual.ta_mode == 1 + @work.teaching_asistant_score = new_score.ta_score @work.id + else + @work.teaching_asistant_score = new_score.score + end + + if @homework.homework_type == "group" && params[:same_score] + add_score_to_member @work, @homework, new_score + end + when 3 #学生评分 学生评分显示平均分 + # 匿评分 + @work.student_score = new_score.stu_score(@work.id) + if @homework.homework_type == "group" && params[:same_score] && new_score.score.present? + add_score_to_member @work, @homework, new_score + end + + current_user.student_works_scores.where(student_work_id: @work.id, reviewer_role: 3, appeal_status: 1).update_all(appeal_status: 5) + end + + @homework.update_column('updated_at', Time.now) + # update_course_activity(@homework.class,@homework.id) + @work.save! + + normal_status(0,"提交成功") + end + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 实训作品的提交总结 + def commit_des + @current_user = current_user + end + + # 实训作品的总结 + def update_des + @work.update_attributes(des_params) + tip_exception(0, "提交成功") + end + + # 实训作品弹框 + def shixun_work + @myshixun = @work.myshixun + if @myshixun.present? + @current_user = current_user + @work_user = @work.user + @shixun = @homework.shixuns.take + else + tip_exception("作品还未提交") + end + end + + # 实训报告 + def shixun_work_report + @user = @work.user + @shixun = @homework.shixuns.take + @games = @work.myshixun.games.includes(:challenge, :game_codes,:outputs) if @work.myshixun + + # 用户最大评测次数 + @user_evaluate_count = @games.inject(0){|sum, g| sum + g.outputs.pluck(:query_index).first.to_i } if @games + # 图形效率图的数据 + @echart_data = student_efficiency(@homework, @work) + end + + def export_shixun_work_report + @user = @work.user + @shixun = @homework.shixuns.take + @games = @work.myshixun.games.includes(:challenge, :game_codes,:outputs) if @work.myshixun + + # 用户最大评测次数 + @user_evaluate_count = @games.inject(0){|sum, g| sum + g.outputs.pluck(:query_index).first.to_i } if @games + # 图形效率图的数据 + @echart_data = student_efficiency(@homework, @work) + @myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id } + @myself_consume = @echart_data[:consume_list].find { |item| item.last == @user.id } + # filename = "实训报告_#{@shixun.name}_#{@use.real_name}_#{Time.current.strftime('%Y%m%d%H%M%S')}.pdf" #下载报错 unknown nil name,下面为修改的-hs-0606 + + filename = "实训报告_#{@shixun&.name}_#{@use&.real_name}_#{Time.current.strftime('%Y%m%d%H%M%S')}.pdf" + stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css) + render pdf: 'shixun_work/shixun_work', filename: filename, stylesheets: stylesheets + end + + # 作品调分 + def adjust_score + tip_exception("分数不能为空") if params[:score].blank? + tip_exception("分数不能超过0-100") if params[:score].to_f < 0 || params[:score].to_f > 100 + ActiveRecord::Base.transaction do + begin + # 分数不为空的历史评阅都置为失效 + @work.student_works_scores.where.not(score: nil).update_all(is_invalid: 1) + reviewer_role = @user_course_identity == Course::ASSISTANT_PROFESSOR ? 2 : 1 + new_score = StudentWorksScore.new(student_work_id: @work.id, score: params[:score].to_f, comment: "使用调分功能调整了作业最终成绩:#{params[:comment]}", + user_id: current_user.id, reviewer_role: reviewer_role, is_ultimate: 1) + new_score.save! + + # 如果作品是未提交的状态则更新为已提交 + if @work.work_status == 0 + @work.work_status = 1 + @work.commit_time = Time.now + # 分组作业更新分组id + @work.group_id = @homework.max_group_id if @homework.homework_type == "group" + end + + @work.ultimate_score = true + @work.work_score = params[:score].to_f + @work.save! + + normal_status(0,"调分成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + #添加评分的回复 + def add_score_reply + tip_exception("回复内容不能为空") if params[:comment].blank? + ActiveRecord::Base.transaction do + begin + score = @work.student_works_scores.find_by!(id: params[:score_id]) + jour = score.journals_for_messages.new(user_id: current_user.id, notes: params[:comment], reply_id: score.user_id) + jour.save + normal_status(0,"回复成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 删除教师/教辅的评分记录 + def destroy_score + score = @work.student_works_scores.find_by(id: params[:score_id]) + tip_exception("该评阅记录不存在") unless score.present? + tip_exception("该评阅记录不能删除") unless score.allow_delete(@current_user, @user_course_identity) + begin + score.destroy + normal_status(0,"删除成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + + # 对学生匿评进行申诉 + def appeal_anonymous_score + tip_exception("申诉原因不能为空") if params[:comment].blank? + score = @work.student_works_scores.find_by(id: params[:score_id].to_i) + tip_exception("无法申诉") unless score.present? && @homework.appeal_duration && + score.reviewer_role == 3 && score.appeal_status == 0 + score_appeal = nil + ActiveRecord::Base.transaction do + begin + score.update_attributes(appeal_status: 1) + score_appeal = StudentWorksScoresAppeal.create!(user_id: current_user.id, student_works_score_id: score.id, + comment: params[:comment], appeal_status: 1) + + normal_status(0,"提交成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + # 提交后给老师和助教、匿评人发消息 + StudentWorkScoreAppealNotifyJob.perform_later(@course.id, score_appeal.id, current_user.id) + end + + # 撤销申诉 + def cancel_appeal + score = @work.student_works_scores.find_by(id: params[:score_id].to_i) + if score.present? && score.appeal_status == 1 + ActiveRecord::Base.transaction do + begin + score.update_attributes(appeal_status: 2) + score_appeal = score.student_works_scores_appeal + score_appeal.update_attributes(appeal_status: 2) + score_appeal.tidings.destroy_all + normal_status(0,"撤销成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + else + tip_exception("无法撤销") + end + end + + # status 3 接受 4 拒绝 + def deal_appeal_score + tip_exception("缺少status参数") if params[:status].blank? + tip_exception("status值不合要求") unless params[:status].to_i == 3 || params[:status].to_i == 4 + score = @work.student_works_scores.find_by(id: params[:score_id].to_i) + if score.present? && score.appeal_status == 1 + ActiveRecord::Base.transaction do + begin + # 更新appeal_status的值 + score.update_attributes(appeal_status: params[:status].to_i) + score_appeal = score.student_works_scores_appeal + score_appeal.update_attributes(appeal_status: params[:status].to_i) + score_appeal.tidings.update_all(status: 1) + + if params[:status].to_i == 3 + # 申诉成功后 扣匿评学生的违规匿评扣分 + sw = @homework.student_works.find_by(user_id: score.user_id) + sw.update_attribute("appeal_penalty", @homework.homework_detail_manual.appeal_penalty + sw.appeal_penalty) if sw.present? + + # 申诉成功 重新计算申诉者的匿评分 + if @work.student_works_scores.where("reviewer_role = 3 AND appeal_status != 3").count > 0 + @work.student_score = score.stu_score(@work.id) + else + @work.student_score = nil + end + @work.save + end + + # todo tiding + Tiding.create(user_id: score_appeal.user_id, trigger_user_id: current_user.id, container_id: score_appeal.id, + container_type: "StudentWorksScoresAppeal", parent_container_id: @work.id, + parent_container_type: 'UserAppealResult', belong_container_id: @course.id, + belong_container_type: "Course", viewed: 0, status: params[:status].to_i == 3 ? 1 : 2, + tiding_type: "HomeworkCommon") + Tiding.create(user_id: score.user_id, trigger_user_id: current_user.id, container_id: score_appeal.id, + container_type: "StudentWorksScoresAppeal", parent_container_id: @work.id, + parent_container_type: 'AppealResult', belong_container_id: @course.id, belong_container_type: "Course", + viewed: 0, status: params[:status].to_i == 3 ? 1 : 2, tiding_type: "HomeworkCommon") + + normal_status(0,"提交成功") + rescue Exception => e + uid_logger(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + else + tip_exception("该申诉不存在") + end + end + + # 查重作品调分 + def adjust_review_score + if params[:score].nil? || params[:challenge_id].nil? || params[:code_rate].nil? || params[:copy_user_id].nil? + tip_exception("参数错误,score和challenge_id和code_rate和copy_user_id不能为空") + end + copy_user = User.find params[:copy_user_id] + comment = "代码查重结果显示与#{copy_user.try(:show_real_name)}的代码相似度#{params[:code_rate]}%" + @work.challenge_work_scores.create(challenge_id: params[:challenge_id], user_id: current_user.id, score: params[:score], + comment: comment) + HomeworksService.new.set_shixun_final_score(@work) + @work_score = @homework.student_works.find_by(id: @work.id).try(:work_score) + + end + + + private + + def find_homework + begin + @homework = HomeworkCommon.find params[:homework_common_id] + @course = @homework.course + rescue Exception => e + uid_logger_error("##########{e.message}") + missing_template + end + end + + def find_work + begin + @work = StudentWork.find params[:id] + @homework = @work.homework_common + @course = @homework.course + rescue Exception => e + uid_logger_error("##########{e.message}") + missing_template + end + end + + def homework_public + tip_exception(403,"没有操作权限") unless @user_course_identity <= Course::STUDENT || + (@course.is_public == 1 && @homework.is_public) + end + + def course_student + uid_logger("#########course-student") + tip_exception(403,"没有操作权限") if @user_course_identity != Course::STUDENT + end + + def my_work + tip_exception(403,"没有操作权限") if @work.user_id != current_user.id || @work.work_status == 0 + end + + def edit_duration + tip_exception("已过了修改时间") if @homework.end_time && @homework.end_time < Time.now + end + + def end_or_late + tip_exception("不在提交/更新阶段") if @homework.end_or_late + end + + def des_params + tip_exception("description参数不能为空") if params[:description].blank? + params.require(:student_work).permit(:description) + end + + def require_score_id + tip_exception("score_id参数不能为空") if params[:score_id].blank? + end + + # 是否匿评阶段 + def is_evaluation + @is_author = @work.user_id == current_user.id + @is_evaluation = @user_course_identity == Course::STUDENT && !@is_author && @homework.anonymous_comment && + [3, 4].include?(@homework.homework_detail_manual.comment_status) + end + + def allow_add_score + # 老师始终有评阅权限,匿评阶段内,学生对分配给该学生的作品有评阅权限 + tip_exception(403, "没有权限") unless allow_score(@homework, @user_course_identity, current_user.id, @work) + end + + def update_check work + tip_exception("作品描述不能为空") if params[:description].blank? + if @homework.homework_type == "group" + tip_exception("小组成员不能为空") if params[:user_ids].blank? + tip_exception("小组成员人数不合要求") if params[:user_ids].length > @homework.homework_detail_group.max_num || + params[:user_ids].length < @homework.homework_detail_group.min_num + tip_exception("请先关联项目") if @homework.homework_detail_group.base_on_project && work.project_id == 0 + end + end + + + def add_score_to_member student_work, homework, new_score + student_works = homework.student_works.where("group_id = #{student_work.group_id} and id != #{student_work.id} and ultimate_score = 0") + student_works.each do |st_work| + st_score = StudentWorksScore.new(user_id: new_score.user_id, score: new_score.score, + reviewer_role: new_score.reviewer_role, comment: new_score.comment) + st_work.student_works_scores << st_score + + score = StudentWorksScore.where(user_id: new_score.user_id, student_work_id: st_work.id).last + # 该用户的历史评阅无效 + score.update_column('is_invalid', true) if score.present? && score.score.present? + + if new_score.reviewer_role == 1 + st_work.teacher_score = new_score.score + elsif new_score.reviewer_role == 2 + if homework.homework_detail_manual.ta_mode == 1 + st_work.teaching_asistant_score = new_score.ta_score st_work.id + else + st_work.teaching_asistant_score = new_score.score + end + else + st_work.student_score = student_work.student_score + end + st_work.save + + Tiding.create(user_id: st_work.user_id, trigger_user_id: current_user.id, container_id: st_score.id, + container_type: "StudentWorksScore", parent_container_id: st_work.id, parent_container_type: "StudentWork", + belong_container_id: homework.course_id, belong_container_type: "Course", viewed: 0, + tiding_type: "HomeworkCommon", extra: new_score.reviewer_role) + + new_score.attachments.each do |attachment| + att = attachment.copy + att.author_id = st_score.user_id + st_score.attachments << att + end + end + end +end diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb new file mode 100644 index 000000000..4b954584b --- /dev/null +++ b/app/controllers/subjects_controller.rb @@ -0,0 +1,413 @@ +class SubjectsController < ApplicationController + before_action :require_login, except: [:index] + # before_action :check_auth, except: [:index] + before_action :find_subject, except: [:index, :create, :append_to_stage] + before_action :allowed, only: [:update, :edit, :destroy, :publish, :cancel_publish, :cancel_has_publish, + :search_members, :add_subject_members, :statistics, :shixun_report, :school_report, + :up_member_position, :down_member_position] + + include ApplicationHelper + + def index + @tech_system = Repertoire.where(nil).order("updated_at desc") + select = params[:select] # 路径导航类型 + reorder = params[:order] || "publish_time" + search = params[:search] + + ## 分页参数 + page = params[:page] || 1 + limit = params[:limit] || 16 + offset = (page.to_i-1) * limit + + # 最热排序 + if reorder == "myshixun_count" + if select + @subjects = Subject.find_by_sql("SELECT subjects.id, subjects.name, subjects.stages_count, subjects.repertoire_id, subjects.status, + subjects.shixuns_count, COUNT(myshixuns.id) AS myshixun_member_count FROM myshixuns, stage_shixuns, subjects + WHERE myshixuns.shixun_id = stage_shixuns.shixun_id AND stage_shixuns.subject_id = subjects.id + AND `subjects`.`hidden` = 0 AND `subjects`.`status` = 2 AND `subjects`.`name` like '%#{search}%' + AND `subjects`.`repertoire_id` = #{select} GROUP BY subjects.id ORDER BY myshixun_member_count DESC") + else + @subjects = Subject.find_by_sql("SELECT subjects.id, subjects.name, subjects.stages_count, subjects.repertoire_id, subjects.status, + subjects.shixuns_count, COUNT(myshixuns.id) AS myshixun_member_count FROM myshixuns, stage_shixuns, subjects + WHERE myshixuns.shixun_id = stage_shixuns.shixun_id AND stage_shixuns.subject_id = subjects.id + AND `subjects`.`hidden` = 0 AND `subjects`.`status` = 2 AND `subjects`.`name` like '%#{search}%' + GROUP BY subjects.id ORDER BY myshixun_member_count DESC") + end + else + # 我的路径 + if reorder == "mine" + mine_subject_id = StageShixun.find_by_sql("select DISTINCT(subject_id) from stage_shixuns where shixun_id in + (select distinct(shixun_id) from myshixuns where user_id=#{current_user.id})").map(&:subject_id) + manage_subject_id = SubjectMember.where(user_id: current_user.id).pluck(:subject_id) + total_subject_id = (mine_subject_id + manage_subject_id).uniq + @subjects = Subject.where(id: total_subject_id) + elsif reorder == "publish_time" + @subjects = Subject.unhidden + else + @subjects = Subject.visible.unhidden + end + + # 类型 + if select + @subjects = @subjects.where(repertoire_id: select) + end + + if search.present? + @subjects = @subjects.where("name like ?", "%#{search}%") + end + + # 排序 + order_str = reorder == "publish_time" ? "status = 2 desc, publish_time asc" : "updated_at desc" + @subjects = @subjects.reorder(order_str) + end + + @total_count = @subjects.size + + if reorder != "myshixun_count" + @subjects = @subjects.page(page).per(limit).includes(:shixuns) + else + @subjects = @subjects[offset, limit] + end + end + + def show + @user = current_user + @is_creator = current_user.creator_of_subject?(@subject) + # 合作团队 + @members = @subject.subject_members.includes(:user) + challenge_ids = Challenge.where(shixun_id: @subject.shixuns.published.pluck(:id)).pluck(:id) + # 实训路径中的所有实训标签 + @tags = ChallengeTag.where(challenge_id: challenge_ids).pluck(:name).uniq + # 用户获取的实训标签 + @user_tags = @subject.shixuns.map(&:user_tags_name).flatten.uniq + end + + def create + ActiveRecord::Base.transaction do + begin + @subject = Subject.new(subject_params) + @subject.user_id = current_user.id + @subject.save! + @subject.subject_members.create!(role: 1, user_id: current_user.id) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("实训路径创建失败") + raise ActiveRecord::Rollback + end + end + end + + def edit + end + + def update + begin + @subject.update_attributes(subject_params) + rescue Exception => e + uid_logger_error(e.message) + tip_exception("实训路径更新失败") + raise ActiveRecord::Rollback + end + end + + def destroy + ActiveRecord::Base.transaction do + begin + ApplyAction.where(container_type: "ApplySubject", container_id: @subject.id).destroy_all + @subject.destroy + rescue Exception => e + uid_logger_error(e.message) + tip_exception("实训路径删除失败") + raise ActiveRecord::Rollback + end + end + end + + def choose_subject_shixun + @search = params[:search] + @type = params[:type] + # 超级管理员用户显示所有未隐藏的实训、非管理员显示合作团队用户的实训(对本单位公开且未隐藏) + if current_user.admin? + @shixuns = Shixun.select([:id, :name, :status, :myshixuns_count, :identifier]).where(hidden: 0) + else + none_shixun_ids = ShixunSchool.where("school_id != #{current_user.user_extension.try(:school_id)}").pluck(:shixun_id) + + @shixuns = Shixun.select([:id, :name, :status, :myshixuns_count, :identifier]).where.not(id: none_shixun_ids).where(hidden: 0) + end + + # 实训课程的所有标签 + tag_ids = @shixuns.joins(:shixun_tag_repertoires).pluck(:tag_repertoire_id).uniq + @tags = TagRepertoire.select([:id, :name]).where(id: tag_ids) + + if params[:search] + @shixuns = @shixuns.where("name like ?", "%#{@search}%") + end + + unless @type.nil? || @type == "" || @type == "all" + shixun_ids = ShixunTagRepertoire.where(tag_repertoire_id: @type).pluck(:shixun_id).uniq + @shixuns = @shixuns.where(id: shixun_ids) + end + + @shixuns = @shixuns.reorder("created_at desc") + @shixuns_count = @shixuns.size + + ## 分页参数 + page = params[:page] || 1 + @shixuns = @shixuns.page(page).per(10) + + @shixuns = @shixuns.includes(:myshixuns) + end + + def append_to_stage + @shixuns = Shixun.where(id: params[:shixun_id]).order("id desc") + end + + def choose_course + course_ids = Course.find_by_sql("SELECT c.id FROM courses c, members m, member_roles mr + WHERE m.course_id = c.id AND m.id=mr.member_id AND mr.role_id in (3,7,9) + AND m.user_id=#{current_user.id} AND c.is_delete = 0 AND c.is_end = 0").map(&:id) + @courses = Course.where(id: course_ids) + @none_shixun_ids = ShixunSchool.where("school_id != #{current_user.user_extension.try(:school_id)}").pluck(:shixun_id) + end + + def send_to_course + @course = Course.find_by!(id: params[:course_id]) + stages = @subject.stages.where(id: @subject.stage_shixuns.where(shixun_id: params[:shixun_ids]).pluck(:stage_id)) + + course_module = @course.course_modules.where(module_type: "shixun_homework").first + + ActiveRecord::Base.transaction do + begin + # 将实训课程下的所有已发布实训按顺序发送到课堂,同时创建与章节同名的实训作业目录 + stages.each do |stage| + category = CourseSecondCategory.where(name: stage.name, course_id: @course.id, category_type: "shixun_homework").first || + CourseSecondCategory.create!(name: stage.name, course_id: @course.id, category_type: "shixun_homework", + course_module_id: course_module, position: course_module.course_second_categories.count + 1) + + stage.shixuns.where(id: params[:shixun_ids], status: 2).each do |shixun| + homework = HomeworksService.new.create_homework shixun, @course, category, current_user + end + end + rescue Exception => e + uid_logger(e.message) + tip_exception("发送失败") + raise ActiveRecord::Rollback + end + end + end + + def publish + apply = ApplyAction.where(container_type: "ApplySubject", container_id: @subject.id).order("created_at desc").first + if apply && apply.status == 0 + @status = 0 + else + @subject.update_attributes(status: 1) + ApplyAction.create(container_type: "ApplySubject", container_id: @subject.id, user_id: current_user.id, status: 0) + begin + status = Trustie::Sms.send(mobile: '18711011226', send_type:'publish_subject' , name: '管理员') + rescue => e + uid_logger_error("发送验证码出错: #{e}") + end + @status = 1 + end + end + + def cancel_publish + begin + apply = ApplyAction.where(container_type: "ApplySubject", container_id: @subject.id).order("created_at desc").first + if apply && apply.status == 0 + apply.update_attributes(status: 3) + apply.tidings.destroy_all + end + @subject.update_attributes(status: 0) + rescue => e + uid_logger_error(e.message) + tip_exception("撤销申请失败") + raise ActiveRecord::Rollback + end + end + + def cancel_has_publish + begin + @subject.update_attributes(:status => 0) + rescue => e + uid_logger_error(e.message) + tip_exception("撤销发布失败") + raise ActiveRecord::Rollback + end + end + + def search_members + tip_exception("搜索内容不能为空") unless params[:search] + page = params[:page] || 1 + member_ids = @subject.subject_members.map(&:user_id).join(',') + condition = "%#{params[:search].strip}%".gsub(" ","") + @users = User.where("id not in (?) and status = 1 and LOWER(concat(lastname, firstname, login, mail)) LIKE ?", member_ids, "#{condition}") + + @users = @users.page(page).per(10) + @users = @users.includes(:user_extension) + end + + def add_subject_members + tip_exception(403, "没权限操作") if !current_user.admin? + tip_exception("user_ids 不能为空!") if params[:user_ids].blank? + memberships = params[:user_ids] + memberships.each do |member| + if SubjectMember.where(user_id: member, subject_id: @subject.id).count == 0 + user = User.find_by!(id: member) + SubjectMember.create!(user_id: member, subject_id: @subject.id, role: 2, position: @subject.subject_members.size + 1) if user.present? + end + end + end + + # 删除实训 + # DELETE: /api/subejcts/:id/delete_member + def delete_member + tip_exception(403, "没权限操作") if !current_user.admin? + tip_exception('用户id不能为空') if params[:user_id].blank? + user = @subject.subject_members.where(:user_id => params[:user_id], :role => 2).first + tip_exception("管理员用户不允许删除,或用户不存在") if user.blank? + ActiveRecord::Base.transaction do + begin + @subject.subject_members.where("position > #{user.position}").update_all("position = position - 1") + user.destroy + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 合作者上移 + def up_member_position + tip_exception('用户id不能为空') if params[:user_id].blank? + ActiveRecord::Base.transaction do + begin + member = @subject.subject_members.where(user_id: params[:user_id]).first + # position为1时不能再往上移 + tip_exception('不能再上移了') if member.position == 1 + + up_member = @subject.subject_members.where(position: member.position - 1).first + up_member.update_attribute(:position, member.position) + member.update_attribute(:position, member.position - 1) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + # 合作者下移 + def down_member_position + tip_exception('用户id不能为空') if params[:user_id].blank? + ActiveRecord::Base.transaction do + begin + member = @subject.subject_members.where(user_id: params[:user_id]).first + + # position已经是最大值时不能再往下移 + tip_exception('不能再下移了') if member.position == @subject.subject_members.size + + down_member = @subject.subject_members.where(:position => member.position + 1).first + down_member.update_attribute(:position, member.position) + member.update_attribute(:position, member.position + 1) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def statistics + @learn_count = @subject.member_count + shixun_ids = @subject.stage_shixuns.pluck(:shixun_id) + # 受用课堂(已经发布的实训(在此路径中的实训)作业的个数) + homework_common_id = HomeworkCommonsShixun.where(shixun_id: shixun_ids).pluck(:homework_common_id).uniq + homework_common_id = homework_common_id.blank? ? -1 : homework_common_id.join(",") + + courses = Course.find_by_sql("select c.id, c.school_id from courses c right join homework_commons hc on c.id = hc.course_id where c.is_delete = 0 + and c.school_id is not null and hc.publish_time < '#{Time.now}' and hc.id in (#{(homework_common_id)})") + course_ids = courses.pluck(:id).uniq + @course_count = course_ids.length + # 受用院校 + school_ids = courses.pluck(:school_id).uniq + @schools_count = school_ids.length + + # 采用课堂情况 + @schools = School.select([:id, :name]).where(id: school_ids) + @schools = + @schools.map do |s| + school_courses = Course.where(id: course_ids, school_id: s.id) + course_count = school_courses.count + student_count = StudentsForCourse.where(course_id: school_courses.pluck(:id)).count + homework_count = HomeworkCommon.find_by_sql("select count(*) cnt from homework_commons hc join courses c on hc.course_id = c.id + where c.school_id = #{s.id} and hc.id in(#{homework_common_id})").first.try(:cnt) + s.attributes.dup.merge({name: s.name, course_count: course_count, student_count: student_count,homework_count: homework_count}) + end + @schools = @schools.sort{|x,y| y['homework_count'] <=> x['homework_count']} + @school_total_count = @schools.size + + page = params[:page] || 1 + @schools = @schools[(page.to_i-1)*10, 10] + + # TODO: 这个可以异步加载,让页面刷新完成后再加载图形数据 + # 章节使用情况 + @stage_user_info = [] + @sum = 0 #总数 + @subject.stages.includes(:stage_shixuns).each do |stage| + shixun_ids = stage.stage_shixuns.pluck(:shixun_id) + if shixun_ids.present? + homework_common_id = HomeworkCommonsShixun.where(shixun_id: shixun_ids).pluck(:homework_common_id).uniq + if homework_common_id.present? + publish_homework = HomeworkDetailManual.where("homework_common_id in(?) and comment_status > 0", homework_common_id.join(",")).pluck(:homework_common_id) + use_count = publish_homework.present? ? HomeworkCommon.find_by_sql("select count(*) cnt from homework_commons hc join courses c on hc.course_id = c.id + where hc.id in(#{publish_homework.join(",")}) and c.school_id is not null").first.try(:cnt) : 0 + @sum += use_count + else + @sum += 0 + use_count = 0 + end + @stage_user_info << use_count + else + @sum += 0 + @stage_user_info << 0 + end + end + end + + def shixun_report + + end + + def school_report + @schools = School.find_by_sql("select count(ms.id) ue_count, s.id, s.name school_name from user_extensions ue, + myshixuns ms, schools s where ue.user_id = ms.user_id and ms.shixun_id in (select shixun_id from + stage_shixuns where subject_id = '#{@subject.id}') and s.id = ue.school_id group by ue.school_id + order by ue_count desc limit 10") + end + + private + def subject_params + tip_exception("实训路径名称不能为空") if params[:name].blank? + tip_exception("实训路径简介不能为空") if params[:description].blank? + tip_exception("实训路径学习须知不能为空") if params[:learning_notes].blank? + params.require(:subject).permit(:name, :description, :learning_notes) + end + + def find_subject + @subject = Subject.find_by!(id: params[:id]) + + unless @subject.status == 2 || current_user.manager_of_subject?(@subject) + tip_exception("403", "") + end + end + + def allowed + unless current_user.manager_of_subject?(@subject) + tip_exception("403", "") + end + end +end diff --git a/app/controllers/tem_tests_controller.rb b/app/controllers/tem_tests_controller.rb new file mode 100644 index 000000000..a3336f3b2 --- /dev/null +++ b/app/controllers/tem_tests_controller.rb @@ -0,0 +1,74 @@ +class TemTestsController < ApplicationController + before_action :set_tem_test, only: [:show, :edit, :update, :destroy] + + # GET /tem_tests + # GET /tem_tests.json + def index + @tem_tests = TemTest.all + end + + # GET /tem_tests/1 + # GET /tem_tests/1.json + def show + end + + # GET /tem_tests/new + def new + @tem_test = TemTest.new + end + + # GET /tem_tests/1/edit + def edit + end + + # POST /tem_tests + # POST /tem_tests.json + def create + @tem_test = TemTest.new(tem_test_params) + + respond_to do |format| + if @tem_test.save + format.html { redirect_to @tem_test, notice: 'Tem test was successfully created.' } + format.json { render :show, status: :created, location: @tem_test } + else + format.html { render :new } + format.json { render json: @tem_test.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /tem_tests/1 + # PATCH/PUT /tem_tests/1.json + def update + respond_to do |format| + if @tem_test.update(tem_test_params) + format.html { redirect_to @tem_test, notice: 'Tem test was successfully updated.' } + format.json { render :show, status: :ok, location: @tem_test } + else + format.html { render :edit } + format.json { render json: @tem_test.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /tem_tests/1 + # DELETE /tem_tests/1.json + def destroy + @tem_test.destroy + respond_to do |format| + format.html { redirect_to tem_tests_url, notice: 'Tem test was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_tem_test + @tem_test = TemTest.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def tem_test_params + params.require(:tem_test).permit(:name, :email) + end +end diff --git a/app/controllers/tidings_controller.rb b/app/controllers/tidings_controller.rb new file mode 100644 index 000000000..686f457f0 --- /dev/null +++ b/app/controllers/tidings_controller.rb @@ -0,0 +1,19 @@ +class TidingsController < ApplicationController + def index + tidings = current_user.tidings.order(created_at: :desc) + + tiding_types = + case params[:type] + when 'notice' then 'System' + when 'apply' then 'Apply' + when 'course' then %w(HomeworkCommon Exercise Poll) + when 'project' then 'Project' + when 'interaction' then %w(Comment Mentioned Praise Fan) + end + + tidings = tidings.where(tiding_type: tiding_types) if tiding_types.present? + + @count = tidings.count + @tidings = paginate tidings + end +end \ No newline at end of file diff --git a/app/controllers/trial_applies_controller.rb b/app/controllers/trial_applies_controller.rb new file mode 100644 index 000000000..f8454e557 --- /dev/null +++ b/app/controllers/trial_applies_controller.rb @@ -0,0 +1,15 @@ +class TrialAppliesController < ApplicationController + + def create + Users::ApplyTrailService.call(current_user, create_params) + render_ok + rescue Users::ApplyTrailService::Error => ex + render_error(ex.message) + end + + private + + def create_params + params.permit(:phone, :code, :reason).merge(remote_ip: request.remote_ip) + end +end diff --git a/app/controllers/users/accounts_controller.rb b/app/controllers/users/accounts_controller.rb new file mode 100644 index 000000000..e88ff4564 --- /dev/null +++ b/app/controllers/users/accounts_controller.rb @@ -0,0 +1,23 @@ +class Users::AccountsController < Users::BaseController + before_action :private_user_resources! + + def show + end + + def update + Users::UpdateAccountService.call(observed_user, update_params) + + render 'show' + end + + private + + def observed_user + @_observed_user ||= (User.find_by_id(params[:id]) || User.find_by_login(params[:id])) + end + + def update_params + params.permit(:nickname, :name, :show_realname, :gender, :location, :location_city, + :identity, :student_id, :technical_title, :school_id, :department_id) + end +end diff --git a/app/controllers/users/avatars_controller.rb b/app/controllers/users/avatars_controller.rb new file mode 100644 index 000000000..6d161ba94 --- /dev/null +++ b/app/controllers/users/avatars_controller.rb @@ -0,0 +1,33 @@ +class Users::AvatarsController < Users::BaseAccountController + before_action :private_user_resources! + before_action :convert_base64_image!, only: [:update] + + def update + Util.write_file(@image, avatar_path) + + # 首次上传头像 + RewardGradeService.call(observed_user, container_id: observed_user.id, container_type: 'Avatar', score: 100) + + render_ok(avatar_url: avatar_url) + rescue StandardError => ex + logger_error(ex) + render_error('修改失败') + end + + private + + def convert_base64_image! + max_size = EduSetting.get('upload_avatar_max_size') + @image = Util.convert_base64_image(params[:image].to_s.strip, max_size: max_size) + rescue Base64ImageConverter::Error => ex + render_error(ex.message) + end + + def avatar_path + ApplicationController.helpers.disk_filename(observed_user.class, observed_user.id) + end + + def avatar_url + ApplicationController.helpers.url_to_avatar(observed_user) + end +end diff --git a/app/controllers/users/base_account_controller.rb b/app/controllers/users/base_account_controller.rb new file mode 100644 index 000000000..b693eaab5 --- /dev/null +++ b/app/controllers/users/base_account_controller.rb @@ -0,0 +1,7 @@ +class Users::BaseAccountController < Users::BaseController + before_action :require_login + + def observed_user + @_observed_user ||= (User.find_by_id(params[:account_id]) || User.find_by_login(params[:account_id])) + end +end diff --git a/app/controllers/users/base_controller.rb b/app/controllers/users/base_controller.rb new file mode 100644 index 000000000..afc03ee13 --- /dev/null +++ b/app/controllers/users/base_controller.rb @@ -0,0 +1,42 @@ +class Users::BaseController < ApplicationController + + before_action :check_observed_user_exists! + + helper_method :observed_logged_user?, :observed_user + + def observed_user + @_observed_user ||= (User.find_by_id(params[:user_id]) || User.find_by_login(params[:user_id])) + end + + def observed_logged_user? + observed_user.id == User.current&.id + end + + private + + def check_observed_user_exists! + return if observed_user.present? + render_not_found + end + + def private_user_resources! + require_login + return if current_user.admin? || observed_logged_user? + + render_forbidden + end + + def paginate(objs, **opts) + 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 + + return Kaminari.paginate_array(objs).page(page).per(per_page) unless observed_logged_user? && opts[:special] + + # note: 为实现第一页少一条记录,让前端放置新建入口 + if page == 1 + objs.limit(per_page - 1) + else + objs.limit(per_page).offset((page - 2) * per_page + per_page - 1) + end + end +end \ No newline at end of file diff --git a/app/controllers/users/courses_controller.rb b/app/controllers/users/courses_controller.rb new file mode 100644 index 000000000..c7e957e1a --- /dev/null +++ b/app/controllers/users/courses_controller.rb @@ -0,0 +1,14 @@ +class Users::CoursesController < Users::BaseController + def index + courses = Users::CourseService.new(observed_user, query_params).call + + @count = courses.count + @courses = paginate(courses.includes(teacher: { user_extension: :school }), special: true) + end + + private + + def query_params + params.permit(:category, :status, :sort_direction) + end +end \ No newline at end of file diff --git a/app/controllers/users/email_binds_controller.rb b/app/controllers/users/email_binds_controller.rb new file mode 100644 index 000000000..417ffc3b8 --- /dev/null +++ b/app/controllers/users/email_binds_controller.rb @@ -0,0 +1,16 @@ +class Users::EmailBindsController < Users::BaseAccountController + before_action :private_user_resources! + + def create + Users::BindEmailService.call(observed_user, create_params) + render_ok + rescue Users::BindEmailService::Error => ex + render_error(ex.message) + end + + private + + def create_params + params.permit(:email, :code) + end +end diff --git a/app/controllers/users/experience_records_controller.rb b/app/controllers/users/experience_records_controller.rb new file mode 100644 index 000000000..3207f7247 --- /dev/null +++ b/app/controllers/users/experience_records_controller.rb @@ -0,0 +1,10 @@ +class Users::ExperienceRecordsController < Users::BaseController + before_action :private_user_resources! + + def show + experiences = observed_user.experiences.where('score > 0') + + @count = experiences.count + @experience_records = paginate(experiences.order(created_at: :desc)) + end +end \ No newline at end of file diff --git a/app/controllers/users/grade_records_controller.rb b/app/controllers/users/grade_records_controller.rb new file mode 100644 index 000000000..c49e8732e --- /dev/null +++ b/app/controllers/users/grade_records_controller.rb @@ -0,0 +1,18 @@ +class Users::GradeRecordsController < Users::BaseController + before_action :private_user_resources! + + def show + grades = observed_user.grades + + type = params[:type].to_s.strip + grades = + case type + when 'income' then grades.where('score > 0') + when 'cost' then grades.where('score < 0') + else grades + end + + @count = grades.count + @grade_records = paginate(grades.order(created_at: :desc)) + end +end \ No newline at end of file diff --git a/app/controllers/users/passwords_controller.rb b/app/controllers/users/passwords_controller.rb new file mode 100644 index 000000000..fd4b4b634 --- /dev/null +++ b/app/controllers/users/passwords_controller.rb @@ -0,0 +1,14 @@ +class Users::PasswordsController < Users::BaseAccountController + def update + Users::UpdatePasswordService.call(observed_user, update_params) + render_ok + rescue Users::UpdatePasswordService::Error => ex + render_error(ex.message) + end + + private + + def update_params + params.permit(:password, :old_password) + end +end diff --git a/app/controllers/users/phone_binds_controller.rb b/app/controllers/users/phone_binds_controller.rb new file mode 100644 index 000000000..873666341 --- /dev/null +++ b/app/controllers/users/phone_binds_controller.rb @@ -0,0 +1,16 @@ +class Users::PhoneBindsController < Users::BaseAccountController + before_action :private_user_resources! + + def create + Users::BindPhoneService.call(observed_user, create_params) + render_ok + rescue Users::BindPhoneService::Error => ex + render_error(ex.message) + end + + private + + def create_params + params.permit(:phone, :code) + end +end diff --git a/app/controllers/users/projects_controller.rb b/app/controllers/users/projects_controller.rb new file mode 100644 index 000000000..863b99b37 --- /dev/null +++ b/app/controllers/users/projects_controller.rb @@ -0,0 +1,14 @@ +class Users::ProjectsController < Users::BaseController + def index + projects = Users::ProjectService.new(observed_user, query_params).call + + @count = projects.count + @projects = paginate(projects.includes(:project_score, owner: { user_extension: :school }), special: true) + end + + private + + def query_params + params.permit(:category, :status, :sort_direction) + end +end \ No newline at end of file diff --git a/app/controllers/users/question_banks_controller.rb b/app/controllers/users/question_banks_controller.rb new file mode 100644 index 000000000..0dc4a3f3f --- /dev/null +++ b/app/controllers/users/question_banks_controller.rb @@ -0,0 +1,73 @@ +class Users::QuestionBanksController < Users::BaseController + before_action :check_query_params! + before_action :check_user_permission! + + def index + service = Users::QuestionBankService.new(observed_user, query_params) + question_banks = service.call + + @count = question_banks.count + @course_lists = service.course_lists + @question_banks = paginate(question_banks.includes(:user, :course_list), special: true) + + load_question_banks_solve_count # for solve n + 1 + end + + private + + def load_question_banks_solve_count + question_bank_ids = @question_banks.map(&:id) + @solve_count_map = + case params[:category] + when 'common', 'group' then + StudentWork.where(is_delete: false, work_status: [1, 2, 3]).joins(:homework_common) + .where(homework_commons: { homework_bank_id: question_bank_ids }) + .group('homework_commons.homework_bank_id').count + when 'exercise' then + ExerciseUser.joins(:exercise) + .where(commit_status: 1, exercises: { exercise_bank_id: question_bank_ids }) + .group('exercises.exercise_bank_id').count + when 'poll' then + PollUser.joins(:poll).where(polls: { exercise_bank_id: question_bank_ids }) + .group('polls.exercise_bank_id').count + when 'gtask' then + GraduationWork.has_committed.joins(:graduation_task) + .where(graduation_tasks: { gtask_bank_id: question_bank_ids }) + .group('graduation_tasks.gtask_bank_id').count + when 'gtopic' then + StudentGraduationTopic.joins(:graduation_topic) + .where(gtopic_banks: { gtopic_bank_id: question_bank_ids }).where('status != 0') + .group('gtopic_banks.gtopic_bank_id').count + end + end + + def query_params + params.permit(:type, :category, :course_list_id, :sort_by, :sort_direction) + end + + def check_query_params! + params[:type] = 'personal' if params[:type].blank? || !%w(personal publicly).include?(params[:type]) + + if params[:category].blank? || !%w(common group exercise poll gtask gtopic).include?(params[:category]) + params[:category] = 'common' + end + + if params[:sort_by].blank? || !%w(updated_at name contributor).include?(params[:sort_by]) + params[:sort_by] = 'updated_at' + end + + if params[:sort_direction].blank? || !%w(desc asc).include?(params[:sort_direction]) + params[:sort_direction] = 'desc' + end + end + + def check_user_permission! + return if User.current.admin? || (observed_logged_user? && read_question_bank_permission?) + + render_forbidden + end + + def read_question_bank_permission? + params[:type] == 'personal' ? User.current.is_teacher? : User.current.certification_teacher? + end +end \ No newline at end of file diff --git a/app/controllers/users/shixuns_controller.rb b/app/controllers/users/shixuns_controller.rb new file mode 100644 index 000000000..c4c0d4c07 --- /dev/null +++ b/app/controllers/users/shixuns_controller.rb @@ -0,0 +1,14 @@ +class Users::ShixunsController < Users::BaseController + def index + shixuns = Users::ShixunService.new(observed_user, query_params).call + + @count = shixuns.count + @shixuns = paginate(shixuns.includes(:first_tag_repertoire), special: true) + end + + private + + def query_params + params.permit(:category, :status, :sort_by, :sort_direction) + end +end \ No newline at end of file diff --git a/app/controllers/users/subjects_controller.rb b/app/controllers/users/subjects_controller.rb new file mode 100644 index 000000000..2a4a7975f --- /dev/null +++ b/app/controllers/users/subjects_controller.rb @@ -0,0 +1,14 @@ +class Users::SubjectsController < Users::BaseController + def index + subjects = Users::SubjectService.new(observed_user, query_params).call + + @count = subjects.count + @subjects = paginate(subjects.includes(:user, :repertoire), special: true) + end + + private + + def query_params + params.permit(:category, :status, :sort_direction) + end +end \ No newline at end of file diff --git a/app/controllers/users/watches_controller.rb b/app/controllers/users/watches_controller.rb new file mode 100644 index 000000000..95a0b38cd --- /dev/null +++ b/app/controllers/users/watches_controller.rb @@ -0,0 +1,28 @@ +class Users::WatchesController < Users::BaseController + before_action :require_login + + def create + if observed_logged_user? + render_error('不能关注自己') + return + end + + if current_user.watched?(observed_user) + render_ok + return + end + + current_user.watch!(observed_user) + render_ok + end + + def destroy + unless current_user.watched?(observed_user) + render_ok + return + end + + current_user.unwatch!(observed_user) + render_ok + end +end \ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 000000000..dc68f47c6 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,136 @@ +class UsersController < ApplicationController + + before_action :load_user, only: [:show, :homepage_info] + before_action :check_user_exist, only: [:show, :homepage_info] + + def show;end + + def update + @user = User.find params[:id] + @user.update!(user_params) + render_ok + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + + # 贴吧获取用户信接口 + def get_user_info + begin + @user = current_user + # TODO 等消息上线再打开注释 + #@tidding_count = unviewed_tiddings(current_user) if current_user.present? + @course = + if params[:course_id] + Course.find params[:course_id] + elsif params[:board_id] + Board.find(params[:board_id]).course + elsif params[:graduation_topic_id] + GraduationTopic.find(params[:graduation_topic_id]).course + elsif params[:graduation_group_id] + GraduationGroup.find(params[:graduation_group_id]).course + elsif params[:graduation_work_id] + GraduationWork.find(params[:graduation_work_id]).course + elsif params[:graduation_task_id] + GraduationTask.find(params[:graduation_task_id]).course + elsif params[:poll_id] + Poll.find(params[:poll_id]).course + elsif params[:attachment_id] + Attachment.find(params[:attachment_id]).course + end + @course_identity = current_user.course_identity(@course) if @course + rescue Exception => e + missing_template + end + + end + + def attachment_show + file_name = params[:file_name] + path = params[:path] + send_file "#{path}/#{file_name}", :filename => "#{file_name}", + :type => 'game', + :disposition => 'attachment' #inline can open in browser + end + + # Redo: 消息总数缓存 + def get_navigation_info + @old_domain = edu_setting('old_edu_host') + @user = current_user + # 新消息数 + @new_message = @user.tidings.where("created_at > '#{@user.click_time}'").count > 0 || @user.private_messages.where("created_at > '#{@user.click_time}'").count > 0 + + @user_url = "#{@old_domain}/users/#{@user.login}" + @career = Career.where(status: true).order("created_at asc").pluck(:id, :name) + ec_user = EcSchoolUser.where(:user_id => current_user.id).first + @auth = ec_user ? "#{@old_domain}/ecs/department?school_id=#{ec_user.school_id}" : nil + end + + # 用户回复功能 + def reply_message + @message = JournalsForMessage.new(reply_message_params) + @message.user_id = current_user.id + @message.save! + #normal_status("回复成功") + end + + # 搜索用户具有管理员角色的项目 + def search_user_projects + condition = '%%' + condition = "%#{params[:search].strip}%".gsub(" ","") if !params[:search].blank? + + project_ids = Project.find_by_sql("SELECT p.id FROM projects p, members m, member_roles mr WHERE m.project_id = p.id + AND m.id=mr.member_id AND mr.role_id = 3 AND m.user_id=#{current_user.id} AND p.status != 9 and + p.name like '#{condition}'") + @projects = Project.where(id: project_ids.pluck(:id)) + end + + # 个人主页信息 + def homepage_info;end + + def brief_introduction + content = params[:content].to_s.strip + if content.blank? + render_error('内容不能为空') + return + end + + current_user.user_extension.update!(brief_introduction: content) + + render_ok + end + + def attendance + attendance = Users::AttendanceService.call(current_user) + render_ok(grade: current_user.grade, next_gold: attendance.next_gold) + rescue Users::AttendanceService::Error => ex + render_error(ex.message) + end + + private + def load_user + @user = User.find_by_login(params[:id]) || User.find_by(id: params[:id]) + end + + def user_params + params.require(:user).permit(:nickname, :lastname, :show_realname, + user_extension_attributes: [ + :gender, :location, :location_city, + :occupation, :technical_title, + :school_id, :department_id] + ) + end + + def reply_message_params + normal_status(-1, "参数不对") if params[:journals_for_message][:jour_type].nil? || params[:journals_for_message][:jour_id].nil? || + params[:journals_for_message][:notes].nil? || params[:journals_for_message][:reply_id].nil? + params.require(:journals_for_message).permit(:jour_type, :jour_id, :notes, :m_parent_id, :reply_id) + end + + def check_user_exist + return if @user.present? + render_not_found + end + +end diff --git a/app/controllers/zips_controller.rb b/app/controllers/zips_controller.rb new file mode 100644 index 000000000..89f473499 --- /dev/null +++ b/app/controllers/zips_controller.rb @@ -0,0 +1,76 @@ +class ZipsController < ApplicationController + before_action :require_login + before_action :load_homework, only: [:shixun_report] + before_action :get_exercise, only: [:export_exercises] + + before_action :require_admin_or_teacher + + def shixun_report + student_work_ids = Array.wrap(params[:student_work_ids]) + + service = BatchExportShixunReportService.new(@homework, student_work_ids) + + filename = filename_for_content_disposition(service.filename) + send_file service.zip, filename: filename, type: 'application/zip' + rescue BatchExportShixunReportService::Error => ex + normal_status(-1, ex.message) + end + + def export_exercises + exercises = ExportExercisesService.new(@exercise,@ex_users) + + file_name = filename_for_content_disposition(exercises.filename) + send_file exercises.ex_zip, filename: file_name, type: 'application/zip' + rescue Exception => e + normal_status(-1, e.message) + end + + private + + def filename_for_content_disposition(name) + request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name + end + + def require_admin_or_teacher + return if current_user.teacher_or_admin?(@course) + normal_status(403, '') + end + + def get_exercise + ActiveRecord::Base.transaction do + begin + @exercise = Exercise.find_by(id:params[:exercise_id]) + group_id = params[:exercise_group_id] + if @exercise.blank? + normal_status(-1,"试卷不存在") + else + @course = @exercise.course + + default_ex_users = @exercise.all_exercise_users(current_user.id).exercise_user_committed + default_ex_users_size = default_ex_users.size + @ex_users = default_ex_users #仅导出已提交的,截止后则是全部为提交的。 + #可以分班选择 + if group_id.present? + exercise_students = @course.students.course_find_by_ids("course_group_id",group_id) # 试卷所分班的全部人数 + user_ids = exercise_students.pluck(:user_id).reject(&:blank?) + @ex_users = @ex_users.exercise_commit_users(user_ids) + end + # @ex_users = @ex_users.first(200) + if default_ex_users_size == 0 + normal_status(-1,"导出失败,暂时没有已提交的学生") + elsif default_ex_users_size > 200 + normal_status(-1,"导出数量超过200,请分班导出或联系网站管理员导出") + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("导出失败!") + end + end + end + + def load_homework + @homework = HomeworkCommon.find(params[:homework_common_id]) + @course = @homework.course + end +end diff --git a/app/decorators/course_decorator.rb b/app/decorators/course_decorator.rb new file mode 100644 index 000000000..9c76b058a --- /dev/null +++ b/app/decorators/course_decorator.rb @@ -0,0 +1,5 @@ +module CourseDecorator + def can_visited? + is_public == 1 || User.current.admin? || User.current.member_of_course?(self) + end +end \ No newline at end of file diff --git a/app/decorators/ec_course_target_decorator.rb b/app/decorators/ec_course_target_decorator.rb new file mode 100644 index 000000000..2965a8381 --- /dev/null +++ b/app/decorators/ec_course_target_decorator.rb @@ -0,0 +1,2 @@ +module EcCourseTargetDecorator +end \ No newline at end of file diff --git a/app/decorators/experience_decorator.rb b/app/decorators/experience_decorator.rb new file mode 100644 index 000000000..f50f479d7 --- /dev/null +++ b/app/decorators/experience_decorator.rb @@ -0,0 +1,16 @@ +module ExperienceDecorator + def container_type_text + I18n.t("experience.container_type.#{container_type.to_s.underscore}") + end + + def content + case container_type.to_s.underscore + when 'game' then + game = Game.find_by(id: container_id) + game.present? ? "通过实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关获得的奖励" : '' + when 'shixun_publish' then + shixun = Shixun.find_by(id: container_id) + shixun.present? ? "发布实训“#{shixun.name}”获得的奖励" : '' + end + end +end \ No newline at end of file diff --git a/app/decorators/grade_decorator.rb b/app/decorators/grade_decorator.rb new file mode 100644 index 000000000..ffffa11c9 --- /dev/null +++ b/app/decorators/grade_decorator.rb @@ -0,0 +1,36 @@ +module GradeDecorator + def container_type_text + I18n.t("grade.container_type.#{container_type.to_s.underscore}") + end + + def content + case container_type.to_s.underscore + when 'avatar' then '用户首次上传头像获得的奖励' + when 'phone' then '用户首次绑定手机号码获得的奖励' + when 'mail' then '用户首次绑定邮箱获得的奖励' + when 'attendance' then '用户每天签到获得的奖励' + when 'account' then '新用户首次填写基本资料获得的奖励' + when 'memo' then '发布的评论或者帖子获得平台奖励' + when 'discusses' then '发布的评论获得平台奖励' + when 'star' then '用户给实训评分获得的随机奖励' + when 'feedback' then '反馈的问题获得平台奖励' + when 'authentication' then '用户首次完成实名认证获得的奖励' + when 'professional' then '用户首次完成职业认证获得的奖励' + when 'answer' then + game = Game.find_by(id: container_id) + game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的参考答案消耗的金币" : '' + when 'game' then + game = Game.find_by(id: container_id) + game.present? ? "通过实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关获得的奖励" : '' + when 'test_set' then + game = Game.find_by(id: container_id) + game.present? ? "查看实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关的隐藏测试集消耗的金币" : '' + when 'shixun_publish' then + shixun = Shixun.find_by(id: container_id) + shixun.present? ? "发布实训“#{shixun.name}”获得的奖励" : '' + when 'check_ta_answer' then + game = Game.find_by(id: container_id) + game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的TA人解答消耗的金币" : '' + end + end +end \ No newline at end of file diff --git a/app/decorators/project_decorator.rb b/app/decorators/project_decorator.rb new file mode 100644 index 000000000..9cde1311e --- /dev/null +++ b/app/decorators/project_decorator.rb @@ -0,0 +1,5 @@ +module ProjectDecorator + def can_visited? + is_public? || User.current.admin? || member?(User.current) + end +end diff --git a/app/decorators/shixun_decorator.rb b/app/decorators/shixun_decorator.rb new file mode 100644 index 000000000..50e2e27eb --- /dev/null +++ b/app/decorators/shixun_decorator.rb @@ -0,0 +1,9 @@ +module ShixunDecorator + def finished_challenges_count(user) + Game.joins(:myshixun).where(user_id: user.id, status: 2, myshixuns: { shixun_id: id }).count + end + + def human_status + I18n.t("shixun.status.#{status}") + end +end diff --git a/app/decorators/subject_decorator.rb b/app/decorators/subject_decorator.rb new file mode 100644 index 000000000..7ba3277f7 --- /dev/null +++ b/app/decorators/subject_decorator.rb @@ -0,0 +1,5 @@ +module SubjectDecorator + def can_visited? + published? || User.current.admin? || member?(User.current) + end +end \ No newline at end of file diff --git a/app/decorators/tiding_decorator.rb b/app/decorators/tiding_decorator.rb new file mode 100644 index 000000000..a9faeae84 --- /dev/null +++ b/app/decorators/tiding_decorator.rb @@ -0,0 +1,343 @@ +module TidingDecorator + def content + method_name = "#{container_type.underscore}_content" + respond_to?(method_name) ? send(method_name) : '' + end + + def how_long_time + time_from_now(created_at) + end + + # 组装国际化路径:locale_format('Apply', 1) ==> tiding.ApplyUserAuthentication.Apply.1_end + def locale_format(*arr) + arr.unshift("tiding.#{container_type}").join('.') << '_end' + end + + def message_content_helper(msg) + msg = (strip_html msg).strip + msg = msg.gsub(/\s+/, ' ') + if msg.gsub(' ', '') == '' + msg = "[非文本消息]" + end + msg + end + + def strip_html(text, len = 0, suffix = "...") + str = "" + if !text.nil? && text.length > 0 + str = text.gsub(/<\/?.*?>/, '').strip + str = str.gsub(/ */, ' ') + + if len > 0 && str.length > len + str = str[0, len] + suffix + elsif len > 0 && str.length <= len + str = str + end + end + str + end + + # ================ 各种类消息内容方法 ================ + def apply_user_authentication_content + return if trigger_user_id.zero? + + if tiding_type == 'Apply' + str1, str2 = if container.auth_type == 1 + [trigger_user.show_real_name, trigger_user.ID_number] + elsif container.auth_type == 2 + ue = trigger_user.user_extension + [[ue.school&.name, ue.department&.name].join('_'), ue.identity_text] + end + I18n.t(locale_format(tiding_type, container.auth_type)) % [str1, str2] + elsif tiding_type == 'System' + I18n.t(locale_format(tiding_type, "#{container.auth_type}_#{status}"), reason: container.try(:remarks)) + end + end + + def cancel_user_authentication_content + I18n.t(locale_format) % [user.show_real_name, user.ID_number] + end + + def cancel_user_pro_certification_content + ue = user.user_extension + I18n.t(locale_format) % [[ue.school&.name, ue.department&.name].join('_'), ue.identity_text] + end + + def join_course_content + I18n.t(locale_format(extra)) % Course.find_by(id: container_id)&.name + end + + def deal_course_content + name = Course.find_by(id: container_id)&.name + I18n.t(locale_format("#{extra}_#{status}")) % name + end + + def student_join_course_content + I18n.t(locale_format) % Course.find_by(id: container_id)&.name + end + + def teacher_join_course_content + name = Course.find_by(id: container_id)&.name + I18n.t(locale_format extra) % [user.show_real_name, name] + end + + def apply_add_department_content + name = container.name + second_name = School.find_by_id(container.school_id).try(:name) + if tiding_type == 'Apply' + I18n.t(locale_format(tiding_type)) % [name, second_name] + elsif status == 2 + I18n.t(locale_format(tiding_type, "#{status}_#{extra.nil?}"), reason: extra) % [name, second_name] + else + I18n.t(locale_format(tiding_type, status)) % [name, second_name] + end + end + + def apply_add_schools_content + name = container.name + if tiding_type == 'Apply' + I18n.t(locale_format(tiding_type)) % name + elsif status == 2 + I18n.t(locale_format(tiding_type, "#{status}_#{extra.nil?}"), reason: extra) % name + else + I18n.t(locale_format(tiding_type, status)) % name + end + end + + def apply_action_content + name = case parent_container_type + when 'ApplyShixun' then Shixun.find_by(id: parent_container_id)&.name + when 'ApplySubject' then Subject.find_by(id: parent_container_id)&.name + when 'TrialAuthorization' then nil + end + + if tiding_type == 'System' + I18n.t(locale_format(parent_container_type, tiding_type, status), name: name, reason: container.try(:reason)) + elsif tiding_type == 'Apply' + I18n.t(locale_format(parent_container_type, tiding_type), name: name) + end + end + + def course_content + I18n.t(locale_format) % container.name + end + + def shixun_content + I18n.t(locale_format) % container.name + end + + def subject_content + I18n.t(locale_format) % container.name + end + + def archive_course_content + I18n.t(locale_format) % Course.find_by(id: container_id)&.name + end + + def journals_for_message_content + format_str = + if tiding_type == 'Mentioned' + locale_format(tiding_type) + elsif parent_container_type == 'Principal' + if container.m_parent_id.present? + locale_format(parent_container_type, "#{container.m_parent_id.present?}_#{container.parent.try(:m_parent_id).present?}") + else + locale_format(parent_container_type, "#{container.m_parent_id.present?}_#{container.private.zero?}") + end + else + locale_format(parent_container_type, container.m_parent_id.present?) + end + + I18n.t(format_str) % message_content_helper(container.notes) + end + + def message_content + if tiding_type == 'Mentioned' + I18n.t(locale_format(tiding_type)) % message_content_helper(container.content) + elsif container.parent.present? + format_str = locale_format("#{true}_#{container.parent_id == container.root_id}") + I18n.t(format_str) % message_content_helper(container.content) + else + I18n.t(locale_format(false)) % message_content_helper(container.subject) + end + end + + def memo_content + if tiding_type == 'Mentioned' + I18n.t(locale_format(tiding_type)) % message_content_helper(container.content) + elsif container.parent.present? + format_str = locale_format("#{true}_#{container.parent_id == container.root_id}") + I18n.t(format_str) % message_content_helper(container.content) + else + I18n.t(locale_format(false)) % message_content_helper(container.subject) + end + end + + def watcher_content + I18n.t(locale_format) + end + + def praise_tread_content + case parent_container_type + when 'Challenge' then + if container + format_str = I18n.t(locale_format(parent_container_type, container.praise_or_tread)) + format_str % [parent_container.shixun.name, parent_container.position] + end + when 'Memo', 'Message' then + message = parent_container.parent_id.present? ? message_content_helper(parent_container.content) : parent_container.subject + I18n.t(locale_format(parent_container_type, parent_container.parent_id.present?)) % message + when 'HomeworkCommon' then + I18n.t(locale_format(parent_container_type)) % parent_container.name + when 'JournalsForMessage' then + i18n_url = locale_format(parent_container_type, parent_container.jour_type == 'Principal' && parent_container.m_parent_id.blank?) + I18n.t(i18n_url) % message_content_helper(parent_container.notes) + when 'Discuss' then + I18n.t(locale_format(parent_container_type)) % message_content_helper(parent_container.content) + when 'Issue' then + I18n.t(locale_format(parent_container_type)) % parent_container.subject + when 'Journal' then + message = object.notes.present? ? ':' + message_content_helper(parent_container.notes) : '' + I18n.t(locale_format(parent_container_type)) % message + end + end + + def discuss_content + I18n.t(locale_format(container.parent_id.present?)) % message_content_helper(container.content) + end + + def grade_content + case parent_container_type + when 'Answer' then + game = Game.find_by(id: parent_container_id) + if game.present? + format_str = I18n.t(locale_format(parent_container_type, true)) + format_str % [game.challenge.shixun.name, game.challenge.position, container.score] + else + # 之所以这样处理,是因为消息的类型是不能和实体绑定,没有关联删除 + I18n.t(locale_format(parent_container_type, false)) % container.score + end + when 'Game' then + game = Game.find_by(id: parent_container_id) + if game.present? + format_str = I18n.t(locale_format(parent_container_type)) + format_str % [game.challenge.shixun.name, game.challenge.position, container.score] + end + when 'testSet' then + position = Game.find_by(id: parent_container_id)&.challenge&.position || '--' + I18n.t(locale_format(parent_container_type)) % [position, container.score] + when 'shixunPublish' then + name = Shixun.find_by(id: parent_container_id)&.name || '---' + I18n.t(locale_format(parent_container_type)) % [name, container.score] + else + I18n.t(locale_format(parent_container_type)) % container.score + end + end + + def join_project_content + project = Project.find_by(id: container_id) + I18n.t(locale_format(extra)) % project.name + end + + def deal_project_content + project = Project.find_by(id: container_id) + I18n.t(locale_format("#{extra}_#{status}")) % project.name + end + + def manager_join_project_content + project = Project.find_by(id: container_id) + I18n.t(locale_format(extra)) % [user&.show_real_name, project.name] + end + + def reporter_join_project_content + project = Project.find_by(id: container_id) + I18n.t(locale_format) % project.name + end + + def journal_content + case tiding_type + when 'Mentioned' then + I18n.t(locale_format(tiding_type)) % message_content_helper(container.notes) + when 'Comment' then + I18n.t(locale_format(tiding_type, container.parent.present?)) % message_content_helper(container.notes) + else + I18n.t(locale_format) % container.issue.subject + end + end + + def issue_content + I18n.t(locale_format) % container.subject + end + + def pull_request_content + if tiding_type == 'Apply' + I18n.t(locale_format(tiding_type)) % container.try(:title) + else + I18n.t(locale_format(status)) % container.try(:title) + end + end + + def send_message_content + data = (JSON.parse(extra) rescue extra) + if data.is_a?(String) + I18n.t(locale_format('old')) % extra + else + I18n.t(locale_format('new')) % [data['language'], data['runtime'], data['run_method']] + end + end + + def poll_content + I18n.t(locale_format(parent_container_type)) % container.polls_name + end + + def exercise_content + I18n.t(locale_format(parent_container_type)) % container.exercise_name + end + + def student_graduation_topic_content + I18n.t(locale_format) % container.graduation_topic.try(:name) + end + + def deal_student_topic_select_content + I18n.t(locale_format(status)) % GraduationTopic.find_by(id: parent_container_id).try(:name) + end + + def graduation_task_content + I18n.t(locale_format(parent_container_type)) % container.name + end + + def graduation_work_content + I18n.t(locale_format(extra.nil?)) % container.graduation_task.try(:name) + end + + def graduation_work_score_content + I18n.t(locale_format) % container.graduation_work.graduation_task.try(:name) + end + + def homework_common_content + I18n.t(locale_format(parent_container_type), name: container.name, reason: extra) + end + + def student_work_content + I18n.t(locale_format(extra.nil?)) % container.homework_common.try(:name) + end + + def student_works_score_content + I18n.t(locale_format(extra)) % container.student_work.homework_common.try(:name) + end + + def challenge_work_score_content + work = StudentWork.find_by(id: parent_container_id) + return if work.blank? + + if parent_container_type == 'StudentWork' + I18n.t(locale_format(parent_container_type, tiding_type)) % work.homework_common.try(:name) + elsif parent_container_type == 'UserAppealResult' || parent_container_type == 'AppealResult' + I18n.t(locale_format(parent_container_type, status)) % work.homework_common.try(:name) + end + end + + def department_content + I18n.t(locale_format) % [container.try(:name), container.try(:school)&.name] + end +end diff --git a/app/decorators/user_decorator.rb b/app/decorators/user_decorator.rb new file mode 100644 index 000000000..0ee9a4b43 --- /dev/null +++ b/app/decorators/user_decorator.rb @@ -0,0 +1,89 @@ +module UserDecorator + def logged_user? + User.current.id == id + end + + def name + [lastname, firstname].join('') + end + + # ---------- homepage helper --------- + def homepage_name + logged_user? ? real_name : full_name + end + + # 关注数 + def follow_count + User.watched_by(id).count + end + + # 粉丝数 + def fan_count + watchers.count + end + + # 是否绑定邮箱 + def email_binded? + mail.present? + end + + # 学院的url标识 + def college_identifier + + Department.find_by_id(department_members.pluck(:department_id).first)&.identifier + end + + # 是否能申请试用 + def can_apply_trial? + return false if certification == 1 + + apply = ApplyAction.order(created_at: :desc).find_by(user_id: id, container_type: 'TrialAuthorization') + + apply && !apply.status.zero? + end + + # 是否已经签到 + def attendance_signed? + attendance = Attendance.find_by(user_id: id) + + attendance && Util.days_between(Time.zone.now, attendance.created_at).zero? + end + + # 明日签到金币 + def tomorrow_attendance_gold + Attendance.find_by(user_id: id)&.next_gold + end + + # ----------- 账号管理 ------------- + def authentication_status + if authentication? + 'certified' + elsif process_real_name_apply.present? + 'applying' + else + 'uncertified' + end + end + + def professional_certification_status + if professional_certification? + 'certified' + elsif process_professional_apply.present? + 'applying' + else + 'uncertified' + end + end + + def base_info_completed? + user_columns = %i[nickname lastname] + user_extension_columns = %i[gender location location_city identity school_id department] + + user_columns.all? { |column| public_send(column).present? } && + user_extension_columns.all? { |column| user_extension.send(column).present? } + end + + def all_certified? + authentication? && professional_certification? + end +end \ No newline at end of file diff --git a/app/forms/apply_shixun_mirror_form.rb b/app/forms/apply_shixun_mirror_form.rb new file mode 100644 index 000000000..4f6b738e2 --- /dev/null +++ b/app/forms/apply_shixun_mirror_form.rb @@ -0,0 +1,27 @@ +class ApplyShixunMirrorForm + include ActiveModel::Model + + attr_accessor :language, :runtime, :run_method, :attachment_id + + validates :language, presence: true + validates :runtime, presence: true + validates :run_method, presence: true + validates :attachment_id, presence: true, numericality: { only_integer: true } + + validate :ensure_attachment_presence + def ensure_attachment_presence + return unless attachment_id + + if attachment.blank? + errors.add(:attachment_id, :attachment_not_exist) + end + end + + def attachment + @attachment ||= Attachment.find_by_id(attachment_id) + end + + def to_json + { language: language, runtime: runtime, run_method: run_method, attachment_id: attachment_id }.to_json + end +end \ No newline at end of file diff --git a/app/forms/ecs/create_course_achievement_methods_form.rb b/app/forms/ecs/create_course_achievement_methods_form.rb new file mode 100644 index 000000000..2c9ceb3c9 --- /dev/null +++ b/app/forms/ecs/create_course_achievement_methods_form.rb @@ -0,0 +1,48 @@ +class Ecs::CreateCourseAchievementMethodsForm + include ActiveModel::Model + + attr_accessor :ec_course, :course_achievement_methods + + validates :course_achievement_methods, presence: true + + validate :check_total_percentage + def check_total_percentage + total_percentage = course_achievement_methods.sum { |item| item[:percentage].to_i } + if total_percentage > 100 || total_percentage < 0 + errors.add(:course_achievement_methods, :percentage_error) + end + end + + def validate! + super + return unless errors.blank? + course_achievement_methods.each { |item| SubForm.new(item.merge(ec_course: ec_course)).validate! } + end + + class SubForm + include ActiveModel::Model + + attr_accessor :ec_course + attr_accessor :id, :course_evaluation_id, :course_evaluation_subitem_ids, :score, :percentage + + validates :course_evaluation_id, presence: true + validates :course_evaluation_subitem_ids, presence: true + validates :score, presence: true, numericality: { only_integer: true } + validates :percentage, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 } + + validate :check_course_evaluation_id_valid + def check_course_evaluation_id_valid + return if ec_course.ec_course_evaluations.exists?(id: course_evaluation_id) + + errors.add(:course_evaluation_id, :record_not_exist) + end + + validate :check_course_evaluation_subitem_ids_valid + def check_course_evaluation_subitem_ids_valid + relations = ec_course.ec_course_evaluation_subitems.where(id: course_evaluation_subitem_ids) + return if relations.count == course_evaluation_subitem_ids.size + + errors.add(:course_evaluation_subitem_ids, :record_not_exist) + end + end +end diff --git a/app/forms/ecs/save_course_evaluation_form.rb b/app/forms/ecs/save_course_evaluation_form.rb new file mode 100644 index 000000000..4e4c4982b --- /dev/null +++ b/app/forms/ecs/save_course_evaluation_form.rb @@ -0,0 +1,22 @@ +class Ecs::SaveCourseEvaluationForm + include ActiveModel::Model + + attr_accessor :name, :evaluation_count, :status, :course_evaluation_subitems + + validates :name, presence: true + validates :evaluation_count, presence: true, numericality: { only_integer: true } + validates :status, presence: true, inclusion: { in: %w[partly totality] } + + validate :course_evaluation_subitems_validate + def course_evaluation_subitems_validate + if course_evaluation_subitems.blank? + errors.add(:course_evaluation_subitems, :blank) + return + end + + if course_evaluation_subitems.any? { |item| item[:name].blank? } + errors.add(:course_evaluation_subitems, :name_blank) + return + end + end +end diff --git a/app/forms/ecs/save_graduation_course_support_form.rb b/app/forms/ecs/save_graduation_course_support_form.rb new file mode 100644 index 000000000..75081fb21 --- /dev/null +++ b/app/forms/ecs/save_graduation_course_support_form.rb @@ -0,0 +1,25 @@ +class Ecs::SaveGraduationCourseSupportForm + include ActiveModel::Model + + attr_accessor :course_supports + + validates :course_supports, presence: true + + validate :check_course_support_unique + def check_course_support_unique + uniq_size = course_supports.map { |support| support[:ec_course_id].to_i }.uniq.size + + if uniq_size != course_supports.size + errors.add(:course_supports, :not_unique) + end + end + + validate :check_weight_total + def check_weight_total + total = course_supports.sum { |item| item[:weights].to_f } + + if total > 1 + errors.add(:course_supports, :weights_too_big) + end + end +end diff --git a/app/forms/users/apply_trail_form.rb b/app/forms/users/apply_trail_form.rb new file mode 100644 index 000000000..14da21d0d --- /dev/null +++ b/app/forms/users/apply_trail_form.rb @@ -0,0 +1,16 @@ +class Users::ApplyTrailForm + include ActiveModel::Model + + attr_accessor :user, :phone, :code, :reason + + validates :reason, presence: true + validates :phone, presence: true, format: { with: CustomRegexp::PHONE }, unless: -> { user.phone_binded? } + validates :code, presence: true, unless: -> { user.phone_binded? } + + validate :check_user_certification + def check_user_certification + return if user.certification != 1 + + errors.add(:user, :already_trial) + end +end \ No newline at end of file diff --git a/app/forms/users/bind_email_form.rb b/app/forms/users/bind_email_form.rb new file mode 100644 index 000000000..2972430fb --- /dev/null +++ b/app/forms/users/bind_email_form.rb @@ -0,0 +1,8 @@ +class Users::BindEmailForm + include ActiveModel::Model + + attr_accessor :email, :code + + validates :email, presence: true#, format: { with: CustomRegexp::EMAIL } + validates :code, presence: true +end \ No newline at end of file diff --git a/app/forms/users/bind_phone_form.rb b/app/forms/users/bind_phone_form.rb new file mode 100644 index 000000000..46cec2d86 --- /dev/null +++ b/app/forms/users/bind_phone_form.rb @@ -0,0 +1,8 @@ +class Users::BindPhoneForm + include ActiveModel::Model + + attr_accessor :phone, :code + + validates :phone, presence: true, format: { with: CustomRegexp::PHONE } + validates :code, presence: true +end \ No newline at end of file diff --git a/app/forms/users/update_account_form.rb b/app/forms/users/update_account_form.rb new file mode 100644 index 000000000..68e7fb7bf --- /dev/null +++ b/app/forms/users/update_account_form.rb @@ -0,0 +1,33 @@ +class Users::UpdateAccountForm + include ActiveModel::Model + + attr_accessor :user + attr_accessor :nickname, :name, :show_realname, :gender, :location, :location_city, + :identity, :student_id, :technical_title, :school_id, :department_id + + validates :nickname, presence: true + validates :name, presence: true + validates :gender, presence: true, numericality: { only_integer: true }, inclusion: { in: [0, 1] } + validates :location, presence: true + validates :location_city, presence: true + validates :identity, presence: true, numericality: { only_integer: true }, inclusion: { in: [0, 1, 2] } + validates :technical_title, presence: true, unless: -> { identity == 1 } + validates :student_id, presence: true, if: -> { identity == 1 } + validates :school_id, presence: true + + validate :check_school_exist + def check_school_exist + return if school_id.blank? + unless School.exists?(id: school_id) + errors.add(:school_id, :not_exist) + end + end + + validate :check_department_exist + def check_department_exist + return if department_id.blank? + unless Department.exists?(id: department_id) + errors.add(:department_id, :not_exist) + end + end +end \ No newline at end of file diff --git a/app/forms/users/update_password_form.rb b/app/forms/users/update_password_form.rb new file mode 100644 index 000000000..023caa40f --- /dev/null +++ b/app/forms/users/update_password_form.rb @@ -0,0 +1,8 @@ +class Users::UpdatePasswordForm + include ActiveModel::Model + + attr_accessor :password, :old_password + + validates :password, presence: true + validates :old_password, presence: true +end \ No newline at end of file diff --git a/app/forms/validate/user.rb b/app/forms/validate/user.rb new file mode 100644 index 000000000..0f8f5e9ba --- /dev/null +++ b/app/forms/validate/user.rb @@ -0,0 +1,10 @@ +module Validate + class User + include ActiveModel::Model + + attr_accessor :nickname, :lastname + + validates :nickname, presence: true, length: { maximum: 10 } + validates :lastname, presence: true + end +end diff --git a/app/forms/validate/user_extension.rb b/app/forms/validate/user_extension.rb new file mode 100644 index 000000000..f302abb2c --- /dev/null +++ b/app/forms/validate/user_extension.rb @@ -0,0 +1,9 @@ +module Validate + class UserExtension + include ActiveModel::Model + attr_accessor :location + + validates :location, presence: true + + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 000000000..ac50e78d3 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,337 @@ +# 所有的方法请按首字母的顺序依次列出 +module ApplicationHelper + include Educoder::I18n + + ONE_MINUTE = 60 * 1000 + ONE_HOUR = 60 * ONE_MINUTE + ONE_DAY = 24 * ONE_HOUR + ONE_MONTH = 30 * ONE_DAY + + ONE_YEAR = 12 * ONE_MONTH + + # 全局参数配置 + def edu_setting name + EduSetting.find_by_name(name).try(:value) + end + + def graduation_navigation graduation + graduation.class.to_s == "GraduationTopic" ? "毕设选题" : "毕设任务" + end + + def graduation_navigation_id course + course.course_modules.find_by(module_type: "graduation").try(:id) + end + + # 是否关注 + # from_user_id为被关注的用户 + def follow?(from_user_id, user_id) + Watcher.where(watchable_type: 'Principal', watchable_id: from_user_id, user_id: user_id).exists? + end + + # git用户 + def git_username(email) + User.find_by_mail(email) + end + + # 不同的类型扩展不同的目录 + def relative_path + "avatars" + end + + def storage_path + File.join(Rails.root, "public", "images", relative_path) + end + + # 推荐实训 + def recommend_shixun(shixun) + tag_repertoire_id = shixun.tag_repertoires.first.present? ? shixun.tag_repertoires.first.try(:id) : 0 + shixun_id = ShixunTagRepertoire.where("tag_repertoire_id = #{tag_repertoire_id} and + shixun_id != #{shixun.id}").pluck(:shixun_id) + + shixun_id = shixun_id.blank? ? -1 : shixun_id.join(",") + Shixun.select([:id, :name, :user_id, :challenges_count, :myshixuns_count, :trainee, :identifier]).where("id + in(#{shixun_id}) or homepage_show =1").unhidden.order("myshixuns_count desc, homepage_show asc").limit(3) + end + + # 相关推荐 + def relation_path(shixun) + shixun.subjects.where(hidden: 0).limit(2) + end + + # shixun开启挑战对应的行为名及url + def task_operation_url current_myshixun, shixun + url = "/shixuns/#{shixun.identifier}/shixun_exec" + name = + if current_myshixun.blank? + shixun.status == 0 ? "模拟实战" : "开启挑战" + elsif current_myshixun.status == 1 + "查看实战" + else + "继续挑战" + end + [name, url] + end + + # 获取当前时间 + def time_from_now(time) + if String === time + time = Time.parse(time) + end + + lastUpdateTime = time.to_i*1000 + + currentTime = Time.now.to_i*1000 + timePassed = currentTime - lastUpdateTime + timeIntoFormat = 0 + updateAtValue = "" + if timePassed < 0 + updateAtValue = "刚刚" + elsif timePassed < ONE_MINUTE + updateAtValue = "1分钟前" + elsif timePassed < ONE_HOUR + timeIntoFormat = timePassed / ONE_MINUTE + updateAtValue = timeIntoFormat.to_s + "分钟前" + elsif (timePassed < ONE_DAY) + timeIntoFormat = timePassed / ONE_HOUR + updateAtValue = timeIntoFormat.to_s + "小时前" + elsif (timePassed < ONE_MONTH) + timeIntoFormat = timePassed / ONE_DAY + updateAtValue = timeIntoFormat.to_s + "天前" + elsif (timePassed < ONE_YEAR) + timeIntoFormat = timePassed / ONE_MONTH + updateAtValue = timeIntoFormat.to_s + "个月前" + else + timeIntoFormat = timePassed / ONE_YEAR + updateAtValue = timeIntoFormat.to_s + "年前" + end + updateAtValue + end + + # 计算到结束还有多长时间 **天**小时**分 + def how_much_time(time) + if time.nil? + '' + else + result = ((time - Time.now.to_i).to_i / (24*60*60)).to_s + " 天 " + result += (((time - Time.now.to_i).to_i % (24*60*60)) / (60*60)).to_s + " 小时 " + result + ((((time - Time.now.to_i).to_i % (24*60*60)) % (60*60)) / 60).to_s + " 分 " + end + end + + def format_time(time) + time.present? ? time.strftime("%Y-%m-%d %H:%M") : '' + end + + # 用户图像url,如果不存在的话,source为匿名用户,即默认使用匿名用户图像 + def url_to_avatar(source) + if File.exist?(disk_filename(source.class, source.id)) + if source.class.to_s == 'User' + File.join(relative_path, ["#{source.class}", "#{source.id}"]) + else + File.join("/images/avatars", ["#{source.class}", "#{source.id}"]) + end + elsif source.class.to_s == 'User' + str = source.user_extension.try(:gender).to_i == 0 ? "b" : "g" + File.join(relative_path, "#{source.class}", str) + elsif source.class.to_s == 'Subject' + File.join("images","educoder", "index", "subject", "subject#{rand(17)}.jpg") + elsif source.class.to_s == 'Shixun' + File.join("images","educoder", "index", "shixun", "shixun#{rand(23)}.jpg") + end + end + + def disk_filename(source_type,source_id,image_file=nil) + File.join(storage_path, "#{source_type}", "#{source_id}") + end + + def shixun_url_to_avatar(shixun) + if File.exist?(disk_filename(shixun.class, shixun.id)) + File.join("/images/#{relative_path}", "#{shixun.class}", "#{shixun.id}") + else + File.join("educoder", "index", "shixun", "shixun#{rand(23)}.jpg") + end + end + + # 选用实训的学校情况 + def school_user_detail shixun + school_ids = shixun.myshixuns.joins("join user_extensions ue on myshixuns.user_id=ue.user_id").pluck(:school_id).uniq + school_names = School.where(id: school_ids[0..1]).pluck(:name) + school_size = school_ids.size + str = school_size > 0 ? "#{school_names.join("、")}等 #{school_size}所" : "0所" + end + + # 普通/分组 作业作品状态数组 + def student_work_status homework, user_id, course, work + status = [] + homework_setting = homework.homework_group_setting user_id + work = work || StudentWork.create(homework_common_id: homework.id, user_id: user_id) + late_time = homework.late_time || course.end_date + + if course.is_end && work && work.work_status > 0 + status << "查看作品" + elsif !course.is_end + if homework_setting.publish_time && homework_setting.publish_time < Time.now + # 作业未截止时 + if homework_setting.end_time > Time.now + if homework.homework_type == "group" && homework.homework_detail_group.base_on_project + if work.project_id.nil? || work.project_id == 0 + status << "创建项目" + status << "关联项目" + elsif work.work_status == 0 + status << "取消关联" + status << "提交作品" + else + status << "修改作品" + end + else + if work.work_status == 0 + status << "提交作品" + else + status << "修改作品" + end + end + + # 补交阶段 + elsif homework.allow_late && (late_time.nil? || late_time > Time.now) + if homework.homework_type == "group" && homework.homework_detail_group.base_on_project + if work.project_id.nil? || work.project_id == 0 + status << "创建项目" + status << "关联项目" + elsif work.work_status == 0 + status << "取消关联" + status << "补交作品" + else + status << "补交附件" + status << "查看作品" + end + else + if work.work_status == 0 + status << "补交作品" + else + status << "补交附件" + status << "查看作品" + end + end + + # 匿评阶段 + elsif work.work_status != 0 + if homework.homework_detail_manual.comment_status == 3 + work_ids = homework.student_works.has_committed.pluck(:id) + if StudentWorksEvaluationDistribution.where(student_work_id: work_ids, user_id: user_id).size > 0 + status << "匿评作品" + end + end + status << "查看作品" + end + end + end + end + + def commit_des_status work, homework + status = [] + homework_setting = homework.homework_group_setting work.user_id + + # 作业已发布且作业未截止(补交未截止)且提交了作品才能提交或修改总结 + if homework_setting.publish_time && homework_setting.publish_time < Time.now && work.work_status > 0 && + ((homework_setting.end_time && homework_setting.end_time > Time.now) || + (homework.allow_late && homework.late_time && homework.late_time > Time.now)) + work.description.present? ? status << "修改总结" : status << "提交总结" + end + end + + def download_url attachment + attachment_path(attachment) + end + + # 耗时:天、小时、分、秒 + # 小于1分钟则不显示 + def game_spend_time time + day = time / 86400 + hour = time % (24*60*60) / (60*60) + min = time % (24*60*60) % (60*60) / 60 + sec = time % (24*60*60) % (60*60) % 60 + if day < 1 + if hour < 1 + if min < 1 + if sec < 1 + time = "--" + else + time = "#{sec}秒" + end + else + time = "#{min}分钟 #{sec}秒" + end + else + time = "#{hour}小时 #{min}分钟 #{sec}秒" + end + else + time = "#{day}天 #{hour}小时 #{min}分钟 #{sec}秒" + end + return time + end + + def absolute_path(file_path) + File.join(edu_setting('attachment_folder'), file_path) + end + + def local_path(file) + File.join(file.disk_directory, file.disk_filename) + end + + def update_downloads(file) + file.update_attributes(:downloads => file.downloads + 1) + end + + # 项目信息, + def project_info work, current_user, course_identity + project = work.project + if project + if project.status == 9 + {id: -1, name: "#{project.name}(已删除)", title: "该项目已删除", author: project.creator, member_count: project.project_members.count} + else + project_score = project.project_score + if project.is_public || current_user.manager_of_project?(project) || course_identity < Course::STUDENT + {id: project.id, name: project.name, author: project.creator, member_count: project.project_members.count, + all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, + attachment_score: project_score.attachment_score, message_score: project_score.message_score} + else + {id: -1, name: "#{project.name}", title: "该项目是私有的", author: project.creator, member_count: project.project_members.count, + all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, + attachment_score: project_score.attachment_score, message_score: project_score.message_score} + end + end + else + {id: -1, name: "--", title: "--"} + end + end + + def message_content(content) + content = (strip_html content).strip + content = content.gsub(/\s+/, " ") + if content.gsub(" ", "") == "" + content = "[非文本消息]" + end + content + end + + def strip_export_title(content) + con_ = "" + if content.length > 0 + con_ = strip_tags(content) + con_ = con_.gsub(/\r\n/,'').gsub(/ */, '').strip + end + con_ + end + + def pdf_load_sources(*arg) + arr = arg.map do |path| + content_tag(:script) do + File.open(Rails.root.join('public', path)).read.to_s.html_safe + end + end + + raw arr.join('') + end +end + + diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb new file mode 100644 index 000000000..e66bdaf6b --- /dev/null +++ b/app/helpers/boards_helper.rb @@ -0,0 +1,2 @@ +module BoardsHelper +end diff --git a/app/helpers/challenges_helper.rb b/app/helpers/challenges_helper.rb new file mode 100644 index 000000000..c6d05817d --- /dev/null +++ b/app/helpers/challenges_helper.rb @@ -0,0 +1,7 @@ +module ChallengesHelper + + def match_begin_symbol str + str.gsub(/\A\r/, "\r\r") + end + +end diff --git a/app/helpers/course_groups_helper.rb b/app/helpers/course_groups_helper.rb new file mode 100644 index 000000000..061c39dd5 --- /dev/null +++ b/app/helpers/course_groups_helper.rb @@ -0,0 +1,2 @@ +module CourseGroupsHelper +end diff --git a/app/helpers/course_modules_helper.rb b/app/helpers/course_modules_helper.rb new file mode 100644 index 000000000..4de7a3826 --- /dev/null +++ b/app/helpers/course_modules_helper.rb @@ -0,0 +1,2 @@ +module CourseModulesHelper +end diff --git a/app/helpers/course_second_categories_helper.rb b/app/helpers/course_second_categories_helper.rb new file mode 100644 index 000000000..7ed9aa1e9 --- /dev/null +++ b/app/helpers/course_second_categories_helper.rb @@ -0,0 +1,2 @@ +module CourseSecondCategoriesHelper +end diff --git a/app/helpers/courses_helper.rb b/app/helpers/courses_helper.rb new file mode 100644 index 000000000..8c88f02d0 --- /dev/null +++ b/app/helpers/courses_helper.rb @@ -0,0 +1,260 @@ +module CoursesHelper + + # 是否有切换为学生的入口 + def switch_student_role is_teacher, course, user + is_teacher && course.course_members.where(user_id: user.id, role: %i(STUDENT)).exists? + end + + # 是否有切换为教师的入口 + def switch_teacher_role is_student, course, user + is_student && course.course_members.where(user_id: user.id, role: %i(CREATOR PROFESSOR)).exists? + end + + # 是否有切换为助教的入口 + def switch_assistant_role is_student, course, user + is_student && course.course_members.where(user_id: user.id, role: %i(ASSISTANT_PROFESSOR)).exists? + end + + # 课堂结束天数 + def course_end_date end_date + if end_date.present? + curr = Time.new + date = ((Date.parse(end_date.to_s) - Date.parse(curr.to_s)).to_i) + date > 0 ? "#{date}天后" : "" + end + end + + # 课堂模块的url + def module_url mod, course + return nil if mod.blank? or course.blank? + case mod.module_type + when "shixun_homework" + "/courses/#{course.id}/shixun_homeworks/#{mod.id}" + when "common_homework" + "/courses/#{course.id}/common_homeworks/#{mod.id}" + when "group_homework" + "/courses/#{course.id}/group_homeworks/#{mod.id}" + when "graduation" + "/courses/#{course.id}/graduation_topics/#{mod.id}" + when "exercise" + "/courses/#{course.id}/exercises/#{mod.id}" + when "poll" + "/courses/#{course.id}/polls/#{mod.id}" + when "attachment" + "/courses/#{course.id}/files/#{mod.id}" + when "board" + course_board = course.course_board + "/courses/#{course.id}/boards/#{course_board.id}" + when "course_group" + "/courses/#{course.id}/students" + end + end + + # 子目录对应的url + def category_url category, course + case category.category_type + when "shixun_homework" + "/courses/#{course.id}/shixun_homework/#{category.id}" + when "graduation" + if category.name == "毕设选题" + "/courses/#{course.id}/graduation_topics/#{category.course_module_id}" + else + "/courses/#{course.id}/graduation_tasks/#{category.course_module_id}" + end + when "attachment" + "/courses/#{course.id}/file/#{category.id}" + end + end + + # 子目录下的任务数 + def category_task_count course, category, user + case category.category_type + when "shixun_homework" + get_homework_commons_count(course, 4, category.id) + when "graduation" + if category.name == "毕设选题" + course.graduation_topics_count + else + course.graduation_tasks_count + end + when "attachment" + get_attachment_count(course, category.id) + end + end + + # 课堂模块的任务数 + def course_task_count(course, module_type) + case module_type + when "shixun_homework" + get_homework_commons_count(course, 4, 0) + when "common_homework" + get_homework_commons_count(course, 1, 0) + when "group_homework" + get_homework_commons_count(course, 3, 0) + when "graduation" + 0 + when "exercise" + course.exercises_count + when "poll" + course.polls_count + when "attachment" + get_attachment_count(course, 0) + when "board" + course_board = course.course_board + course_board.present? ? course_board.messages.size : 0 + when "course_group" + course.course_groups_count + end + end + + # 当前用户可见的课堂作业,type指定作业类型, category_id指定二级目录 + def visible_homework course, user, type, category_id=0 + if user.teacher_of_course?(course) + homeworks = course.homework_commons.where("homework_type = #{type} and course_second_category_id = #{category_id}") + elsif user.member_of_course?(course) + member = course.course_members.find_by(user_id: user.id, role: 4) + if member.try(:course_group_id).to_i == 0 + homeworks = course.homework_commons.where("homework_commons.homework_type = #{type} and publish_time <= '#{Time.now}' + and unified_setting = 1 and course_second_category_id = #{category_id}") + else + not_homework_ids = course.homework_group_settings.where("course_group_id = #{member.try(:course_group_id)} and + (publish_time > '#{Time.now}' or publish_time is null)").pluck(:homework_common_id) + # not_homework_ids = not_homework_ids.blank? ? "(-1)" : "(" + not_homework_ids.map(&:homework_common_id).join(",") + ")" + homeworks = course.homework_commons.where.not(id: not_homework_ids).where("homework_commons.homework_type = #{type} and publish_time <= '#{Time.now}' + and course_second_category_id = #{category_id}") + end + else + homeworks = course.homework_commons.where("homework_type = #{type} and publish_time <= '#{Time.now}' and unified_setting = 1 + and course_second_category_id = #{category_id}") + end + homeworks + end + + # 当前用户可见的课堂试卷 + def visible_exercise course, user + if user.teacher_of_course?(course) + exercises = course.exercises + elsif user.member_of_course?(course) + member = course.course_members.find_by(user_id: user.id, role: 4) + if member.try(:course_group_id).to_i == 0 + exercises = course.exercises.where("publish_time <= '#{Time.now}' and unified_setting = 1") + else + not_exercise_ids = course.exercise_group_settings.where("course_group_id = #{member.try(:course_group_id)} and + (publish_time > '#{Time.now}' or publish_time is null)").pluck(:exercise_id) + exercises = course.exercises.where.not(id: not_exercise_ids).where("publish_time <= '#{Time.now}'") + end + else + exercises = course.exercises.where("publish_time <= '#{Time.now}' and unified_setting = 1") + end + exercises + end + + # 当前用户可见的课堂问卷 + def visible_poll course, user + if user.teacher_of_course?(course) + polls = course.polls + elsif user.member_of_course?(course) + member = course.course_members.find_by(user_id: user.id, role: 4) + if member.try(:course_group_id).to_i == 0 + polls = course.polls.where("publish_time <= '#{Time.now}' and unified_setting = 1") + else + not_poll_ids = course.poll_group_settings.where("course_group_id = #{member.try(:course_group_id)} and + (publish_time > '#{Time.now}' or publish_time is null)").pluck(:poll_id) + polls = course.polls.where.not(id: not_poll_ids).where("publish_time <= '#{Time.now}'") + end + else + polls = course.polls.where("publish_time <= '#{Time.now}' and unified_setting = 1") + end + polls + end + + # 当前用户可见的课堂资源,category_id指定资源的目录 + def visible_attachment course, user, category_id=0 + result = [] + course.attachments.where(course_second_category_id: category_id).each do |attachment| + if attachment.unified_setting + if attachment.is_public == 1 && attachment.is_publish == 1 || user == attachment.author || user.teacher_of_course?(course) || (user.member_of_course?(course) && attachment.is_publish == 1) + result << attachment + end + else + if attachment.is_public == 1 && attachment.is_publish == 1 && !user.member_of_course?(course) || user == attachment.author || user.teacher_of_course?(course) + result << attachment + elsif user.member_of_course?(course) && attachment.is_publish == 1 + member = course.course_members.find_by(user_id: user.id, role: 4) + if member.try(:course_group_id).to_i == 0 && attachment.unified_setting + result << attachment + elsif attachment.attachment_group_settings.where("course_group_id = #{member.try(:course_group_id)} and publish_time > '#{Time.now}'").count == 0 + result << attachment + end + end + end + end + result + end + + # 获取课堂的资源数 + def get_attachment_count(course, category_id) + course.attachments.where(course_second_category_id: category_id).size + end + + # 获取课堂的作业数 + def get_homework_commons_count(course, type, category_id) + HomeworkCommon.where(course_id: course.id, homework_type: type, course_second_category_id: category_id).size + end + + + # 获取课堂的任务数(作业数+试卷数+问卷数) + def get_tasks_count(course) + course.homework_commons_count + course.exercises_count + course.polls_count + end + + # 当前用户可见的毕设任务 + def visible_graduation_task course, user + if user.teacher_of_course?(course) + tasks = course.graduation_tasks + else + tasks = course.graduation_tasks.where("publish_time <= '#{Time.now}'") + end + tasks + end + + # 分班情况 + def course_group_info course, user_id + course_group_ids = course.group_course_power(user_id) + course_groups = + if course_group_ids.present? + sql = %Q{ + SELECT * FROM course_groups WHERE id in(SELECT course_group_id FROM teacher_course_groups WHERE id + IN(#{course_group_ids.join(",")})) order by position ASC + } + CourseGroup.find_by_sql(sql) + else + course.course_groups.includes(:course_members) + end + group_info = [] + if course_groups.count > 0 + course_groups.each do |group| + group_info << {course_group_id: group.id, group_group_name: group.name, count: group.course_members_count} + end + + none_group_count = course.students.where(course_group_id: 0).size + group_info << {course_group_id: 0, group_group_name: "未分班", count: none_group_count} if none_group_count > 0 && !course_group_ids.present? + end + + return group_info + end + + def left_group_info course + group_info = [] + course.course_groups.each do |course_group| + group_info << {category_id: course_group.id, category_name: course_group.name, position: course_group.position, + category_count: course_group.course_members_count, category_type: false, + second_category_url: "/courses/#{@course.id}/course_groups/#{course_group.id}"} + end + none_group_count = course.students.where(course_group_id: 0).size + group_info << {category_id: 0, category_name: "未分班", position: course.course_groups.pluck(:position).max.to_i + 1, + category_count: none_group_count, category_type: false, + second_category_url: "/courses/#{@course.id}/course_groups/0"} + end + +end diff --git a/app/helpers/discusses_helper.rb b/app/helpers/discusses_helper.rb new file mode 100644 index 000000000..c686fcada --- /dev/null +++ b/app/helpers/discusses_helper.rb @@ -0,0 +1,2 @@ +module DiscussesHelper +end diff --git a/app/helpers/ecs_helper.rb b/app/helpers/ecs_helper.rb new file mode 100644 index 000000000..5820cc0a7 --- /dev/null +++ b/app/helpers/ecs_helper.rb @@ -0,0 +1,2 @@ +module EcsHelper +end diff --git a/app/helpers/edu_settings_helper.rb b/app/helpers/edu_settings_helper.rb new file mode 100644 index 000000000..831fb8c8a --- /dev/null +++ b/app/helpers/edu_settings_helper.rb @@ -0,0 +1,2 @@ +module EduSettingsHelper +end diff --git a/app/helpers/exercise_questions_helper.rb b/app/helpers/exercise_questions_helper.rb new file mode 100644 index 000000000..28f3fddb0 --- /dev/null +++ b/app/helpers/exercise_questions_helper.rb @@ -0,0 +1,48 @@ +module ExerciseQuestionsHelper + def get_exercise_question_info(question,exercise,ex_user,ex_answerer_id) + answered_content = [] + exercise_answers = question.exercise_answers.search_exercise_answer("user_id",ex_answerer_id) #试卷用户的回答 + if question.question_type <= 2 + answered_content = exercise_answers.pluck(:exercise_choice_id) + elsif question.question_type == 3 + exercise_answers.each do |a| + u_answer = { + "choice_id": a.exercise_choice_id, + "answer_text": a.answer_text + } + answered_content.push(u_answer) + end + elsif question.question_type == 4 + answered_content = exercise_answers.pluck(:answer_text) + end + if question.question_type == 5 && ex_user.present? && ex_user.commit_status == 1 #存在实训题,且用户已提交了的,如果实训题只做了一半就关闭,则相当于不要了 + if exercise.exercise_status == 3 #如果试卷已截止,则可以看到分数,否则不能查看分数 + shixun_type = 2 + else + shixun_type =1 + end + else + shixun_type = 0 + end + { + "answered_content":answered_content, + "shixun_type":shixun_type + } + end + + def shixun_game_scores(challenge,ex_answerer,shixun_type,question_id) + game_score = challenge.question_score + game_answers = challenge.exercise_shixun_answers.search_shixun_answers("user_id",ex_answerer.id).search_shixun_answers("exercise_question_id",question_id) + if shixun_type == 2 && game_answers.present? #试卷已截止,用户才可以查看答案 + s_score = game_answers.first.score + else + s_score = nil + end + games = ex_answerer.games.ch_games(challenge.challenge_id).uniq + { + "games":games, + "s_score":s_score, + "game_score":game_score + } + end +end diff --git a/app/helpers/exercises_helper.rb b/app/helpers/exercises_helper.rb new file mode 100644 index 000000000..4f4c015eb --- /dev/null +++ b/app/helpers/exercises_helper.rb @@ -0,0 +1,669 @@ + +module ExercisesHelper + + #获取每个学生对每个题的答案状态 + def get_each_student_exercise(exercise_id,exercise_questions,user_id) + @exercise_user = ExerciseUser.current_exercise_user(user_id,exercise_id).first + exercise_obj_status = exercise_questions.find_objective_questions + @ex_obj_array = [] + exercise_obj_status.each do |q| + if q.question_type == 5 + ques_score = q.exercise_shixun_answers.search_shixun_answers("user_id",user_id).pluck(:score).sum + else + ques_score = q.exercise_answers.search_answer_users("user_id",user_id).score_reviewed.pluck(:score).sum + end + + if ques_score == q.question_score #满分作答为正确 + stand_answer = 1 + elsif ques_score > 0.0 #部分作答 + stand_answer = 2 + else + stand_answer = 0 + end + + ques_option = { + "q_id":q.id, #该问题的id + "q_type":q.question_type, + "q_position":q.question_number, #该问题的位置 + "stand_status":stand_answer, #用户是否回答 + "user_score":ques_score.round(1).to_s #每个问题的总得分 + } + @ex_obj_array.push(ques_option) + end + exercise_sub_status = exercise_questions.find_by_custom("question_type",4) #主观题 + @ex_sub_array = [] #主观题的已答/未答 + exercise_sub_status.each do |s| + sub_answer = s.exercise_answers.search_answer_users("user_id",user_id) #主观题只有一个回答 + if sub_answer.present? && sub_answer.first.score >= 0.0 + if s.question_score == sub_answer.first.score + stand_status = 1 + else + stand_status = 2 + end + # stand_status = 1 + sub_answer_score = sub_answer.first.score + else + stand_status = 0 + sub_answer_score = 0.0 + end + + sub_score = { + "q_id":s.id, + "q_type":s.question_type, + "q_position":s.question_number, + "stand_status":stand_status, + "user_score":sub_answer_score.round(1).to_s + } + @ex_sub_array.push(sub_score) + end + @ex_obj_array.sort_by {|k| k[:q_position]} + @ex_sub_array.sort_by {|k| k[:q_position]} + end + + #试卷的统计结果页面计算各题的 + def exercise_commit_result(questions,user_ids) + question_infos = [] + questions.each do |ex| + ex_total_score = user_ids.count * ex&.question_score #该试卷的已回答的总分 + ex_answers = ex.exercise_answers + if ex.question_type != 5 + ques_title = ex.question_title + ques_less_title = nil + effictive_users = ex_answers.search_answer_users("user_id",user_ids) + else + ques_title = ex.shixun.name + ques_less_title = ex.question_title + effictive_users = ex.exercise_shixun_answers.search_shixun_answers("user_id",user_ids) + end + effictive_users_count = effictive_users.count #有效回答数,可能有重复的用户id,这里仅统计是否回答这个问题的全部人数 + ex_answered_scores = effictive_users.score_reviewed.pluck(:score).sum #该问题的全部得分 + if ex_total_score == 0.0 + percent = 0.0 + else + percent = (ex_answered_scores / ex_total_score.to_f).round(3) * 100 #正确率 + end + question_answer_infos = [] + if ex.question_type <= 2 #单选题 + standard_answer = ex.exercise_standard_answers.pluck(:exercise_choice_id) #标准答案的位置 + ex.exercise_choices.each do |c| + if standard_answer.include?(c.choice_position) #选项的标准答案为选项的位置 + right_answer = true + else + right_answer = false + end + answer_this_choice = effictive_users.search_exercise_answer("exercise_choice_id",c.id) + answer_users_count = answer_this_choice.count + if effictive_users_count == 0 + answer_percent = 0.0 + else + answer_percent = (answer_users_count / effictive_users_count.to_f ).round(3) + end + answer_option = { + :choice_position => c.choice_position, + :choice_text => c.choice_text, + :choice_users_count => answer_users_count, + :choice_percent => answer_percent.round(1), + :right_answer => right_answer + } + question_answer_infos.push(answer_option) + end + elsif ex.question_type == 3 #填空题 + ex_ordered = ex.is_ordered + null_standard_answer = ex.exercise_standard_answers + null_stand_choice = null_standard_answer.pluck(:exercise_choice_id) + null_stand_text = null_standard_answer.pluck(:answer_text) + standard_answer_count = 0 + all_user_count = 0 + null_stand_choice.each_with_index do |s,index| + user_count = 0 + s_choice_text = null_stand_text[index] + if ex_ordered #有序排列 + user_ids.each do |u| + user_answers = ex_answers.search_answer_users("user_id",u).search_answer_users("exercise_choice_id",s) + user_answers_choice = user_answers.present? ? user_answers.first.answer_text : "" + if s_choice_text == user_answers_choice + user_count += 1 + end + end + else + user_count = user_count + effictive_users.search_exercise_answer("answer_text",s_choice_text).count #回答了标准答案的用户 + end + if effictive_users_count == 0 + answer_percent = 0.0 + else + answer_percent = (user_count / effictive_users_count.to_f ).round(3) + end + + answer_option = { + :choice_position => index+1, + :choice_text => s_choice_text, + :choice_users_count => user_count, + :choice_percent => answer_percent.round(1), + :right_answer => true + } + question_answer_infos.push(answer_option) + all_user_count += user_count + standard_answer_count += 1 + end + user_wrong_count = (effictive_users_count - all_user_count ) + + if effictive_users_count > 0 && user_wrong_count >= 0 + wrong_percent = (user_wrong_count / effictive_users_count.to_f ).round(3) + else + wrong_percent = 0.0 + end + wrong_answer_position = { + :choice_position => (standard_answer_count + 1), + :choice_text => "wrong", + :choice_users_count => user_wrong_count, + :choice_percent => wrong_percent.round(1), + :right_answer => false + } + question_answer_infos.push(wrong_answer_position) + elsif ex.question_type == 4 #主观题 + ex_score = ex&.question_score + full_scores = effictive_users.search_exercise_answer("score",ex_score).count #满分人数 + no_full_scores = effictive_users.exercise_no_full_scores(ex_score).count #部分分数人数 + all_zero_scores = effictive_users.search_exercise_answer("score",0.0).count #包含为0分的,及未评阅的 + review_scores = ex.exercise_answer_comments.count #主观题的评阅数量 + un_review_scores = effictive_users_count - review_scores #未评阅数 + zero_scores = all_zero_scores - un_review_scores #已评阅,且答案未0分的人数 + main_scores_array = [full_scores,no_full_scores,zero_scores,un_review_scores] + main_scores_array.each_with_index do |s,index| + if index == 0 + right_answer = true + else + right_answer = false + end + if effictive_users_count == 0 || s < 0 + s = 0 + score_percent = 0.0 + else + score_percent = (s.to_i / effictive_users_count.to_f ).round(3) + end + answer_option = { + :choice_position => index+1, + :choice_text => index+1, + :choice_users_count => s, + :choice_percent => score_percent.round(1), + :right_answer => right_answer + } + question_answer_infos.push(answer_option) + end + elsif ex.question_type == 5 #实训题 + ex.exercise_shixun_challenges.each do |c| + cha_score = c&.question_score + cha_shixun_answer = effictive_users.search_shixun_keys("exercise_shixun_challenge_id",c.id) + effictive_users_count = cha_shixun_answer.count #实训题的每个关卡的有效填写量 + full_scores = cha_shixun_answer.search_shixun_keys("score",cha_score).count #满分人数 + no_full_scores = cha_shixun_answer.shixun_no_full_scores(cha_score).count #部分分数人数c + all_zero_scores = cha_shixun_answer.search_shixun_keys("score",0.0).count #满分人数 + shixun_score_array = [full_scores,no_full_scores,all_zero_scores] + shixun_chas = [] + shixun_score_array.each_with_index do |s,index| + if index == 0 + right_answer = true + else + right_answer = false + end + if effictive_users_count == 0 + score_percent = 0.0 + else + score_percent = (s.to_i / effictive_users_count.to_f ).round(3) + end + answer_option = { + :choice_position => index+1, + :choice_text => index+1, + :choice_users_count => s, + :choice_percent => score_percent.round(1), + :right_answer => right_answer + } + shixun_chas.push(answer_option) + end + shixun_new_chas = { + :cha_id => c.challenge_id, + :cha_name => c.challenge.subject, + :cha_position => c.position, + :cha_details => shixun_chas + } + question_answer_infos.push(shixun_new_chas) + end + end + ques_option = { + :ques_title => ques_title, + :ques_less_title => ques_less_title, #副标题,仅实训题才有 + :type => ex.question_type, + :position => ex.question_number, + :percent => percent.round(1).to_s, + :ques_effictive_counts => effictive_users_count, + :ques_details => question_answer_infos + } + question_infos.push(ques_option) + end + question_infos + end + + #获取试卷的已答/未答人数 + def get_exercise_answers(ex_users) + @commit_ex_users = ex_users.commit_exercise_by_status(1) #当前老师的全部学生中已提交的 + + @exercise_answers = @commit_ex_users.present? ? @commit_ex_users.size : 0 #表示已经提交了的用户 + course_all_members_count = ex_users.present? ? ex_users.size : 0 + @exercise_unanswers = (course_all_members_count - @exercise_answers) + end + + def exercise_index_show(exercise,course,is_teacher_or,user) + # exercise_all_users = exercise.exercise_users + ex_show_text = [] + + if course.is_end #课堂停止后,试卷显示为已结束 + exercise_status = 4 + elsif is_teacher_or == 1 #当前为老师的时候,显示的是老师身份的对应试卷的状态,因为该试卷,可能对应老师的多个分班 + exercise_status = exercise.exercise_status + else + exercise_status = exercise.get_exercise_status(user.id) #当前用户查看的试卷的发布状态 + end + + case exercise_status + when 2 + ex_show_text.push("提交中") + when 3 + ex_show_text.push("已截止") + when 4 + ex_show_text.push("已结束") + else + ex_show_text + end + if is_teacher_or == 1 + exercise_users_list = exercise.all_exercise_users(user.id) #当前老师所在班级的全部学生 + unreview_count = exercise_users_list.exercise_unreview.size + get_exercise_answers(exercise_users_list) + ex_pb_time = exercise.get_exercise_times(user.id,true) + exercise_publish_time = ex_pb_time[:publish_time] + exercise_end_time = ex_pb_time[:end_time] + current_status = 3 + lock_icon = 1 #不显示锁图标 + if exercise_status == 1 + ex_show_text.push("未发布") + elsif exercise_status == 3 + ex_show_text.push("评阅中") + end + elsif is_teacher_or == 2 + exercise_users_list = exercise.get_stu_exercise_users + get_exercise_answers(exercise_users_list) # 未答和已答的 + unreview_count = exercise_users_list.exercise_unreview.size + ex_pb_time = exercise.get_exercise_times(user.id,false) + exercise_publish_time = ex_pb_time[:publish_time] + exercise_end_time = ex_pb_time[:end_time] + current_status = exercise.check_user_answer_status(user) + lock_icon = 1 #不显示锁图标 + if current_status == 4 + ex_show_text.push("未提交") + end + else + exercise_users_list = exercise.get_stu_exercise_users + get_exercise_answers(exercise_users_list) # 未答和已答的 + exercise_publish_time = exercise.publish_time + exercise_end_time = exercise.end_time + unreview_count = nil + if exercise.is_public + current_status = exercise.check_user_answer_status(user) + lock_icon = 1 #非课堂成员,但是试卷为公开的,不加锁 + if current_status == 4 + ex_show_text.push("未提交") + end + else + current_status = 4 + lock_icon = 0 #显示锁图标 + end + end + + if exercise_status > 1 + show_unreview_count = unreview_count + else + show_unreview_count = nil + end + + if exercise_status == 2 && exercise_end_time.present? + ex_left_time = how_much_time(exercise_end_time) + elsif exercise_status == 3 && course.end_date.present? + ex_left_time = how_much_time(course.end_date.to_time) + else + ex_left_time = nil + end + + { + "publish_time":exercise_publish_time, + "end_time":exercise_end_time, + "exercise_answer":@exercise_answers, + "exercise_unanswer":@exercise_unanswers, + "current_status":current_status, + "lock_icon":lock_icon, + "unreview_count": show_unreview_count, + "ex_status":exercise_status, + "ex_tips":ex_show_text, + "ex_left_time": ex_left_time + } + end + + #计算试卷的总分和试卷的答题状态 + def calculate_student_score(exercise,user) + score1 = 0.0 #选择题/判断题 + score2 = 0.0 #填空题 + score5 = 0.0 #实训题 + ques_stand = [] #问题是否正确 + exercise_questions = exercise.exercise_questions + exercise_questions.each do |q| + if q.question_type != 5 + answers_content = q.exercise_answers.search_answer_users("user_id",user.id) #学生的答案 + else + answers_content = q.exercise_shixun_answers.search_shixun_answers("user_id",user.id) #学生的答案 + end + if q.question_type <= 2 #为选择题或判断题时 + answer_choice_array = [] + answers_content.each do |a| + answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置 + end + user_answer_content = answer_choice_array.sort + standard_answer = q.exercise_standard_answers.pluck(:exercise_choice_id).sort #该问题的标准答案,可能有多个 + if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 + if standard_answer.count > 0 + multi_each_score = (q.question_score / standard_answer.count) #当多选答案正确时,每个answer的分数均摊。 + else + multi_each_score = 0.0 + end + answers_content.update_all(:score => multi_each_score) + score1 = score1 + q.question_score + end + elsif q.question_type == 3 #填空题 + null_standard_answer = q.exercise_standard_answers + standard_answer_array = null_standard_answer.select(:exercise_choice_id,:answer_text) + standard_answer_ids = standard_answer_array.pluck(:exercise_choice_id).reject(&:blank?).uniq #标准答案的exercise_choice_id数组 + standard_answer_count = standard_answer_ids.count + if standard_answer_count > 0 #存在标准答案时才有分数 + each_standard_score = (q.question_score.to_f / standard_answer_count).round(1) #每一空的得分 + else + each_standard_score = 0.0 + end + if q.is_ordered + answers_content.each do |u| + i_standard_answer = standard_answer_array.where(exercise_choice_id:u.exercise_choice_id).pluck(:answer_text).reject(&:blank?).map!(&:downcase) #该选项的全部标准答案 + if i_standard_answer.include?(u.answer_text.downcase) #该空的标准答案包含用户的答案才有分数 + u.update_attribute("score",each_standard_score) + score2 = score2 + each_standard_score + end + end + else + st_answer_text = standard_answer_array.pluck(:answer_text).reject(&:blank?).map!(&:downcase) + answers_content.each do |u| + u_answer_text = u.answer_text.downcase + if st_answer_text.include?(u_answer_text) #只要标准答案包含用户的答案,就有分数。同时,下一次循环时,就会删除该标准答案。防止用户的相同答案获分 + u.update_attribute("score",each_standard_score) + score2 = score2 + each_standard_score + st_answer_text.delete(u_answer_text) + end + end + end + elsif q.question_type == 5 #实训题时,主观题这里不评分 + q.exercise_shixun_challenges.each do |exercise_cha| + game = Game.user_games(user.id,exercise_cha.challenge_id).first #当前用户的关卡 + if game.present? + exercise_cha_score = 0 + answer_status = 0 + cha_path = challenge_path exercise_cha.challenge.path + if game.status == 2 && game.final_score >= 0 + exercise_cha_score = game.real_score exercise_cha.question_score #每一关卡的得分 + answer_status = 1 + end + if exercise_cha.exercise_shixun_answers.search_shixun_answers("user_id",user.id).blank? #把关卡的答案存入试卷的实训里 + game_challenge = game.game_codes.search_challenge_path(cha_path).first + if game_challenge.present? + game_code = game_challenge + code = game_code.try(:new_code) + else + code = git_fle_content(exercise_cha.shixun.repo_path,cha_path) + end + sx_option = { + :exercise_question_id => q.id, + :exercise_shixun_challenge_id => exercise_cha.id, + :user_id => user.id, + :score => exercise_cha_score, + :answer_text => code, + :status => answer_status + } + ExerciseShixunAnswer.create(sx_option) + end + score5 += exercise_cha_score + end + end + end + user_scores = answers_content.score_reviewed.pluck(:score).sum + if user_scores > 0 + stand_answer = 1 + else + stand_answer = 0 + end + ques_option = { + "q_id":q.id, #该问题的id + "q_type":q.question_type, + "q_position":q.question_number, #该问题的位置 + "stand_status":stand_answer, #该问题是否正确,1为正确,0为错误 + "user_score":user_scores #每个问题的总得分 + } + ques_stand.push(ques_option) + end + total_score = score1 + score2 + score5 + { + "total_score":total_score, + "stand_status":ques_stand + } + end + + #获取用户的相关信息 + def exercise_use_info(ex_user,user_status,exercise) + course = exercise.course + current_user_group_id = "" + current_user_group_name = "" + ex_user_user = ex_user.user + exercise_user_name = ex_user_user.real_name + exercise_user_id = ex_user_user.id + ex_user_exercise_status = exercise.get_exercise_status(exercise_user_id) + ex_user_student_id = ex_user_user.student_id + if ex_user.start_at.present? && ex_user.commit_status == 0 #用户已回答,但未提交 + commit_status = 2 #继续答题 + else + commit_status = ex_user.commit_status + end + + ex_user_end_at = ex_user.end_at + course_member = course.students.course_find_by_ids("user_id",ex_user.user.id) + current_user_group_id = course_member.first.course_group_id if course_member.present? + course_group = course.course_groups.by_group_ids(current_user_group_id) + current_user_group_name = course_group.first.name if course_group.present? + teacher_review = ex_user.subjective_score < 0.0 ? false : true + if ex_user_exercise_status != 3 || commit_status != 1 #试卷未截止或用户未提交 + # if (user_status != 0 && ex_user_exercise_status != 3)|| commit_status == 0 #不为教师,且试卷未截止;当前用户未提交 不显示分数 + ex_object_score = nil + ex_subject_score = nil + score = nil + else + ex_object_score = ex_user.objective_score < 0.0 ? 0.0 : ex_user.objective_score.round(1).to_s + ex_subject_score = ex_user.subjective_score < 0.0 ? nil : ex_user.subjective_score.round(1).to_s + score = ex_user.score.present? ? ex_user.score.round(1).to_s : 0.0.to_s + end + + { + "user_name":exercise_user_name, + "login":ex_user_user.login, + "user_group_id":current_user_group_id, + "user_group_name":current_user_group_name, + "teacher_review":teacher_review, + "ex_object_score":ex_object_score, + "ex_subject_score":ex_subject_score, + "score":score, + "user_id":exercise_user_id, + "commit_status":commit_status, + "student_id":ex_user_student_id, + "end_at":ex_user_end_at + } + end + + #公用tab页的相关信息 + def ex_common_header(is_teacher_or,exercise) + exercise_url_status = [] + if is_teacher_or == 1 #当为老师的 + common_tabs = %w(1 2 3 4) + else + if exercise.show_statistic #开启了公开统计 + common_tabs = %w(1 2) + else + common_tabs = %w(1) + end + end + + common_tabs.each do |c| + if request.url.include?("exercise_lists") + active_status = 1 + elsif request.url.include?("exercises_result") + active_status = 1 + elsif request.url.include?("exercise_setting") + active_status = 1 + elsif request.url == exercise_path(exercise) + active_status = 1 + else + active_status = 0 + end + common_tab = { + :common_tab => c, + :active_status => active_status + } + exercise_url_status.push(common_tab) + end + exercise_url_status + end + + #试卷/问卷 设置页面的发布规则返回内容 + def get_user_setting_course(user_published_setting,user_course_groups) + loop_course_publish_time = [] + total_array_groups = [] + user_published_setting.each do |u| + new_json_array_group = {} + setting_group_name = user_course_groups.detect{|g| g[:group_id] == u.course_group_id} + if loop_course_publish_time.length > 0 + time_length = loop_course_publish_time.length #问卷发布时间和截止时间相同的集合 + (1..time_length).each do |i| + if (loop_course_publish_time[i-1][:publish_time] == u.publish_time) && (loop_course_publish_time[i-1][:end_time] == u.end_time) #当起止时间已存在时,直接更新 + loop_course_ids = total_array_groups[i-1][:course_group_id] +[u.course_group_id] + loop_course_names = total_array_groups[i-1][:course_group_name] + [setting_group_name[:group_name]] + new_json_array_group = { + "loop_times":i-1, + "course_group_id":loop_course_ids, + "course_group_name":loop_course_names, + } + end + end + if new_json_array_group.length > 0 + loop_times = new_json_array_group[:loop_times] + total_array_groups[loop_times][:course_group_id] = new_json_array_group[:course_group_id] + total_array_groups[loop_times][:course_group_name] = new_json_array_group[:course_group_name] + else + loop_course_times = { + "publish_time":u.publish_time, + "end_time": u.end_time + } + loop_course_publish_time.push(loop_course_times) + json_array_group = { + "course_group_id":[u.course_group_id], + "course_group_name":[setting_group_name[:group_name]], + "course_publish_time":u.publish_time, + "course_end_time":u.end_time + } + total_array_groups.push(json_array_group) + end + else #第一次循环获得初始值 第一步 + loop_course_times = { + "publish_time":u.publish_time, + "end_time": u.end_time + } + loop_course_publish_time.push(loop_course_times) + json_array_group = { #第一个问卷发布规则的第一条记录 + "course_group_id":[u.course_group_id], + "course_group_name":[setting_group_name[:group_name]], + "course_publish_time":u.publish_time, + "course_end_time":u.end_time + } + total_array_groups.push(json_array_group) + end + end + total_array_groups + end + + #学生的分数状态及回答的内容 + def user_question_answers(q,ex_answerer_id,student_status,is_teacher_or,ex_status,ques_type,ex_type) + answered_content = [] + user_score = 0.0 + shixun_type = 0 + question_comment = [] + if q.question_type == 5 + exercise_answers = q.exercise_shixun_answers.search_shixun_answers("user_id",ex_answerer_id) + else + exercise_answers = q.exercise_answers.search_exercise_answer("user_id",ex_answerer_id) #试卷用户的回答 + end + if student_status == 2 #当前为老师,或为学生且已提交 + user_score = exercise_answers.score_reviewed.pluck(:score).sum + end + if ques_type <= 2 + answered_content = exercise_answers.pluck(:exercise_choice_id) + elsif ques_type == 3 + exercise_answers.each do |a| + u_answer = { + "choice_id":a.exercise_choice_id, + "answer_text": a.answer_text + } + answered_content.push(u_answer) + end + elsif ques_type == 4 + answered_content = exercise_answers.pluck(:answer_text) + end + if ques_type == 5 #存在实训题,及已经做了实训题的 + if ex_status == 3 || is_teacher_or == 1 #如果试卷已截止,则可以看到分数,否则不能查看分数 + shixun_type = 2 + elsif ex_status == 2 && q.exercise_shixun_answers.present? #试卷未截止,且用户已回答的,则能看到答题的状态 + shixun_type =1 + end + end + + if ex_type == 4 #填空题/主观题/实训题有评论的 + q_answer_id = exercise_answers.present? ? exercise_answers.first.id : nil + question_comment = q.exercise_answer_comments.search_answer_comments("exercise_answer_id",q_answer_id) + end + { + "user_score": user_score.round(1), + "answered_content":answered_content, + "shixun_type":shixun_type, + "question_comment":question_comment + } + end + + def convert_to_char(str) + result = "" + length = str.length + unless str.nil? + if length === 1 + result += (str.to_i + 64).chr + return result + elsif length > 1 + for i in 0...length + result += (str[i].to_i + 64).chr + end + return result + end + end + result + end + + #实训题学生代码的行数 + def content_line(content) + content.split(/\r?\n/).length + end +end diff --git a/app/helpers/export_helper.rb b/app/helpers/export_helper.rb new file mode 100644 index 000000000..a5e3c5d9d --- /dev/null +++ b/app/helpers/export_helper.rb @@ -0,0 +1,488 @@ +module ExportHelper + include ApplicationHelper + require "base64" + require 'zip' + + # 附件导出最大值 + MAX_DOWN_SIZE = 500 * 1024 * 1024 + SAVE_FOLDER = "#{Rails.root}/files" + OUTPUT_FOLDER = "#{Rails.root}/files/archiveZip" + MAX_PATH = 50 + + # 作业导出为xlsx,homework_type 1:普通作业 2:编程作业(弃用) 3:分组作业 4:实训作业 + def student_work_to_xlsx(works,homework) + @work_head_cells = [] + @work_cells_column = [] + course = homework.course + head_cells_format = %w(序号 登录名 真实姓名 邮箱 学号 分班 提交状态) + allow_late_boolean = homework.allow_late + if allow_late_boolean #允许迟交 + allow_late_cell = ["迟交扣分"] + else + allow_late_cell = [] + end + if homework.homework_type != "practice" #普通作业/分组作业 + homework_type_name = homework.homework_type + if homework_type_name == "group" #分组作业 + group_cells = ["关联项目"] + else + group_cells = [] + end + normal_head_cells = %w(作品描述 教师评分 教辅评分) + anon_boolean = homework.anonymous_comment + if anon_boolean + head_cells_add = %w(匿名评分 缺评扣分 违规匿评申诉扣分) + else + head_cells_add = [] + end + normal_head_b_cells = %w(最终成绩 提交时间 更新时间) + @work_head_cells = (head_cells_format + group_cells + normal_head_cells + head_cells_add + allow_late_cell + normal_head_b_cells).reject(&:blank?) + works.each_with_index do |w, index| + w_user = w.user + w_1 = (index + 1) + w_2 = w_user.login + w_3 = w_user.real_name + w_3_1 = w_user.mail + w_4 = w_user.student_id.present? ? w_user.student_id : "--" + course_name = course.course_member(w.user_id).try(:course_group_name) + w_5 = course_name.present? ? course_name : "--" + #0: 未提交, 1 按时提交, 2 延迟提交 + if w.work_status == 0 + w_6 = "未提交" + elsif w.work_status == 1 + w_6 = "按时提交" + elsif w.work_status == 2 + w_6 = "延迟提交" + else + w_6 = "--" + end + if homework_type_name == "group" + project_name = w.project + if project_name.present? + w_7 = w.project.name + else + w_7 = "--" + end + else + w_7 = nil + end + w_8 = w.description.present? ? strip_html(w.description) : "--" + w_9 = w.teacher_score.nil? ? "未评分" : w.teacher_score.round(1) + w_10 = w.teaching_asistant_score.nil? ? "未评分" : w.teaching_asistant_score.round(1) + if anon_boolean + w_11 = w.student_score.nil? ? "未评分" : w.student_score.round(1) + w_12 = (homework.teacher_priority == 1 && !w.teacher_score.nil?) ? 0 : w.absence_penalty #缺评扣分 + home_work_de = homework.homework_detail_manual + w_13 = home_work_de.present? ? home_work_de.appeal_penalty : "--" #违规匿评申诉扣分 + else + w_11,w_12,w_13 = nil + end + if allow_late_boolean #允许迟交 + w_14 = (homework.teacher_priority == 1 && !w.teacher_score.nil?) ? 0 : w.late_penalty #迟交扣分 + else + w_14 = nil + end + w_15 = w.work_score.nil? ? "未评分" : w.work_score.round(1) + w_16 = w.commit_time ? format_time(w.commit_time) : "--" + w_17 = w.update_time ? format_time(w.update_time) : "--" + + row_cells_column = [w_1,w_2,w_3,w_3_1,w_4,w_5,w_6,w_7,w_8,w_9,w_10,w_11,w_12,w_13,w_14,w_15,w_16,w_17] + row_cells_column = row_cells_column.reject(&:blank?) + @work_cells_column.push(row_cells_column) + end + else #实训题 + shixun = homework.shixuns.first + shixun_head_cells = %w(完成情况 通关时间 总耗时 总评测次数 获得经验值 关卡得分) + eff_boolean = homework.work_efficiency + if eff_boolean + eff_score_cell = ["效率分"] + else + eff_score_cell = [] + end + if allow_late_boolean #允许迟交 + eff_score_cell.push("迟交扣分") + end + shixun_time_cells = %w(最终成绩 更新时间 提交耗时) + @work_head_cells = (head_cells_format + shixun_head_cells + eff_score_cell + shixun_time_cells).reject(&:blank?) + works.each_with_index do |w, index| + myshixun = w.try(:myshixun) + w_user = w.user + w_1 = (index + 1) + w_2 = w_user.login + w_3 = w_user.real_name + w_3_1 = w_user.mail + w_4 = w_user.student_id.present? ? w_user.student_id : "--" + course_name = course.course_member(w.user_id).try(:course_group_name) + w_5 = course_name.present? ? course_name : "--" + #0: 未提交, 1 按时提交, 2 延迟提交 + if w.work_status == 0 + w_6 = "未提交" + elsif w.work_status == 1 + w_6 = "按时提交" + elsif w.work_status == 2 + w_6 = "延迟提交" + else + w_6 = "--" + end + w_7 = w.work_status == 0 ? '--' : myshixun.try(:passed_count).to_s+"/"+shixun.challenges.count.to_s + w_8 = myshixun ? myshixun.try(:passed_time) == "--" ? "--" : format_time(myshixun.try(:passed_time)) : "--" # 通关时间 + w_9 = myshixun ? (myshixun.try(:passed_count) > 0 ? myshixun.total_spend_time : '--') : "--" #总耗时 + w_10 = myshixun ? myshixun.output_times : 0 #评测次数 + w_11 = myshixun ? myshixun.total_score : "--" #获得经验值 + w_12 = w.final_score.present? ? w.final_score : 0 + if eff_boolean + w_13 = w.eff_score + else + w_13 = nil + end + if allow_late_boolean #允许迟交 + w_14 = w.late_penalty #迟交扣分 + else + w_14 = nil + end + w_15 = w.work_score.nil? ? "--" : w.work_score.round(1) + w_16 = w.update_time ? format_time(w.update_time) : "--" "更新时间" + w_17 = w.cost_time + row_cells_column = [w_1,w_2,w_3,w_3_1,w_4,w_5,w_6,w_7,w_8,w_9,w_10,w_11,w_12,w_13,w_14,w_15,w_16,w_17] + row_cells_column = row_cells_column.reject(&:blank?) + @work_cells_column.push(row_cells_column) + end + end + end + + #毕设任务的导出 + def graduation_work_to_xlsx(items,task,current_user) + head_cells_format = %w(序号 登录名 真实姓名 邮箱 学号 分班) + task_type_boolean = task.task_type == 2 + if task_type_boolean #是否分组 + head_cells_format = head_cells_format + ["分组"] + end + head_cells_format = head_cells_format + ["提交状态"] + task_project_boolean = task.base_on_project + if task_project_boolean #关联项目 + head_cells_format = head_cells_format + ["关联项目"] + end + + head_cells_format = head_cells_format + %w(作品描述 教师评分) + + task_comment_boolean = task.cross_comment + if task_comment_boolean #是否交叉评阅 + head_cells_format = head_cells_format + ["交叉评分"] + end + + head_cells_format = head_cells_format + %w(迟交扣分 最终成绩 提交时间 更新时间) + + @head_cells_column = head_cells_format + @task_cells_column = [] + + items.each_with_index do |work,index| + w_1 = (index+1) + w_user = work.user + w_2 = w_user.login + w_3 = w_user.real_name + w_3_1 = w_user.mail + w_4 = w_user.student_id.present? ? w_user.student_id : "--" + w_5 = work.class_grouping_name + if task_type_boolean #是否分组 + w_6 = work.grouping_name + else + w_6 = nil + end + w_7 = work.work_status + if task_project_boolean #关联项目 + w_project = project_info work, current_user, @user_course_identity #因为课堂引用了export_helper + w_8 = w_project[:name] + else + w_8 = nil + end + + if work.description + w_9 = strip_html work.description + else + w_9 = "--" + end + + w_10 = work.teacher_score.nil? ? "未评分" : work.teacher_score.round(1) + if task_comment_boolean #是否交叉评阅 + w_11 = work.cross_score.nil? ? "未评分" : work.cross_score.round(1) + else + w_11 = nil + end + w_12 = work.late_penalty + w_13 = work.work_score.nil? ? "未评分" : work.work_score.round(1) + w_14 = work.commit_time.present? ? format_time(work.commit_time) : "--" + w_15 = work.update_time.present? ? format_time(work.update_time) : "--" + + row_cells_column = [w_1,w_2,w_3,w_3_1,w_4,w_5,w_6,w_7,w_8,w_9,w_10,w_11,w_12,w_13,w_14,w_15] + + row_cells_column = row_cells_column.reject(&:blank?) + @task_cells_column.push(row_cells_column) + end + end + + #试卷的导出 + def get_export_users(exercise,course,export_ex_users) + question_types = exercise.exercise_questions.pluck(:question_type).uniq + @table_columns = %w(序号 登录名 真实姓名 邮箱 学号 分班 提交状态) + @user_columns = [] + ques_type_boolean = question_types.include?(4) + if ques_type_boolean #仅存在主观题或客观题的时候 + @table_columns = @table_columns + %w(客观题成绩 主观题成绩 最终成绩 开始答题时间 提交时间) + else + @table_columns = @table_columns + %w(最终成绩 开始答题时间 提交时间) + end + export_ex_users.each_with_index do |e_user,index| + user_info = e_user.user + user_course_id = user_info.course_members.course_find_by_ids("course_id",course.id).first + if user_course_id.present? + get_course_group_id = user_course_id.course_group_id + if get_course_group_id.present? && get_course_group_id != 0 + user_course_info = CourseGroup.by_group_ids(get_course_group_id) + user_course = user_course_info.first.name + else + user_course = "--" + end + else + user_course = "--" + end + user_obj_score = e_user.objective_score < 0.0 ? 0.0 : e_user.subjective_score.round(1).to_s + user_suj_score = e_user.subjective_score < 0.0 ? 0.0 : e_user.subjective_score.round(1).to_s + user_score = e_user.score.present? ? e_user.score.round(1).to_s : 0.0 + if e_user.commit_status.present? && e_user.commit_status == 1 + user_commit_stu = "按时提交" + else + user_commit_stu = "未提交" + end + user_start_time = e_user.start_at.present? ? e_user.start_at.strftime('%Y-%m-%d %H:%M') : "--" + user_end_time = e_user.end_at.present? ? e_user.end_at.strftime('%Y-%m-%d %H:%M') : "--" + user_student_id = user_info.student_id.present? ? user_info.student_id : "--" + + user_option = [index+1,user_info.login,user_info.real_name, user_info.mail || '--', + user_student_id,user_course,user_commit_stu] + if ques_type_boolean + other_user_option = [user_obj_score,user_suj_score,user_score,user_start_time,user_end_time] + else + other_user_option = [user_score,user_start_time,user_end_time] + end + user_option = user_option + other_user_option + @user_columns.push(user_option) + end + end + + #毕设选题的导出 + def graduation_topic_to_xlsx(students,course) + @topic_head_cells = %w(序号 登录名 真实姓名 邮箱 学号 分班 课题名称 指导教师 教师职位 设计 论文 创作 生产/社会实际 结合科研 其它 真题 模拟题 纵向课题 横向课题 自选 新题 往届题,有新要求 + 往届题,无新要求 课题来源单位 调研或实习地点 确认结果) + + @topic_body_cells = [] + if students.count > 0 + students.each_with_index do |student, index| + user = student.user + student_topic = course.student_graduation_topics.user_topics_accept(user.id).first + if student_topic.present? + topic = student_topic.graduation_topic + else + student_topic = nil + topic = nil + end + w_1 = (index+1) + w_2 = user.login + w_3 = user.real_name + w_3_1 = user.mail + w_4 = user.user_extension.student_id + w_5 = student.course_group_name + w_6 = topic.present? ? topic.name : "--" + w_7 = topic.present? ? topic.teacher.full_name : "--" + w_8 = topic.present? ? topic.teacher.identity : "--" + + if topic.present? + w_9 = topic.topic_type == 1 ? "√" : "" + w_10 = topic.topic_type == 2 ? "√" : "" + w_11 = topic.topic_type == 3 ? "√" : "" + w_12 = topic.topic_source == 1 ? "√" : "" + w_13 = topic.topic_source == 2 ? "√" : "" + w_14 = topic.topic_source == 3 ? "√" : "" + w_15 = topic.topic_property_first == 1 ? "√" : "" + w_16 = topic.topic_property_first == 2 ? "√" : "" + w_17 = topic.topic_property_second == 1 ? "√" : "" + w_18 = topic.topic_property_second == 2 ? "√" : "" + w_19 = topic.topic_property_second == 3 ? "√" : "" + w_20 = topic.topic_repeat == 1 ? "√" : "" + w_21 = topic.topic_repeat == 2 ? "√" : "" + w_22 = topic.topic_repeat == 3 ? "√" : "" + w_23 = topic.source_unit + w_24 = "#{topic.province}#{topic.city}" + else + w_9,w_10,w_11,w_12,w_13,w_14,w_15,w_16,w_17,w_18,w_19,w_20,w_21,w_22,w_23,w_24 = "--" + end + if student_topic.present? + w_25 = student_topic.status == 0 ? "待确认" : "已同意" + else + w_25 = "--" + end + student_info_array = [w_1,w_2,w_3,w_3_1,w_4,w_5,w_6,w_7,w_8,w_9,w_10,w_11,w_12,w_13,w_14,w_15,w_16,w_17,w_18,w_19,w_20,w_21,w_22,w_23,w_24,w_25] + @topic_body_cells.push(student_info_array) + end + end + end + + def encode64(str) + Base64.urlsafe_encode64(str) + end + + def decode64(str) + Base64.urlsafe_decode64(str) + end + + # 检测文件大小是否超过500m + def checkfileSize(works) + file_count = 0 + file_size = 0 + works.each do |work| + file_count += work.attachments.count + work.attachments.each do |attach| + file_size += attach.filesize + end + end + + if file_size > MAX_DOWN_SIZE + status = -1 + elsif file_count > 0 + status = 0 + else + status = -2 + end + status + end + + def zip_homework_common homework_common, student_works + bid_homework_path = [] + digests = [] + student_works.each do |work| + unless work.attachments.empty? + out_file = zip_student_work_by_user(work, homework_common) + + bid_homework_path << out_file.file_path + digests << out_file.file_digest + end + end + + out_file_name = "#{Time.now.to_i}_#{homework_common.name}.zip" + out_file_name.gsub!(" ", "-") + out_file_name.gsub!("/", "_") + out_file = find_or_pack(homework_common, homework_common.user_id, digests.sort){ + zipping(out_file_name, bid_homework_path, OUTPUT_FOLDER) + } + + [{files:[out_file.file_path], count: 1, index: 1, + real_file: out_file.file_path, + file: File.basename(out_file.file_path), + base64file: encode64(File.basename(out_file.file_path)), + size:(out_file.pack_size / 1024.0 / 1024.0).round(2) + }] + end + + def zip_student_work_by_user(work, object) + homeworks_attach_path = [] + not_exist_file = [] + filename = [] + # 需要将所有homework.attachments遍历加入zip + digests = [] + work.attachments.each do |attach| + if File.exist?(attach.diskfile) + homeworks_attach_path << attach.diskfile + digests << attach.digest + filename << attach.filename + else + not_exist_file << attach.filename + digests << 'not_exist_file' + filename << attach.filename + end + end + + #单个文件的话,不需要压缩,只改名 + if homeworks_attach_path.size == 1 + out_file = find_or_pack(object, work.user_id, digests.sort){ + des_path = "#{OUTPUT_FOLDER}/#{make_zip_name(work, filename.first)}_#{File.basename(homeworks_attach_path.first)}" + FileUtils.cp homeworks_attach_path.first, des_path + des_path + } + else + out_file = find_or_pack(object, work.user_id, digests.sort){ + zipping("#{make_zip_name(work)}.zip", + homeworks_attach_path, OUTPUT_FOLDER, true, not_exist_file) + } + end + out_file + + end + + def find_or_pack(homework, user_id, digests) + raise "please given a pack block" unless block_given? + + out_file = ZipPack.packed?(homework, user_id, digests.sort) + + unless out_file && out_file.file_valid? + file = yield + + ZipPack.where(container_id: homework.id, container_type: homework.class.to_s, user_id: user_id).delete_all + + out_file = ZipPack.create(container_id: homework.id, + container_type: homework.class.to_s, + user_id: user_id, + file_digest: Educoder::Utils.digest(file), + file_path: file, + pack_size: File.size(file), + file_digests: digests.join(',') + ) + else + out_file.pack_times = out_file.pack_times + 1 + out_file.save + end + + out_file + end + + def make_zip_name(work, file_name="") + Rails.logger.info("######################file_name: #{file_name}") + name = file_name === "" ? "" : (file_name[0, file_name.rindex('.')]+"_") + "#{name}#{work.user.real_name}_#{((work.user.student_id.nil?) ? "" : work.user.student_id)}" + end + + def zipping(zip_name_refer, files_paths, output_path, is_attachment=false, not_exist_file=[]) + rename_zipfile = zip_name_refer ||= "#{Time.now.to_i.to_s}.zip" + # 文件名过长 + + if rename_zipfile.size > MAX_PATH + rename_zipfile = rename_zipfile[0,rename_zipfile.size-4][0,MAX_PATH-4] + rename_zipfile[-4,4] + end + + zipfile_name = "#{output_path}/#{rename_zipfile}" + + Dir.mkdir(File.dirname(zipfile_name)) unless File.exist?(File.dirname(zipfile_name)) + Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile| + files_paths.each do |filename| + rename_file = File.basename(filename) + rename_file = filename_to_real( File.basename(filename)) if is_attachment + + begin + zipfile.add(rename_file, filename) + rescue Exception => e + zipfile.get_output_stream('FILE_NOTICE.txt'){|os| os.write "该作品中有重复命名文件,请通过文件名学号和姓名信息进入该作业详细界面手动下载"} + next + end + end + unless not_exist_file.empty? + zipfile.get_output_stream('FILE_LOST.txt'){|os| os.write "以下文件无法成功下载,请联系相关人员重新上传:" + + not_exist_file.join(',').to_s} + end + end + zipfile_name + end + + def filename_to_real(name) + attach = Attachment.find_by_disk_filename(name) + attach.filename + end + +end diff --git a/app/helpers/games_helper.rb b/app/helpers/games_helper.rb new file mode 100644 index 000000000..aff05904f --- /dev/null +++ b/app/helpers/games_helper.rb @@ -0,0 +1,54 @@ +module GamesHelper + + def game_code_init(game_id, path) + game_code = GameCode.where(:game_id => game_id, :path => path).first + GameCode.create(:game_id => game_id, :path => path) if game_code.blank? + end + + # 获取目录下所有文件,返回一个文件名的数组 type是查看文件的类型image表示图片 + # type [[1, "图片"], [2, "apk/exe"], [3, "txt"], [4, "html"]] + def get_dir_filename(path, type, game_id) + answer_picture = [] + return answer_picture unless File.directory?(path) + + images_suffix = %w(png jpg gif jpeg bmp pic) + Dir.foreach(path) do |file| + next if file == '.' || file == '..' + + extension = file.split(".")[1].try(:downcase) + if images_suffix.include?(extension) && type == 1 + answer_picture << file + @type = 'image' + elsif extension == 'html' && type == 4 + answer_picture << file + @type = 'html' + elsif extension == 'txt' && type == 3 + answer_picture << file + @contents = '' + f = File.open("#{path}/#{file}", 'r') + # ... process the file + f.each_line do |line| + if line.include?('Your score') + game = Game.find(game_id) + max_query_index = game.query_index - 1 + a = line[11, line.length-1].try(:strip) + outputs = game.outputs.where(:query_index => max_query_index) + outputs.update_all(:text_scor => a) if outputs.present? + end + @contents += "#{line}" + end + f.close + @type = 'txt' + end + end + + answer_picture + end + + def evaluate_actual_output test_set + if test_set.has_attribute?(:code) + test_set.try(:compile_success).to_s == '0' && test_set.code.to_s == "-1" ? + "编译失败,请在测试结果中查看具体的错误信息" : test_set.try(:actual_output) + end + end +end diff --git a/app/helpers/graduation_tasks_helper.rb b/app/helpers/graduation_tasks_helper.rb new file mode 100644 index 000000000..5253b0d56 --- /dev/null +++ b/app/helpers/graduation_tasks_helper.rb @@ -0,0 +1,134 @@ +module GraduationTasksHelper + include CoursesHelper + # 教师评阅 + def teacher_comment task, user_id + [{ id: 0 ,name: "未评", count: task.uncomment_count(user_id)}, {id: 1, name: "已评", count: task.comment_count(user_id)}] + end + + # 作品状态 + def task_status task, user_id + [{id: 0, name: "未提交", count: task.unfinished_count(user_id)}, + {id: 1, name: "按时提交", count: task.finished_count(user_id)}, + {id: 2, name: "延时提交", count: task.delay_finished_count(user_id)}] + end + + # 交叉评阅 + def cross_comment task, user_id + if task.cross_comment + [{id: 1, name: "只看我的交叉评阅", count: task.graduation_work_comment_assignations.myself(user_id).count}] + else + [] + end + end + + def task_curr_status task, course + result = {} + status = [] + time = "" + + if course.try(:is_end) + status << "已结束" + time = course.end_date.present? ? course.end_date.strftime("%Y-%m-%d") : "" + else + if task.status > 1 && task.allow_late && (task.late_time.nil? || task.late_time > Time.now) + status << "补交中" + end + + case task.status + when 0 + status << "未发布" + time = task.publish_time.present? ? "将于 #{format_time(task.publish_time)} 发布" : "创建于#{time_from_now(task.created_at)}" + when 1 + if task.end_time && task.end_time >= Time.now + status << "提交中" + time = how_much_time(task.end_time) + end + when 2 + status << "评阅中" + time = task.comment_time.present? ? how_much_time(task.comment_time) : course.end_date.present? ? how_much_time(course.end_date.end_of_day) : "" + when 3 + status << "交叉评阅中" + time = course.end_date.present? ? how_much_time(course.end_date.end_of_day) : "" + end + + status << "未开启补交" if (!task.allow_late && task.status != 0) #6.11 -hs 新增status不等于0 + + # 如果还在补交阶段则显示补交结束时间 + if task.status > 1 && task.allow_late && task.late_time && task.late_time > Time.now + time = how_much_time(task.late_time) + end + end + + result[:status] = status + result[:time] = time + result + end + + # 作品数统计:type: 1 已提交 0 未提交 + def grduationwork_count task, type + works = task.graduation_works + type == 1 ? works.where("work_status !=?", 0).size : works.where("work_status =?", 0).size + end + + # 普通/分组 作业作品状态数组 + def graduation_work_status task, user_id, course + status = [] + work = task.graduation_works.find_by(user_id: user_id) + + work = work || GraduationWork.create(graduation_task_id: task.id, user_id: user_id) + late_time = task.late_time || course.end_date + + if course.is_end && work && work.work_status > 0 + status << "查看作品" + elsif !course.is_end + if task.publish_time && task.publish_time < Time.now + # 作业未截止时 + if task.end_time > Time.now + if task.task_type == 2 && task.base_on_project + if work.project_id.nil? || work.project_id == 0 + status << "创建项目" + status << "关联项目" + elsif work.work_status == 0 + status << "取消关联" + status << "提交作品" + else + status << "修改作品" + end + else + if work.work_status == 0 + status << "提交作品" + else + status << "修改作品" + end + end + + # 补交阶段 + elsif task.allow_late && (late_time.nil? || late_time > Time.now) + if task.task_type == 2 && task.base_on_project + if work.project_id.nil? || work.project_id == 0 + status << "创建项目" + status << "关联项目" + elsif work.work_status == 0 + status << "取消关联" + status << "补交作品" + else + status << "补交附件" + status << "查看作品" + end + else + if work.work_status == 0 + status << "补交作品" + else + status << "补交附件" + status << "查看作品" + end + end + + # 匿评阶段 + elsif work.work_status != 0 + status << "查看作品" + end + end + end + end +end diff --git a/app/helpers/graduation_topics_helper.rb b/app/helpers/graduation_topics_helper.rb new file mode 100644 index 000000000..ae15d201e --- /dev/null +++ b/app/helpers/graduation_topics_helper.rb @@ -0,0 +1,30 @@ +module GraduationTopicsHelper + + # 课题类型 + def topic_type + [{id: 1, name: "设计"}, {id: 2, name: "论文"}, {id: 3, name: "创作"}] + end + + # 课程来源 + def topic_source + [{id: 1, name: "生产/社会实际"}, {id: 2, name:"结合科研"}, {id: 3, name: "其它"}] + end + + # 课题性质1 + def topic_property_first + [{id: 1, name: "真题"}, {id: 2, name:"模拟题"}] + end + + # 课题性质2 + def topic_property_second + [{id: 1, name: "纵向课题"}, {id: 2, name:"横向课题"}, {id: 3, name: "自选"}] + end + + # 课题重复 + def topic_repeat + [{id: 1, name: "新题"}, {id: 2, name:"往届题,有新要求"}, {id: 3, name: "往届题,无新要求"}] + end + + + +end diff --git a/app/helpers/graduation_works_helper.rb b/app/helpers/graduation_works_helper.rb new file mode 100644 index 000000000..177720d24 --- /dev/null +++ b/app/helpers/graduation_works_helper.rb @@ -0,0 +1,21 @@ +module GraduationWorksHelper + include GraduationTasksHelper + + # 作品最终成绩 + # 参数: work作品, current_user用户,course_identity用户在课堂的身份 + def work_final_score work, current_user, course_identity + work_score = + if work.work_score.nil? + "--" + else + if work.check_score_power? current_user, course_identity + format("%.1f", work.work_score < 0 ? 0 : work.work_score.round(1)) + else + "**" + end + end + # work_score 最终成绩; late_penalty 迟交扣分; final_score 最终评分 + {username: work.user.full_name, login: work.user.login, work_score: work_score, final_score: work.final_score, + late_penalty:work.late_penalty } + end +end diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb new file mode 100644 index 000000000..cfc942e67 --- /dev/null +++ b/app/helpers/home_helper.rb @@ -0,0 +1,2 @@ +module HomeHelper +end diff --git a/app/helpers/homework_commons_helper.rb b/app/helpers/homework_commons_helper.rb new file mode 100644 index 000000000..0d166729c --- /dev/null +++ b/app/helpers/homework_commons_helper.rb @@ -0,0 +1,240 @@ +module HomeworkCommonsHelper + + # 未发布时非老师角色不能访问,发布后非课堂成员不能访问未公开的作业,学生需要考虑分班设置的作业是否已发布 + def homework_publish + if (@user_course_identity >= Course::STUDENT && (@homework.publish_time.nil? || @homework.publish_time > Time.now)) || + (@user_course_identity > Course::STUDENT && (!@homework.unified_setting || @course.is_public == 0 || !@homework.is_public)) + tip_exception(403,"没有操作权限") + elsif @user_course_identity == Course::STUDENT && !@homework.unified_setting + member = @course.course_member(current_user.id) + group_setting = @homework.homework_group_settings.find_by(course_group_id: member.try(:course_group_id)) + if group_setting.try(:publish_time).nil? || group_setting.try(:publish_time) > Time.now + tip_exception(403,"没有操作权限") + end + end + end + + def homework_curr_status homework_common, identity, course, member, teacher_course_groups + result = {} + status = [] + time = "" + time_status = nil + if course.try(:is_end) + status << "已结束" + time = course.end_date.strftime("%Y-%m-%d") + time_status = 6 + else + if homework_common.end_time && homework_common.end_time < Time.now && homework_common.allow_late && + (homework_common.late_time.nil? || homework_common.late_time > Time.now) + status << "补交中" + end + + ho_detail_manual = homework_common.homework_detail_manual + if ho_detail_manual + # 作业状态大于“提交”状态时,不用考虑分班权限 + if ho_detail_manual.comment_status > 1 + case ho_detail_manual.comment_status + when 3 + if ho_detail_manual.evaluation_end && ho_detail_manual.evaluation_end > Time.now + status << "匿评中" + time = how_much_time(ho_detail_manual.evaluation_end) + time_status = 3 + end + when 4 + if ho_detail_manual.appeal_time && ho_detail_manual.appeal_time > Time.now + status << "申诉中" + time = how_much_time(ho_detail_manual.appeal_time) + time_status = 4 + end + when 2, 5, 6 + status << "评阅中" + time = course.end_date.present? ? how_much_time(course.end_date.end_of_day) : "" + time_status = 5 + end + + # 如果还在补交阶段则显示补交结束时间 + if homework_common.end_time && homework_common.end_time < Time.now && homework_common.allow_late && + homework_common.late_time && homework_common.late_time > Time.now + time = how_much_time(homework_common.late_time) + time_status = 2 + end + else + # member = course.course_members.find_by(user_id: user.id, is_active: 1) + # teacher_course_groups = member.try(:teacher_course_groups) + # identity = user.course_identity(course) + + # 作业统一设置、游客身份、超级管理员、分班权限不限的老师身份 + if homework_common.unified_setting || identity > Course::STUDENT || identity == Course::ADMIN || + (identity < Course::STUDENT && teacher_course_groups.size == 0) + case ho_detail_manual.comment_status + when 0 + status << "未发布" + time = homework_common.publish_time.present? ? "将于 #{format_time(homework_common.publish_time)} 发布" : "创建于#{time_from_now(homework_common.created_at)}" + time_status = 0 + when 1 + if homework_common.end_time && homework_common.end_time >= Time.now + status << "提交中" + time = how_much_time(homework_common.end_time) + time_status = 1 + elsif homework_common.end_time && homework_common.end_time < Time.now + time_status = 5 + if homework_common.allow_late && (homework_common.late_time.nil? || homework_common.late_time >= Time.now) + time = how_much_time(homework_common.late_time) + time_status = 2 + end + status << "评阅中" + end + end + else + # 未分班的学生始终显示“未发布”(按理不会来到这个判断) + if member.role == "STUDENT" && member.course_group_id == 0 + status << "未发布" + time = "" + time_status = 0 + else + if member.role == "STUDENT" + setting = homework_common.homework_group_settings.find_by(course_group_id: member.course_group_id) + min_publish_time = setting.try(:publish_time) + max_end_time = setting.try(:end_time) + else + # 多个分班权限的取最小publish_time,最大end_time + min_publish_time = homework_common.homework_group_settings.where.not(publish_time: nil). + where(course_group_id: teacher_course_groups.pluck(:course_group_id)).pluck(:publish_time).min + max_end_time = homework_common.homework_group_settings.where.not(end_time: nil). + where(course_group_id: teacher_course_groups.pluck(:course_group_id)).pluck(:end_time).max + end + + if min_publish_time.nil? + status << "未发布" + time = "创建于#{time_from_now(homework_common.created_at)}" + time_status = 0 + elsif min_publish_time > Time.now + status << "未发布" + time = "将于 #{format_time(min_publish_time)} 发布" + time_status = 0 + elsif max_end_time.present? && max_end_time > Time.now #6.14 -hs 添加present? + status << "提交中" + time = how_much_time(max_end_time) + time_status = 1 + elsif homework_common.allow_late && (homework_common.late_time.nil? || homework_common.late_time >= Time.now) + status << "评阅中" + time = how_much_time(homework_common.late_time) + time_status = 2 + else + status << "评阅中" + time = "" + time_status = 5 + end + end + end + status << "未开启补交" if !homework_common.allow_late && time_status != 0 + end + end + end + # 如果作业状态都没有的话,在课堂结束前,都显示评阅中 + if status.blank? + status << "评阅中" + end + result[:status] = status + result[:time] = time + result[:time_status] = time_status + result + end + + + # 阶段剩余时间 + def left_time homework, user_id + setting = homework.homework_group_setting(user_id) + if setting.publish_time && setting.publish_time < Time.now + if setting.end_time > Time.now + status = "剩余提交时间" + time = "#{how_much_time(setting.end_time)}" + else + ho_detail_manual = homework.homework_detail_manual + case ho_detail_manual.comment_status + when 3 + if ho_detail_manual.evaluation_end && ho_detail_manual.evaluation_end > Time.now + status = "剩余匿评时间" + time = "#{how_much_time(ho_detail_manual.evaluation_end)}" + end + when 4 + if ho_detail_manual.appeal_time && ho_detail_manual.appeal_time > Time.now + status = "剩余申诉时间" + time = "#{how_much_time(ho_detail_manual.appeal_time)}" + end + else + if homework.allow_late && homework.late_time && homework.late_time >= Time.now + status = "剩余补交时间" + time = "#{how_much_time(homework.late_time)}" + end + end + end + end + {status: status, time: time} + end + + # 作品数统计:type: 1 已提交 0 未提交 + def studentwork_count homework_common, type, user_id + student_works = homework_common.teacher_works(user_id) + type == 1 ? student_works.select{|work| work.work_status != 0}.size : student_works.select{|work| work.work_status = 0}.size + end + + # 上次查重的时间 + def last_review_time homework_common, course_group + review = homework_common.homework_group_reviews.where(:course_group_id => course_group.id).last + review ? (format_time review.created_at) : "--" + end + + # 分班的有效作品数 + def homework_works_count homework_common, course_group + myshixun_ids = homework_common.student_works.where(user_id: course_group.course_members.pluck(:user_id)).pluck(:myshixun_id) + myshixuns = Myshixun.joins(:games).where(id: myshixun_ids).where("games.status = ?", 2).count + end + + # 未分班的有效作品数 + def homework_ungroup_works_count homework_common, user_ids + myshixun_ids = homework_common.student_works.where(user_id: user_ids).pluck(:myshixun_id) + myshixuns = Myshixun.joins(:games).where(id: myshixun_ids).where("games.status = ?", 2).count + end + + def ungroup_last_review_time homework_common + review = homework_common.homework_group_reviews.where(:course_group_id => 0).last + review ? (format_time review.created_at) : "--" + end + + def work_finished_time challenge_id, user_id + Challenge.find(challenge_id).games.find_by(user_id: user_id) + end + + def challenge_setting homework, challenge_id + homework.homework_challenge_settings.find_by(challenge_id: challenge_id) + end + + def group_homework_setting homework, group_id + homework.homework_group_settings.find_by(course_group_id: group_id) + end + + def homework_st_proportion homework + (1.0 - homework.homework_detail_manual.te_proportion - homework.homework_detail_manual.ta_proportion).round(2) + end + + def teacher_comment homework, user_id + [{ id: 0 ,name: "未评", count: homework.uncomment_count(user_id)}, {id: 1, name: "已评", count: homework.comment_count(user_id)}] + end + + # 作品状态 + def homework_status homework, user_id + [{id: 0, name: "未提交", count: homework.unfinished_count(user_id)}, + {id: 1, name: "按时提交", count: homework.finished_count(user_id)}, + {id: 2, name: "延时提交", count: homework.delay_finished_count(user_id)}] + end + + # 作品分数的显示 + def work_score_format score, current_user, score_open + score.nil? ? "--" : (current_user || score_open) ? number_with_precision(score, precision: 1) : "**" + end + + def anon_comments user, work_id + StudentWorksScore.where(student_work_id: work_id, reviewer_role: 3, user_id: user.id) + end +end diff --git a/app/helpers/memos_helper.rb b/app/helpers/memos_helper.rb new file mode 100644 index 000000000..7df887a4b --- /dev/null +++ b/app/helpers/memos_helper.rb @@ -0,0 +1,2 @@ +module MemosHelper +end diff --git a/app/helpers/messages_helper.rb b/app/helpers/messages_helper.rb new file mode 100644 index 000000000..84d6b08d2 --- /dev/null +++ b/app/helpers/messages_helper.rb @@ -0,0 +1,67 @@ +module MessagesHelper + + def by_user_liked?(obj, user) + obj.praise_treads.user_liker(user).present? + end + # 置顶降序排序(置顶排最前面) + def sort_by_sticky(messages) + messages = messages.sort_by {|message| -message.sticky } if messages.map(&:sticky).include?(1) + return messages + end + + # 根据回复数(包含二级回复)排序 + def sort_by_all_replies(sort, sort_type, arr) + return arr unless sort_type == "hot" + logger.info("####====> order by replies") + arr.each do |message| + message.total_replies_count = message.replies_count + message.children.sum(:replies_count) + end + return arr.sort_by { |msg| sort == 1 ? msg.total_replies_count : -msg.total_replies_count } + end + + def validate_delete_params + return normal_status(403, "") unless current_user.teacher_of_course?(@board.course) + return normal_status(2, "缺少ids参数!") if params[:ids].blank? + return normal_status(2, "参数ids格式不对!") unless params[:ids].is_a? Array + end + + def validate_move_params + return normal_status(2, "参数ids不能为空!") if params[:ids].blank? + return normal_status(2, "参数ids格式错误!") unless params[:ids].is_a? Array + return normal_status(2, "参数to_board_id不能为空!") if params[:to_board_id].blank? + end + + def message_validate_create_params + msg = if params[:select_board_id].blank? + "目录id不能为空!" + elsif params[:subject].blank? + "帖子标题不能为空!" + elsif params[:content].blank? + "帖子内容不能为空!" + elsif params.has_key?(:attachment_ids) && !params[:attachment_ids].is_a?(Array) + "参数attachment_ids格式错误!" + else + nil + end + normal_status(2, msg) unless msg.nil? + end + + def validate_update_params + normal_status(2, "目录id不能为空!") if params.has_key?(:select_board_id) && params[:select_board_id].blank? + normal_status(2, "帖子标题不能为空!") if params.has_key?(:subject) && params[:subject].blank? + normal_status(2, "帖子内容不能为空!") if params.has_key?(:content) && params[:content].blank? + end + + def validate_send_message_to_course_params + return normal_status(2, "ids参数不能为空!") if params[:ids].blank? + return normal_status(2, "参数ids格式不对!") unless params[:ids].is_a? Array + return normal_status(2, "to_course_ids参数不能为空!") if params[:to_course_ids].blank? + return normal_status(2, "参数to_course_ids格式不对!") unless params[:to_course_ids].is_a? Array + end + + def validate_page_size + return if !params.has_key?(:page_size) + return normal_status(0, "每页请求的数量只能为5-50") if params[:page_size].to_i < 5 || params[:page_size].to_i > 50 + end + +end diff --git a/app/helpers/myshixuns_helper.rb b/app/helpers/myshixuns_helper.rb new file mode 100644 index 000000000..650f32f40 --- /dev/null +++ b/app/helpers/myshixuns_helper.rb @@ -0,0 +1,2 @@ +module MyshixunsHelper +end diff --git a/app/helpers/poll_votes_helper.rb b/app/helpers/poll_votes_helper.rb new file mode 100644 index 000000000..723f56782 --- /dev/null +++ b/app/helpers/poll_votes_helper.rb @@ -0,0 +1,2 @@ +module PollVotesHelper +end diff --git a/app/helpers/polls_helper.rb b/app/helpers/polls_helper.rb new file mode 100644 index 000000000..5b4702174 --- /dev/null +++ b/app/helpers/polls_helper.rb @@ -0,0 +1,124 @@ +module PollsHelper + + #获取试卷的已答/未答人数 + def get_poll_answers(poll_users) + @commit_poll_users = poll_users.commit_by_status(1) #当前老师的全部学生中已提交的 + @poll_answers = @commit_poll_users.present? ? @commit_poll_users.count : 0 #表示已经提交了的用户 + course_all_members_count = poll_users.present? ? poll_users.count : 0 + @poll_unanswers = (course_all_members_count - @poll_answers) + end + + def poll_votes_count(votes,user_ids) + votes.find_current_vote("user_id",user_ids.uniq).size + end + + #公用tab页的相关信息 + def poll_common_header(is_teacher_or,poll) + poll_url_status = [] + if is_teacher_or == 1 #当为老师的 + common_tabs = %w(1 2 3 4) + else + if poll.show_result #开启了公开统计 + common_tabs = %w(1 2) + else + common_tabs = %w(1) + end + end + + common_tabs.each do |c| + if request.url.include?("polls_lists") + active_status = 1 + elsif request.url.include?("commit_result") + active_status = 1 + elsif request.url.include?("poll_setting") + active_status = 1 + elsif request.url == poll_path(poll) + active_status = 1 + else + active_status = 0 + end + common_tab = { + :common_tab => c, + :active_status => active_status + } + poll_url_status.push(common_tab) + end + poll_url_status + end + + #poll的列表页的显示 + def poll_index_show(poll,course,is_teacher_or,user) + # poll_all_users = poll.poll_users + if course.is_end #课堂停止后,试卷显示为已结束 + poll_status = 4 + elsif is_teacher_or == 1 || is_teacher_or == 0 || poll.unified_setting + #当前为老师(非课堂成员、统一设置)的时候,显示的是老师身份的对应试卷的状态,因为该试卷,可能对应老师的多个分班 + poll_status = poll.polls_status + else + poll_status = poll.get_poll_status(user.id) #当前用户查看的试卷的发布状态 + end + + if is_teacher_or == 1 + poll_users_list = poll.all_poll_users(user.id) #当前老师所在班级的全部学生 + get_poll_answers(poll_users_list) + ex_pb_time = poll.get_poll_times(user.id,true) + poll_publish_time = ex_pb_time[:publish_time] + poll_end_time = ex_pb_time[:end_time] + current_status = 3 + lock_icon = 1 #不显示锁图标 + elsif is_teacher_or == 2 + poll_users_list = poll.get_poll_exercise_users + get_poll_answers(poll_users_list) # 未答和已答的 + # get_poll_answers(poll_all_users) + ex_pb_time = poll.get_poll_times(user.id,false) + poll_publish_time = ex_pb_time[:publish_time] + poll_end_time = ex_pb_time[:end_time] + current_status = poll.check_user_votes_status(user) + lock_icon = 1 #不显示锁图标 + else + poll_users_list = poll.get_poll_exercise_users + get_poll_answers(poll_users_list) # 未答和已答的 + poll_publish_time = poll.publish_time + poll_end_time = poll.end_time + current_status = 4 + if poll.is_public + lock_icon = 1 #非课堂成员,但是试卷为公开的,不加锁 + else + lock_icon = 0 #显示锁图标 + end + end + { + "publish_time":poll_publish_time, + "end_time":poll_end_time, + "poll_answer":@poll_answers, + "poll_unanswer":@poll_unanswers, + "current_status":current_status, + "lock_icon":lock_icon, + "polls_status":poll_status + } + end + + #问卷列表页的用户信息显示 + def poll_user_info(poll_user,course_members,course) + poll = poll_user.poll + user = poll_user.user + user_student_id = user.student_id + + if poll.un_anonymous #是否开启实名认证 + poll_user_name = user.real_name + else + poll_user_name = user.nickname + end + course_member = course_members.find_by(user_id:user.id) + current_user_group_id = course_members.present? ? course_member.course_group_id : nil + course_group = course.course_groups.find_by_id(current_user_group_id) + { + "user_name":poll_user_name, + "user_id": user.id, + "student_id":user_student_id, + "group_name":course_group.try(:name), + "group_id":course_group.try(:id), + "login":user.login + } + end +end diff --git a/app/helpers/praise_tread_helper.rb b/app/helpers/praise_tread_helper.rb new file mode 100644 index 000000000..2e13973e7 --- /dev/null +++ b/app/helpers/praise_tread_helper.rb @@ -0,0 +1,2 @@ +module PraiseTreadHelper +end diff --git a/app/helpers/question_banks_helper.rb b/app/helpers/question_banks_helper.rb new file mode 100644 index 000000000..2d129eed5 --- /dev/null +++ b/app/helpers/question_banks_helper.rb @@ -0,0 +1,2 @@ +module QuestionBanksHelper +end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb new file mode 100644 index 000000000..05ffdf1cc --- /dev/null +++ b/app/helpers/repositories_helper.rb @@ -0,0 +1,2 @@ +module RepositoriesHelper +end diff --git a/app/helpers/schools_helper.rb b/app/helpers/schools_helper.rb new file mode 100644 index 000000000..caddacedc --- /dev/null +++ b/app/helpers/schools_helper.rb @@ -0,0 +1,2 @@ +module SchoolsHelper +end diff --git a/app/helpers/shixuns_helper.rb b/app/helpers/shixuns_helper.rb new file mode 100644 index 000000000..71bc833d4 --- /dev/null +++ b/app/helpers/shixuns_helper.rb @@ -0,0 +1,154 @@ +module ShixunsHelper + + def level_to_s(level) + %W(初级 中级 高级 顶级)[level-1] + end + + #难度 + def diff_to_s(trainee) + %W(初级学员 中级学员 高级学员 顶级学员)[trainee-1] + end + + #1. 未发布 + def status_to_s(status) + %W(未发布 已发布 已关闭)[status-1] + end + + # 已完成实训所获得的经验值 + def myshixun_exp myshixun + score = 0 + myshixun.games.each do |game| + score += game.final_score.to_i < 0 ? 0 : game.challenge.score.to_i + end + score + end + + # 已完成实训所消耗的时间 + def myshixun_spend_time myshixun + time = myshixun.games.map(&:cost_time).sum + time + end + + # 已完成实训的准确率 + def myshixun_accuracy myshixun + accuracy = 0 + count = 0 + myshixun.games.each do |game| + count += 1 + accuracy += game.accuracy ? game.accuracy : 0 + end + accuracy.to_f / count + end + + # 实训的最终通关时间 + def myshixun_done_time myshixun + time = "" + if myshixun.status == 1 || myshixun.games.where(:status => 2).count == myshixun.shixun.challenges.count + time = myshixun.games.where(:status => 2).map(&:end_time).max + end + time + end + + def had_passed_count + + end + + #显示项目配置菜单 + def show_project_memu user + if user.allowed_to?(:edit_project, @shixun) + result = "edit_project" + elsif user.allowed_to?(:manage_members, @shixun) + result = "training_task" + elsif user.allowed_to?(:manage_versions, @shixun) + result = "manage_versions" + elsif user.allowed_to?(:manage_repository, @shixun) + result = "manage_repository" + end + result + end + + def show_shixun_mirror shixun + mirror_name = "" + shixun.mirror_repositories.try(:each) do |mirror| + if mirror_name.blank? + mirror_name = mirror.type_name + else + mirror_name = "#{mirror_name};#{mirror.type_name}" + end + end + return mirror_name + end + + def generate_script shixun, script + if script.present? + source_class_name = [] + challenge_program_name = [] + shixun.challenges.map(&:exec_path).each do |exec_path| + challenge_program_name << "\"#{exec_path}\"" + if shixun.mirror_name.try(:first) == "Java" + if exec_path.nil? || exec_path.split("src/")[1].nil? + source = "" + else + source = "\"#{exec_path.split("src/")[1].split(".java")[0]}\"" + end + source_class_name << source.gsub("/", ".") if source.present? + end + end + script = if script.include?("sourceClassName") && script.include?("challengeProgramName") + script.gsub("CHALLENGEPROGRAMNAMES","#{challenge_program_name.reject(&:blank?).join(" ")}").gsub("SOURCECLASSNAMES", "#{source_class_name.reject(&:blank?).join(" ")}") + else + script.gsub("CHALLENGEPROGRAMNAMES","#{challenge_program_name.reject(&:blank?).join(" ")}").gsub("SOURCECLASSNAMES", "#{challenge_program_name.reject(&:blank?).join(" ")}") + end + end + return script + end + + def had_passed_challenge challenge + Game.where(:challenge_id => challenge.id, :status => 2).limit(3).reorder("final_score desc") + end + + def finished_num challenge + Game.finished_num(challenge.id).count + end + + def doing_num challenge + Game.doing_num(challenge.id).count + end + + def challenge_status(challenge_id, user_id) + Game.where(challenge_id: challenge_id, user_id: user_id).limit(1).try(:status) || 0 + end + + # 若实训关卡位置,关卡数等信息发生变化则需要修改脚本内容 + def modify_shixun_script shixun, script + if script.present? + source_class_name = [] + challenge_program_name = [] + shixun.challenges.map(&:exec_path).each do |exec_path| + challenge_program_name << "\"#{exec_path}\"" + if shixun.main_mirror_name.try(:first) == "Java" + if exec_path.nil? || exec_path.split("src/")[1].nil? + source = "\"\"" + else + source = "\"#{exec_path.split("src/")[1].split(".java")[0]}\"" + end + source_class_name << source.gsub("/", ".") if source.present? + elsif shixun.main_mirror_name.try(:first) == "C#" + if exec_path.nil? || exec_path.split(".")[1].nil? + source = "\"\"" + else + source = "\"#{exec_path.split(".")[0]}.exe\"" + end + source_class_name << source if source.present? + end + end + script = if script.include?("sourceClassName") && script.include?("challengeProgramName") + script.gsub(/challengeProgramNames=\(.*\)/,"challengeProgramNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)").gsub(/sourceClassNames=\(.*\)/, "sourceClassNames=\(#{source_class_name.reject(&:blank?).join(" ")}\)") + else + script.gsub(/challengeProgramNames=\(.*\)/,"challengeProgramNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)").gsub(/sourceClassNames=\(.*\)/, "sourceClassNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)") + end + end + return script + end + +end \ No newline at end of file diff --git a/app/helpers/stages_helper.rb b/app/helpers/stages_helper.rb new file mode 100644 index 000000000..de6501fa6 --- /dev/null +++ b/app/helpers/stages_helper.rb @@ -0,0 +1,59 @@ +module StagesHelper + + # 章节实训的通关情况 + def stage_myshixun_status shixun, user + myshixun = Myshixun.where(user_id: user.id, shixun_id: shixun.id).first + myshixun.try(:status) == 1 ? 1 : 0 + end + + # 实训路径详情列表,右侧实训的状态显示栏 + def stage_shixun_status subject_status, shixun_status, shixun_hidden + status = if shixun_hidden + '暂未公开' + else + if subject_status < 2 + case shixun_status + when 0, 1 + '暂未公开' + when 2 + '已发布' + when 3 + '已关闭' + end + else + if shixun_status != 2 + case shixun_status + when 0, 1 + '暂未公开' + when 3 + '已关闭' + end + else + '' + end + end + end + return status + end + + # 开启挑战的path + def stage_tpi_path shixun, user, subject_id + path = "" + if shixun.status == 2 || user.manager_of_shixun?(shixun) + myshixun = Myshixun.where(user_id: user.id, shixun_id: shixun.id).first + if myshixun.present? + if user.try(:mail).blank? + path = security_settings_path + elsif shixun.challenges_count > 0 + is_modify = ShixunModify.where(:myshixun_id => myshixun.try(:id), :shixun_id => shixun.try(:id), :status => 1).first + if is_modify.blank? + path = shixun_exec_shixun_path(shixun, :is_subject => subject_id) + else + path = myshixun_reset_myshixun_path(myshixun, :is_subject => subject_id) + end + end + end + end + return path + end +end diff --git a/app/helpers/student_works_helper.rb b/app/helpers/student_works_helper.rb new file mode 100644 index 000000000..93a1a3f9a --- /dev/null +++ b/app/helpers/student_works_helper.rb @@ -0,0 +1,165 @@ +module StudentWorksHelper + # 学生作业是否迟交 + def student_work_is_delay? homework_common, game + (Time.now > homework_common.end_time && game.end_time.blank?) || (game.end_time.present? && game.end_time > homework_common.end_time) + end + + # 关卡的完成状态:提交截止(不允许补交)后或补交截止后通关的是无效状态,允许补交且在补交阶段内通关的是延时状态,提交截止前完成的是正常状态 + # 0:未通关 1:正常 2:延时 3:无效 + def game_status game, homework + if game.status == 2 + homework_setting = homework.homework_group_setting game.user_id + status = homework_setting.end_time >= game.end_time ? 1 : + (homework.allow_late && homework.late_time > game.end_time) ? 2 : 3 + else + status = 0 + end + status + end + + # 作业的开启时间 + def myshixun_open_time game + game.open_time ? (format_time game.open_time) : "--" + end + + # 作业完成时间 + def finished_time end_time + end_time ? (format_time end_time) : "--" + end + + # 作业耗时 + def time_consuming game + game.end_time.blank? ? "--" : (game_spend_time game.cost_time) + end + + # 用户个人实训总得分:user_total_score; + # consume_time通关的关卡总耗时间; + # all_tine实训的总耗时 + # evaluate_count: 每次总评测次数; + # eff_score:用户得分/总评测次数; + # round_size:log(所有课堂实训最大评测次数/当前实训评测次数) + + def student_efficiency(homework_common, work) + myshixun_ids = homework_common.student_works.pluck(:myshixun_id) + myshixuns = Myshixun.where(id: myshixun_ids).includes(games: [:outputs]) + #student_works_user_id = homework_common.student_works.pluck(:user_id).uniq + #shixun = homework_common.shixuns.first + #logger.info("#########shixun_id: ###{shixun.id}") + #myshixuns = shixun.myshixuns.where(:user_id => student_works_user_id).includes(games: [:outputs]) + + # 最大评测次数 + max_evaluate_count = 0 + + # 数据库操作改成对hash数组的操作 + objects = + myshixuns.map do |myshixun| + # 评测次数 + evaluate_count = myshixun.games.inject(0) {|sum, g| sum + g.outputs.pluck(:query_index).first.to_i} + # 获取最大评测次数 + max_evaluate_count = (evaluate_count > max_evaluate_count ? evaluate_count : max_evaluate_count) + # 通关耗时 + pass_consume_time = (myshixun.games.where(status: 2).pluck(:cost_time).sum / 60.0) + # 总耗时 + all_time = (myshixun.games.pluck(:cost_time).sum / 60.0) + # 通关得分 + user_total_score = myshixun.total_score.to_i + # 耗时,保留2位小数, + consume_time = all_time <= 1 ? 1 : Math.log(all_time).to_f + consume_time = format("%.2f", consume_time).to_f + # 效率 + efficiency = (pass_consume_time == 0 ? 0 : Math.log((user_total_score / pass_consume_time.to_f) + 1.0)) + efficiency = format("%.2f", efficiency).to_f + + {consume_time: consume_time, evaluate_count: evaluate_count, user_id: myshixun.user_id, + user_total_score: user_total_score, efficiency: efficiency} + end + + # 我的效率 + myself_eff = [] + myself_object = [] + # 最小效率值 + min_efficiency = objects.map {|o| o[:efficiency]}.min + # 最大效率值 + # max_efficiency = objects.map{|o| o[:efficiency]}.max + results = + objects.each_with_index.map do |object, index| + y_score = (object[:evaluate_count] == 0 ? 0 : (object[:user_total_score] / object[:evaluate_count].to_f)) + eff_score = format("%.2f", y_score).to_f + # 效率值 + efficiency = object[:efficiency] < 0 ? + format("%.2f", object[:efficiency] - min_efficiency) : object[:efficiency] + + # 圆圈的大小 + round_size = (object[:evaluate_count] == 0 ? 0 : Math.log(max_evaluate_count / object[:evaluate_count].to_f)) * 3.14 + # 作品本人的数据 + if object[:user_id] == work.user.id + myself_eff = [index + 1, efficiency] + myself_object = [object[:consume_time], eff_score, round_size] + end + {:eff_score => eff_score, :user_id => object[:user_id], :consume_time => object[:consume_time], + :efficiency => efficiency, :round_size => round_size} + end + + # 对结果进行排序 + efficiency_list = + results.sort {|x, y| x[:efficiency] <=> y[:efficiency]}.each_with_index.map do |result, index| + [index + 1, result[:efficiency], result[:user_id]] + end + + consume_list = + results.sort {|x, y| x[:consume_time] <=> y[:consume_time]}.map do |result| + [result[:consume_time], result[:eff_score], result[:round_size], result[:user_id]] + end + + return {myself_eff: myself_eff, myself_object: myself_object, efficiency_list: efficiency_list, consume_list: consume_list} + end + + # tpi详情信息 + def output_detail game, output + if game.challenge.st == 0 + output.try(:out_put).delete("详情如下:") + else + if game.status == 2 + "评测通过" + else + "共有#{game.challenge.challenge_chooses.count}组测试集,其中有#{game.challenge.challenge_chooses.count-game.choose_correct_num}组测试结果不匹配" + end + end + end + + def allow_score homework, identity, user_id, work + (identity < Course::STUDENT && !work.ultimate_score) || + (identity == Course::STUDENT && homework.anonymous_comment && + [3, 4].include?(homework.homework_detail_manual.comment_status) && + StudentWorksEvaluationDistribution.where(user_id: user_id, student_work_id: work.id).count > 0) + end + + def message_user_name(message_user, score, work_user, current_user, identity) + user_name = "" + user_login = "--" + image_url = "--" + if score.reviewer_role == 3 && score.user == message_user && message_user != current_user && identity >= Course::STUDENT + user_name = "匿评人" + elsif score.reviewer_role == 3 && work_user == message_user && message_user != current_user && identity >= Course::STUDENT + user_name = "被匿评人" + else + user_name = message_user.real_name + user_login = message_user.login + image_url = url_to_avatar(score.user) + end + {user_name: user_name, user_login: user_login, user_image_url: image_url} + end + + def appeal_info work_appeal, user_identity, current_user + if user_identity < Course::STUDENT || work_appeal.user == current_user + user_name = work_appeal.user.try(:real_name) + user_login = work_appeal.user.try(:login) + image_url = url_to_avatar(work_appeal.user) + else + user_name = "匿名" + user_login = "--" + image_url = "--" + end + {id: work_appeal.id, user_name: user_name, user_login: user_login, user_image_url: image_url, time: work_appeal.created_at, content: work_appeal.comment} + end +end diff --git a/app/helpers/subjects_helper.rb b/app/helpers/subjects_helper.rb new file mode 100644 index 000000000..21fb3bb0d --- /dev/null +++ b/app/helpers/subjects_helper.rb @@ -0,0 +1,13 @@ +module SubjectsHelper + + # 实训路径的发布状态 + def publish_status subject, is_manager, user + status = -1 + if is_manager + status = 0 if subject.status == 0 && subject.shixuns_count > 0 + status = 1 if subject.status == 1 + status = 2 if subject.status == 2 && user.admin? + end + status + end +end diff --git a/app/helpers/tem_tests_helper.rb b/app/helpers/tem_tests_helper.rb new file mode 100644 index 000000000..15bfcc4b3 --- /dev/null +++ b/app/helpers/tem_tests_helper.rb @@ -0,0 +1,2 @@ +module TemTestsHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 000000000..bee0f6b1a --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/imports/application_import.rb b/app/imports/application_import.rb new file mode 100644 index 000000000..cd2e8734c --- /dev/null +++ b/app/imports/application_import.rb @@ -0,0 +1,5 @@ +class ApplicationImport + def logger(msg) + Rails.logger.error(msg) + end +end \ No newline at end of file diff --git a/app/imports/base_import_excel.rb b/app/imports/base_import_excel.rb new file mode 100644 index 000000000..9646c8ec0 --- /dev/null +++ b/app/imports/base_import_excel.rb @@ -0,0 +1,29 @@ +class BaseImportExcel < ApplicationImport + Error = Class.new(StandardError) + + attr_reader :sheet + + def initialize(path) + raise Error, '不支持的文件格式' unless path.end_with?('.xls') || path.end_with?('.xlsx') + + begin + @sheet = Roo::Spreadsheet.open(path).sheet(0) + rescue Exception => ex + logger ex.message + ex.backtrace.each(&method(:logger)) + raise Error, '打开文件失败' + end + + check_sheet_valid! + end + + def read_each(&block);end + + private + + def check_sheet_valid!;end + + def raise_import_error(message) + raise Error, message + end +end \ No newline at end of file diff --git a/app/imports/ecs/import_achievement_excel.rb b/app/imports/ecs/import_achievement_excel.rb new file mode 100644 index 000000000..1aa703bc4 --- /dev/null +++ b/app/imports/ecs/import_achievement_excel.rb @@ -0,0 +1,37 @@ +class Ecs::ImportAchievementExcel < BaseImportExcel + def average_score_template? + type == :average_score + end + + def detail_score_template? + type == :detail_score + end + + def read_each(&block) + average_score_template? ? read_average_score(&block) : read_detail_score(&block) + end + + private + + def read_average_score(&block) + block.call(sheet.row(3)) + end + + def read_detail_score(&block) + 3.upto(sheet.last_row) do |index| + data = sheet.row(index) + next if data.all?(:blank?) + + block.call(data) + end + end + + def type + @_type ||= sheet.cell(1, 1)&.strip == '学号' && sheet.cell(1, 2)&.strip == '姓名' ? :detail_score : :average_score + end + + def check_sheet_valid! + raise_import_error('请按照模板格式导入') if sheet.last_row.nil? || sheet.last_row < 3 + raise_import_error('平均成绩只能有一行数据') if average_score_template? && sheet.last_row > 3 + end +end \ No newline at end of file diff --git a/app/imports/ecs/import_course_excel.rb b/app/imports/ecs/import_course_excel.rb new file mode 100644 index 000000000..5cfedca69 --- /dev/null +++ b/app/imports/ecs/import_course_excel.rb @@ -0,0 +1,16 @@ +class Ecs::ImportCourseExcel < BaseImportExcel + def read_each(&block) + 2.upto(sheet.last_row) do |row_num| + name = sheet.row(row_num)[0].to_s.strip + next if name.blank? + + block.call(name) + end + end + + private + + def check_sheet_valid! + raise_import_error('请按照模板格式导入') if sheet.cell(1, 1) != '课程名称(必填)' + end +end \ No newline at end of file diff --git a/app/imports/ecs/import_student_excel.rb b/app/imports/ecs/import_student_excel.rb new file mode 100644 index 000000000..ad60a5e1d --- /dev/null +++ b/app/imports/ecs/import_student_excel.rb @@ -0,0 +1,19 @@ +class Ecs::ImportStudentExcel < BaseImportExcel + def read_each(&block) + 2.upto(sheet.last_row) do |row_num| + data = sheet.row(row_num) + + number = data[0].to_s.strip + name = data[1].to_s.strip + next if number.blank? + + block.call(number, name) + end + end + + private + + def check_sheet_valid! + raise_import_error('请按照模板格式导入') if sheet.cell(1, 1) != '学号(必填)' || sheet.cell(1, 2) != '姓名' + end +end \ No newline at end of file diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 000000000..d7c48b9a3 --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/jobs/apply_teacher_role_join_course_notify_job.rb b/app/jobs/apply_teacher_role_join_course_notify_job.rb new file mode 100644 index 000000000..c2495c036 --- /dev/null +++ b/app/jobs/apply_teacher_role_join_course_notify_job.rb @@ -0,0 +1,23 @@ +# 申请成为老师加入课堂 消息通知 +class ApplyTeacherRoleJoinCourseNotifyJob < ApplicationJob + queue_as :notify + + def perform(user_id, course_id, role) + user = User.find_by(id: user_id) + course = Course.find_by(id: course_id) + return if user.blank? || course.blank? + + attrs = %i[user_id trigger_user_id container_id container_type belong_container_id + belong_container_type tiding_type extra created_at updated_at] + + same_attrs = { + trigger_user_id: user.id, container_id: course.id, container_type: 'JoinCourse', + belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'Apply', extra: role + } + Tiding.bulk_insert(*attrs) do |worker| + course.teachers_without_assistant_professor.each do |teacher| + worker.add same_attrs.merge(user_id: teacher.user_id) + end + end + end +end diff --git a/app/jobs/exercise_publish_notify_job.rb b/app/jobs/exercise_publish_notify_job.rb new file mode 100644 index 000000000..c66fa5660 --- /dev/null +++ b/app/jobs/exercise_publish_notify_job.rb @@ -0,0 +1,34 @@ +# 试卷发布 消息通知 +class ExercisePublishNotifyJob < ApplicationJob + queue_as :notify + + def perform(exercise_id, receiver_ids) + exercise = Exercise.find_by(id: exercise_id) + return if exercise.blank? + user = exercise.user + + attrs = %i[ + user_id trigger_user_id container_id container_type parent_container_id parent_container_type + belong_container_id belong_container_type viewed tiding_type created_at updated_at + ] + + same_attrs = { + trigger_user_id: user.id, container_id: exercise.id, container_type: 'Exercise', + parent_container_id: exercise.id, parent_container_type: 'ExercisePublish', + belong_container_id: exercise.course_id, belong_container_type: 'Course', + viewed: 0, tiding_type: 'Exercise' + } + Tiding.bulk_insert(*attrs) do |worker| + teacher_ids = exercise.course.teachers.pluck(:user_id) + unless exercise.tidings.exists?(parent_container_type: 'ExercisePublish', user_id: teacher_ids) + exercise.course.teachers.find_each do |teacher| + worker.add same_attrs.merge(user_id: teacher.user_id) + end + end + + receiver_ids.each do |user_id| + worker.add same_attrs.merge(user_id: user_id) + end + end + end +end diff --git a/app/jobs/graduation_task_publish_notify_job.rb b/app/jobs/graduation_task_publish_notify_job.rb new file mode 100644 index 000000000..3489aa711 --- /dev/null +++ b/app/jobs/graduation_task_publish_notify_job.rb @@ -0,0 +1,26 @@ +# 任务发布 消息通知 +class GraduationTaskPublishNotifyJob < ApplicationJob + queue_as :notify + + def perform(graduation_task_id) + task = GraduationTask.find_by(id: graduation_task_id) + return if task.blank? + + attrs = %i[ + user_id trigger_user_id container_id container_type parent_container_id parent_container_type + belong_container_id belong_container_type viewed tiding_type created_at updated_at + ] + + same_attrs = { + trigger_user_id: task.user_id, container_id: task.id, container_type: 'GraduationTask', + parent_container_id: task.id, parent_container_type: 'TaskPublish', + belong_container_id: task.course_id, belong_container_type: 'Course', + viewed: 0, tiding_type: 'GraduationTask' + } + Tiding.bulk_insert(*attrs) do |worker| + task.course.students.find_each do |student| + worker.add same_attrs.merge(user_id: student.user_id) + end + end + end +end diff --git a/app/jobs/homework_common_push_notify_job.rb b/app/jobs/homework_common_push_notify_job.rb new file mode 100644 index 000000000..961face58 --- /dev/null +++ b/app/jobs/homework_common_push_notify_job.rb @@ -0,0 +1,43 @@ +# 任务发布 消息通知 +class HomeworkCommonPushNotifyJob < ApplicationJob + queue_as :notify + + def perform(homework_common_id, group_ids) + homework = HomeworkCommon.find_by(id: homework_common_id) + return if homework.blank? + course = homework.course + + if group_ids.present? + students = course.students.where(course_group_id: group_ids) + subquery = course.teacher_course_groups.where(course_group_id: group_ids).select(:course_member_id) + teachers = course.teachers.where(id: subquery) + else + students = course.students + teachers = course.teachers + end + + attrs = %i[ + user_id trigger_user_id container_id container_type parent_container_id parent_container_type + belong_container_id belong_container_type viewed tiding_type created_at updated_at + ] + + same_attrs = { + trigger_user_id: homework.user_id, container_id: homework.id, container_type: 'HomeworkCommon', + parent_container_id: homework.id, parent_container_type: 'HomeworkPublish', + belong_container_id: task.course_id, belong_container_type: 'Course', + viewed: 0, tiding_type: 'HomeworkCommon' + } + Tiding.bulk_insert(*attrs) do |worker| + teacher_ids = teachers.pluck(:user_id) + if homework.tidings.where(parent_container_type: 'HomeworkPublish', user_id: teacher_ids).exists? + teacher_ids.each do |user_id| + worker.add same_attrs.merge(user_id: user_id) + end + end + + students.pluck(:user_id).each do |user_id| + worker.add same_attrs.merge(user_id: user_id) + end + end + end +end diff --git a/app/jobs/homework_publish_update_work_status_job.rb b/app/jobs/homework_publish_update_work_status_job.rb new file mode 100644 index 000000000..0060ab270 --- /dev/null +++ b/app/jobs/homework_publish_update_work_status_job.rb @@ -0,0 +1,33 @@ +class HomeworkPublishUpdateWorkStatusJob < ApplicationJob + # 作业发布时更新学生(发布前已开启过实训)的作业状态和成绩 + queue_as :default + + def perform(group_ids, homework_id) + # Do something later + homework = HomeworkCommon.find_by(id: homework_id) + return if homework.blank? + course = homework.course + return if course.blank? + + where_con = group_ids.nil? ? {course_id: homework.course_id, role: 4} : {course_id: homework.course_id, role: 4, course_group_id: group_ids} + + shixun_id = homework.homework_commons_shixun.try(:shixun_id) + + student_works = homework.student_works.joins("join course_members on student_works.user_id = course_members.user_id"). + where(course_members: where_con, work_status: 0).joins("join myshixuns on myshixuns.user_id = student_works.user_id"). + where(myshixuns: {shixun_id: shixun_id}) + + student_works.each do |work| + myshixun = Myshixun.find_by(shixun_id: shixun_id, user_id: work.user_id) + + work.work_status = 1 + work.commit_time = myshixun.updated_at + work.update_time = myshixun.updated_at + work.myshixun_id = myshixun.id + + work.save! + + HomeworksService.new.set_shixun_final_score work + end + end +end diff --git a/app/jobs/poll_publish_notify_job.rb b/app/jobs/poll_publish_notify_job.rb new file mode 100644 index 000000000..bc31957e0 --- /dev/null +++ b/app/jobs/poll_publish_notify_job.rb @@ -0,0 +1,34 @@ +# 问卷发布 消息通知 +class PollPublishNotifyJob < ApplicationJob + queue_as :notify + + def perform(poll_id, receiver_ids) + poll = Poll.find_by(id: poll_id) + return if poll.blank? + user = poll.user + + attrs = %i[ + user_id trigger_user_id container_id container_type parent_container_id parent_container_type + belong_container_id belong_container_type viewed tiding_type created_at updated_at + ] + + same_attrs = { + trigger_user_id: user.id, container_id: poll.id, container_type: 'Poll', + parent_container_id: poll.id, parent_container_type: 'PollPublish', + belong_container_id: poll.course_id, belong_container_type: 'Course', + viewed: 0, tiding_type: 'Poll' + } + Tiding.bulk_insert(*attrs) do |worker| + teacher_ids = poll.course.teachers.pluck(:user_id) + unless poll.tidings.exists?(parent_container_type: 'PollPublish', user_id: teacher_ids) + poll.course.teachers.find_each do |teacher| + worker.add same_attrs.merge(user_id: teacher.user_id) + end + end + + receiver_ids.each do |user_id| + worker.add same_attrs.merge(user_id: user_id) + end + end + end +end diff --git a/app/jobs/student_join_course_notify_job.rb b/app/jobs/student_join_course_notify_job.rb new file mode 100644 index 000000000..3768ee756 --- /dev/null +++ b/app/jobs/student_join_course_notify_job.rb @@ -0,0 +1,23 @@ +# 学生加入课堂 消息通知 +class StudentJoinCourseNotifyJob < ApplicationJob + queue_as :notify + + def perform(student_id, course_id) + student = User.find_by(id: student_id) + course = Course.find_by(id: course_id) + return if student.blank? || course.blank? + + attrs = %i[user_id trigger_user_id status container_id container_type belong_container_id + belong_container_type tiding_type created_at updated_at] + + same_attrs = { + trigger_user_id: student.id, container_id: course.id, container_type: 'StudentJoinCourse', + belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'System', status: 0 + } + Tiding.bulk_insert(*attrs) do |worker| + course.teachers_without_assistant_professor.each do |teacher| + worker.add same_attrs.merge(user_id: teacher.user_id) + end + end + end +end diff --git a/app/jobs/student_work_score_appeal_notify_job.rb b/app/jobs/student_work_score_appeal_notify_job.rb new file mode 100644 index 000000000..4d8076a0e --- /dev/null +++ b/app/jobs/student_work_score_appeal_notify_job.rb @@ -0,0 +1,29 @@ +# 学生匿评进行申诉 消息通知 +class StudentWorkScoreAppealNotifyJob < ApplicationJob + queue_as :notify + + def perform(course_id, score_appeal_id, user_id) + course = Course.find_by(id: course_id) + appeal = StudentWorksScoresAppeal.find_by(id: score_appeal_id) + user = User.find_by(id: user_id) + return if [course, appeal, user].any?(&:blank?) + score = appeal.student_works_score + + attrs = %i[user_id trigger_user_id container_id container_type parent_container_id parent_container_type + belong_container_id belong_container_type tiding_type viewed status created_at updated_at] + + same_attrs = { + trigger_user_id: user.id, + container_id: appeal.id, container_type: 'StudentWorksScoresAppeal', + parent_container_id: score.student_work_id, parent_container_type: 'StudentWork', + belong_container_id: course.id, belong_container_type: 'Course', + tiding_type: 'HomeworkCommon', viewed: 0, status: 0 + } + Tiding.bulk_insert(*attrs) do |worker| + course.course_member(user).member_teachers.each do |teacher| + worker.add same_attrs.merge(user_id: teacher.user_id) + end + worker.add same_attrs.merge(user_id: score.user_id) + end + end +end diff --git a/app/jobs/submit_graduation_work_notify_job.rb b/app/jobs/submit_graduation_work_notify_job.rb new file mode 100644 index 000000000..17cfc21d2 --- /dev/null +++ b/app/jobs/submit_graduation_work_notify_job.rb @@ -0,0 +1,32 @@ +# 学生提交作品 消息通知 +class SubmitGraduationWorkNotifyJob < ApplicationJob + queue_as :notify + + def perform(task_id, student_ids) + task = GraduationTask.find_by(id: task_id) + return if task.blank? || student_ids.blank? + course = task.course + + attrs = %i[user_id trigger_user_id container_id container_type parent_container_id parent_container_type + belong_container_id belong_container_type tiding_type viewed created_at updated_at] + + same_attrs = { + container_type: 'GraduationWork', parent_container_id: task.id, parent_container_type: 'GraduationTask', + belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'GraduationTask', viewed: 0 + } + Tiding.bulk_insert(*attrs) do |worker| + student_ids.each do |user_id| + next unless User.exists?(id: user_id) + + work = task.graduation_works.find_by(user_id: user_id) + next if work.blank? + + attrs = same_attrs.merge(trigger_user_id: user_id, container_id: work.id) + + course.course_member(user_id).member_teachers.find_each do |teacher| + worker.add attrs.merge(user_id: teacher.user_id) + end + end + end + end +end diff --git a/app/jobs/submit_student_work_notify_job.rb b/app/jobs/submit_student_work_notify_job.rb new file mode 100644 index 000000000..acb7873ac --- /dev/null +++ b/app/jobs/submit_student_work_notify_job.rb @@ -0,0 +1,32 @@ +# 学生提交作业 消息通知 +class SubmitStudentWorkNotifyJob < ApplicationJob + queue_as :notify + + def perform(homework_id, student_ids) + homework = HomeworkCommon.find_by(id: homework_id) + return if homework.blank? || student_ids.blank? + course = homework.course + + attrs = %i[user_id trigger_user_id container_id container_type parent_container_id parent_container_type + belong_container_id belong_container_type tiding_type viewed created_at updated_at] + + same_attrs = { + container_type: 'StudentWork', parent_container_id: homework.id, parent_container_type: 'HomeworkCommon', + belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'HomeworkCommon', viewed: 0 + } + Tiding.bulk_insert(*attrs) do |worker| + student_ids.each do |user_id| + next unless User.exists?(id: user_id) + + work = homework.student_works.find_by(user_id: user_id) + next if work.blank? + + attrs = same_attrs.merge(trigger_user_id: user_id, container_id: work.id) + + course.course_member(user_id).member_teachers.find_each do |teacher| + worker.add attrs.merge(user_id: teacher.user_id) + end + end + end + end +end diff --git a/app/jobs/teacher_invite_join_course_notify_job.rb b/app/jobs/teacher_invite_join_course_notify_job.rb new file mode 100644 index 000000000..5f9812bb4 --- /dev/null +++ b/app/jobs/teacher_invite_join_course_notify_job.rb @@ -0,0 +1,23 @@ +# 老师邀请用户加入课堂 消息通知 +class TeacherInviteJoinCourseNotifyJob < ApplicationJob + queue_as :notify + + def perform(inviter_id, course_id, role, user_ids) + inviter = User.find_by(id: inviter_id) + course = Course.find_by(id: course_id) + return if inviter.blank? || course.blank? + + attrs = %i[user_id trigger_user_id container_id container_type belong_container_id + belong_container_type tiding_type extra created_at updated_at] + + same_attrs = { + trigger_user_id: inviter.id, container_id: course.id, container_type: 'TeacherJoinCourse', + belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'System', extra: role + } + Tiding.bulk_insert(*attrs) do |worker| + user_ids.each do |user_id| + worker.add same_attrs.merge(user_id: user_id) + end + end + end +end diff --git a/app/libs/base64_image_converter.rb b/app/libs/base64_image_converter.rb new file mode 100644 index 000000000..2a8155283 --- /dev/null +++ b/app/libs/base64_image_converter.rb @@ -0,0 +1,77 @@ +class Base64ImageConverter + BASE64_HEAD = 'data:image/jpeg;base64,'.freeze + + Error = Class.new(StandardError) + OutLimit = Class.new(Error) + InvalidData = Class.new(Error) + InvalidFormat = Class.new(Error) + + attr_reader :opts + + def initialize(**opts) + @opts = opts + end + + def convert(data) + raise InvalidData, '不合法的Base64数据' unless valid_base64?(data) + + io = StringIO.new(Base64.decode64(image_data data)) + + raise OutLimit, '文件大小超过限制' if opts[:max_size].present? && io.size > opts[:max_size] + + raise InvalidFormat, '无效的格式' unless Image.new(io).image? + + io + end + + private + + def valid_base64?(data) + data&.start_with?(BASE64_HEAD) + end + + def image_data(data) + data[BASE64_HEAD.size..-1] + end + + def size_limit + EduSetting.find_by_name('upload_avatar_max_size')&.value + end + + class Image + attr_reader :io + + def initialize(io) + raise ArgumentError unless io.respond_to?(:read) + @io = io + end + + def data + @_data ||= begin + data = io.read(9) + io.rewind + data + end + end + + def image? + bitmap? || gif? || jpeg? || png? + end + + def bitmap? + data[0,2] == 66.chr + 77.chr + end + + def gif? + data[0,4] == 71.chr + 73.chr + 70.chr + 56.chr + end + + def jpeg? + data[0,3] == 0xff.chr + 0xd8.chr + 0xff.chr + end + + def png? + data[0,2] == 0x89.chr + 80.chr + end + end +end \ No newline at end of file diff --git a/app/libs/custom_regexp.rb b/app/libs/custom_regexp.rb new file mode 100644 index 000000000..d7afc61ed --- /dev/null +++ b/app/libs/custom_regexp.rb @@ -0,0 +1,4 @@ +module CustomRegexp + PHONE = /1\d{10}/ + EMAIL = /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ +end \ No newline at end of file diff --git a/app/libs/custom_sortable.rb b/app/libs/custom_sortable.rb new file mode 100644 index 000000000..21ead8a4e --- /dev/null +++ b/app/libs/custom_sortable.rb @@ -0,0 +1,38 @@ +module CustomSortable + extend ActiveSupport::Concern + + included do |base| + base.instance_variable_set("@_sort_options", {}) + base.instance_variable_set("@_sort_columns", []) + base.instance_variable_set("@_sort_directions", %w(asc desc)) + end + + def custom_sort(relations, sort_by, sort_direction) + sort_by = self.class.sort_options[:default_by] if sort_by.blank? + sort_direction = self.class.sort_options[:default_direction] if sort_direction.blank? + + return relations unless self.class.check_sort_parameter_validate(sort_by.to_s, sort_direction.to_s) + + order_method = self.class.sort_options[:reorder] ? :reorder : :order + relations.send(order_method, "#{sort_by} #{sort_direction}") + end + + module ClassMethods + def sort_columns(*columns) + opts = columns.extract_options! + @_sort_options[:default_by] = opts[:default_by].to_s + @_sort_options[:default_direction] = opts[:default_direction].to_s + @_sort_options[:reorder] = opts[:reorder] + + @_sort_columns = columns.map(&:to_s) + end + + def check_sort_parameter_validate(sort_by, sort_direction) + (sort_by.blank? || @_sort_columns.include?(sort_by)) && @_sort_directions.include?(sort_direction) + end + + def sort_options + @_sort_options + end + end +end diff --git a/app/libs/util.rb b/app/libs/util.rb new file mode 100644 index 000000000..f6c8855b9 --- /dev/null +++ b/app/libs/util.rb @@ -0,0 +1,31 @@ +module Util + module_function + + def days_between(time, other_time) + raise ArgumentError if time.blank? || other_time.blank? + Date.parse(time.to_s) - Date.parse(other_time.to_s) + end + + def convert_base64_image(str, **opts) + return if str.blank? + + Base64ImageConverter.new(**opts).convert(str) + end + + def write_file(io, path) + dir = File.dirname(path) + FileUtils.mkdir_p(dir) unless File.directory?(dir) + + Rails.logger.info("### save file #{path}, size: #{io.size} ~") + File.open(path, 'wb') do |file| + if io.respond_to?(:read) + io.rewind + while buffer = io.read(8192) + file.write(buffer) + end + else + file.write(io) + end + end + end +end \ No newline at end of file diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 000000000..8e1c7ec84 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: 'from@example.com' + layout 'mailer' +end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb new file mode 100644 index 000000000..03ef63bb2 --- /dev/null +++ b/app/mailers/user_mailer.rb @@ -0,0 +1,10 @@ +class UserMailer < ApplicationMailer + # 注意:这个地方一定要和你的邮箱服务域名一致 + default from: 'educoder@trustie.org' + + # 用户注册验证码 + def register_email(mail, code) + @code = code + mail(to: mail, subject: '验证你的电子邮件') + end +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 000000000..a876440c3 --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,9 @@ +class ApplicationRecord < ActiveRecord::Base + include NumberDisplayHelper + + self.abstract_class = true + + def format_time(time) + time.present? ? time.strftime('%Y-%m-%d %H:%M') : '' + end +end diff --git a/app/models/apply_action.rb b/app/models/apply_action.rb new file mode 100644 index 000000000..2d31f394d --- /dev/null +++ b/app/models/apply_action.rb @@ -0,0 +1,22 @@ +# 申请消息 +class ApplyAction < ApplicationRecord + has_many :tidings, :as => :container, :dependent => :destroy + after_create :send_tiding + + def send_tiding + if container_type == 'TrialAuthorization' && status == 1 + tidings.create(user_id: user_id, trigger_user_id: 0, status: 1, viewed: 0, tiding_type: 'System', + parent_container_id: container_id, parent_container_type: container_type, + belong_container_id: container_id, belong_container_type: 'User') + else + belong_container_type = if container_type == 'TrialAuthorization' + 'User' + else + container_type == 'ApplyShixun' ? 'Shixun' : 'Subject' + end + tidings.create(user_id: '1', trigger_user_id: user_id, status: 0, viewed: 0, tiding_type: 'Apply', + parent_container_id: container_id, parent_container_type: container_type, + belong_container_id: container_id, belong_container_type: belong_container_type) + end + end +end \ No newline at end of file diff --git a/app/models/apply_user_authentication.rb b/app/models/apply_user_authentication.rb new file mode 100644 index 000000000..3907c3f16 --- /dev/null +++ b/app/models/apply_user_authentication.rb @@ -0,0 +1,9 @@ +# status:0 审核中 1 同意 2 拒绝 3 撤销 +# auth_type:1 实名认证, 2 职业认证 +class ApplyUserAuthentication < ApplicationRecord + belongs_to :user + + scope :real_name_auth, -> { where(auth_type: 1) } + scope :professional_auth, -> { where(auth_type: 2) } + scope :processing, -> { where(status: 0) } +end diff --git a/app/models/attachment.rb b/app/models/attachment.rb new file mode 100644 index 000000000..bdd749108 --- /dev/null +++ b/app/models/attachment.rb @@ -0,0 +1,118 @@ +class Attachment < ApplicationRecord + include BaseModel + include Publicable + include Publishable + include Lockable + + belongs_to :container, polymorphic: true, touch: true, optional: true + belongs_to :author, class_name: "User", foreign_key: :author_id + belongs_to :course, foreign_key: :container_id, optional: true + has_many :attachment_group_settings, :dependent => :destroy + has_many :attachment_histories, -> { order(version: :desc) }, :dependent => :destroy + + scope :by_filename_or_user_name, -> (keywords) { joins(:author).where("filename like :search or LOWER(concat(users.lastname, users.firstname)) LIKE :search", + :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } + scope :by_keywords, -> (keywords) { where("filename LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } + scope :ordered, -> (opts = {}) { order("#{opts[:sort_type]} #{opts[:sort] == 1 ? 'asc': 'desc'}") } + scope :by_course_second_category_id, -> (course_second_category_id = 0) { where(course_second_category_id: course_second_category_id) } + scope :contains_only_course, -> { where(container_type: 'Course') } + scope :contains_only_project, -> { where(container_type: 'Project') } + scope :contains_course_and_project, -> { contains_only_course.or(contains_only_project) } + scope :mine, -> (author_id) { where(author_id: author_id) } + scope :simple_columns, -> { select(:id, :filename, :filesize, :created_on, :cloud_url, :author_id) } + scope :search_by_container, -> (ids) {where(container_id: ids)} + + validates_length_of :description, maximum: 100 + + def diskfile + File.join(File.join(Rails.root, "files"), disk_directory.to_s, disk_filename.to_s) + end + + def title + filename + end + + def downloads_count + downloads + end + + def quotes_count + quotes.nil? ? 0 : quotes + end + + def self.associate_container(ids, container_id, container_type, attachtype=1) + return false if ids.blank? || !ids.is_a?(Array) + ids.each do |id| + attachment = Attachment.find id + attachment.update_attributes(container_id: container_id, container_type: container_type, attachtype: attachtype) + end + end + + # Returns an unsaved copy of the attachment + def copy(attributes=nil) + copy = self.class.new + copy.attributes = self.attributes.dup.except("id", "downloads", "quotes") + copy.attributes = attributes if attributes + copy + end + + def set_publish_time(publish_time) + self.unified_setting = 1 + if publish_time.blank? + self.publish_time = Time.now + self.is_publish = 1 + else + self.is_publish = publish_time.to_s > (format_time Time.now).to_s ? 0 : 1 + self.publish_time = publish_time.to_s > (format_time Time.now).to_s ? publish_time : Time.now + end + end + + def set_course_group_publish_time(course, course_group_publish_times) + self.unified_setting = 0 + min_publish_time = "" + course_group_publish_times.each do |obj| + if obj && obj[:course_group_id] + publish_time = obj[:publish_time] + if !publish_time.blank? && publish_time < min_publish_time + min_publish_time = publish_time + elsif publish_time.blank? + publish_time = Time.now + end + attachment_group_setting = self.attachment_group_settings.where(course_group_id: obj[:course_group_id], course_id: course.id).first + if attachment_group_setting.present? + attachment_group_setting.update_columns(publish_time: publish_time) + else + self.attachment_group_settings.create( + :course_group_id => obj[:course_group_id], + :course_id => course.id, + :publish_time => publish_time + ) + end + end + end + self.is_publish = min_publish_time > (format_time Time.now).to_s ? 0 : 1 + self.publish_time = min_publish_time > (format_time Time.now).to_s ? min_publish_time : self.created_on + end + + def become_history + history = self.attachment_histories.first + new_attachment_history = AttachmentHistory.new(self.attributes.except("id", "resource_bank_id", "unified_setting", "course_second_category_id").merge( + attachment_id: self.id, + version: history.nil? ? 1 : history.version + 1, + )) + new_attachment_history + end + + def copy_attributes_from_new_attachment(new_attachment) + self.attributes = new_attachment.attributes.dup.except("id","container_id","container_type","is_public","downloads", "quotes",'is_publish','publish_time') + end + + def set_public(is_public) + if is_public == true + is_public = 1 + elsif is_public == false + is_public = 0 + end + end + +end diff --git a/app/models/attachment_group_setting.rb b/app/models/attachment_group_setting.rb new file mode 100644 index 000000000..67240d88f --- /dev/null +++ b/app/models/attachment_group_setting.rb @@ -0,0 +1,6 @@ +class AttachmentGroupSetting < ActiveRecord::Base + belongs_to :attachment + belongs_to :course_group + belongs_to :course + +end diff --git a/app/models/attachment_history.rb b/app/models/attachment_history.rb new file mode 100644 index 000000000..220f92535 --- /dev/null +++ b/app/models/attachment_history.rb @@ -0,0 +1,23 @@ +class AttachmentHistory < ApplicationRecord + include Publishable + include Publicable + + belongs_to :attachment, foreign_key: 'attachment_id' + + def title + filename + end + + def downloads_count + downloads + end + + def quotes_count + quotes.nil? ? 0 : quotes + end + + def public? + is_public == 1 + end + +end diff --git a/app/models/attendance.rb b/app/models/attendance.rb new file mode 100644 index 000000000..ffe3f63a1 --- /dev/null +++ b/app/models/attendance.rb @@ -0,0 +1,16 @@ +class Attendance < ApplicationRecord + belongs_to :user + + default_scope { order(created_at: :desc) } + + def next_gold + # 超过1天即没有连续的签到则又从10个金币开始累加 + return 50 if Util.days_between(Time.zone.now, created_at) > 1 + + [[score.to_i, 50].max + 10, 100].min + end + + def today? + Util.days_between(Time.current, created_at).zero? + end +end diff --git a/app/models/board.rb b/app/models/board.rb new file mode 100644 index 000000000..9f3152727 --- /dev/null +++ b/app/models/board.rb @@ -0,0 +1,25 @@ +class Board < ApplicationRecord + belongs_to :course, touch: true + + has_many :messages, -> { order(created_on: :desc) }, dependent: :destroy + has_many :visible_messages, -> { visible }, class_name: "Message" + belongs_to :last_message, class_name: 'Message', foreign_key: :last_message_id, optional: true + + scope :roots, -> { where(parent_id: 0)} + + validates :name, presence: true, length: {maximum: 30} + # validates :description, presence: true, length: {maximum: 255} + + # 子讨论区 + def children + Board.where(parent_id: self.id).reorder("position asc") + end + + def fix_name + return name if parent_id != 0 + + course_modules = self.course.board_course_modules + course_modules.present? ? course_modules[0].module_name : self.name + end + +end diff --git a/app/models/career.rb b/app/models/career.rb new file mode 100644 index 000000000..b7b6f11a1 --- /dev/null +++ b/app/models/career.rb @@ -0,0 +1,2 @@ +class Career < ApplicationRecord +end diff --git a/app/models/challenge.rb b/app/models/challenge.rb new file mode 100644 index 000000000..a5d9874ce --- /dev/null +++ b/app/models/challenge.rb @@ -0,0 +1,102 @@ +class Challenge < ApplicationRecord + # difficulty: 关卡难度: 1.简单 2.中等 3.困难 + default_scope { order("challenges.position asc") } + + belongs_to :shixun, :touch => true, counter_cache: true + belongs_to :user + has_many :challenge_samples, :dependent => :destroy + has_many :test_sets, :dependent => :destroy + has_many :challenge_tags, :dependent => :destroy + has_many :games, :dependent => :destroy + has_many :challenge_chooses, :dependent => :destroy + has_many :homework_challenge_settings, :dependent => :destroy + has_many :praise_tread, as: :praise_tread_object, dependent: :destroy + has_one :praise_tread_cache, as: :object, dependent: :destroy + has_many :tidings + # 参考答案 + has_many :challenge_answers, :dependent => :destroy + has_many :exercise_bank_shixun_challenges, :dependent => :destroy + + # acts_as_attachable + + scope :base_attrs, -> { select([:id, :subject, :position, :shixun_id, :st, :score, :path, :task_pass, :modify_time, + :web_route, :answer]) } + scope :choose_type, -> { where(st: 1) } + scope :practice_type, -> { where(st: 0) } + + scope :fields_for_list, -> { select([:id, :subject, :st, :score, :position, :shixun_id]) } + + def next_challenge + position = self.position + 1 + Challenge.where(:position => position, :shixun_id => self.shixun).first + end + + # 用户关卡是否通关 + def has_passed?(user_id) + self.games.present? && self.games.select{|game| game.user_id == user_id && game.status == 2}.length > 0 + end + + ## 选择题总分 + def choose_score + self.challenge_chooses.sum(:score) + end + + # 关卡总分 + def all_score + if self.st == 1 + self.choose_score + else + self.score + end + end + + # 开启挑战 + def open_game(user_id) + game = self.games.select([:status, :identifier]).where(user_id: user_id).first + shixun = self.shixun + if game.present? + shixun.task_pass || game.status != 3 ? "/tasks/#{game.identifier}" : "" + else + "/api/shixuns/#{shixun.identifier}/shixun_exec" + end + end + + ## 用户关卡状态 0: 不能开启实训; 1:直接开启; 2表示已完成 + def user_tpi_status user_id + # todo: 以前没加索引导致相同关卡,同一用户有多个games + game = self.games.where(user_id: user_id).last + status = + if game.blank? + self.position == 1 ? 1 : 0 + elsif game.status == 2 + 2 + else + 1 + end + end + + ## 选择题答案 + def choose_answer + result = [] + self.challenge_chooses.each do |choose| + result << {:position => choose.position, :answer => (choose.answer.blank? ? choose.standard_answer : choose.answer)} + end + end + + # 关卡用户通关数 + def user_passed_count + games.where(status: 2).count + end + + # 关卡用户正在挑战的人数 + def playing_count + games.where(status: [0, 1]).count + end + + def last_challenge + Challenge.find_by(position: position - 1, shixun_id: shixun_id) + end + + # 关卡评测文件 + +end diff --git a/app/models/challenge_answer.rb b/app/models/challenge_answer.rb new file mode 100644 index 000000000..93b11be66 --- /dev/null +++ b/app/models/challenge_answer.rb @@ -0,0 +1,4 @@ +class ChallengeAnswer < ApplicationRecord + default_scope { order("challenge_answers.level asc") } + belongs_to :challenge +end diff --git a/app/models/challenge_choose.rb b/app/models/challenge_choose.rb new file mode 100644 index 000000000..07b0813bb --- /dev/null +++ b/app/models/challenge_choose.rb @@ -0,0 +1,6 @@ +class ChallengeChoose < ApplicationRecord + default_scope {order("position asc")} + belongs_to :challenge, optional: true + has_many :challenge_tags, :dependent => :destroy + has_many :challenge_questions, dependent: :destroy +end diff --git a/app/models/challenge_question.rb b/app/models/challenge_question.rb new file mode 100644 index 000000000..b0927aec0 --- /dev/null +++ b/app/models/challenge_question.rb @@ -0,0 +1,3 @@ +class ChallengeQuestion < ApplicationRecord + belongs_to :challenge_choose +end diff --git a/app/models/challenge_sample.rb b/app/models/challenge_sample.rb new file mode 100644 index 000000000..e523a8087 --- /dev/null +++ b/app/models/challenge_sample.rb @@ -0,0 +1,4 @@ +class ChallengeSample < ApplicationRecord + belongs_to :challenge +end + diff --git a/app/models/challenge_tag.rb b/app/models/challenge_tag.rb new file mode 100644 index 000000000..6f176cc67 --- /dev/null +++ b/app/models/challenge_tag.rb @@ -0,0 +1,5 @@ +class ChallengeTag < ApplicationRecord + + belongs_to :challenge, counter_cache: true + belongs_to :challenge_choose +end diff --git a/app/models/challenge_work_score.rb b/app/models/challenge_work_score.rb new file mode 100644 index 000000000..8316e228b --- /dev/null +++ b/app/models/challenge_work_score.rb @@ -0,0 +1,5 @@ +class ChallengeWorkScore < ApplicationRecord + belongs_to :user + belongs_to :student_work + belongs_to :challenge +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/app/models/concerns/base_model.rb b/app/models/concerns/base_model.rb new file mode 100755 index 000000000..1f55d4db5 --- /dev/null +++ b/app/models/concerns/base_model.rb @@ -0,0 +1,34 @@ +module BaseModel + extend ActiveSupport::Concern + + included do + scope :recent, -> { order(id: :desc) } + scope :exclude_ids, -> (ids) { where.not(id: ids.map(&:to_i)) } + scope :by_ids, -> (ids) { where(id: ids) unless ids.blank? } + scope :by_week, -> { where("created_at > ?", 7.days.ago.utc) } + + delegate :url_helpers, to: 'Rails.application.routes' + end + + # FIXME: 需要原子化操作 + def push(hash) + hash.each_key do |key| + self.send("#{key}_will_change!") + old_val = self[key] || [] + old_val << hash[key].to_i + old_val.uniq! + update_attributes(key => old_val) + end + end + + # FIXME: 需要原子化操作 + def pull(hash) + hash.each_key do |key| + self.send("#{key}_will_change!") + old_val = self[key] + return true if old_val.blank? + old_val.delete(hash[key].to_i) + update_attributes(key => old_val) + end + end +end diff --git a/app/models/concerns/lockable.rb b/app/models/concerns/lockable.rb new file mode 100644 index 000000000..cb8072804 --- /dev/null +++ b/app/models/concerns/lockable.rb @@ -0,0 +1,10 @@ +module Lockable + extend ActiveSupport::Concern + + included do + end + + def locked?(is_member) + is_member == true ? false : !publiced? + end +end diff --git a/app/models/concerns/number_display_helper.rb b/app/models/concerns/number_display_helper.rb new file mode 100644 index 000000000..0a0ee7638 --- /dev/null +++ b/app/models/concerns/number_display_helper.rb @@ -0,0 +1,13 @@ +module NumberDisplayHelper + extend ActiveSupport::Concern + + module ClassMethods + def number_display_methods(*columns, **opts) + columns.each do |column| + define_method "display_#{column}" do + number_to_currency(column.to_f, opts) + end + end + end + end +end \ No newline at end of file diff --git a/app/models/concerns/publicable.rb b/app/models/concerns/publicable.rb new file mode 100644 index 000000000..a9c8cb41f --- /dev/null +++ b/app/models/concerns/publicable.rb @@ -0,0 +1,9 @@ +module Publicable + extend ActiveSupport::Concern + + included do + alias_attribute :public, :is_public + enum public: { publiced: 1, hidden: 0 } + end + +end diff --git a/app/models/concerns/publishable.rb b/app/models/concerns/publishable.rb new file mode 100644 index 000000000..6d7c1421f --- /dev/null +++ b/app/models/concerns/publishable.rb @@ -0,0 +1,9 @@ +module Publishable + extend ActiveSupport::Concern + + included do + alias_attribute :publish, :is_publish + enum publish: { published: 1, unpublish: 0 } + end + +end diff --git a/app/models/concerns/watchable.rb b/app/models/concerns/watchable.rb new file mode 100644 index 000000000..7be7d1b4c --- /dev/null +++ b/app/models/concerns/watchable.rb @@ -0,0 +1,26 @@ +module Watchable + extend ActiveSupport::Concern + + included do + has_many :watchers, as: :watchable, dependent: :destroy # 关注我的 + has_many :watcher_users, through: :watchers, source: :user, validate: false # 我的粉丝 + + scope :watched_by, -> (user_id) { includes(:watchers).where(watchers: { user_id: user_id }) } + end + + def watched?(watchable) + watchable.watchers.exists?(user: self) + end + + def watch!(user) + user.watchers.create!(user: self) + end + + def unwatch!(user) + obj = user.watchers.find_by(user: self) + obj.destroy! if obj.present? + end + + module ClassMethods + end +end \ No newline at end of file diff --git a/app/models/course.rb b/app/models/course.rb new file mode 100644 index 000000000..dd2248d7c --- /dev/null +++ b/app/models/course.rb @@ -0,0 +1,359 @@ +class Course < ApplicationRecord + has_many :boards, dependent: :destroy + + belongs_to :teacher, class_name: 'User', foreign_key: :tea_id # 定义一个方法teacher,该方法通过tea_id来调用User表 + belongs_to :school, class_name: 'School', foreign_key: :school_id #定义一个方法school,该方法通过school_id来调用School表 + belongs_to :course_list + + has_many :course_infos, dependent: :destroy + # 课堂左侧导航栏的模块 + has_many :course_modules, dependent: :destroy + has_many :board_course_modules, -> { board_module }, class_name: "CourseModule" + has_many :attachment_course_modules, -> { attachment_module }, class_name: "CourseModule" + has_many :common_course_modules, -> { common_homework_module }, class_name: "CourseModule" + has_many :group_course_modules, -> { group_homework_module }, class_name: "CourseModule" + has_many :shixun_course_modules, -> { shixun_homework_module }, class_name: "CourseModule" + + # 课堂模块的二级目录 + has_many :course_second_categories, dependent: :destroy + # 课堂分班 + has_many :course_groups, dependent: :destroy + # 答辩组 + has_many :graduation_groups, dependent: :destroy + + has_many :course_members, dependent: :destroy + has_many :course_messages, dependent: :destroy + has_many :homework_commons, dependent: :destroy + has_many :homework_group_settings + has_many :graduation_works, dependent: :destroy + + # 实训作业的二级目录(已弃用) + has_many :course_homework_categories, dependent: :destroy + has_many :exercises, dependent: :destroy + + #课堂的试卷 + has_many :exercise_group_settings, :dependent => :destroy + + # 课堂的问卷 + has_many :polls, dependent: :destroy + has_many :poll_group_settings, :dependent => :destroy + + # 毕业设计 + has_many :graduation_topics, dependent: :destroy + has_many :graduation_tasks, dependent: :destroy + has_many :student_graduation_topics, :dependent => :destroy + has_many :teacher_course_groups, :dependent => :destroy + + # 资源 + has_many :attachments, as: :container, dependent: :destroy + has_many :attachment_group_settings, :dependent => :destroy + + # 课堂学生,弃用 + has_many :student, :class_name => 'StudentsForCourse', :source => :user + + + # 课堂动态 + has_many :course_acts, class_name: 'CourseActivity', as: :course_act, dependent: :destroy + has_many :tidings, as: :container, dependent: :destroy + + # 老版的members弃用 现用course_members + has_many :members + + scope :hidden, ->(is_hidden = true) { where(is_hidden: is_hidden) } + scope :ended, ->(is_end = true) { where(is_end: is_end) } + scope :deleted, ->(is_delete = 1) { where(is_delete: is_delete) } + scope :by_user, ->(user) { joins(:course_members).where('course_members.user_id = ?', user.id).order(updated_at: :desc) } + scope :by_keywords, lambda { |keywords| + where("name LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank? + } + + acts_as_taggable + + + # 课程权限判断 + ADMIN = 0 # 超级管理员 + BUSINESS = 1 # 运营人员 + CREATOR = 2 # 课程创建者 + PROFESSOR = 3 # 课程老师 + ASSISTANT_PROFESSOR = 4 # 课程助教 + STUDENT = 5 # 学生 + NORMAL = 6 # 普通用户 + Anonymous = 7 # 普未登录 + + validates :name, presence: true, length: { maximum: 30 } + + after_create :create_board_sync, :act_as_course_activity, :send_tiding + + def course_member? user_id, role + course_members.where(user_id: user_id, role: role).exists? + end + + # 作业对应的子目录/父目录名称 + def category_info type + course_module = course_modules.find_by(module_type: type) + { category_id: course_module&.id, category_name: course_module&.module_name } + end + + # 未分班的学生数 + def none_group_count + course_members.where(role: 4, course_group_id: 0).count + end + + def course_member(user_id) + course_members.find_by(user_id: user_id, is_active: 1) + end + + def course_student(user_id) + course_members.find_by(user_id: user_id, role: %i(STUDENT)) + end + + + def teacher_group(user_id) + data = + if teacher_course_groups.exists?(user_id: user_id) + teacher_course_groups.joins(:course_group).where(user_id: user_id) + .pluck('course_groups.id', 'course_groups.name') + else + course_groups.pluck(:id, :name) + end + + data.map { |arr| { group_id: arr.first, group_name: arr.last } } + end + + #当前老师的班级id + def teacher_course_group_ids(user_id) + course_teacher_member = teacher_course_groups.get_user_groups(user_id) #获取当前老师的分班 + if course_teacher_member.blank? + if none_group_count > 0 #有未分班的,则发布到未发布分班 + un_group_ids = [0] + else + un_group_ids = [] + end + course_groups.pluck(:id) + un_group_ids #所有分班和未分班 + else + course_teacher_member.pluck(:course_group_id).reject(&:blank?).uniq #当前用户所在的班级,老师可能有多个班级 + end + end + + # 查询老师分班的所有学生 + def teacher_group_user_ids user_id + teachers = teacher_course_groups.where(user_id: user_id) + if teachers.exists? + course_members.where(course_group_id: teachers.pluck(:course_group_id)).pluck(:user_id) + else + course_members.where(role: 4).pluck(:user_id) + end + end + + # 创建课程模块 + def create_course_modules(course_module_types) + course_modules.destroy_all if course_modules.present? + + all_course_module_types.each do |type| + name = get_name_by_type(type) + position = get_position_by_type(type) + + hidden = course_module_types.include?(type) ? 0 : 1 + CourseModule.create(course_id: id, module_type: type, position: position, hidden: hidden, module_name: name) + end + end + + # 更新课程模块 + def update_course_modules(course_module_types) + all_course_module_types.each do |type| + hidden_value = course_module_types.include?(type) ? 0 : 1 + + course_module = get_course_module_by_type(type, self.id) + course_module.update_attribute(:hidden, hidden_value) if course_module.present? + end + end + + def all_course_module_types + %w[activity shixun_homework common_homework group_homework graduation exercise poll attachment board course_group] + end + + def get_course_module_by_type(type, course_id) + CourseModule.where(course_id: course_id, module_type: type).first + end + + # 创建课程讨论区 + def create_board_sync + boards.create(name: '讨论区', description: name, project_id: -1) + end + + def delete! + update_attribute(:is_delete, true) + end + + def attachment_count + Attachment.where(container: self).count + end + + # 课堂某角色的成员数量:[1, 2, 3] 是教师身份、4 学生身份 + def course_member_count(roles) + course_members.where(role: roles).size + end + + # 课堂老师 + def teachers + course_members.where(role: %i[CREATOR PROFESSOR ASSISTANT_PROFESSOR]) + end + + def teachers_without_assistant_professor + course_members.where(role: %i[CREATOR PROFESSOR]) + end + + # 课堂学生 + def students + course_members.where(role: %i[STUDENT]) + end + + # 更新课程的访问人数 + def update_visits(new_visits) + update_attributes(visits: new_visits) + end + + # 老师负责的分班id + def charge_group_ids user + member = course_member(user.id) + group_ids = if member.present? + member.teacher_course_groups.size > 0 ? member.teacher_course_groups.pluck(:course_group_id) : course_groups.pluck(:id) + elsif user.admin? + course_groups.pluck(:id) + else + [] + end + end + + # 生成邀请码 + CODES = %W(2 3 4 5 6 7 8 9 A B C D E F G H J K L N M O P Q R S T U V W X Y Z) + def generate_invite_code + return invite_code if invite_code.present? && invite_code.size >= 5 + + code = CODES.sample(5).join + while Course.exists?(invite_code: code) do + code = CODES.sample(5).join + end + update_attribute(:invite_code, code) + + code + end + + # 课堂主讨论区 + def course_board + board = boards.find_by(parent_id: 0) + return board if board.present? + + create_board_sync + Board.find_by(parent_id: 0, course_id: id) + end + + # 是否是课堂的成员(未实现,暂时返回true) + def member?(user) + true + end + + # 是否具有分班权限,返回分班的id + def group_course_power(user_id) + teacher_course_groups.where(user_id: user_id).pluck(:id) + end + + #课程动态公共表记录 + def act_as_course_activity + self.course_acts << CourseActivity.new(user_id: tea_id, course_id: id) + end + + # 当前老师分班下的所有学生 + def user_group_students(user_id) + group_ids = teacher_course_groups.where(user_id: user_id).pluck(:course_group_id) + course_members.where(course_group_id: group_ids) + end + + def self_duplicate + DuplicateCourseService.call(self, User.current) + end + + def update_quotes attachment + if attachment.copy_from + attachments = Attachment.find_by_sql("select * from attachments where copy_from = #{attachment.copy_from} or id = #{attachment.copy_from}") + else + attachments = Attachment.find_by_sql("select * from attachments where copy_from = #{attachment.id} or id = #{attachment.copy_from}") + end + attachment.quotes = get_qute_number attachment + attachment.save + attachments.each do |att| + att.quotes = attachment.quotes + att.save + end + end + + def get_qute_number attachment + if attachment.copy_from + result = Attachment.find_by_sql("select count(*) as number from attachments where copy_from = #{attachment.copy_from}") + else + result = Attachment.find_by_sql("select count(*) as number from attachments where copy_from = #{attachment.id}") + end + if result.nil? || result.count <= 0 + 0 + else + result[0].number + end + end + + #获取试卷/问卷已发布的班级id,名称和人数。当为统一设置时,显示全部,否则只显示当前已发布的班级信息 + def get_ex_published_course(common_ids) + teacher_power_courses = [] + if course_groups.present? + common_ids.each do |i| + student_count = students.where(course_group_id:i).count + if i == 0 + teacher_power_courses << {course_name:"未分班",course_id:0,student_count:student_count} + else + course_group_name = course_groups.find_by(id:i) + teacher_power_courses << {course_name:course_group_name&.name,course_id:i,student_count:student_count} + end + end + end + teacher_power_courses + end + + private + + #创建课程后,给该用户发送消息 + def send_tiding + self.tidings << Tiding.new(user_id: tea_id, trigger_user_id: tea_id, belong_container_id: id, + belong_container_type: 'Course', tiding_type: 'System') + end + + def get_name_by_type(type) + case type + when 'activity' then '动态' + when 'shixun_homework' then '实训作业' + when 'common_homework' then '普通作业' + when 'group_homework' then '分组作业' + when 'graduation' then '毕业设计' + when 'exercise' then '试卷' + when 'poll' then '问卷' + when 'attachment' then '资源' + when 'board' then '讨论' + when 'course_group' then '分班' + else '' + end + end + + def get_position_by_type(type) + case type + when 'activity' then 1 + when 'shixun_homework' then 2 + when 'common_homework' then 3 + when 'group_homework' then 4 + when 'graduation' then 5 + when 'exercise' then 6 + when 'poll' then 7 + when 'attachment' then 8 + when 'board' then 9 + when 'course_group' then 10 + else 100 + end + end +end diff --git a/app/models/course_activity.rb b/app/models/course_activity.rb new file mode 100644 index 000000000..b2ea0b146 --- /dev/null +++ b/app/models/course_activity.rb @@ -0,0 +1,37 @@ +class CourseActivity < ApplicationRecord + belongs_to :course_act, polymorphic: true + belongs_to :course + belongs_to :user + belongs_to :exercise + belongs_to :poll + + after_create :add_course_lead + + # 发布新课导语 + # 导语要放置在课程创建信息之后 + def add_course_lead + # 避免空数据迁移报错问题 + if self.course_act_type == "Course" + sample = PlatformSample.where(:samples_type => "courseGuide").first + if sample.present? && sample.contents.present? + content = sample.contents + elsif Message.find(12440) + lead_message = Message.find(12440) + content = lead_message.content + end + if content + # message的status状态为0为正常,为1表示创建课程时发送的message + # author_id 默认为课程使者创建 + message = Message.create(subject: "新课导语", + board_id: course.course_board.try(:id), + author_id: 1, + sticky: true, + status: true, + message_detail_attributes: {content: content} + ) + # 更新的目的是为了排序,因为该条动态的时间可能与课程创建的动态创建时间一致 + message.course_acts.first.update_attribute(:updated_at, message.course_acts.first.updated_at + 1) if message.course_acts.first + end + end + end +end diff --git a/app/models/course_group.rb b/app/models/course_group.rb new file mode 100644 index 000000000..33e40ee52 --- /dev/null +++ b/app/models/course_group.rb @@ -0,0 +1,32 @@ +class CourseGroup < ApplicationRecord + default_scope { order("course_groups.position ASC") } + belongs_to :course, counter_cache: true + has_many :course_members + + has_many :exercise_group_settings,:dependent => :destroy + has_many :attachment_group_settings, :dependent => :destroy + has_many :homework_group_reviews, :dependent => :destroy + scope :by_group_ids, lambda { |ids| where(id: ids)} + + validates :name, length: { maximum: 20 } + + after_create :generate_invite_code + + # 延迟生成邀请码 + def invite_code + return generate_invite_code + end + + # 生成邀请码 + CODES = %W(2 3 4 5 6 7 8 9 A B C D E F G H J K L N M O P Q R S T U V W X Y Z) + def generate_invite_code + code = read_attribute(:invite_code) + if !code || code.size < 6 + code = CODES.sample(6).join + return generate_invite_code if CourseGroup.where(invite_code: code).present? + update_attribute(:invite_code, code) + end + code + end + +end diff --git a/app/models/course_homework_category.rb b/app/models/course_homework_category.rb new file mode 100644 index 000000000..79f105da8 --- /dev/null +++ b/app/models/course_homework_category.rb @@ -0,0 +1,3 @@ +class CourseHomeworkCategory < ApplicationRecord + belongs_to :course +end diff --git a/app/models/course_info.rb b/app/models/course_info.rb new file mode 100644 index 000000000..1cd0a763c --- /dev/null +++ b/app/models/course_info.rb @@ -0,0 +1,3 @@ +class CourseInfo < ApplicationRecord + belongs_to :course +end diff --git a/app/models/course_list.rb b/app/models/course_list.rb new file mode 100644 index 000000000..080c05ae2 --- /dev/null +++ b/app/models/course_list.rb @@ -0,0 +1,8 @@ +class CourseList < ApplicationRecord + has_many :courses + has_many :question_banks + has_many :homework_banks + has_many :exercise_banks + has_many :gtask_banks + has_many :gtopic_banks +end diff --git a/app/models/course_member.rb b/app/models/course_member.rb new file mode 100644 index 000000000..d9995d463 --- /dev/null +++ b/app/models/course_member.rb @@ -0,0 +1,159 @@ +class CourseMember < ApplicationRecord + # role 1:创建者 2:老师 3:助教 4:学生 + enum role: { CREATOR: 1, PROFESSOR: 2, ASSISTANT_PROFESSOR: 3, STUDENT: 4 } + # is_active: true:当前活跃身份(多重身份的用户) + + belongs_to :course, counter_cache: true + belongs_to :user + belongs_to :course_group, counter_cache: true, optional: true + belongs_to :graduation_group, optional: true + has_many :teacher_course_groups, dependent: :destroy + + scope :teachers_and_admin, -> { where(role: %i[CREATOR PROFESSOR ASSISTANT_PROFESSOR]) } + scope :students, ->(course) { where(course_id: course.id, role: %i[STUDENT])} + scope :course_find_by_ids, lambda { |k,ids| where("#{k}": ids)} + scope :course_students, -> {where(role: %i[STUDENT])} + + #用户的身份查询 + scope :course_user_role, lambda { |k| where(role: k)} + + # 未分班 + scope :ungroup_students, -> { where(course_group_id: 0, role: 4) } + + after_destroy :delete_works + after_create :work_operation + def delete_works + if self.role == "STUDENT" + course = self.course + student_works = StudentWork.joins(:homework_common).where(user_id: self.user_id, homework_commons: {course_id: course.id}) + student_works.update_all(is_delete: 1) + + exercise_users = ExerciseUser.joins(:exercise).where(user_id: self.user_id, exercises: {course_id: course.id}) + exercise_users.update_all(is_delete: 1) + + poll_users = PollUser.joins(:poll).where(user_id: self.user_id, polls: {course_id: course.id}) + poll_users.update_all(is_delete: 1) + + course.graduation_works.where(user_id: self.user_id).update_all(is_delete: 1) + end + end + + def work_operation + if self.role == "STUDENT" + recover_works + create_exercise_users + create_graduation_works + create_poll_users + create_student_works + end + end + + # 加入班级时还原作品(如果有已删除作品的话) + def recover_works + course = self.course + + student_works = StudentWork.where(user_id: self.user_id, homework_common_id: course.homework_commons) + student_works.update_all(is_delete: 0) + + exercise_users = ExerciseUser.where(user_id: self.user_id, exercise_id: course.exercises) + exercise_users.update_all(is_delete: 0) + + poll_users = PollUser.where(user_id: self.user_id, poll_id: course.polls) + poll_users.update_all(is_delete: 0) + + graduation_works = course.graduation_works.where(user_id: self.user_id) + graduation_works.update_all(is_delete: 0) + end + + # 加入班级时创建作业的作品(如果没有作品才创建) + def create_student_works + course = self.course + + homework_commons = course.homework_commons.where(homework_type: %i[normal group practice]) + str = "" + homework_commons.each do |homework| + next if homework.student_works.where(user_id: self.user_id).any? + str += "," if str != "" + str += "(#{homework.id}, #{user_id}, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + + if str != "" + sql = "insert into student_works (homework_common_id, user_id, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + + # 加入班级时创建已发布试卷的作品(如果没有作品才创建) + def create_exercise_users + course = self.course + exercises = course.exercises + + str = "" + exercises.each do |exercise| + next if exercise.exercise_users.where(user_id: self.user_id).any? + str += "," if str != "" + str += "(#{user_id}, #{exercise.id}, 0, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + + if str != "" + sql = "insert into exercise_users (user_id, exercise_id, commit_status, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + + # 加入班级时创建已发布问卷的作品(如果没有作品才创建) + def create_poll_users + course = self.course + polls = course.polls + + str = "" + polls.each do |poll| + next if poll.poll_users.where(user_id: self.user_id).any? + str += "," if str != "" + str += "(#{user_id}, #{poll.id}, 0, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + + if str != "" + sql = "insert into poll_users (user_id, poll_id, commit_status, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + + # 创建毕设任务作品(如果没有作品才创建) + def create_graduation_works + course = self.course + tasks = course.graduation_tasks + + str = "" + tasks.each do |task| + next if task.graduation_works.where(user_id: self.user_id).any? + str += "," if str != "" + str += "(#{task.id}, #{user_id}, #{course_id}, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + + if str != "" + sql = "insert into graduation_works (graduation_task_id, user_id, course_id, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + + # 分班名称 + def course_group_name + self.course_group_id == 0 ? "未分班" : course_group.try(:name) + end + + # 学生的分班老师 + def member_teachers + teacher_groups = course.teacher_course_groups + if teacher_groups.count > 0 + member_ids = teacher_groups.where(course_group_id: self.try(:course_group_id)).pluck(:course_member_id) + + none_group_teachers = teacher_groups.pluck(:course_member_id).size > 0 ? teacher_groups.pluck(:course_member_id).join(',') : -1 + teachers = course.teachers.where("members.id not in (#{none_group_teachers}) or + members.id in (#{member_ids.size > 0 ? member_ids.join(',') : -1})") + else + teachers = course.teachers + end + teachers + end +end diff --git a/app/models/course_message.rb b/app/models/course_message.rb new file mode 100644 index 000000000..acb45d5f4 --- /dev/null +++ b/app/models/course_message.rb @@ -0,0 +1,37 @@ +class CourseMessage < ApplicationRecord + enum status: { UNHANDLED: 0, PASSED: 1, REJECTED: 2 } + belongs_to :course + belongs_to :user + + scope :find_by_course, ->(course) { where(course_id: course.id) } + scope :join_course_requests, -> { where(course_message_type: "JoinCourseRequest") } + scope :unhandled, -> { where(status: :UNHANDLED) } + + scope :unhandled_join_course_requests_by_course, ->(course) { find_by_course(course).join_course_requests.unhandled } + + def pass! + update!(status: :PASSED) + send_deal_tiding + end + + def application_user + User.find_by(id: course_message_id) + end + + def reject! + update!(status: :REJECTED) + send_deal_tiding + end + + private + + def send_deal_tiding + # 发送申请处理结果消息 + Tiding.create!( + user_id: user_id, trigger_user: User.current, container_id: course_id, container_type: 'DealCourse', + belong_container: course, extra: content.to_i == 2 ? '7' : '9', tiding_type: 'System', status: status == :PASSED ? 1 : 2 + ) + # 将申请消息置为已处理 + Tiding.where(trigger_user_id: user_id, container_id: course_id, container_type: 'JoinCourse', status: 0).update_all(status: 1) + end +end \ No newline at end of file diff --git a/app/models/course_module.rb b/app/models/course_module.rb new file mode 100644 index 000000000..7b96a044f --- /dev/null +++ b/app/models/course_module.rb @@ -0,0 +1,27 @@ +class CourseModule < ApplicationRecord + default_scope { order("course_modules.position ASC") } + belongs_to :course + + # 二级目录 + has_many :course_second_categories + + validates :module_name, length: { maximum: 20 } + + scope :graduation_module, -> { where(module_type: "graduation") } + scope :graduation_module_not_hidden, -> { graduation_module.where(hidden: 0) } + scope :board_module, -> { where(module_type: 'board') } + scope :attachment_module, -> { includes(:course_second_categories).where(module_type: 'attachment') } + scope :common_homework_module, -> { where(module_type: 'common_homework') } + scope :group_homework_module, -> { where(module_type: 'group_homework') } + scope :shixun_homework_module, -> { where(module_type: 'shixun_homework') } + scope :search_by_module_type, -> (type) {where(module_type:type)} + + # 课堂模块的子目录 + def course_second_categories + if module_type == "graduation" && CourseSecondCategory.where(course_module_id: self.id).count == 0 + CourseSecondCategory.create!(course_module_id: self.id, course_id: self.course_id, name: "毕设选题", category_type: "graduation", position: 1) + CourseSecondCategory.create!(course_module_id: self.id, course_id: self.course_id, name: "毕设任务", category_type: "graduation", position: 2) + end + CourseSecondCategory.where(course_module_id: self.id) + end +end diff --git a/app/models/course_second_category.rb b/app/models/course_second_category.rb new file mode 100644 index 000000000..125a81cb6 --- /dev/null +++ b/app/models/course_second_category.rb @@ -0,0 +1,15 @@ +class CourseSecondCategory < ApplicationRecord + default_scope { order("course_second_categories.position ASC") } + + belongs_to :course + belongs_to :course_module + has_many :homework_commons + + validates :name, length: { maximum: 30 } + + def category_type_str + category_type == "graduation" && name == "毕设选题" ? "graduation_topics" : ( + category_type == "graduation" && name == "毕设任务" ? "graduation_tasks" : category_type + ) + end +end diff --git a/app/models/department.rb b/app/models/department.rb new file mode 100644 index 000000000..15a8a7c1b --- /dev/null +++ b/app/models/department.rb @@ -0,0 +1,5 @@ +class Department < ApplicationRecord + belongs_to :school + + has_many :department_members, dependent: :destroy +end diff --git a/app/models/department_member.rb b/app/models/department_member.rb new file mode 100644 index 000000000..f1f3859ec --- /dev/null +++ b/app/models/department_member.rb @@ -0,0 +1,4 @@ +class DepartmentMember < ApplicationRecord + belongs_to :user + belongs_to :department +end diff --git a/app/models/discuss.rb b/app/models/discuss.rb new file mode 100644 index 000000000..602813e66 --- /dev/null +++ b/app/models/discuss.rb @@ -0,0 +1,52 @@ +class Discuss < ApplicationRecord + default_scope { order(created_at: :desc) } + + belongs_to :user + belongs_to :parent, class_name: 'Discuss', foreign_key: :parent_id, optional: true + + has_many :children, -> { reorder(created_at: :asc) }, class_name: 'Discuss', foreign_key: :parent_id + has_many :praise_tread, as: :praise_tread_object, dependent: :destroy + has_many :tidings, as: :container, dependent: :destroy + has_one :praise_tread_cache, as: :object, dependent: :destroy + + after_create :send_tiding + + scope :children, -> (discuss_id){ where(parent_id: discuss_id).includes(:user).reorder(created_at: :asc) } + + def has_parent? + parent_id.present? + end + + def username + user.full_name + end + + def can_deleted?(user) + user.admin? || user.id == user_id + end + + def game_url(shixun, user) + return '' unless shixun.has_manager?(user) + + game = Game.joins(:challenge).where(challenges: { shixun_id: shixun.id, position: position || 1 }) + .select(:identifier).find_by(user_id: user_id) + "/tasks/#{game&.identifier}" + end + + def contents(shixun, user) + return content unless hidden? + + shixun.has_manager?(user) ? content : '违规评论已被屏蔽!' + end + + private + + def send_tiding + base_attrs = { + trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: 'Challenge', + belong_container_id: dis_id, belong_container_type: 'Shixun', viewed: 0, tiding_type: 'Comment' + } + user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id + tidings.create!(base_attrs.merge(user_id: user_id)) + end +end diff --git a/app/models/ec_achievement_evaluation_relate.rb b/app/models/ec_achievement_evaluation_relate.rb new file mode 100644 index 000000000..246e4c2e4 --- /dev/null +++ b/app/models/ec_achievement_evaluation_relate.rb @@ -0,0 +1,4 @@ +class EcAchievementEvaluationRelate < ApplicationRecord + belongs_to :ec_course_achievement_method + belongs_to :ec_course_evaluation_subitem +end diff --git a/app/models/ec_course.rb b/app/models/ec_course.rb new file mode 100644 index 000000000..6f5480ea8 --- /dev/null +++ b/app/models/ec_course.rb @@ -0,0 +1,27 @@ +class EcCourse < ApplicationRecord + belongs_to :ec_year + + # 课程目标 + has_many :ec_course_targets, dependent: :destroy + has_many :ec_graduation_subitem_course_targets, through: :ec_course_targets + # 课程负责教师 + has_many :ec_course_users + has_many :course_managers, through: :ec_course_users, class_name: 'User' + # 课程考核标准 + has_many :ec_course_evaluations, dependent: :destroy + # 课程等级 + has_many :ec_score_levels, dependent: :destroy + # 课程支撑 + has_many :ec_course_supports, dependent: :destroy + has_many :ec_graduation_subitems, through: :ec_course_supports + # 达成评价 + has_many :ec_course_student_scores, dependent: :destroy + # 工程课堂和educoder课堂关联 + has_many :ec_major_courses, dependent: :destroy + has_many :courses, through: :ec_major_courses + + # 课程目标达成方法 + # has_many :ec_course_achievement_methods + + accepts_nested_attributes_for :ec_course_targets, :ec_score_levels, allow_destroy: true +end diff --git a/app/models/ec_course_achievement_method.rb b/app/models/ec_course_achievement_method.rb new file mode 100644 index 000000000..bf27eab62 --- /dev/null +++ b/app/models/ec_course_achievement_method.rb @@ -0,0 +1,12 @@ +class EcCourseAchievementMethod < ApplicationRecord + belongs_to :ec_course + belongs_to :ec_course_target + belongs_to :ec_course_evaluation + + has_many :ec_achievement_evaluation_relates, dependent: :delete_all + has_many :ec_course_evaluation_subitems, through: :ec_achievement_evaluation_relates + + validates :percentage, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 } + + accepts_nested_attributes_for :ec_achievement_evaluation_relates, allow_destroy: true +end diff --git a/app/models/ec_course_evaluation.rb b/app/models/ec_course_evaluation.rb new file mode 100644 index 000000000..6b778de66 --- /dev/null +++ b/app/models/ec_course_evaluation.rb @@ -0,0 +1,18 @@ +# 工程认证课程达成度计算--课程评估标准 +# status: 1 单次考核总成绩支撑课程目标, 2 单次考核的某分项成绩支撑课程目标 +# score_type: 1:导入的是明细成绩 2:导入的是平均成绩 +class EcCourseEvaluation < ApplicationRecord + belongs_to :ec_course + # 考核分项 + has_many :ec_course_evaluation_subitems, dependent: :destroy + has_many :ec_student_achievements + + enum status: { partly: 1, totality: 2 }, _suffix: :support # :partly_support?, :totality_support? + enum score_type: { detail: 1, average: 2 }, _suffix: :score_type # :detail_score_type?, :average_score_type? + + accepts_nested_attributes_for :ec_course_evaluation_subitems, allow_destroy: true + + def imported? + import_status? + end +end diff --git a/app/models/ec_course_evaluation_subitem.rb b/app/models/ec_course_evaluation_subitem.rb new file mode 100644 index 000000000..e23254cc2 --- /dev/null +++ b/app/models/ec_course_evaluation_subitem.rb @@ -0,0 +1,6 @@ +class EcCourseEvaluationSubitem < ApplicationRecord + belongs_to :ec_course_evaluation + + has_many :ec_achievement_evaluation_relates, dependent: :delete_all + has_many :ec_student_achievements, dependent: :delete_all +end diff --git a/app/models/ec_course_student_score.rb b/app/models/ec_course_student_score.rb new file mode 100644 index 000000000..5b45e34a9 --- /dev/null +++ b/app/models/ec_course_student_score.rb @@ -0,0 +1,7 @@ +class EcCourseStudentScore < ApplicationRecord + belongs_to :ec_year_student + belongs_to :ec_course + belongs_to :ec_course_target + + has_many :ec_student_score_targets, dependent: :delete_all +end \ No newline at end of file diff --git a/app/models/ec_course_support.rb b/app/models/ec_course_support.rb new file mode 100644 index 000000000..a6ca96ea9 --- /dev/null +++ b/app/models/ec_course_support.rb @@ -0,0 +1,13 @@ +class EcCourseSupport < ApplicationRecord + default_scope { order(position: :asc) } + + belongs_to :ec_course + belongs_to :ec_graduation_subitem + # TODO: 将 ec_graduation_subitem_courses 移除,这个表作为关系表 + + has_one :ec_graduation_requirement_calculation, dependent: :destroy + + validates :weights, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 } + + number_display_methods :weights +end \ No newline at end of file diff --git a/app/models/ec_course_target.rb b/app/models/ec_course_target.rb new file mode 100644 index 000000000..9b93cb73c --- /dev/null +++ b/app/models/ec_course_target.rb @@ -0,0 +1,19 @@ +# TODO:: change table column :weigths => :weight +class EcCourseTarget < ApplicationRecord + belongs_to :ec_course + + has_many :ec_graduation_subitem_course_targets, dependent: :destroy + has_many :ec_graduation_subitems, through: :ec_graduation_subitem_course_targets + has_many :ec_student_score_targets + has_many :ec_course_achievement_methods, dependent: :destroy + has_many :ec_achievement_evaluation_relates, dependent: :destroy + + validates :content, presence: true + validates :standard_grade, numericality: { only_integer: true, greater_than: 0 } + validates :weight, presence: true, numericality: { less_than_or_equal_to: 1, greater_than_or_equal_to: 0 } + + accepts_nested_attributes_for :ec_graduation_subitem_course_targets, allow_destroy: true + accepts_nested_attributes_for :ec_course_achievement_methods, allow_destroy: true + + number_display_methods :weight +end diff --git a/app/models/ec_course_user.rb b/app/models/ec_course_user.rb new file mode 100644 index 000000000..8ef6cd721 --- /dev/null +++ b/app/models/ec_course_user.rb @@ -0,0 +1,5 @@ +class EcCourseUser < ApplicationRecord + belongs_to :ec_course + belongs_to :user + belongs_to :ec_year +end diff --git a/app/models/ec_graduation_requirement.rb b/app/models/ec_graduation_requirement.rb new file mode 100644 index 000000000..d0f4195d0 --- /dev/null +++ b/app/models/ec_graduation_requirement.rb @@ -0,0 +1,11 @@ +class EcGraduationRequirement < ApplicationRecord + belongs_to :ec_year + + has_many :ec_graduation_subitems, dependent: :destroy + has_many :ec_requirement_vs_objectives, dependent: :destroy + + validates :position, presence: true, numericality: { only_integer: true, greater_than: 0 } + validates :content, presence: true + + default_scope { order(position: :asc) } +end diff --git a/app/models/ec_graduation_requirement_calculation.rb b/app/models/ec_graduation_requirement_calculation.rb new file mode 100644 index 000000000..2f9c92f71 --- /dev/null +++ b/app/models/ec_graduation_requirement_calculation.rb @@ -0,0 +1,3 @@ +class EcGraduationRequirementCalculation < ApplicationRecord + belongs_to :ec_course_support +end \ No newline at end of file diff --git a/app/models/ec_graduation_standard.rb b/app/models/ec_graduation_standard.rb new file mode 100644 index 000000000..ba653ab86 --- /dev/null +++ b/app/models/ec_graduation_standard.rb @@ -0,0 +1,5 @@ +class EcGraduationStandard < ApplicationRecord + has_many :ec_require_sub_vs_standards, dependent: :destroy + + validates :content, presence: true +end diff --git a/app/models/ec_graduation_subitem.rb b/app/models/ec_graduation_subitem.rb new file mode 100644 index 000000000..2104f5c40 --- /dev/null +++ b/app/models/ec_graduation_subitem.rb @@ -0,0 +1,18 @@ +class EcGraduationSubitem < ApplicationRecord + + default_scope { order(position: :asc) } + + belongs_to :ec_graduation_requirement + + has_many :ec_require_sub_vs_standards, dependent: :destroy + has_many :ec_course_supports, dependent: :destroy + has_many :ec_courses, through: :ec_course_supports + + has_many :ec_graduation_subitem_course_targets, dependent: :delete_all + has_many :ec_course_targets, through: :ec_graduation_subitem_course_targets + + validates :position, presence: true, numericality: { only_integer: true, greater_than: 0 } + validates :content, presence: true + + accepts_nested_attributes_for :ec_course_supports, allow_destroy: true +end diff --git a/app/models/ec_graduation_subitem_course_target.rb b/app/models/ec_graduation_subitem_course_target.rb new file mode 100644 index 000000000..3dffe2c21 --- /dev/null +++ b/app/models/ec_graduation_subitem_course_target.rb @@ -0,0 +1,4 @@ +class EcGraduationSubitemCourseTarget < ApplicationRecord + belongs_to :ec_course_target + belongs_to :ec_graduation_subitem +end \ No newline at end of file diff --git a/app/models/ec_major.rb b/app/models/ec_major.rb new file mode 100644 index 000000000..4842f7d70 --- /dev/null +++ b/app/models/ec_major.rb @@ -0,0 +1,7 @@ +class EcMajor < ApplicationRecord + # 主页对应的学校,不同学校可以选用同样的专业,而每个专业又各具特色 + has_many :schools, through: :ec_major_schools + has_many :ec_major_schools, dependent: :destroy + + scope :search_name_or_code, -> (keyword) { where('name LIKE :keyword OR code LIKE :keyword', keyword: "%#{keyword.strip}%") } +end diff --git a/app/models/ec_major_course.rb b/app/models/ec_major_course.rb new file mode 100644 index 000000000..d43f0da9c --- /dev/null +++ b/app/models/ec_major_course.rb @@ -0,0 +1,4 @@ +class EcMajorCourse < ApplicationRecord + belongs_to :ec_course + belongs_to :course +end diff --git a/app/models/ec_major_school.rb b/app/models/ec_major_school.rb new file mode 100644 index 000000000..41a835f63 --- /dev/null +++ b/app/models/ec_major_school.rb @@ -0,0 +1,19 @@ +class EcMajorSchool < ApplicationRecord + belongs_to :ec_major + belongs_to :school + + # 专业对应的学年 + has_many :ec_years, dependent: :destroy + + # 学校对应的专业中成员 + has_many :ec_major_school_users, dependent: :destroy + has_many :users, through: :ec_major_school_users + + scope :is_template, -> { where(template_major: true) } + scope :not_template, -> { where(template_major: false) } + + # 是否为该专业管理员 + def manager?(user) + ec_major_school_users.exists?(user_id: user.id) + end +end diff --git a/app/models/ec_major_school_user.rb b/app/models/ec_major_school_user.rb new file mode 100644 index 000000000..538e5674b --- /dev/null +++ b/app/models/ec_major_school_user.rb @@ -0,0 +1,4 @@ +class EcMajorSchoolUser < ApplicationRecord + belongs_to :user + belongs_to :ec_major_school +end diff --git a/app/models/ec_require_sub_vs_standard.rb b/app/models/ec_require_sub_vs_standard.rb new file mode 100644 index 000000000..c04ca322b --- /dev/null +++ b/app/models/ec_require_sub_vs_standard.rb @@ -0,0 +1,4 @@ +class EcRequireSubVsStandard < ApplicationRecord + belongs_to :ec_graduation_standard + belongs_to :ec_graduation_subitem +end diff --git a/app/models/ec_requirement_vs_objective.rb b/app/models/ec_requirement_vs_objective.rb new file mode 100644 index 000000000..88f969e10 --- /dev/null +++ b/app/models/ec_requirement_vs_objective.rb @@ -0,0 +1,4 @@ +class EcRequirementVsObjective < ApplicationRecord + belongs_to :ec_training_subitem + belongs_to :ec_graduation_requirement +end diff --git a/app/models/ec_school_user.rb b/app/models/ec_school_user.rb new file mode 100644 index 000000000..77e069c4d --- /dev/null +++ b/app/models/ec_school_user.rb @@ -0,0 +1,4 @@ +class EcSchoolUser < ApplicationRecord + belongs_to :user + belongs_to :school +end diff --git a/app/models/ec_score_level.rb b/app/models/ec_score_level.rb new file mode 100644 index 000000000..c9573a9b0 --- /dev/null +++ b/app/models/ec_score_level.rb @@ -0,0 +1,11 @@ +class EcScoreLevel < ApplicationRecord + belongs_to :ec_course + + default_scope { order(position: :asc) } + + def compare_condition + max_position = self.class.maximum(:position) + # 特殊情况:只有一条记录 + position < max_position || max_position == 1 ? 'not_less_than' : 'less_than' + end +end diff --git a/app/models/ec_student_achievement.rb b/app/models/ec_student_achievement.rb new file mode 100644 index 000000000..c1363c91c --- /dev/null +++ b/app/models/ec_student_achievement.rb @@ -0,0 +1,5 @@ +class EcStudentAchievement < ApplicationRecord + belongs_to :ec_year_student + belongs_to :ec_course_evaluation + belongs_to :ec_course_evaluation_subitem +end diff --git a/app/models/ec_student_score_target.rb b/app/models/ec_student_score_target.rb new file mode 100644 index 000000000..668e1325b --- /dev/null +++ b/app/models/ec_student_score_target.rb @@ -0,0 +1,5 @@ +class EcStudentScoreTarget < ApplicationRecord + belongs_to :ec_year_student + belongs_to :ec_course_student_score + belongs_to :ec_course_target +end \ No newline at end of file diff --git a/app/models/ec_training_objective.rb b/app/models/ec_training_objective.rb new file mode 100644 index 000000000..56460561d --- /dev/null +++ b/app/models/ec_training_objective.rb @@ -0,0 +1,11 @@ +class EcTrainingObjective < ApplicationRecord + + belongs_to :ec_year + + # 培养目标分项 + has_many :ec_training_subitems, dependent: :destroy + + validates :content, presence: true + + accepts_nested_attributes_for :ec_training_subitems, allow_destroy: true +end diff --git a/app/models/ec_training_subitem.rb b/app/models/ec_training_subitem.rb new file mode 100644 index 000000000..0c9c61fbc --- /dev/null +++ b/app/models/ec_training_subitem.rb @@ -0,0 +1,7 @@ +class EcTrainingSubitem < ApplicationRecord + belongs_to :ec_training_objective + + has_many :ec_requirement_vs_objectives, foreign_key: :ec_training_objective_id, dependent: :destroy + + validates :content, presence: true +end diff --git a/app/models/ec_year.rb b/app/models/ec_year.rb new file mode 100644 index 000000000..69ae4c291 --- /dev/null +++ b/app/models/ec_year.rb @@ -0,0 +1,12 @@ +class EcYear < ApplicationRecord + belongs_to :ec_major_school + + # 课堂配置 + has_many :ec_courses, dependent: :destroy + has_many :ec_course_targets, through: :ec_courses + has_one :ec_training_objective, dependent: :destroy + has_many :ec_training_subitems, through: :ec_training_objective + has_many :ec_graduation_requirements, dependent: :destroy + has_many :ec_graduation_subitems, through: :ec_graduation_requirements + has_many :ec_year_students, dependent: :destroy +end diff --git a/app/models/ec_year_student.rb b/app/models/ec_year_student.rb new file mode 100644 index 000000000..3d8b0b6df --- /dev/null +++ b/app/models/ec_year_student.rb @@ -0,0 +1,7 @@ +class EcYearStudent < ApplicationRecord + belongs_to :ec_year + + has_many :ec_student_achievements, dependent: :delete_all + has_many :ec_course_student_scores, dependent: :destroy + has_many :ec_student_score_targets, dependent: :delete_all +end diff --git a/app/models/edu_setting.rb b/app/models/edu_setting.rb new file mode 100644 index 000000000..db6d545f0 --- /dev/null +++ b/app/models/edu_setting.rb @@ -0,0 +1,5 @@ +class EduSetting < ApplicationRecord + def self.get(key) + find_by_name(key.to_s)&.value + end +end diff --git a/app/models/evaluate_record.rb b/app/models/evaluate_record.rb new file mode 100644 index 000000000..451409493 --- /dev/null +++ b/app/models/evaluate_record.rb @@ -0,0 +1,6 @@ +class EvaluateRecord < ApplicationRecord + default_scope { order("evaluate_records.id desc") } + belongs_to :game + belongs_to :shixun + belongs_to :user +end diff --git a/app/models/exercise.rb b/app/models/exercise.rb new file mode 100644 index 000000000..e2623c692 --- /dev/null +++ b/app/models/exercise.rb @@ -0,0 +1,178 @@ +class Exercise < ApplicationRecord + belongs_to :course, counter_cache: true + belongs_to :exercise_bank, optional: true + belongs_to :user + + has_many :exercise_users,:dependent => :destroy + has_many :exercise_questions,:dependent => :destroy + has_many :exercise_group_settings,:dependent => :destroy + has_many :tidings, as: :container + has_many :course_acts, class_name: 'CourseActivity', as: :course_act, dependent: :destroy + + scope :is_exercise_published, -> { where("exercise_status > ? ",1)} + scope :unified_setting, -> { where("unified_setting = ?",true) } + scope :exercise_by_ids, lambda { |ids| where(id: ids) unless ids.blank? } + scope :exercise_by_status, lambda { |s| where(exercise_status: s) unless s.blank? } + scope :exercise_search, lambda { |keywords| + where("exercise_name LIKE ?", "%#{keywords}%") unless keywords.blank?} + + validates :exercise_name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" } + + after_create :create_exercise_list + + def create_exercise_list + str = "" + # TODO: 一次性为所有学生创建数据是否存在问题? + self.course.students.find_each do |student| + str += "," if str != "" + str += "(#{student.user_id}, #{self.id}, 0, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + + if str != "" + sql = "insert into exercise_users (user_id, exercise_id, commit_status, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + + #获取学生视角的试卷用户 + def get_stu_exercise_users + if unified_setting #试卷统一设置 + exercise_users + else + ex_group_setting_ids = exercise_group_settings.exercise_group_published.pluck(:course_group_id) + course_user_ids = course.students.where(course_group_id:ex_group_setting_ids).pluck(:user_id) + exercise_users.where(user_id:course_user_ids) + end + end + + def get_exercise_end_time(user_id) + if unified_setting + self&.end_time + else + user_course_group = course.course_members.find_by(user_id: user_id)&.course_group_id + exercise_group_settings.find_by(course_group_id:user_course_group)&.end_time + end + end + + #统一设置,为当前老师有权限的分班学生,分班设置,也为当前老师有权限的分班的学生 + def all_exercise_users(user_id) + ex_users = self.exercise_users + group_ids = common_published_ids(user_id) + if group_ids.present? + ex_users = ex_users.where(user_id: course.students.where(course_group_id: group_ids).pluck(:user_id)) + end + ex_users + end + + #当前用户已发布的班级id和试卷分组已发布的班级id的交集 + def common_published_ids(user_id) + current_user_groups = course.teacher_course_group_ids(user_id) + if unified_setting + if course.none_group_count > 0 #有未分班的,则发布到未发布分班 + un_group_ids = [0] + else + un_group_ids = [] + end + published_group_ids = (current_user_groups + un_group_ids).uniq #统一设置时,为当前用户的分班id及未分班 + else + ex_group_setting = exercise_group_settings.pluck("course_group_id").uniq + common_all_ids = ex_group_setting & current_user_groups #当前用户有权限的已发布的分班id #非统一设置时,为当前用户有权限的且已发布分班的id + published_group_ids = common_all_ids.uniq + end + published_group_ids + end + + + #判断用户是否属于试卷分班的学生中 + def check_user_in_course(user_id,user_identity) + ex_group_settings = exercise_group_settings.pluck(:course_group_id) + member = course.course_members.course_find_by_ids("user_id",user_id) + member_group_id = member.pluck(:course_group_id).uniq + if (member_group_id & ex_group_settings).size > 0 || user_identity < Course::STUDENT + true + else + false + end + end + + #判断是否为分班,如果分班,试卷的截止时间为当前分班时间,否则为试卷的截止时间 + def get_exercise_status(user_id) + user_group = course.course_members.find_by(user_id: user_id) + if user_group.present? + if user_group.role == "STUDENT" #为学生 + is_teacher = false + else + is_teacher = true + end + ex_time = get_exercise_times(user_id,is_teacher) + + pb_time = ex_time[:publish_time] + ed_time = ex_time[:end_time] + + if pb_time.present? && ed_time.present? && pb_time <= Time.now && ed_time > Time.now + status = 2 + elsif ed_time.present? && ed_time <= Time.now + status = 3 + else + status = 1 + end + else + status = exercise_status + end + status + end + + #获取试卷的发布时间和截止时间。teacher 为boolean,当为true时,表示的是当前为老师 + def get_exercise_times(user_id,teacher) + if unified_setting + pb_time = publish_time + en_time = end_time + else + ex_group_setting = exercise_group_settings + if teacher #当前为老师,为设置组的最大值和最小值 + user_group = course.teacher_course_groups.get_user_groups(user_id) + user_group_ids = user_group.present? ? user_group.pluck(:course_group_id) : course.course_groups.pluck(:id) + user_ex_group_settings = ex_group_setting.find_in_exercise_group("course_group_id",user_group_ids) + pb_time_min = user_ex_group_settings.publish_time_no_null.map(&:publish_time) + en_time_max = user_ex_group_settings.end_time_no_null.map(&:end_time) + pb_time = pb_time_min.size > 0 ? pb_time_min.min : nil + en_time = en_time_max.size > 0 ? en_time_max.max : nil + else + user_group = course.students.course_find_by_ids("user_id",user_id) + if user_group.present? + user_group_id = user_group.first.course_group_id + user_ex_group_setting = ex_group_setting.find_in_exercise_group("course_group_id",user_group_id) + pb_time = user_ex_group_setting.present? ? user_ex_group_setting.first.publish_time : nil + en_time = user_ex_group_setting.present? ? user_ex_group_setting.first.end_time : nil + else + pb_time = nil + en_time = nil + end + end + end + { + "publish_time":pb_time, + "end_time":en_time + } + end + + #判断当前用户的答题状态 + def check_user_answer_status(user) + ex_answer_user = exercise_users.find_by(user_id: user.id) + user_ex_status = get_exercise_status(user.id) + user_status = 2 + if ex_answer_user.present? && (ex_answer_user.start_at.present? || ex_answer_user.end_at.present?) #学生有过答题的,或者立即截止,但学生未做试卷的 + user_status = ex_answer_user.commit_status + end + if ex_answer_user.present? && ex_answer_user.start_at.blank? && user_ex_status == 3 + user_status = 4 + end + + user_status + end + +end + + + + diff --git a/app/models/exercise_answer.rb b/app/models/exercise_answer.rb new file mode 100644 index 000000000..465fa036b --- /dev/null +++ b/app/models/exercise_answer.rb @@ -0,0 +1,14 @@ +class ExerciseAnswer < ApplicationRecord + #学生答题 + belongs_to :user + belongs_to :exercise_question + belongs_to :exercise_choice, optional: true + has_many :exercise_answer_comments, :dependent => :destroy + + scope :search_exercise_answer, lambda { |name,key| where("#{name} = ?",key)} + scope :search_answer_users, lambda {|name,ids| where("#{name}":ids)} + scope :exercise_no_full_scores, lambda { |score| where("score > 0.0 AND score < ?",score)} + scope :exercise_answer_is_right, -> {where("score > ?",0.0)} #判断答案是否正确,根据分数总和大于0 + scope :score_reviewed, lambda {where("score >= ?",0.0)} #是否评分,用于判断主观题的 + +end \ No newline at end of file diff --git a/app/models/exercise_answer_comment.rb b/app/models/exercise_answer_comment.rb new file mode 100644 index 000000000..7da0ec4c7 --- /dev/null +++ b/app/models/exercise_answer_comment.rb @@ -0,0 +1,9 @@ +class ExerciseAnswerComment < ApplicationRecord + # belongs_to :exercise_answer + belongs_to :user + belongs_to :exercise_question + belongs_to :exercise_shixun_answer, optional: true + belongs_to :exercise_answer,optional: true + + scope :search_answer_comments, lambda {|name,ids| where("#{name}":ids)} +end diff --git a/app/models/exercise_bank.rb b/app/models/exercise_bank.rb new file mode 100644 index 000000000..22c2a5041 --- /dev/null +++ b/app/models/exercise_bank.rb @@ -0,0 +1,21 @@ +class ExerciseBank < ApplicationRecord + # container_type: Poll 问卷; Exercise试卷 + belongs_to :user + belongs_to :course_list + + has_many :exercise_bank_questions, :dependent => :destroy + has_many :polls, dependent: :nullify + has_many :exercises, dependent: :nullify + + # def course_list_name + # self.course_list ? self.course_list.name : "" + # end + # + scope :myself, -> (user_id){where(user_id: user_id)} + scope :find_by_container, lambda { |id,type| where(container_id: id,container_type:type)} + scope :find_by_c_type, lambda { |keywords| where(container_type: keywords) unless keywords.blank?} + scope :public_exercises, -> {where(is_public: true)} + scope :exercise_bank_search, lambda { |keywords| + where("name LIKE ?", "%#{keywords}%") unless keywords.blank?} + +end \ No newline at end of file diff --git a/app/models/exercise_bank_choice.rb b/app/models/exercise_bank_choice.rb new file mode 100644 index 000000000..d3a91bb02 --- /dev/null +++ b/app/models/exercise_bank_choice.rb @@ -0,0 +1,4 @@ +class ExerciseBankChoice < ApplicationRecord + belongs_to :exercise_bank_question + has_many :exercise_bank_standard_answers +end \ No newline at end of file diff --git a/app/models/exercise_bank_question.rb b/app/models/exercise_bank_question.rb new file mode 100644 index 000000000..5a39fd5d2 --- /dev/null +++ b/app/models/exercise_bank_question.rb @@ -0,0 +1,23 @@ +class ExerciseBankQuestion < ApplicationRecord + belongs_to :exercise_bank + belongs_to :shixun + has_many :exercise_bank_shixun_challenges,:dependent => :destroy + has_many :exercise_bank_choices, :dependent => :destroy + has_many :exercise_bank_standard_answers, :dependent => :destroy + #attr_accessible :question_number, :question_score, :question_title, :question_type + + def question_type_name + case self.question_type + when 1 + "单选题" + when 2 + "多选题" + when 3 + "填空题" + when 4 + "简答题" + when 5 + "实训题" + end + end +end \ No newline at end of file diff --git a/app/models/exercise_bank_shixun_challenge.rb b/app/models/exercise_bank_shixun_challenge.rb new file mode 100644 index 000000000..2a9fafff3 --- /dev/null +++ b/app/models/exercise_bank_shixun_challenge.rb @@ -0,0 +1,7 @@ +class ExerciseBankShixunChallenge < ApplicationRecord + belongs_to :challenge + belongs_to :shixun + belongs_to :exercise_question + belongs_to :exercise_bank_question + # has_many :exercise_shixun_answers, :dependent => :destroy +end \ No newline at end of file diff --git a/app/models/exercise_bank_standard_answer.rb b/app/models/exercise_bank_standard_answer.rb new file mode 100644 index 000000000..9cd82afe6 --- /dev/null +++ b/app/models/exercise_bank_standard_answer.rb @@ -0,0 +1,5 @@ +class ExerciseBankStandardAnswer < ApplicationRecord + belongs_to :exercise_bank_question + belongs_to :exercise_bank_choice + #attr_accessible :answer_text +end \ No newline at end of file diff --git a/app/models/exercise_choice.rb b/app/models/exercise_choice.rb new file mode 100644 index 000000000..525251ce6 --- /dev/null +++ b/app/models/exercise_choice.rb @@ -0,0 +1,9 @@ +class ExerciseChoice < ApplicationRecord + + belongs_to :exercise_question + has_many :exercise_answers, :dependent => :destroy + has_many :exercise_standard_answers, :dependent => :destroy + + scope :find_choice_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题 + scope :left_choice_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题 +end \ No newline at end of file diff --git a/app/models/exercise_group_setting.rb b/app/models/exercise_group_setting.rb new file mode 100644 index 000000000..35af61af5 --- /dev/null +++ b/app/models/exercise_group_setting.rb @@ -0,0 +1,15 @@ +class ExerciseGroupSetting < ApplicationRecord + belongs_to :exercise,optional:true + belongs_to :course_group,optional:true + belongs_to :course,optional:true + # attr_accessible :end_time, :publish_time + # scope :find_by_exercise_course,lambda{|k,v| where("#{k} =?",v)} + scope :end_time_no_null, -> { where("end_time is NOT NULL")} + scope :publish_time_no_null, -> { where("publish_time is NOT NULL")} + scope :exercise_group_not_published, -> {where("publish_time is NULL OR publish_time > ?",Time.now)} + scope :exercise_group_published, -> {where("publish_time IS NOT NULL AND publish_time <= ?",Time.now)} + scope :exercise_group_ended, -> {where("end_time is NOT NULL AND end_time <= ?",Time.now)} + + scope :find_in_exercise_group, lambda { |name,ids| where("#{name}": ids)} + +end \ No newline at end of file diff --git a/app/models/exercise_question.rb b/app/models/exercise_question.rb new file mode 100644 index 000000000..ae58a7592 --- /dev/null +++ b/app/models/exercise_question.rb @@ -0,0 +1,47 @@ +#encoding: utf-8 +class ExerciseQuestion < ApplicationRecord + + belongs_to :exercise + belongs_to :shixun, optional: true + + has_many :exercise_choices, :dependent => :destroy + has_many :exercise_answers, :dependent => :destroy + has_many :exercise_shixun_challenges,:dependent => :destroy + has_many :exercise_shixun_answers, :dependent => :destroy + has_many :exercise_answer_comments, :dependent => :destroy + has_many :exercise_standard_answers, :dependent => :destroy + + scope :insert_question_ex, lambda {|k| where("question_number > ?",k)} + scope :find_by_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题 + scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题 + scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题 + scope :next_exercise, lambda {|k| where("question_number > ?",k).first} + scope :last_exercise, lambda {|k| where("question_number < ?",k).last} + + def question_type_name + case self.question_type + when 0 + "单选题" + when 1 + "多选题" + when 2 + "判断题" + when 3 + "填空题" + when 4 + "简答题" + when 5 + "实训题" + end + end + + #获取问题的全部标准答案 + def get_standard_answer_ids + exercise_standard_answers.pluck(:exercise_choice_id) + end + + def get_standard_answer_text + exercise_standard_answers.pluck(:answer_text) + end + +end diff --git a/app/models/exercise_shixun_answer.rb b/app/models/exercise_shixun_answer.rb new file mode 100644 index 000000000..8548e497d --- /dev/null +++ b/app/models/exercise_shixun_answer.rb @@ -0,0 +1,13 @@ +class ExerciseShixunAnswer < ApplicationRecord + belongs_to :exercise_question + belongs_to :user + belongs_to :exercise_shixun_challenge + has_many :exercise_answer_comments, :dependent => :destroy + # status 0: 未通过, 1:通过 + # attr_accessible :answer_text, :score, :status + scope :search_shixun_answers, lambda {|name,ids| where("#{name}":ids)} + scope :search_shixun_keys, lambda { |name,key| where("#{name} = ?",key)} + scope :shixun_no_full_scores, lambda { |score| where("score > 0.0 AND score < ?",score)} + scope :score_reviewed, lambda {where("score is not NULL AND score >= ?",0.0)} #是否评分 + +end diff --git a/app/models/exercise_shixun_challenge.rb b/app/models/exercise_shixun_challenge.rb new file mode 100644 index 000000000..c88e78ca7 --- /dev/null +++ b/app/models/exercise_shixun_challenge.rb @@ -0,0 +1,8 @@ +class ExerciseShixunChallenge < ApplicationRecord + belongs_to :challenge + belongs_to :shixun + belongs_to :exercise_question + has_many :exercise_shixun_answers, :dependent => :destroy + + scope :cha_id_find, lambda {|id| where(id:id)} +end diff --git a/app/models/exercise_standard_answer.rb b/app/models/exercise_standard_answer.rb new file mode 100644 index 000000000..b4c71bd76 --- /dev/null +++ b/app/models/exercise_standard_answer.rb @@ -0,0 +1,10 @@ +class ExerciseStandardAnswer < ApplicationRecord + #标准答案 + belongs_to :exercise_question, optional:true + belongs_to :exercise_choice, optional:true + + scope :find_standard_answer_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题 + scope :standard_by_ids, lambda { |s| where(exercise_choice_id: s) } + + +end diff --git a/app/models/exercise_user.rb b/app/models/exercise_user.rb new file mode 100644 index 000000000..84f042b25 --- /dev/null +++ b/app/models/exercise_user.rb @@ -0,0 +1,12 @@ +class ExerciseUser < ApplicationRecord + belongs_to :user + belongs_to :exercise + + scope :commit_exercise_by_status, lambda { |s| where(commit_status: s) } + scope :exercise_user_committed, -> {where("commit_status != ?",0) } + scope :current_exercise_user, lambda { |user_id,exercise_id| where(user_id: user_id,exercise_id:exercise_id)} + scope :exercise_commit_users, lambda {|user_ids| where(user_id:user_ids)} + scope :exercise_review, -> {where("subjective_score >= ?",0.0)} #已评阅,测试版的不一样是因为测试版的 主观题默认为0。0分,没有修改为-1分 + scope :exercise_unreview, -> {where("subjective_score < ?",0.0)} #未评阅 + scope :search_by_exercise, lambda {|ids| where(exercise_id:ids)} #根据试卷来查找 +end diff --git a/app/models/experience.rb b/app/models/experience.rb new file mode 100644 index 000000000..a5d828da3 --- /dev/null +++ b/app/models/experience.rb @@ -0,0 +1,3 @@ +class Experience < ApplicationRecord + belongs_to :user +end diff --git a/app/models/game.rb b/app/models/game.rb new file mode 100644 index 000000000..c08884afb --- /dev/null +++ b/app/models/game.rb @@ -0,0 +1,137 @@ +## 数据库字段说明 +# status 0:已开启;1:正在评测;2:通过评测;3:锁定 +# modify_time: 与challenges表的modify_time联合使用,2个字段一致,则标识测试集未修改,反之,被修改 +# answer_open: 查看查看答案的深度, 0: 未查看过答案, 其他数值与challenge_answer的level值相关 +# answer_deduction: 查看答案扣分的百分比;如 查看答案 扣除70% +# +class Game < ApplicationRecord + default_scope { order("games.created_at desc") } + + has_many :outputs, -> { order('query_index DESC') } + has_many :challenge_samples, :dependent => :destroy + has_many :game_codes, :dependent => :destroy + has_many :evaluate_records, -> { order('id DESC') }, :dependent => :destroy + belongs_to :myshixun + belongs_to :user + belongs_to :challenge + has_one :run_code_message, :dependent => :destroy + + + #全部关卡数 + scope :ch_games, lambda { |challenge_id| where(challenge_id:challenge_id) } + # 已通关的数量 + scope :finished_num, -> (challenge_id) { where(:challenge_id => challenge_id, :status => 1)} + # 正在通关的数量 + scope :doing_num, -> (challenge_id) { where(:challenge_id => challenge_id, :status => 0)} + + #用户的全部关卡 + scope :user_games, lambda { |user_id,challenge_id| where("user_id = ? AND challenge_id = ?",user_id,challenge_id) } + + validates :identifier, uniqueness: true + + # 根据得分比例来算实际得分(试卷、实训作业) + def real_score score + final_score == challenge.score ? score : (final_score.to_f / challenge.score) * score + end + + # 判断实训是否全部通关 + def had_done + Game.where(myshixun: self.myshixun_id).where("status != 2").count > 0 ? 0 : 1 + end + + def owner + self.user + end + + def had_passed? + self.status == 2 + end + + # 因为outputs是按qurey_index倒序,所有first取的qurey_index的最大值 + # 之所以加1是因为,存的时候要递增,如果仅取的话,则注意:必须减一 + def query_index + # Output.unscope(:order).maximum("query_index").where(game_id: self.id) + self.outputs.unscope(:order).maximum("query_index") + end + + # 用户在game关卡中获得的金币和经验值 + # st: 0 实战类型;1 选择题类型 + def user_get_gold_and_experience shixun_status, challenge + if challenge.st == 0 # 实战类型 + if self.status == 2 # 通关了则取实际得分,没通关则取总分 + gold = (shixun_status <= 1) ? 0 : self.final_score.to_i + # 只要过关了,查看了答案经验值就是0;通关前查看了答案金final_score为负数 + experience = (shixun_status <= 1 || self.final_score.to_i < 0) ? 0 : challenge.score.to_i + else + gold = challenge.score.to_i + experience = gold + end + else + if self.status == 2 + gold = (shixun_status <= 1) ? 0 : self.final_score.to_i + experience = (shixun_status <= 1 || self.final_score.to_i < 0) ? 0 : challenge.score.to_i + else + # 选择题只有在全对的时候才会获取final score总分,错任何一个题final_score就为0 + gold = challenge.choose_score + experience = challenge.choose_score + end + end + [gold, experience] + end + + # 上一关 + def prev_of_current_game shixun_id, myshixun_id, challenge_position + Game.find_by_sql("select identifier from games where myshixun_id=#{myshixun_id} + and challenge_id=(select id from challenges where shixun_id=#{shixun_id} and + position=#{challenge_position - 1})").first.try(:identifier) + end + + # 下一关 + def next_of_current_game shixun_id, myshixun_id, challenge_position + Game.find_by_sql("select * from games where myshixun_id=#{myshixun_id} + and challenge_id=(select id from challenges where shixun_id=#{shixun_id} and + position=#{challenge_position + 1})").first.try(:identifier) + end + + # 针对api形式取下一关identifier + def next_game shixun_id, myshixun_id, challenge_position + Game.find_by_sql("select * from games where myshixun_id=#{myshixun_id} + and challenge_id=(select id from challenges where shixun_id=#{shixun_id} and + position=#{challenge_position + 1})").first + end + + # 因为outputs是按qurey_index倒序,所有first取的qurey_index的最大值 + # 之所以加1是以为,存的时候要递增,如果仅取的话,则注意:必须减一 + def next_query_index + if self.outputs.try(:first).present? + self.outputs.first.try(:query_index).to_i + 1 + else + 1 + end + end + + def choose_correct_num query_index + self.outputs.where(query_index: query_index, result: 1).count + end + + # 评测次数 + def evaluate_count + self.outputs.pluck(:query_index).first + end + + # 用户关卡得分 + def get_user_final_score + + end + + # 按评测次数的查询 + def distinct_query_index + self.outputs.group("outputs.query_index").reorder("query_index asc") + end + + def lastest_code + self.game_codes.first.try(:new_code) + # game_code = GameCode.where(:game_id => self.id).first + # game_code.try(:new_code) + end +end diff --git a/app/models/game_code.rb b/app/models/game_code.rb new file mode 100644 index 000000000..65181aa9a --- /dev/null +++ b/app/models/game_code.rb @@ -0,0 +1,7 @@ +class GameCode < ApplicationRecord + belongs_to :game + + # 按关卡路径搜索 + scope :search_challenge_path, lambda { |cha_path| where("path = ?",cha_path) } + +end diff --git a/app/models/grade.rb b/app/models/grade.rb new file mode 100644 index 000000000..60a913e2e --- /dev/null +++ b/app/models/grade.rb @@ -0,0 +1,11 @@ +class Grade < ApplicationRecord + + belongs_to :user + + has_many :tidings, :as => :container, :dependent => :destroy + after_create :send_tiding + def send_tiding + self.tidings << Tiding.new(:user_id => self.user_id, :trigger_user_id => 0, :parent_container_id => self.container_id, + :parent_container_type => self.container_type, :viewed => 0, :tiding_type => "System") + end +end diff --git a/app/models/graduation_group.rb b/app/models/graduation_group.rb new file mode 100644 index 000000000..a7f3f227f --- /dev/null +++ b/app/models/graduation_group.rb @@ -0,0 +1,7 @@ +class GraduationGroup < ApplicationRecord + belongs_to :course + has_many :course_members + belongs_to :user + has_one :graduation_task_group_assignation, dependent: :destroy + has_many :graduation_work_comment_assignations +end diff --git a/app/models/graduation_task.rb b/app/models/graduation_task.rb new file mode 100644 index 000000000..308c51be4 --- /dev/null +++ b/app/models/graduation_task.rb @@ -0,0 +1,174 @@ +class GraduationTask < ApplicationRecord + # task_type 1: 普通作业 2:分组作业 + # status 0:未发布 1:已发布 2:评阅中 3:交叉评阅 + # comment_status 1:随机分配 2:指导老师手动分配 3:答辩组内老师互评 4:答辩组间老师互评 + + belongs_to :course, counter_cache: true + belongs_to :user + + has_many :journals_for_messages, as: :jour, dependent: :destroy + has_many :praise_tread, as: :praise_tread_object, dependent: :destroy + has_many :course_acts, class_name: 'CourseActivity', as: :course_act, dependent: :destroy + has_many :tidings, as: :container, dependent: :destroy + + has_many :attachments, as: :container, dependent: :destroy + + has_many :graduation_task_group_assignations, dependent: :destroy + has_many :graduation_work_comment_assignations, dependent: :destroy + + has_many :graduation_works, -> { where("is_delete != 1") } + has_many :graduation_work_scores + + validates :name, length: { maximum: 60 } + validates :description, length: { maximum: 5000 } + + # 未提交 + scope :unfinished, -> {where(status: 0)} + # 按时提交 + scope :finished, -> {where(status: 1)} + # 延迟提交 + scope :delay_finished, -> {where(status: 2)} + + #已发布的 + scope :task_published, -> {where("publish_time <= ?",Time.now)} + + + def user_work user_id + work = self.graduation_works.find_by(user_id: user_id) + end + + def task_type_name + task_type == 1 ? "普通作业" : "分组作业" + end + + # 是否有学生提交过作品 + def student_commit_works + graduation_works.has_committed.count > 0 + end + + # 是否有学生关联了项目 + def student_relate_projects + task_type == 2 && graduation_works.where("project_id != 0").count > 0 + end + + # 是否发布 + def published? + self.publish_time.present? && self.publish_time < Time.now + end + + # 答辩组互评分配 + def task_assign_group group_id + graduation_task_group_assignations.find_by(graduation_group_id: group_id) + end + + def create_work_list + str = "" + self.course.students.each do |student| + str += "," if str != "" + str += "(#{self.id}, #{student.user_id}, #{self.course_id}, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if str != "" + sql = "insert into graduation_works (graduation_task_id, user_id, course_id, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + + #课程动态公共表记录 + def act_as_course_activity + if self.course_acts.size == 0 + self.course_acts << CourseActivity.new(user_id: self.user_id, course_id: self.course_id) + end + end + + # 是否提交了作品 + def has_commit_work user_id + work = self.graduation_works.find_by(user_id: user_id) + work.present? && work.work_status != 0 + end + + # 任务已评数 user_id: 对应老师的id + def comment_count(user_id) + course = self.course + # 如果有分班,则取此老师对应分班的已评数,没有分班,则取所有的 + course_group_ids = course.group_course_power(user_id) + sql = + if course_group_ids.count > 0 + %Q{ + SELECT count(distinct graduation_work_id) cnt FROM graduation_work_scores WHERE reviewer_role IN(1,2) AND graduation_work_id + IN(SELECT id FROM graduation_works WHERE graduation_task_id = #{self.id} AND user_id + IN(SELECT user_id FROM course_members WHERE role = 4 AND course_group_id + IN(SELECT course_group_id FROM teacher_course_groups WHERE id IN(#{course_group_ids.join(",")})) + ) + ) + } + else + %Q{ + SELECT COUNT(distinct graduation_work_id) cnt FROM graduation_works gw + JOIN graduation_work_scores gwc ON gw.graduation_task_id = gwc.graduation_task_id + WHERE reviewer_role IN(1,2) AND gwc.graduation_task_id = #{self.id} + } + end + GraduationWorkScore.find_by_sql(sql).first.try(:cnt).to_i + end + + # 任务未评数 + def uncomment_count(user_id) + user_ids = course.teacher_group_user_ids user_id + self.graduation_works.where(user_id: user_ids).count - self.comment_count(user_id) + end + + # 任务未提交数 + def unfinished_count user_id + course_group_ids = course.group_course_power(user_id) + if course_group_ids.count > 0 + sql = %Q{ + SELECT count(*) cnt FROM graduation_works gw WHERE work_status = 0 AND gw.graduation_task_id = #{self.id} AND gw.user_id + IN( SELECT user_id FROM course_members WHERE role = 4 AND course_group_id + IN( SELECT course_group_id FROM teacher_course_groups WHERE id not IN(#{course_group_ids.join(",")}) ) + ) + } + GraduationWork.find_by_sql(sql).first.try(:cnt) + else + self.graduation_works.where(work_status: 0).count + end + end + + # 任务按时提交数 + def finished_count(user_id) + course = self.course + course_group_ids = course.group_course_power(user_id) + if course_group_ids.count > 0 + sql = %Q{ + SELECT count(*) cnt FROM graduation_works gw WHERE work_status = 1 AND gw.graduation_task_id = #{self.id} AND gw.user_id + IN( SELECT user_id FROM course_members WHERE role = 4 AND course_group_id + IN( SELECT course_group_id FROM teacher_course_groups WHERE id IN(#{course_group_ids.join(",")}) ) + ) + } + GraduationWork.find_by_sql(sql).first.try(:cnt) + else + self.graduation_works.where(work_status: 1).count + end + end + + def delay_finished_count(user_id) + course = self.course + course_group_ids = course.group_course_power(user_id) + if course_group_ids.count > 0 + sql = %Q{ + SELECT count(*) cnt FROM graduation_works gw WHERE work_status = 2 AND gw.graduation_task_id = #{self.id} AND gw.user_id + IN( SELECT user_id FROM course_members WHERE role = 4 AND course_group_id + IN( SELECT course_group_id FROM teacher_course_groups WHERE id IN(#{course_group_ids.join(",")}) ) + ) + } + GraduationWork.find_by_sql(sql).first.try(:cnt) + else + self.graduation_works.where(work_status: 2).count + end + end + + # 是否具有分组 + def have_grouping? + self.task_type == 2 + end + +end diff --git a/app/models/graduation_task_group_assignation.rb b/app/models/graduation_task_group_assignation.rb new file mode 100644 index 000000000..52da65191 --- /dev/null +++ b/app/models/graduation_task_group_assignation.rb @@ -0,0 +1,6 @@ +class GraduationTaskGroupAssignation < ApplicationRecord + belongs_to :graduation_task + belongs_to :graduation_group + belongs_to :assign_group, class_name: 'GraduationGroup', foreign_key: :assign_graduation_group_id # 分配的互评组 + +end diff --git a/app/models/graduation_topic.rb b/app/models/graduation_topic.rb new file mode 100644 index 000000000..3aed72d9c --- /dev/null +++ b/app/models/graduation_topic.rb @@ -0,0 +1,72 @@ +# status 0:待选中 1:待确认 2:已确认 +class GraduationTopic < ApplicationRecord + belongs_to :course, counter_cache: true + belongs_to :user + has_many :student_graduation_topics, :dependent => :destroy + # 附件 + #acts_as_attachable + has_many :attachments, as: :container, dependent: :destroy + # 回复 + has_many :journals_for_messages, :as => :jour, :dependent => :destroy + + # 题库 + + + scope :search_by_name, ->(name) { where("graduation_topics.name LIKE ?", "%#{name}%")} + scope :search_by_status, ->(status) {where(status: status)} + + + #after_create :act_as_course_activity + + # 课题名称和描述字段长度限制 + validates :name, length: { maximum: 60, + too_long: "60 characters is the maximum allowed" } + validates :description, length: { maximum: 5000, + too_long: "5000 characters is the maximum allowed" } + + def status_name + case self.status + when 0 + "待选中" + when 1 + "待确认" + when 2 + "已确认" + else + "状态错误!" + end + end + + #课程动态公共表记录 + def act_as_course_activity + if self.course + if self.course_acts.size == 0 + self.course_acts << CourseActivity.new(:user_id => self.user_id, :course_id => self.course_id) + end + end + end + + # 跟选题后,查询所有选题的状态 + def student_graduation_topic_status + sgt = self.student_graduation_topics + status = + if sgt.is_accepting.count == 0 + 2 + elsif sgt.is_refused.count == self.student_graduation_topics.size + 0 + else + 1 + end + return status + end + + def teacher + User.find(self.tea_id) + end + + # 用户选题的状态 + def user_status(user_id) + self.student_graduation_topics.where(user_id: user_id).last.try(:status) + end + +end diff --git a/app/models/graduation_work.rb b/app/models/graduation_work.rb new file mode 100644 index 000000000..11255ce4e --- /dev/null +++ b/app/models/graduation_work.rb @@ -0,0 +1,115 @@ +class GraduationWork < ApplicationRecord + # work_status: 0 未提交, 1 按时提交, 2 延时提交 + belongs_to :user + belongs_to :course + belongs_to :project, optional: true + belongs_to :graduation_task, optional: true + + belongs_to :commit_user, class_name: 'User', foreign_key: :commit_user_id, optional: true + has_many :attachments, as: :container, dependent: :destroy + has_many :tidings, as: :container, dependent: :destroy + has_many :graduation_work_scores, dependent: :destroy + has_many :graduation_work_comment_assignations, dependent: :destroy + + validates :description, length: { maximum: 5000 } + + scope :has_committed, lambda { where("work_status != 0") } + + # 未提交 + scope :unfinished, -> {where(work_status: 0)} + # 按时提交 + scope :finished, -> {where(work_status: 1)} + # 延迟提交 + scope :delay_finished, -> {where(work_status: 2)} + + #根据graduation_task_id查找 + scope :find_by_task, lambda{|ids| where(graduation_task_id: ids)} + scope :find_by_task_user, lambda{|ids| where(user_id: ids)} + + before_save :set_work_score + + def set_work_score + unless self.ultimate_score + if self.teacher_score.present? && self.cross_score.nil? + self.final_score = self.teacher_score + elsif self.cross_score.present? && self.teacher_score.nil? + self.final_score = self.cross_score + elsif self.teacher_score.present? && self.cross_score.present? + self.final_score = ((self.cross_score + self.teacher_score).to_f / 2.0).try(:round, 2) + end + if self.final_score + score = self.final_score - self.late_penalty + self.work_score = (score < 0 ? 0 : score).to_f.try(:round, 2) if score + else + self.work_score = nil + end + end + end + + def delete_atta atta + last_score = graduation_work_scores.where.not(score: nil).last + atta.author_id == user_id && (!last_score.present? || last_score.try(:created_at) < atta.created_on) + end + + # 分班名 + def class_grouping_name + CourseMember.find_by(user_id: self.user_id, course_id: self.course_id).try(:course_group).try(:name) || '未分班' + end + + # 分组名 + def grouping_name + self.group_id == 0 ? "--" : "分组#{self.group_id}" + end + + #用户是否有查看分数的权限 + def check_score_power? current_user, course_identity + self.work_score.present? || course_identity < Course::STUDENT || self.user_id = current_user.id + end + + # 作品是否能够分配指导老师 + def assign_power?(course_identity) + course_identity < Course::STUDENT && self.graduation_task.cross_comment.present? && self.graduation_task.comment_status == 2 + end + + # 老师评阅分 + def teacher_comment_score current_user, course_identity + # 为提交 + if self.work_status == 0 + "--" + else + # 未打分 + if self.teacher_score.nil? + "未批阅" + else + # 是否有权限看 + if self.check_score_power?(current_user, course_identity) + format("%.1f", self.teacher_score.round(1)) + else + "**" + end + end + end + end + + # 交叉评阅分 + def cross_comment_score current_user, course_identity + if self.work_status == 0 + "--" + else + if self.cross_score.nil? + "未批阅" + else + if self.check_score_power?(current_user, course_identity) + "#{format("%.1f", self.cross_score.round(1))}(#{self.graduation_work_scores + .where(reviewer_role: 2).group_by(&:user_id).count})" + else + "**" + end + end + end + end + + def scored? + graduation_work_scores.where.not(reviewer_role: 3).exists? + end +end diff --git a/app/models/graduation_work_comment_assignation.rb b/app/models/graduation_work_comment_assignation.rb new file mode 100644 index 000000000..33f30d2a0 --- /dev/null +++ b/app/models/graduation_work_comment_assignation.rb @@ -0,0 +1,8 @@ +class GraduationWorkCommentAssignation < ApplicationRecord + belongs_to :graduation_work + belongs_to :graduation_task + belongs_to :user + belongs_to :graduation_group + + scope :myself, ->(user_id) {where(user_id: user_id)} +end diff --git a/app/models/graduation_work_score.rb b/app/models/graduation_work_score.rb new file mode 100644 index 000000000..fa978b68f --- /dev/null +++ b/app/models/graduation_work_score.rb @@ -0,0 +1,8 @@ +class GraduationWorkScore < ApplicationRecord + belongs_to :graduation_work + belongs_to :user + belongs_to :graduation_task + has_many :attachments, as: :container, dependent: :destroy + + validates :comment, length: { maximum: 2000 } +end diff --git a/app/models/gtask_bank.rb b/app/models/gtask_bank.rb new file mode 100644 index 000000000..55f83ef10 --- /dev/null +++ b/app/models/gtask_bank.rb @@ -0,0 +1,12 @@ +class GtaskBank < ApplicationRecord + belongs_to :user + belongs_to :graduation_task, optional: true + belongs_to :course_list, optional: true + + has_many :attachments, as: :container, dependent: :destroy + has_many :graduation_tasks, dependent: :nullify + + scope :myself, ->(user_id) { where(user_id: user_id)} + scope :is_public, -> { where(:is_public => true) } + +end diff --git a/app/models/gtopic_bank.rb b/app/models/gtopic_bank.rb new file mode 100644 index 000000000..af5b267a6 --- /dev/null +++ b/app/models/gtopic_bank.rb @@ -0,0 +1,10 @@ +class GtopicBank < ApplicationRecord + belongs_to :user + belongs_to :graduation_topic + belongs_to :course_list + + has_many :attachments, as: :container, dependent: :destroy + has_many :graduation_topics, dependent: :nullify + + scope :myself, ->(user_id) { where(user_id: user_id)} +end diff --git a/app/models/homework_bank.rb b/app/models/homework_bank.rb new file mode 100644 index 000000000..7c9de0cda --- /dev/null +++ b/app/models/homework_bank.rb @@ -0,0 +1,13 @@ +class HomeworkBank < ApplicationRecord + # homework_type: 1:普通作业 2:编程作业(弃用) 3:分组作业 4:实训作业 + belongs_to :course_list + belongs_to :homework_common, optional: true + belongs_to :user + + has_many :attachments, as: :container, :dependent => :destroy + has_many :homework_commons, dependent: :nullify + + scope :is_public, -> { where(is_public: true)} + scope :myself, ->(user_id) { where(user_id: user_id)} + +end diff --git a/app/models/homework_challenge_setting.rb b/app/models/homework_challenge_setting.rb new file mode 100644 index 000000000..9aec5fb44 --- /dev/null +++ b/app/models/homework_challenge_setting.rb @@ -0,0 +1,3 @@ +class HomeworkChallengeSetting < ApplicationRecord + belongs_to :challenge +end diff --git a/app/models/homework_common.rb b/app/models/homework_common.rb new file mode 100644 index 000000000..74d85e2ae --- /dev/null +++ b/app/models/homework_common.rb @@ -0,0 +1,251 @@ +class HomeworkCommon < ApplicationRecord + # homework_type 1:普通作业 2:编程作业(弃用) 3:分组作业 4:实训作业 + enum homework_type: { normal: 1, program: 2, group: 3, practice: 4 }, _suffix: true + has_many :homework_group_settings, dependent: :destroy + has_many :student_works, -> { where("is_delete != 1") } + has_one :homework_detail_manual, dependent: :destroy + + # 分组作业的设置 + has_one :homework_detail_group, dependent: :destroy + + belongs_to :course, counter_cache: true + belongs_to :homework_bank, optional: true + has_many :homework_challenge_settings, dependent: :destroy + + has_one :homework_commons_shixun, dependent: :destroy + has_and_belongs_to_many :shixuns, through: :homework_commons_shixun + + # attachtype: 1(描述的附件), 2(参考答案的附件) + has_many :attachments, as: :container, dependent: :destroy + + # 作业的评论 + has_many :journals_for_messages, as: :jour, dependent: :destroy + + # 二级目录 + belongs_to :course_second_category, optional: true + + # 课堂动态 + has_many :course_acts, class_name: 'CourseActivity', as: :course_act, dependent: :destroy + has_many :tidings, as: :container, dependent: :destroy + # 实训作业的分班查重记录 + has_many :homework_group_reviews, :dependent => :destroy + # 学生的查重情况 + has_many :homework_review_results, :dependent => :destroy + + validates :name, length: { maximum: 60 } + validates :description, length: { maximum: 5000 } + validates :reference_answer, length: { maximum: 5000 } + + # after_update :update_activity + before_destroy :update_homework_bank_quotes + + #1已发布的课堂作业 + scope :homework_published, -> {where("homework_commons.publish_time IS NOT NULL AND homework_commons.publish_time <= ? ",Time.now)} + scope :published_no_end, -> {where("homework_commons.publish_time IS NOT NULL AND homework_commons.publish_time < ? + and homework_commons.end_time > ?", Time.now, Time.now)} + scope :search_homework_type, lambda {|num| where(homework_type:num)} + scope :unified_setting, -> {where("unified_setting = ? ", 1)} + + + # 是否显示参考答案 + def view_answer identity, user_id + identity < Course::STUDENT || (identity == Course::STUDENT && answer_public && + self.end_or_late && self.user_work(user_id).try(:work_status).to_i > 0) + end + + # 申诉阶段 + def appeal_duration + self.anonymous_appeal && [3, 4].include?(homework_detail_manual.comment_status) + end + + # 作业对应的子目录/父目录名称 + def category_info + case self.homework_type + when 'normal' + {category_id: course.common_course_modules.first.try(:id), category_name: course.common_course_modules.first.try(:module_name)} + when 'group' + {category_id: course.group_course_modules.first.try(:id), category_name: course.group_course_modules.first.try(:module_name)} + when 'practice' + if self.course_second_category.present? + {category_id: self.course_second_category.try(:id), category_name: self.course_second_category.try(:name)} + else + {category_id: course.shixun_course_modules.first.try(:id), category_name: course.shixun_course_modules.first.try(:module_name)} + end + end + end + + # 根据是否统一发布获取作业的作品列表 + def all_works + student_works = self.unified_setting ? self.student_works : + self.student_works.where(user_id: self.course.students.where( + course_group_id: self.homework_group_settings.group_published.pluck(:course_group_id)). + pluck(:user_id)) + end + + # 分班权限的老师可见的作品列表 + def teacher_works user_id + member = course.course_member(user_id) + teacher_course_groups = member.try(:teacher_course_groups) + all_student_works = self.all_works + # 有分班权限的统计管理的分班且已发布的学生情况 + if member.present? && teacher_course_groups.size > 0 + group_ids = teacher_course_groups.pluck(:course_group_id) + all_student_works = all_student_works.where(user_id: course.students.where(course_group_id: group_ids).pluck(:user_id)) + end + all_student_works + end + + def user_work user_id + work = self.student_works.find_by_user_id(user_id) + end + + # 是否在补交阶段内 + def late_duration + homework_setting = self.homework_group_setting(User.current.id) + !course.is_end && self.publish_time && self.publish_time < Time.now && homework_setting.end_time && + homework_setting.end_time < Time.now && self.allow_late && (self.late_time.nil? || self.late_time > Time.now) + end + + # 作业是否补交截止或者不允许补交且提交截止 + def end_or_late + status = false + if self.course.is_end || (self.allow_late && self.late_time && self.late_time < Time.now) + status = true + elsif !self.allow_late + homework_setting = self.homework_group_setting(User.current.id) + status = homework_setting.end_time && homework_setting.end_time < Time.now + end + status + end + + # 作业是否可以查重 + def code_review + self.homework_type == 'practice' && self.publish_time.present? && self.publish_time < Time.now && self.homework_group_reviews.count == 0 + end + + # 作业能否立即发布 + def publish_immediately user + homework_detail_manual.try(:comment_status) == 0 || homework_group_settings.where(course_group_id: course.charge_group_ids(user)). + none_published.count > 0 + end + + # 作业能否立即截止 + def end_immediately user + (unified_setting && homework_detail_manual.try(:comment_status) == 1 && end_time > Time.now) || homework_group_settings. + where(course_group_id: course.charge_group_ids(user)).published_no_end.count > 0 + end + + # 学生是否提交了作品 + def user_has_commit_work user_id + work = self.student_works.find_by_user_id(user_id) + work.present? && work.work_status != 0 + end + + # 是否有学生提交过作品 + def has_commit_work + student_works.has_committed.count > 0 + end + + # 是否有学生关联了项目 + def has_relate_project + homework_type == "group" && student_works.where("project_id != 0").count > 0 + end + + # 作业描述的附件 + def des_attachments + attachments.where(attachtype: 1) + end + + # 参考答案的附件 + def ref_attachments + attachments.where(attachtype: 2) + end + + def update_activity + course_activity = CourseActivity.find_by_course_act_type_and_course_act_id(self.class.to_s, self.id) + + course_activity.update_attributes(updated_at: Time.now) if course_activity + end + + #删除时更新题库中的引用数 + def update_homework_bank_quotes + old_banks = HomeworkBank.where(homework_common_id: self.id) + unless old_banks.blank? + old_banks.each do |bank| + bank.update_attributes(quotes: (bank.quotes - 1) > 0 ? (bank.quotes - 1) : 0, homework_common_id: nil) + end + end + end + + # 查重是否有新结果 + def code_reviews_new_results? + self.homework_group_reviews.where(status: 0).count > 0 + end + + # 任务已评数 user_id: 对应老师的id + def comment_count(user_id) + course = self.course + # 如果有分班,则取此老师对应分班的已评数,没有分班,则取所有的 + course_group_ids = course.group_course_power(user_id) + sql = + if course_group_ids.count > 0 + %Q{ + SELECT count(distinct sw.id) cnt FROM student_works sw + JOIN student_works_scores sws on sws.student_work_id = sw.id WHERE + reviewer_role IN(1,2) AND sw.id IN (SELECT id FROM student_works WHERE homework_common_id = #{self.id} + AND user_id IN (SELECT user_id FROM course_members WHERE role = 4 AND course_group_id + IN (SELECT course_group_id FROM teacher_course_groups WHERE id IN(#{course_group_ids.join(",")})) + ) + ) + } + else + %Q{ + SELECT COUNT(distinct sw.id) cnt FROM student_works sw + JOIN student_works_scores sws ON sw.id = sws.student_work_id + WHERE reviewer_role IN(1,2) AND sw.homework_common_id = #{self.id} + } + end + StudentWorksScore.find_by_sql(sql).first.try(:cnt).to_i + end + + # 任务未评数 + def uncomment_count(user_id) + user_ids = course.teacher_group_user_ids user_id + self.student_works.where(user_id: user_ids).count - self.comment_count(user_id) + end + + # 作品未提交数 + def unfinished_count user_id + self.teacher_works(user_id).unfinished.count + end + + # 任务按时提交数 + def finished_count user_id + self.teacher_works(user_id).finished.count + end + + def delay_finished_count user_id + self.teacher_works(user_id).delay_finished.count + end + + # 分组作业的最大分组id + def max_group_id + self.student_works.has_committed.maximum(:group_id).to_i + 1 + end + + # 作业的分班设置时间 + def homework_group_setting user_id + member = course.course_member(user_id) + group_setting = self.homework_group_settings.find_by_course_group_id(member.try(:course_group_id)) + homework_setting = group_setting.present? ? group_setting : self + homework_setting + end + + def min_group_publish_time + HomeworkGroupSetting.where("homework_common_id = #{self.id} and publish_time is not null").pluck(:publish_time).min + end + + def max_group_end_time + HomeworkGroupSetting.where("homework_common_id = #{self.id} and end_time is not null").pluck(:end_time).max + end +end diff --git a/app/models/homework_commons_shixun.rb b/app/models/homework_commons_shixun.rb new file mode 100644 index 000000000..38df119ed --- /dev/null +++ b/app/models/homework_commons_shixun.rb @@ -0,0 +1,4 @@ +class HomeworkCommonsShixun < ApplicationRecord + belongs_to :homework_common + belongs_to :shixun +end diff --git a/app/models/homework_detail_group.rb b/app/models/homework_detail_group.rb new file mode 100644 index 000000000..ab0d13303 --- /dev/null +++ b/app/models/homework_detail_group.rb @@ -0,0 +1,3 @@ +class HomeworkDetailGroup < ApplicationRecord + belongs_to :homework_common +end diff --git a/app/models/homework_detail_manual.rb b/app/models/homework_detail_manual.rb new file mode 100644 index 000000000..6bc8e3ce7 --- /dev/null +++ b/app/models/homework_detail_manual.rb @@ -0,0 +1,3 @@ +class HomeworkDetailManual < ApplicationRecord + belongs_to :homework_common +end diff --git a/app/models/homework_group_review.rb b/app/models/homework_group_review.rb new file mode 100644 index 000000000..e0fef39a4 --- /dev/null +++ b/app/models/homework_group_review.rb @@ -0,0 +1,9 @@ +class HomeworkGroupReview < ApplicationRecord + belongs_to :homework_common + belongs_to :course_group + belongs_to :user + # status 0: 新建 1:已返回结果 + # query_id 查询返回id 通过这个id取结果 + # attr_accessible :status +end + diff --git a/app/models/homework_group_setting.rb b/app/models/homework_group_setting.rb new file mode 100644 index 000000000..ae9491cb3 --- /dev/null +++ b/app/models/homework_group_setting.rb @@ -0,0 +1,11 @@ +class HomeworkGroupSetting < ApplicationRecord + belongs_to :homework_common + belongs_to :course + + scope :group_published, -> {where("homework_group_settings.publish_time IS NOT NULL AND homework_group_settings.publish_time <= ?", Time.now)} + scope :none_published, -> {where("homework_group_settings.publish_time IS NULL OR homework_group_settings.publish_time > ?", Time.now)} + scope :published_no_end, -> {where("homework_group_settings.publish_time IS NOT NULL AND homework_group_settings.publish_time < ? + and homework_group_settings.end_time > ?", Time.now, Time.now)} + scope :none_end, -> {where("homework_group_settings.end_time IS NOT NULL AND homework_group_settings.end_time > ?", Time.now)} + +end diff --git a/app/models/homework_review_result.rb b/app/models/homework_review_result.rb new file mode 100644 index 000000000..70c0afca3 --- /dev/null +++ b/app/models/homework_review_result.rb @@ -0,0 +1,4 @@ +class HomeworkReviewResult < ApplicationRecord + belongs_to :homework_common + belongs_to :user +end diff --git a/app/models/issue.rb b/app/models/issue.rb new file mode 100644 index 000000000..e8f05202c --- /dev/null +++ b/app/models/issue.rb @@ -0,0 +1,3 @@ +class Issue < ApplicationRecord + belongs_to :project +end \ No newline at end of file diff --git a/app/models/journals_for_message.rb b/app/models/journals_for_message.rb new file mode 100644 index 000000000..1da26fd22 --- /dev/null +++ b/app/models/journals_for_message.rb @@ -0,0 +1,50 @@ +class JournalsForMessage < ApplicationRecord + belongs_to :jour, :polymorphic => true + belongs_to :user + belongs_to :parent, class_name: "JournalsForMessage", foreign_key: "m_parent_id", + counter_cache: :m_reply_count, optional: true + + has_many :praise_treads, as: :praise_tread_object, dependent: :destroy + + #scope :children, -> {where(m_parent_id: self.id).includes(:user).reorder("created_on asc")} + #scope :children, -> (discuss_id){ where(parent_id: discuss_id).includes(:user).reorder("created_at asc") } + + scope :parent_comment, -> { where(m_parent_id: nil)} + scope :search_by_jour_type, lambda{|type,ids| where(jour_type:type,jour_id: ids)} + + # "jour_type", # 留言所属类型 + # "jour_id", # 留言所属类型的id + # "notes", # 留言内容 + # "reply_id", # 留言被回复留言者的用户id(用户a回复了用户b,这是b的id,用以查询谁给b留言了) + # "status", # 留言是否被查看(弃用) + # "user_id", # 留言者的id + # "m_parent_id", # 留言信息的父留言id + # "is_readed", # 留言是否已读 + # "m_reply_count", # 留言的回复数量 + # "m_reply_id" , # 回复某留言的留言id(a留言回复了b留言,这是b留言的id) + # "is_comprehensive_evaluation", # 1 教师评论、2 匿评、3 留言 + # "hidden", 隐藏 + + + # course_identity 课堂用户身份 + def contents_show course_identity + if self.hidden && course_identity >= Course::STUDENT + nil + else + self.notes + end + end + + def can_delete course_identity + course_identity < Course::STUDENT + end + + def created_at + self.created_on + end + + def children page, limit + JournalsForMessage.includes(:user).where(m_parent_id: self.id).page(page).per(limit).reorder("created_on asc") + end + +end diff --git a/app/models/member.rb b/app/models/member.rb new file mode 100644 index 000000000..d1feb8a37 --- /dev/null +++ b/app/models/member.rb @@ -0,0 +1,6 @@ +class Member < ApplicationRecord + has_many :member_roles, dependent: :destroy + belongs_to :course, optional: true + belongs_to :project, optional: true + belongs_to :user +end diff --git a/app/models/member_role.rb b/app/models/member_role.rb new file mode 100644 index 000000000..900efc732 --- /dev/null +++ b/app/models/member_role.rb @@ -0,0 +1,3 @@ +class MemberRole < ApplicationRecord + belongs_to :member +end diff --git a/app/models/memo.rb b/app/models/memo.rb new file mode 100644 index 000000000..524c37a96 --- /dev/null +++ b/app/models/memo.rb @@ -0,0 +1,49 @@ +class Memo < ApplicationRecord + + has_many :memo_tag_repertoires, :dependent => :destroy + has_many :tag_repertoires, :through => :memo_tag_repertoires + + has_many :praise_tread, as: :praise_tread_object, dependent: :destroy + has_one :praise_tread_cache, as: :object, dependent: :destroy + + belongs_to :author, class_name: 'User', foreign_key: 'author_id' + belongs_to :parent, class_name: 'Memo', foreign_key: 'parent_id' + + scope :field_for_list, lambda{ + select([:id, :subject, :author_id, :sticky, :updated_at, :language, :reward, :all_replies_count, :viewed_count, :forum_id]) + } + scope :user_posts, -> (user_id){ where(root_id: nil, author_id: user_id, forum_id: [3, 5]) } + scope :field_for_recommend, -> { select([:id, :subject, :language, :forum_id, :all_replies_count]) } + scope :memo_replies, -> (id) { where(root_id: id) } + scope :hot, -> { order("all_replies_count desc, updated_at desc") } + scope :posts, -> { where(root_id: nil, forum_id: [3, 5]) } + + after_create :send_tiding + + # 帖子的回复 + def reply_for_memo + Memo.where(parent_id: id) + end + + # 子回复 + def children_of_reply + Memo.where(parent_id: id).includes(:author).reorder("created_at asc") + end + + private + + def send_tiding + tiding_attr = { + trigger_user_id: author_id, viewed: 0, tiding_type: 'Comment', + parent_container_type: 'Memo', belong_container_id: forum_id, belong_container_type: 'Forum' + } + if parent_id.present? + tiding_attr.merge!(user_id: parent.author_id, parent_container_id: root_id) + else + # 新帖子给超级管理员发消息 + tiding_attr.merge!(user_id: 1, parent_container_id: id) + end + + self.tidings << Tiding.new(tiding_attr) + end +end diff --git a/app/models/memo_tag_repertoire.rb b/app/models/memo_tag_repertoire.rb new file mode 100644 index 000000000..99bb04f78 --- /dev/null +++ b/app/models/memo_tag_repertoire.rb @@ -0,0 +1,4 @@ +class MemoTagRepertoire < ApplicationRecord + belongs_to :memo + belongs_to :tag_repertoire +end diff --git a/app/models/message.rb b/app/models/message.rb new file mode 100644 index 000000000..ae804e991 --- /dev/null +++ b/app/models/message.rb @@ -0,0 +1,87 @@ +class Message < ApplicationRecord + attr_accessor :total_replies_count + + belongs_to :board, counter_cache: true + belongs_to :author, class_name: "User", foreign_key: 'author_id' + belongs_to :parent, class_name: "Message", foreign_key: "parent_id", counter_cache: :replies_count, optional: true + has_one :message_detail, dependent: :destroy + accepts_nested_attributes_for :message_detail, update_only: true + + has_many :children, -> { order(updated_on: :desc ) }, class_name: "Message", foreign_key: "parent_id", dependent: :destroy + has_many :praise_treads, as: :praise_tread_object, dependent: :destroy + has_many :tidings, as: :container, dependent: :destroy + has_many :attachments, as: :container, dependent: :destroy + has_many :course_acts, :class_name => 'CourseActivity',:as =>:course_act ,:dependent => :destroy # 课程动态 + + scope :root_nodes, -> { where("parent_id IS NULL") } #判断该信息是帖子还是回复。null为发布的帖子 + scope :reply_nodes, -> { where("parent_id IS NOT NULL") } + scope :visible, -> { where(is_hidden: false)} + scope :by_user, ->(user) { visible if user.nil? || !user.admin? } + scope :preload_messages, -> { includes(:author, :message_detail) } + scope :short, -> { select(:id, :subject, :created_on, :replies_count, :visits, :sticky, :praises_count) } + scope :ordered, -> (opts={}) { reorder("created_on #{opts[:sort] == 1 ? 'asc': 'desc'}") } + scope :by_ids, lambda { |ids| where(id: ids) unless ids.blank? } + scope :find_by_boards, ->(ids) {where(board_id: ids)} + scope :by_keywords, lambda { |keywords| + where("subject LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank? + } + + + #转发表 + # has_many :forwards, as: :from, dependent: :destroy + + validates :subject, length: { maximum: 255 } + + def update_content(content) + message_detail.update_attributes(content: content) + end + + def copy_attachments_to_new_message(new_message, user) + attachments.each do |attach| + new_message.attachments << Attachment.new(attach.attributes.except("id").merge( + quotes: 0, + downloads: 0, + author_id: user.id, + created_on: Time.now + )) + end + end + + def self.bulk_move_to_other_board(message_ids, to_board_id, author_id) + message_ids.each do |id| + message = Message.find id + message.update_attributes(board_id: to_board_id, author_id: author_id) if message.parent_id.nil? # TODO 暂时只支持跟节点移动 + end + end + + # 包含二级回复的总点赞数 + def total_praises_count + praises_count + children.includes(:children).reduce(0) { |count, filed| + sub_sum_count = filed.children.reduce(0) { |sub_count, sub_filed| sub_count += sub_filed.praises_count } + count += filed.praises_count + sub_sum_count += count + } + end + + # 包含二级回复数的总回复数 + def total_replies_count + replies_count + children.includes(:children).reduce(0) { |count, child| + sub_sum_count = child.children.reduce(0) { |sub_count, sub_child| sub_count += sub_child.replies_count } + count += child.replies_count + sub_sum_count += count + } + end + + def has_replies + children.present? + end + + # + def by_user_with_visible(user) + user.nil? || !user.admin? ? children.visible.limit(5) : children.limit(5) + end + + def update_visits + update_attributes(:visits => visits + 1) + end +end diff --git a/app/models/message_detail.rb b/app/models/message_detail.rb new file mode 100644 index 000000000..945d875f5 --- /dev/null +++ b/app/models/message_detail.rb @@ -0,0 +1,4 @@ +class MessageDetail < ApplicationRecord + belongs_to :message, :touch => true + +end diff --git a/app/models/mirror_repository.rb b/app/models/mirror_repository.rb new file mode 100644 index 000000000..be26b5ad1 --- /dev/null +++ b/app/models/mirror_repository.rb @@ -0,0 +1,11 @@ +class MirrorRepository < ApplicationRecord + has_many :shixun_mirror_repositories, :dependent => :destroy + has_many :shixun, :through => :shixun_mirror_repositories + has_many :mirror_scripts, :dependent => :destroy + + + + scope :published_mirror, -> { where(status: 1) } + scope :published_main_mirror, -> { published_mirror.where(main_type: 1) } + scope :published_small_mirror, -> { published_mirror.where(main_type: 0) } +end diff --git a/app/models/mirror_script.rb b/app/models/mirror_script.rb new file mode 100644 index 000000000..f4cb60867 --- /dev/null +++ b/app/models/mirror_script.rb @@ -0,0 +1,4 @@ +class MirrorScript < ApplicationRecord + belongs_to :mirror_repository + +end diff --git a/app/models/myshixun.rb b/app/models/myshixun.rb new file mode 100644 index 000000000..089b416de --- /dev/null +++ b/app/models/myshixun.rb @@ -0,0 +1,107 @@ +class Myshixun < ApplicationRecord + include ApplicationHelper + has_many :games, :dependent => :destroy + has_many :student_works + has_one :shixun_modify, :dependent => :destroy + + belongs_to :user + belongs_to :shixun, counter_cache: true + + validates_uniqueness_of :shixun_id, :scope => :user_id, :message => "shixun_id and user_id unique error" + scope :finished, lambda { where(status: 1) } + scope :search_myshixun_user, ->(user_id){where(user_id:user_id)} + + + def owner + self.user + rescue ActiveRecord::RecordNotFound + end + + def output_times + games.sum(:evaluate_count) + end + + def repo_path + "#{self.repo_name}.git" + end + + def is_complete? + self.status == 1 + end + + # 判断TPM的代码是否被修改了 + # 判断依据是看tpm的最新提交记录和tpi数据库中存储的commit_id是否一致 + def repository_is_modified shixun_repo_path + myshixun_commit_id = self.commit_id + if myshixun_commit_id.blank? + myshixun_commit_id = GitService.commits(repo_path: self.repo_path).last["id"] + self.update_column(:commit_id, myshixun_commit_id) + end + shixun_commit_id = GitService.commits(repo_path: shixun_repo_path).first["id"] + Rails.logger.warn("###############shixun_commit_id is #{shixun_commit_id}") + Rails.logger.warn("###############myshixun_commit_id is #{self.commit_id}") + result = myshixun_commit_id != shixun_commit_id ? true :false + return result + end + + def mirror_name + self.shixun.mirror_repositories.map(&:type_name).blank? ? "" : self.shixun.mirror_repositories.map(&:type_name) + end + + def main_mirror + self.shixun.mirror_repositories.published_main_mirror.try(:first) + end + + # 当前任务:一个实训中只可能一个未完成任务(status 0或1只会存在一条记录) + # status:0 可以测评的,正在测评的 + # 如果都完成,则当前任务为最后一个任务 + def current_task + + current_game = self.games.select{|game| game.status == 1 || game.status == 0}.first + if current_game.blank? + if self.status == 1 + logger.info("@3333333333344444444#{self.id}") + current_game = Game.find_by_sql("SELECT g.* FROM games g, challenges c where g.myshixun_id=#{self.id} and + g.challenge_id = c.id and g.status = 2 order by c.position desc").first + else + # 如果没开启过的,status都为3,所以应该进入第一关 + current_game = Game.find_by_sql("SELECT g.* FROM games g, challenges c where g.myshixun_id=#{self.id} and + g.challenge_id = c.id and g.status = 3 order by c.position asc").first + end + end + return current_game + end + + + # 挑战至第几关(已完成关卡数+1) + def exec_count + gcount = self.games.select{|game| game.status == 2}.size + gcount = gcount < self.games.size ? (gcount + 1) : gcount + end + + # 个人实训得分 + def total_score + self.games.where("status = 2 and final_score > 0").sum(:final_score).to_i + end + + # 个人通关数 + def passed_count + self.games.where(status: 2).count + end + + # 通关时间 + def passed_time + self.status == 1 ? self.games.map(&:end_time).max : "--" + end + + # 耗时 + def total_spend_time + game_spend_time self.games.where(status: 2).sum(:cost_time).to_i + end + + # 通关总耗时 + def total_cost_time + self.games.where(status: 2).sum(:cost_time).to_i + end + +end diff --git a/app/models/onclick_time.rb b/app/models/onclick_time.rb new file mode 100644 index 000000000..588da23f5 --- /dev/null +++ b/app/models/onclick_time.rb @@ -0,0 +1,4 @@ +class OnclickTime < ApplicationRecord + belongs_to :user + +end diff --git a/app/models/output.rb b/app/models/output.rb new file mode 100644 index 000000000..b813f6070 --- /dev/null +++ b/app/models/output.rb @@ -0,0 +1,3 @@ +class Output < ApplicationRecord + belongs_to :game +end diff --git a/app/models/platform_sample.rb b/app/models/platform_sample.rb new file mode 100644 index 000000000..4d6cd21af --- /dev/null +++ b/app/models/platform_sample.rb @@ -0,0 +1,5 @@ +class PlatformSample < ApplicationRecord + # samples_type: taskPass-实训过关任务; script-实训通用脚本模板; + # introduction-实训简介模板; knowledge-实训背景知识 + validates_uniqueness_of :samples_type +end diff --git a/app/models/poll.rb b/app/models/poll.rb new file mode 100644 index 000000000..7ebcceafd --- /dev/null +++ b/app/models/poll.rb @@ -0,0 +1,156 @@ +class Poll < ApplicationRecord + belongs_to :course, counter_cache: true + belongs_to :user + belongs_to :exercise_bank, optional: true + + # belongs_to :exercise_bank + has_many :poll_questions,dependent: :destroy + has_many :poll_users, :dependent => :destroy + has_many :users, :through => :poll_users #该文件被哪些用户提交答案过 + has_many :poll_group_settings, :dependent => :destroy + has_many :course_acts, class_name: 'CourseActivity', as: :course_act, dependent: :destroy + + has_many :tidings, as: :container, dependent: :destroy + + scope :publish_or_not, -> { where("polls_status > ? ",1)} + scope :only_public, -> {where("is_public = ?",true)} + scope :public_or_unset, -> { where("unified_setting = ?",true) } + scope :poll_by_ids, lambda { |ids| where(id: ids) unless ids.blank? } + scope :poll_by_status, lambda { |s| where(polls_status: s) unless s.blank? } + scope :poll_group_ended, -> {where("end_time is NOT NULL AND end_time <= ?",Time.now)} + + scope :poll_search, lambda { |keywords| + where("polls_name LIKE ?", "%#{keywords}%") unless keywords.blank?} + + validates :polls_name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" } + + after_create :create_polls_list + + def create_polls_list + str = "" + self.course.students.find_each do |student| + str += "," if str != "" + str += "(#{student.user_id},#{self.id}, 0, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + + if str != "" + sql = "insert into poll_users (user_id, poll_id, commit_status, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + + #获取学生视角的试卷用户 + def get_poll_exercise_users + if unified_setting #试卷统一设置 + poll_users + else + ex_group_setting_ids = poll_group_settings.poll_group_published.pluck(:course_group_id) + course_user_ids = course.students.where(course_group_id:ex_group_setting_ids).pluck(:user_id) + poll_users.where(user_id:course_user_ids) + end + end + + # 统一设置,为当前老师有权限的分班学生,分班设置,也为当前老师有权限的分班的学生 + def all_poll_users(user_id) + poll_users = self.poll_users + group_ids = poll_published_ids(user_id) + logger.info("##########_________group_ids______#########################{group_ids}") + if group_ids.present? + poll_users = poll_users.where(user_id: course.students.where(course_group_id: group_ids).pluck(:user_id)) + end + poll_users + end + + #当前用户已发布的班级id和试卷分组已发布的班级id的交集 + def poll_published_ids(user_id) + current_user_groups = course.teacher_course_group_ids(user_id) + logger.info("##########_________current_user_groups______#########################{current_user_groups}") + if unified_setting + if course.none_group_count > 0 #有未分班的,则发布到未发布 + un_group_ids = [0] + else + un_group_ids = [] + end + (current_user_groups + un_group_ids).uniq #统一设置时,为当前用户的分班id + else + ex_group_setting = poll_group_settings.pluck("course_group_id").uniq + ex_group_setting & current_user_groups #当前用户有权限的已发布的分班id #非统一设置时,为当前用户有权限的且已发布分班的id + end + end + + def get_poll_status(user_id) + user_group = course.course_members.find_by(user_id: user_id, is_active: 1) + if user_group.present? + if user_group.role == "STUDENT" #为学生 + is_teacher = false + else + is_teacher = true + end + ex_time = get_poll_times(user_id,is_teacher) + pb_time = ex_time[:publish_time] + ed_time = ex_time[:end_time] + if pb_time.present? && ed_time.present? && pb_time <= Time.now && ed_time > Time.now + status = 2 + elsif ed_time.present? && ed_time <= Time.now + status = 3 + else + status = 1 + end + else + status = polls_status + end + status + end + + #获取问卷的发布时间和截止时间。teacher 为boolean,当为true时,表示的是当前为老师 + def get_poll_times(user_id,teacher) + if unified_setting + pb_time = publish_time + en_time = end_time + else + poll_group_setting = poll_group_settings + if teacher #当前为老师,为设置组的最大值和最小值 + user_group = course.teacher_course_groups.get_user_groups(user_id) + user_group_ids = user_group.present? ? user_group.pluck(:course_group_id) : course.course_groups.pluck(:id) + user_poll_group_settings = poll_group_setting.find_in_poll_group("course_group_id",user_group_ids) + pb_time_min = user_poll_group_settings.publish_time_present.map(&:publish_time) + en_time_max = user_poll_group_settings.end_time_present.map(&:end_time) + pb_time = pb_time_min.size > 0 ? pb_time_min.min : nil + en_time = en_time_max.size > 0 ? en_time_max.max : nil + else + user_group = course.students.find_by(user_id: user_id) + if user_group.present? + user_group_id = user_group.course_group_id + user_p_group_setting = poll_group_setting.find_by(course_group_id: user_group_id) + pb_time = user_p_group_setting.present? ? user_p_group_setting.publish_time : nil + en_time = user_p_group_setting.present? ? user_p_group_setting.end_time : nil + else + pb_time = nil + en_time = nil + end + end + end + { + "publish_time":pb_time, + "end_time":en_time + } + end + + #判断当前用户的答题状态 + def check_user_votes_status(user) + poll_answer_user = poll_users.find_by(user_id: user.id) + user_poll_status = get_poll_status(user.id) + user_status = 2 + + if poll_answer_user.present? && (poll_answer_user.start_at.present? || poll_answer_user.end_at.present?) #学生有过答题的,或者立即截止,但学生未做试卷的 + user_status = poll_answer_user.commit_status + end + + if poll_answer_user.present? && poll_answer_user.start_at.blank? && user_poll_status == 3 + user_status = 4 + end + + user_status + end + +end diff --git a/app/models/poll_answer.rb b/app/models/poll_answer.rb new file mode 100644 index 000000000..423198bbf --- /dev/null +++ b/app/models/poll_answer.rb @@ -0,0 +1,11 @@ +class PollAnswer < ApplicationRecord + # default_scope :order => 'answer_position' + # include Redmine::SafeAttributes + + belongs_to :poll_question + has_many :poll_votes, :dependent => :destroy + + scope :find_answer_by_custom, lambda {|k,v| where("#{k}":v)} #根据传入的参数查找问题 + scope :left_answer_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题 + +end \ No newline at end of file diff --git a/app/models/poll_group_setting.rb b/app/models/poll_group_setting.rb new file mode 100644 index 000000000..159b4a9c0 --- /dev/null +++ b/app/models/poll_group_setting.rb @@ -0,0 +1,15 @@ +class PollGroupSetting < ApplicationRecord + belongs_to :poll + belongs_to :course_group + belongs_to :course + + scope :group_settings_by_ids, lambda { |ids| where(id: ids) unless ids.blank? } + scope :find_in_poll_group, lambda { |name,ids| where("#{name}": ids)} + scope :end_time_present, -> { where("end_time is not NULL")} + scope :publish_time_present, -> { where("publish_time is not NULL")} + scope :poll_group_published, -> {where("publish_time IS NOT NULL AND publish_time <= ?",Time.now)} + scope :poll_group_ended, -> {where("end_time is NOT NULL AND end_time <= ?",Time.now)} + scope :poll_group_not_published, -> {where("publish_time is NULL OR publish_time > ?",Time.now)} + + +end \ No newline at end of file diff --git a/app/models/poll_question.rb b/app/models/poll_question.rb new file mode 100644 index 000000000..958b69acd --- /dev/null +++ b/app/models/poll_question.rb @@ -0,0 +1,26 @@ +class PollQuestion < ApplicationRecord + + belongs_to :poll + has_many :poll_answers, :dependent => :destroy + attr_accessor :question_answers, :question_other_anser + has_many :poll_votes, :dependent => :destroy + + scope :ques_count, lambda {|k| where("question_type = ?",k)} + scope :ques_necessary, -> {where("is_necessary = ?",1)} + scope :insert_question, lambda {|k| where("question_number > ?",k)} + scope :next_poll, lambda {|k| where("question_number > ?",k).first} + scope :last_poll, lambda {|k| where("question_number < ?",k).last} + + def question_type_name + case self.question_type + when 1 + "单选题" + when 2 + "多选题" + when 3 + "主观题" + when 4 + "多行主观题" + end + end +end diff --git a/app/models/poll_user.rb b/app/models/poll_user.rb new file mode 100644 index 000000000..3b17ef3b6 --- /dev/null +++ b/app/models/poll_user.rb @@ -0,0 +1,10 @@ +class PollUser < ApplicationRecord + belongs_to :poll + belongs_to :user + + scope :current_poll_user, lambda { |user_id,poll_id| where(user_id: user_id,poll_id:poll_id)} + scope :commit_by_status, lambda { |s| where(commit_status: s)} + scope :find_by_group_ids, lambda { |ids| where(user_id: ids) } + scope :search_by_poll, lambda {|ids| where(poll_id:ids)} #根据问卷来查找 +end + diff --git a/app/models/poll_vote.rb b/app/models/poll_vote.rb new file mode 100644 index 000000000..67b832890 --- /dev/null +++ b/app/models/poll_vote.rb @@ -0,0 +1,11 @@ +class PollVote < ApplicationRecord + # attr_accessible :poll_answers_id, :poll_questions_id, :user_id, :vote_text + # include Redmine::SafeAttributes + + belongs_to :poll_answer, optional: true + belongs_to :poll_question + belongs_to :user + + scope :find_current_vote,lambda {|k,v| where("#{k}": v)} + scope :find_vote_text,-> {where("vote_text IS NOT NULL")} +end \ No newline at end of file diff --git a/app/models/portal_image.rb b/app/models/portal_image.rb new file mode 100644 index 000000000..24b9af39d --- /dev/null +++ b/app/models/portal_image.rb @@ -0,0 +1,2 @@ +class PortalImage < ApplicationRecord +end diff --git a/app/models/praise_tread.rb b/app/models/praise_tread.rb new file mode 100644 index 000000000..58ec965b4 --- /dev/null +++ b/app/models/praise_tread.rb @@ -0,0 +1,29 @@ +class PraiseTread < ApplicationRecord + belongs_to :praise_tread_object, polymorphic: true, counter_cache: :praises_count + has_many :tidings, :as => :container, :dependent => :destroy + + scope :liker, lambda { where(:praise_or_tread => 1) } + scope :user_liker, ->(user_id) { where(user_id: user_id, praise_or_tread: 1) } + scope :by_praise_tread_object_id_and_type, -> (object_id, object_type) { where(praise_tread_object_id: object_id, praise_tread_object_type: object_type)} + + after_create :send_tiding + + def send_tiding + case self.praise_tread_object_type + when "Memo","Message","Issue" + self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.author_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise") + when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask" + self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.user_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise") + end + end + + def self.find_object_by_type_and_id(id, type) + type.constantize find_by_id id + end + + # 用户是否点赞 + def self.user_praise?(user) + self.select{|pt| pt.user_id == user.id}.length > 0 + end + +end diff --git a/app/models/praise_tread_cache.rb b/app/models/praise_tread_cache.rb new file mode 100644 index 000000000..5544d1854 --- /dev/null +++ b/app/models/praise_tread_cache.rb @@ -0,0 +1,2 @@ +class PraiseTreadCache < ApplicationRecord +end diff --git a/app/models/private_message.rb b/app/models/private_message.rb new file mode 100644 index 000000000..1db4c9f66 --- /dev/null +++ b/app/models/private_message.rb @@ -0,0 +1,3 @@ +class PrivateMessage < ApplicationRecord + belongs_to :user +end diff --git a/app/models/project.rb b/app/models/project.rb new file mode 100644 index 000000000..ddc6f6e5f --- /dev/null +++ b/app/models/project.rb @@ -0,0 +1,20 @@ +class Project < ApplicationRecord + belongs_to :owner, class_name: 'User', foreign_key: :user_id + has_many :members + has_one :project_score, dependent: :destroy + + has_many :issues + + # 创建者 + def creator + User.find(user_id).full_name + end + + def project_members + self.members + end + + def member?(user) + members.exists?(user_id: user.id) + end +end diff --git a/app/models/project_score.rb b/app/models/project_score.rb new file mode 100644 index 000000000..51ed29a67 --- /dev/null +++ b/app/models/project_score.rb @@ -0,0 +1,29 @@ +class ProjectScore < ApplicationRecord + belongs_to :project + + def all_score + self.issue_num * 4 + self.issue_journal_num + (self.changeset_num||0) * 4 + self.board_num * 2 + + self.board_message_num + self.attach_num * 5 + end + + # 代码提交得分 + def code_score + (self.changeset_num||0) * 4 + end + + # issues得分 + def issue_score + self.issue_num * 4 + self.issue_journal_num + end + + # 资源得分 + def attachment_score + self.attach_num * 5 + end + + # 帖子得分 + def message_score + self.board_message_num + end + +end diff --git a/app/models/question_bank.rb b/app/models/question_bank.rb new file mode 100644 index 000000000..8b16b6b0f --- /dev/null +++ b/app/models/question_bank.rb @@ -0,0 +1,10 @@ +class QuestionBank < ActiveRecord::Base + belongs_to :user + belongs_to :course_list + #attr_accessible :container_id, :container_type, :quotes + scope :ques_by_container, lambda { |id,type| where(container_id: id,container_type:type)} + + def bank_type + I18n.t("question_bank.container_type.#{container_type}", locale: 'zh-CN') + end +end \ No newline at end of file diff --git a/app/models/relationship.rb b/app/models/relationship.rb new file mode 100644 index 000000000..d5c754745 --- /dev/null +++ b/app/models/relationship.rb @@ -0,0 +1,6 @@ +class Relationship < ApplicationRecord + belongs_to :follower, class_name: "User" + belongs_to :followed, class_name: "User" + validates :follower_id, presence: true + validates :followed_id, presence: true +end diff --git a/app/models/repertoire.rb b/app/models/repertoire.rb new file mode 100644 index 000000000..400cef494 --- /dev/null +++ b/app/models/repertoire.rb @@ -0,0 +1,6 @@ +class Repertoire < ApplicationRecord + + has_many :sub_repertoires + + has_many :tag_repertoires, through: :sub_repertoires +end diff --git a/app/models/run_code_message.rb b/app/models/run_code_message.rb new file mode 100644 index 000000000..1fcac1cf7 --- /dev/null +++ b/app/models/run_code_message.rb @@ -0,0 +1,3 @@ +class RunCodeMessage < ApplicationRecord + belongs_to :game +end diff --git a/app/models/school.rb b/app/models/school.rb new file mode 100644 index 000000000..af04ed0c7 --- /dev/null +++ b/app/models/school.rb @@ -0,0 +1,31 @@ +class School < ApplicationRecord + has_many :shixun_schools, :dependent => :destroy + has_many :shixuns, :through => :shixun_schools + + has_many :ec_school_users, :dependent => :destroy + has_many :users, :through => :ec_school_users + + has_many :ec_major_schools, :dependent => :destroy + has_many :ec_majors, :through => :ec_major_schools + + # 学校管理员 + def manager?(user) + ec_school_users.exists?(user_id: user.id) + end + + # 专业管理员 + def major_manager?(user) + relations = ec_major_schools.not_template.joins(:ec_major_school_users) + relations.exists?(ec_major_school_users: { user_id: user.id }) + end + + # 课程管理员 + def course_manager?(user) + relations = ec_major_schools.not_template.joins(ec_years: :ec_course_users) + relations.exists?(ec_course_users: { user_id: user.id }) + end + + def manage_permission?(user) + manager?(user) || major_manager?(user) || course_manager?(user) + end +end diff --git a/app/models/shixun.rb b/app/models/shixun.rb new file mode 100644 index 000000000..9ccefca92 --- /dev/null +++ b/app/models/shixun.rb @@ -0,0 +1,236 @@ +class Shixun < ApplicationRecord + # status: 0:编辑 1:申请发布 2:正式发布 3:关闭 -1:软删除 + has_many :challenges, dependent: :destroy + has_many :myshixuns, :dependent => :destroy + has_many :shixun_members, dependent: :destroy + has_many :users, through: :shixun_members + has_many :discusses, as: :dis, dependent: :destroy + has_many :evaluate_records, dependent: :destroy + has_many :shixun_mirror_repositories + has_many :mirror_repositories, through: :shixun_mirror_repositories + + has_many :shixun_schools, :dependent => :destroy + has_many :schools, :through => :shixun_schools + + has_many :shixun_tag_repertoires, dependent: :destroy + has_many :tag_repertoires, through: :shixun_tag_repertoires + has_one :first_shixun_tag_repertoire, class_name: 'ShixunTagRepertoire' + has_one :first_tag_repertoire, through: :first_shixun_tag_repertoire, source: :tag_repertoire + + + #实训的关卡 + has_many :exercise_shixun_challenges, :dependent => :destroy + has_many :exercise_bank_shixun_challenges, :dependent => :destroy + + # 注意:这个地方是一张关联表,关联三张表(多对多关系) + has_many :stage_shixuns, dependent: :destroy + has_many :stages, through: :stage_shixuns + has_many :subjects, through: :stage_shixuns + + has_one :shixun_info, dependent: :destroy + + belongs_to :user + + + scope :search_by_name, ->(keyword) { where("name like ? or description like ? ", + "%#{keyword}%", "%#{keyword}%") } + + #scope :include_user, ->(user_id) { where(id: Myshixun.where(user_id: user_id).pluck(:shixun_id))} + + scope :filter_tag, ->(tag_level, tag_id) { + case tag_level + when 1 #大类 + where(id: Repertoire.find(tag_id).tag_repertoires.joins(:shixun_tag_repertoires).pluck("shixun_tag_repertoires.shixun_id")) + when 2 #子类 + where(id: SubRepertoire.find(tag_id).tag_repertoires.joins(:shixun_tag_repertoires).pluck("shixun_tag_repertoires.shixun_id")) + when 3 #tag + where(id: TagRepertoire.find(tag_id).shixun_tag_repertoires.pluck(:shixun_id)) + end + } + + scope :visible, -> { where("status != -1") } + scope :published, lambda{ where(status: 2) } + scope :unhidden, lambda{ where(hidden: 0, status: 2) } + scope :field_for_recommend, lambda{ select([:id, :name, :identifier, :myshixuns_count]) } + scope :find_by_ids,lambda{|k| where(id:k)} + + # REDO:  + def propaedeutics + shixun_info.try(:propaedeutics) + end + + def description + shixun_info.try(:description) + end + + def evaluate_script + shixun_info.try(:evaluate_script) + end + + # 实训用户tag + def user_tags_name(user = User.current) + challenge_ids = challenges.pluck(:id) + user_challenge_ids = user.games.where(challenge_id: challenge_ids, status: 2).pluck(:challenge_id) + ChallengeTag.where(challenge_id: user_challenge_ids).pluck(:name).uniq + end + + # 实训关卡tag + def challenge_tags_name + ChallengeTag.where(challenge_id: challenges.pluck(:id)).pluck(:name).uniq + end + + def repo_path + "#{repo_name}.git" + end + + # 实训对应的镜像主类别名(已选) + def main_mirror_name + mirror_repositories.published_main_mirror.first.try(:type_name) || "" + end + + def main_mirror_id + mirror_repositories.published_main_mirror.first.try(:id) || -1 + end + + # 实训对应的镜像小类别名(已选) + def small_mirror_name + mirror_repositories.published_small_mirror.map(&:type_name) + end + + def small_mirror_id + mirror_repositories.published_small_mirror.map(&:id) + end + + # 实训镜像名 + def mirror_name + names = mirror_repositories.map(&:type_name) + names.blank? ? '' : names + end + + def script_tag + return unless mirror_script_id + + MirrorScript.find_by_id(mirror_script_id) + end + + def standrad_script + mirrors_id = mirror_repositories.map(&:id) + mirror_scripts = MirrorScript.where(mirror_repository_id: mirrors_id) + mirror_scripts.map { |ms| { scptname: ms.script_type, id: ms.id } } + end + + def owner + User.find(self.user_id) + end + + def is_published? + status > 1 + end + + # 当前用户开启的实训 + def current_myshixun(user_id) + myshixuns.find_by(user_id: user_id) + end + + # 实训技术平台 + def show_shixun_mirror + mirror_repositories.map(&:type_name).join(';') + end + + # 实训评分 cnt-评分次数 sum-总评分 + def shixun_preference + game_star_info = Game.find_by_sql("select g.star from + (games g left join (myshixuns m join shixuns s on s.id = m.shixun_id) on m.id = g.myshixun_id) + where g.star != 0 and s.id = #{self.id}") + if game_star_info.present? + cnt = game_star_info.count + sum = game_star_info.sum(&:star).to_f + (sum / cnt.to_f).round(1) + else + 5.0 + end + end + + # 实训评分信息 + # return [实训评分, 5星评分比例, 4星评分比例, 3星评分比例, 2星评分比例, 1星评分比例] + def shixun_preference_info + game_star_info = Game.find_by_sql("select g.star from + (games g left join (myshixuns m join shixuns s on s.id = m.shixun_id) on m.id = g.myshixun_id) + where g.star != 0 and s.id = #{self.id}") + star_info = [] + if game_star_info.present? + 5.downto(1) do |i| + star_info << ((game_star_info.select{|s| s.star == i}.count / game_star_info.count.to_f) * 100).round + end + sum = star_info.sum + max = star_info.max + # 四舍五入引起5星比例超过100%, 将最大的比例的评分做出调整 + if sum > 100 + star_info = star_info.map{|s| s == max ? s - 1 : s} + elsif sum < 100 + star_info = star_info.map{|s| s == max ? s + 1 : s} + end + cnt = game_star_info.count + sum = game_star_info.sum(&:star) + star_info.unshift((sum / cnt.to_f).round(1)) + else + star_info = [5.0, 100, 0, 0, 0, 0] + end + + star_info + end + + + # 实训关卡的总分(由于大部分是实践题,因此没关联查choose表) + # 提前加载问题:由于选择题比较少,所以几乎不会触发选择题的查询,所以没必要提前载入choose_score + def all_score + sum = 0 + challenges.each do |challenge| + sum += challenge.st == 0 ? challenge.score : challenge.choose_score + end + sum + end + + ### fork 数量 + def fork_count + self.class.where(fork_from: id).count + end + + # 学员等级 + def shixun_trainee + case trainee + when 1 then '初级学员' + when 2 then '中级学员' + when 3 then '高级学员' + when 4 then '顶级学员' + else '' + end + end + + def shixun_level + case trainee + when 1 then '初级' + when 2 then '中级' + when 3 then '高级' + when 4 then '顶级' + else '' + end + end + + # 纯选择提类型 + def is_choice_type? + challenges_count == challenges.where(st: 1).count + end + + # 实训受用学校个数 + def school_count + UserExtension.find_by_sql("select count(distinct ue.school_id) school_count from user_extensions ue right join myshixuns + on ue.user_id = myshixuns.user_id where myshixuns.shixun_id = #{self.id}").first.try(:school_count).to_i + end + + def has_manager?(user) + return true if user.admin? + + shixun_members.where(role: [1, 2]).exists?(user_id: user.id) + end +end diff --git a/app/models/shixun_info.rb b/app/models/shixun_info.rb new file mode 100644 index 000000000..542e0222d --- /dev/null +++ b/app/models/shixun_info.rb @@ -0,0 +1,5 @@ +class ShixunInfo < ApplicationRecord + belongs_to :shixun + validates_uniqueness_of :shixun_id + validates_presence_of :shixun_id +end diff --git a/app/models/shixun_member.rb b/app/models/shixun_member.rb new file mode 100644 index 000000000..2b8b43171 --- /dev/null +++ b/app/models/shixun_member.rb @@ -0,0 +1,5 @@ +class ShixunMember < ApplicationRecord + belongs_to :shixun, counter_cache: :users_count + belongs_to :user + +end diff --git a/app/models/shixun_mirror_repository.rb b/app/models/shixun_mirror_repository.rb new file mode 100644 index 000000000..9376aac0b --- /dev/null +++ b/app/models/shixun_mirror_repository.rb @@ -0,0 +1,5 @@ +class ShixunMirrorRepository < ApplicationRecord + belongs_to :shixun + belongs_to :mirror_repository + validates_uniqueness_of :shixun_id, :scope => :mirror_repository_id +end diff --git a/app/models/shixun_modify.rb b/app/models/shixun_modify.rb new file mode 100644 index 000000000..a59f0ea13 --- /dev/null +++ b/app/models/shixun_modify.rb @@ -0,0 +1,4 @@ +class ShixunModify < ApplicationRecord + # attr_accessible :myshixun_id, :shixun_id, :status + belongs_to :myshixun +end diff --git a/app/models/shixun_school.rb b/app/models/shixun_school.rb new file mode 100644 index 000000000..01e279eae --- /dev/null +++ b/app/models/shixun_school.rb @@ -0,0 +1,6 @@ +class ShixunSchool < ApplicationRecord + belongs_to :shixun + belongs_to :school + + scope :find_by_school, lambda { |k| where(school_id:k)} +end diff --git a/app/models/shixun_tag_repertoire.rb b/app/models/shixun_tag_repertoire.rb new file mode 100644 index 000000000..6cb311f7a --- /dev/null +++ b/app/models/shixun_tag_repertoire.rb @@ -0,0 +1,7 @@ +class ShixunTagRepertoire < ApplicationRecord + belongs_to :shixun + belongs_to :tag_repertoire + + has_many :memos, :through => :memo_tag_repertoires + has_many :memo_tag_repertoires, :dependent => :destroy +end diff --git a/app/models/stage.rb b/app/models/stage.rb new file mode 100644 index 000000000..7c80c4f9c --- /dev/null +++ b/app/models/stage.rb @@ -0,0 +1,9 @@ +class Stage < ApplicationRecord + belongs_to :subject, counter_cache: true + + has_many :stage_shixuns, -> { order("stage_shixuns.position ASC") }, dependent: :destroy + has_many :shixuns, :through => :stage_shixuns + + validates :name, length: { maximum: 30 } + validates :description, length: { maximum: 300 } +end diff --git a/app/models/stage_shixun.rb b/app/models/stage_shixun.rb new file mode 100644 index 000000000..eedb1f838 --- /dev/null +++ b/app/models/stage_shixun.rb @@ -0,0 +1,8 @@ +class StageShixun < ApplicationRecord + belongs_to :subject, counter_cache: :stages_count, counter_cache: :shixuns_count + # belongs_to :subject, counter_cache: :shixuns_count + belongs_to :shixun + belongs_to :stage, counter_cache: :shixuns_count +end + + diff --git a/app/models/student_graduation_topic.rb b/app/models/student_graduation_topic.rb new file mode 100644 index 000000000..ea1774695 --- /dev/null +++ b/app/models/student_graduation_topic.rb @@ -0,0 +1,54 @@ +class StudentGraduationTopic < ApplicationRecord + # status 0:待确认 1:已同意 2:已拒绝 + belongs_to :user + belongs_to :course + # belongs_to course_member, optional: true + + belongs_to :graduation_topic + belongs_to :course_member + + has_many :tidings, as: :container, dependent: :destroy + + # 毕设确认数 + scope :confirmation_count, ->{ where(:status => [1, 2]).count } + + #用户的选题 + scope :user_topics_accept, lambda{|user_id| where(user_id:user_id,status:[0,1])} + scope :is_refused, -> {where(status: 2)} + scope :is_accepted, -> {where(status: 1)} + scope :is_accepting, -> {where(status: 0)} + + + # 学生名称 + def name + self.user.real_name + end + + # 学生学号 + def student_id + self.user.student_id + end + + # 学生班级名称 + def class_group_name + self.course_member.try(:course_group).try(:name) + end + + # 学生选题时间 + def selected_time + format_time self.created_at + end + + # 学生选题状态名 + def status_name + case self.status + when 0 + "待确认" + when 1 + "已同意" + when 2 + "已拒绝" + end + end + +end diff --git a/app/models/student_work.rb b/app/models/student_work.rb new file mode 100644 index 000000000..0e674dd4c --- /dev/null +++ b/app/models/student_work.rb @@ -0,0 +1,186 @@ +class StudentWork < ApplicationRecord + #学生提交作品表 #work_status :0 未提交 1 已提交 2 迟交 + belongs_to :user + belongs_to :commit_user, class_name: 'User', foreign_key: :commit_user_id, optional: true + belongs_to :homework_common + belongs_to :myshixun, optional: true + has_many :student_works_evaluation_distributions, dependent: :destroy + has_many :student_works_scores, dependent: :destroy + belongs_to :project, optional: true + + # attachtype: 1(正常提交的附件), 7(补交的附件) + has_many :attachments, as: :container, dependent: :destroy + + has_many :tidings, as: :container, dependent: :destroy + + has_many :challenge_work_scores, dependent: :destroy + + before_save :set_work_score + + validates :description, length: { maximum: 5000 } + + scope :has_committed, lambda { where("work_status != 0") } + # 未提交 + scope :unfinished, -> {where(work_status: 0)} + # 按时提交 + scope :finished, -> {where(work_status: 1)} + # 延迟提交 + scope :delay_finished, -> {where(work_status: 2)} + + #按用户id查找 + scope :homework_by_user, lambda{|ids| where(user_id: ids)} + + #根据homework_common_id查找 + scope :find_by_homework, lambda{|ids| where(homework_common_id: ids)} + + def myshixun_consume + self.myshixun && self.myshixun.passed_count > 0 ? self.myshixun.total_spend_time : "--" + end + + # 助教评分次数 + def ta_comment_count + self.student_works_scores.where(reviewer_role: 2).group_by(&:user_id).count + end + + # 匿评次数 + def student_comment_num + homework_common.homework_detail_manual.comment_status > 2 ? self.student_works_scores.where(reviewer_role: 3).group_by(&:user_id).count : 0 + end + + # 匿评申诉总条数 + def appeal_all_count + homework_common.homework_detail_manual.comment_status >= 3 ? self.student_works_scores.where("reviewer_role = 3 and appeal_status != 0"). + group_by(&:user_id).count : 0 + end + + # 匿评申诉待处理条数 + def appeal_deal_count + homework_common.homework_detail_manual.comment_status >= 3 ? self.student_works_scores.where("reviewer_role = 3 and appeal_status = 1"). + group_by(&:user_id).count : 0 + end + + # 分组名 + def work_group_name + self.group_id == 0 ? "--" : "分组#{self.group_id}" + end + + # 助教评分 + def ta_score ta_mode + if ta_mode == 1 + ts_score = StudentWorksScore.find_by_sql("SELECT AVG(score) AS score FROM (SELECT * FROM + (SELECT * FROM student_works_scores WHERE student_work_id = #{self.id} + AND reviewer_role = 2 AND score IS NOT NULL ORDER BY created_at DESC) + AS t GROUP BY user_id) AS a") + score = ts_score.first.score.nil? ? nil : ts_score.first.score.to_f.try(:round, 2) + else + score = StudentWorksScore.where("student_work_id = #{self.id} AND reviewer_role = 2 AND score IS NOT NULL").last.try(:score) + end + end + + # 缺评次数 + def absence_count + absence_penalty_count = self.user.student_works_evaluation_distributions.joins(:student_work). + where("homework_common_id = #{self.homework_common_id}").count - + self.user.student_works_scores.joins(:student_work).where("homework_common_id = #{self.homework_common_id} + and reviewer_role = 3").select("distinct student_work_id").count + absence_penalty_count = absence_penalty_count < 0 ? 0 : absence_penalty_count + end + + # 违规匿评次数 + def appeal_count + appeal_count = self.user.student_works_scores.joins(:student_work).where("homework_common_id = #{self.homework_common_id} + and appeal_status = 3").select("distinct student_work_id").count + end + + def delete_atta atta + last_score = student_works_scores.where.not(score: nil).last + atta.author_id == user_id && (!last_score.present? || last_score.try(:created_at) < atta.created_on) + end + + # 作品总体评价 + def overall_appraisal + case self.work_score.to_i + when (90..100) + '优秀' + when (70...90) + '良好' + when (60...70) + '及格' + when (0...60) + '不及格' + end + end + + # 更新作品成绩 + def set_work_score + if work_status > 0 && homework_common && homework_common.homework_detail_manual && !self.ultimate_score + case homework_common.homework_type + when "normal", "group" + if !homework_common.homework_detail_manual.final_mode + tea_ass_proportion = homework_common.homework_detail_manual.ta_proportion + tea_proportion = homework_common.homework_detail_manual.te_proportion + if self.teacher_score + if self.teaching_asistant_score.nil? + if self.student_score.nil? + self.final_score = self.teacher_score + else + te_proportion = tea_proportion + tea_ass_proportion / 2 + final_te_score = BigDecimal.new("#{self.teacher_score}") * BigDecimal.new("#{te_proportion}") + final_s_score = BigDecimal.new("#{self.student_score}") * (BigDecimal.new('1.0') - + BigDecimal.new("#{te_proportion}")) + final_score = final_te_score + final_s_score + self.final_score = format("%.2f", final_score.to_f) + end + else + if self.student_score.nil? + te_proportion = tea_proportion + (1.0 - tea_proportion - tea_ass_proportion) / 2 + final_te_score = BigDecimal.new("#{self.teacher_score}") * BigDecimal.new("#{te_proportion}") + final_ta_score = BigDecimal.new("#{self.teaching_asistant_score}") * (BigDecimal.new('1.0') - + BigDecimal.new("#{te_proportion}")) + final_score = final_te_score + final_ta_score + self.final_score = format("%.2f",final_score.to_f) + else + final_te_score = BigDecimal.new("#{self.teacher_score}") * BigDecimal.new("#{tea_proportion}") + final_ta_score = BigDecimal.new("#{self.teaching_asistant_score}") * BigDecimal.new("#{tea_ass_proportion}") + final_s_score = BigDecimal.new("#{self.student_score}") * (BigDecimal.new('1.0') - + BigDecimal.new("#{tea_proportion}") - BigDecimal.new("#{tea_ass_proportion}")) + final_score = final_te_score + final_ta_score + final_s_score + self.final_score = format("%.2f",final_score.to_f) + end + end + else + if self.teaching_asistant_score.nil? + self.final_score = self.student_score + elsif self.student_score.nil? + self.final_score = self.teaching_asistant_score + else + ta_proportion = tea_ass_proportion + tea_proportion / 2 + final_ta_score = BigDecimal.new("#{self.teaching_asistant_score}") * BigDecimal.new("#{ta_proportion}") + final_s_score = BigDecimal.new("#{self.student_score}") * (BigDecimal.new('1.0') - + BigDecimal.new("#{ta_proportion}")) + final_score = final_ta_score + final_s_score + self.final_score = format("%.2f",final_score.to_f) + end + end + + else + self.final_score = self.teacher_score ? self.teacher_score : + (self.teaching_asistant_score ? self.teaching_asistant_score : self.student_score) + end + + # 作品最终得分work_score 等于作品得分 - 缺评扣分 - 迟交扣分 - 申诉扣分 + score = self.final_score.to_f - self.absence_penalty - self.late_penalty - self.appeal_penalty if self.final_score + self.work_score = score ? format("%.2f",(score < 0 ? 0 : score).to_f) : nil + + when "practice" + # 作品最终得分work_score 等于作品关卡得分 + 效率分 - 迟交扣分 + work_score = self.final_score + self.eff_score - self.late_penalty if self.final_score + self.work_score = work_score ? format("%.2f", work_score < 0 ? 0 : work_score) : nil + end + end + end + + def scored? + student_works_scores.where.not(reviewer_role: 3).exists? + end +end diff --git a/app/models/student_works_evaluation_distribution.rb b/app/models/student_works_evaluation_distribution.rb new file mode 100644 index 000000000..7c3246e61 --- /dev/null +++ b/app/models/student_works_evaluation_distribution.rb @@ -0,0 +1,4 @@ +class StudentWorksEvaluationDistribution < ApplicationRecord + belongs_to :student_work + belongs_to :user +end diff --git a/app/models/student_works_score.rb b/app/models/student_works_score.rb new file mode 100644 index 000000000..f6c7b3e33 --- /dev/null +++ b/app/models/student_works_score.rb @@ -0,0 +1,34 @@ +class StudentWorksScore < ApplicationRecord + #appeal_status: 0:正常;1:申诉中,2:撤销申诉;3:申诉成功;4:申诉被拒绝;5:申诉失效 +belongs_to :student_work + belongs_to :user + has_many :journals_for_messages, -> { order('created_on desc') }, as: :jour, dependent: :destroy + has_one :student_works_scores_appeal, dependent: :destroy + has_many :tidings, as: :container, dependent: :destroy + has_many :attachments, as: :container, dependent: :destroy + + validates :comment, length: { maximum: 2000 } + + def show_name identity, user + identity < Course::STUDENT || self.user == user || self.reviewer_role != 3 + end + + def allow_delete current_user, identity + self.is_invalid && (current_user == self.user || identity < Course::STUDENT) || + (self.score.nil? && current_user == self.user) + end + + # 匿评分 + def stu_score work_id + StudentWorksScore.find_by_sql("SELECT AVG(score) AS score FROM student_works_scores WHERE + student_work_id = #{work_id} AND reviewer_role = 3 AND score IS NOT NULL + AND appeal_status != 3 AND is_invalid = 0").first.score.try(:round, 2).to_f + end + + # 助教平均分 + def ta_score work_id + StudentWorksScore.find_by_sql("SELECT AVG(score) AS score FROM student_works_scores WHERE + student_work_id = #{work_id} AND reviewer_role = 2 AND score IS NOT NULL + AND is_invalid = 0").first.score.try(:round, 2).to_f + end +end diff --git a/app/models/student_works_scores_appeal.rb b/app/models/student_works_scores_appeal.rb new file mode 100644 index 000000000..9c9b33199 --- /dev/null +++ b/app/models/student_works_scores_appeal.rb @@ -0,0 +1,5 @@ +class StudentWorksScoresAppeal < ApplicationRecord + belongs_to :student_works_score + belongs_to :user + has_many :tidings, as: :container, dependent: :destroy +end diff --git a/app/models/students_for_course.rb b/app/models/students_for_course.rb new file mode 100644 index 000000000..f0a8f1fbd --- /dev/null +++ b/app/models/students_for_course.rb @@ -0,0 +1,4 @@ +class StudentsForCourse < ApplicationRecord + belongs_to :course, :class_name => 'Course', :foreign_key => :course_id + belongs_to :student, :class_name => 'User', :foreign_key => :student_id +end diff --git a/app/models/sub_repertoire.rb b/app/models/sub_repertoire.rb new file mode 100644 index 000000000..d94db66c7 --- /dev/null +++ b/app/models/sub_repertoire.rb @@ -0,0 +1,3 @@ +class SubRepertoire < ApplicationRecord + has_many :tag_repertoires +end diff --git a/app/models/subject.rb b/app/models/subject.rb new file mode 100644 index 000000000..ced610377 --- /dev/null +++ b/app/models/subject.rb @@ -0,0 +1,91 @@ +## 这个模块的统计有很大的性能问题 +# 可以在初始创建的时候 + +class Subject < ApplicationRecord + #status :0 编辑中 1 审核中 2 发布 + belongs_to :repertoire + belongs_to :user + + has_many :stages, -> { order("stages.position ASC") }, dependent: :destroy + + has_many :stage_shixuns, dependent: :destroy + has_many :shixuns, through: :stage_shixuns + + has_many :subject_members, ->{ order("subject_members.position asc")}, dependent: :destroy + has_many :users, through: :subject_members + has_many :tidings, as: :container, dependent: :destroy + has_many :stages, -> { order("stages.position ASC") }, dependent: :destroy + + validates :name, length: { maximum: 40 } + validates :description, length: { maximum: 5000 } + validates :learning_notes, length: { maximum: 500 } + + scope :visible, lambda{where(status: 2)} + scope :published, lambda{where(status: 1)} + scope :unhidden, lambda{where(hidden: 0)} + + after_create :send_tiding + def send_tiding + self.tidings << Tiding.new(user_id: self.user_id, trigger_user_id: self.user_id, belong_container_id: self.id, belong_container_type: 'Subject', tiding_type: "System", viewed: 0) + end + + # 挑战过路径的成员数 + def member_count + shixuns.sum(:myshixuns_count) + end + + def all_score + subject_shixun_score + subject_shixun_choose_score + end + + def subject_shixun_score + Challenge.find_by_sql("select sum(score) as shixun_count from challenges where st=0 and shixun_id in + (select id from shixuns where status > 1 and id in (SELECT distinct shixun_id + FROM `stage_shixuns` where subject_id=#{self.id}))").first.try(:shixun_count).to_i + end + + def subject_shixun_choose_score + ChallengeChoose.find_by_sql("select sum(score) as choose_score from challenge_chooses where challenge_id in + (select distinct(id) from challenges where st !=0 and shixun_id in (select id from shixuns where status > 1 and id in + (SELECT distinct shixun_id FROM `stage_shixuns` where subject_id=#{self.id})))").first.try(:choose_score).to_i + end + + def my_subject_score + shixuns_id = self.stage_shixuns.map(&:shixun_id) + shixuns_id = Shixun.where(:id => shixuns_id, :status =>[2, 3]).map(&:id) + shixuns_id = shixuns_id.present? ? shixuns_id.join(",") : -1 + my_shixun_score = Challenge.find_by_sql("select sum(c.score) as score FROM challenges c join games g on g.challenge_id = c.id where g.status = 2 and g.user_id = #{User.current.id} and c.shixun_id in(#{shixuns_id})").first.try(:score) + my_choose_score = ChallengeChoose.find_by_sql("SELECT sum(g.final_score) score FROM (`challenge_chooses` cc join challenges c on cc.challenge_id = c.id) join games g on g.challenge_id = c.id where g.status = 2 and g.user_id = #{User.current.id} and c.shixun_id in(#{shixuns_id})").first.try(:score) + return my_shixun_score.to_i + my_choose_score.to_i + end + + def subject_challenge_count + Challenge.find_by_sql("select count(*) as challenge_count from challenges where st=0 and shixun_id in(SELECT distinct shixun_id FROM `stage_shixuns` where subject_id=#{self.id})").first.try(:challenge_count).to_i + end + + def subject_challenge_choose_count + Challenge.find_by_sql("select count(*) as challenge_choose_count from challenges where st!=0 and shixun_id in(SELECT distinct shixun_id FROM `stage_shixuns` where subject_id=#{self.id})").first.try(:challenge_choose_count).to_i + end + + def my_subject_progress + shixun_id = self.stage_shixuns.map(&:shixun_id) + challenge_id = Game.where(:user_id => User.current.id, :status => 2).pluck(:challenge_id) + my_challenge_count = Challenge.where(:id => challenge_id, :shixun_id => shixun_id).count + count = self.subject_challenge_count == 0 ? 0 : ((my_challenge_count.to_f / self.subject_challenge_count).round(2) * 100).to_i + end + + def my_consume_time + shixuns_id = self.stage_shixuns.map(&:shixun_id) + shixuns_id = shixuns_id.present? ? shixuns_id.join(",") : -1 + my_shixun_time = Challenge.find_by_sql("select sum(g.cost_time) as score FROM challenges c join games g on g.challenge_id = c.id where g.status = 2 and g.user_id = #{User.current.id} and c.shixun_id in(#{shixuns_id})").first.try(:score) + return my_shixun_time.to_i + end + + def member?(user) + subject_members.exists?(user_id: user.id) + end + + def published? + status == 2 + end +end \ No newline at end of file diff --git a/app/models/subject_member.rb b/app/models/subject_member.rb new file mode 100644 index 000000000..4bebb44f4 --- /dev/null +++ b/app/models/subject_member.rb @@ -0,0 +1,4 @@ +class SubjectMember < ApplicationRecord + belongs_to :subject + belongs_to :user +end diff --git a/app/models/tag_repertoire.rb b/app/models/tag_repertoire.rb new file mode 100644 index 000000000..fe7054e23 --- /dev/null +++ b/app/models/tag_repertoire.rb @@ -0,0 +1,13 @@ +class TagRepertoire < ApplicationRecord + belongs_to :sub_repertoire + + has_many :shixun_tag_repertoires, dependent: :destroy + has_many :shixuns, through: :shixun_tag_repertoires + + has_many :memo_tag_repertoires, :dependent => :destroy + has_many :memos, :through => :memo_tag_repertoires + + + scope :field_for_list, lambda{select([:id, :name])} + +end diff --git a/app/models/teacher_course_group.rb b/app/models/teacher_course_group.rb new file mode 100644 index 000000000..fbf9849ac --- /dev/null +++ b/app/models/teacher_course_group.rb @@ -0,0 +1,15 @@ +class TeacherCourseGroup < ApplicationRecord + belongs_to :course_group + belongs_to :course, optional: true + belongs_to :user + + belongs_to :course_member, optional: true + + scope :find_teacher_group_ids, lambda { |ids| where(course_group_id: ids) unless ids.blank?} + scope :get_user_groups,lambda {|ids| where(user_id:ids)} + + def course_members + self.course_group.course_members + end + +end diff --git a/app/models/tem_test.rb b/app/models/tem_test.rb new file mode 100644 index 000000000..ca4a1b98f --- /dev/null +++ b/app/models/tem_test.rb @@ -0,0 +1,2 @@ +class TemTest < ApplicationRecord +end diff --git a/app/models/test_set.rb b/app/models/test_set.rb new file mode 100644 index 000000000..148cb8720 --- /dev/null +++ b/app/models/test_set.rb @@ -0,0 +1,2 @@ +class TestSet < ApplicationRecord +end diff --git a/app/models/tiding.rb b/app/models/tiding.rb new file mode 100644 index 000000000..66b1f85be --- /dev/null +++ b/app/models/tiding.rb @@ -0,0 +1,9 @@ +class Tiding < ApplicationRecord + belongs_to :user + belongs_to :trigger_user, class_name: 'User', optional: true + belongs_to :container, polymorphic: true, optional: true + belongs_to :parent_container, polymorphic: true, optional: true + belongs_to :belong_container, polymorphic: true, optional: true + + has_many :attachments, as: :container +end \ No newline at end of file diff --git a/app/models/token.rb b/app/models/token.rb new file mode 100644 index 000000000..cd61090be --- /dev/null +++ b/app/models/token.rb @@ -0,0 +1,103 @@ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +class Token < ActiveRecord::Base + belongs_to :user + validates_uniqueness_of :value + + before_create :delete_previous_tokens, :generate_new_token + + @@validity_time = 1.day + + def generate_new_token + self.value = Token.generate_token_value + end + + def self.get_or_create_permanent_login_token(user, type) + token = Token.get_token_from_user(user, type) + unless token + token = Token.create(:user => user, :action => type) + else + token.update_attribute(:created_on, Time.now) + end + token + end + + def self.get_token_from_user(user, action) + token = Token.where(:action => action, :user_id => user).first + unless token + token = Token.create!(user_id: user.id, action: action) + end + token + end + + # Return true if token has expired + def expired? + return Time.now > self.created_on + @@validity_time + end + + # Delete all expired tokens + def self.destroy_expired + Token.delete_all ["action NOT IN (?) AND created_on < ?", ['feeds', 'api', 'autologin'], Time.now - @@validity_time] + end + + # Returns the active user who owns the key for the given action + def self.find_active_user(action, key, validity_days=nil) + user = find_user(action, key, validity_days) + if user && user.active? + user + end + end + + # Returns the user who owns the key for the given action + def self.find_user(action, key, validity_days=nil) + token = find_token(action, key, validity_days) + if token + token.user + end + end + + # Returns the token for action and key with an optional + # validity duration (in number of days) + def self.find_token(action, key, validity_days=nil) + action = action.to_s + key = key.to_s + return nil unless action.present? && key =~ /\A[a-z0-9]+\z/i + + token = Token.where(value: key, action: action).first + if token && (token.action == action) && (token.value == key) && token.user + if validity_days.nil? || (token.created_on > validity_days.days.ago) + token + end + end + end + + def self.generate_token_value + Educoder::Utils.random_hex(20) + end + + def self.delete_user_all_tokens(user) + Token.delete_all(user_id: user.id) + end + + private + + # Removes obsolete tokens (same user and action) + def delete_previous_tokens + if user + Token.where(['user_id = ? AND action = ?', user.id, action]).delete_all + end + end +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 000000000..60765b852 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,589 @@ +class User < ApplicationRecord + include Watchable + # Account statuses + STATUS_ANONYMOUS = 0 + STATUS_ACTIVE = 1 + STATUS_REGISTERED = 2 + STATUS_LOCKED = 3 + + # tpi tpm权限控制 + EDU_ADMIN = 1 # 超级管理员 + EDU_BUSINESS = 2 # 运营人员 + EDU_SHIXUN_MANAGER = 3 # 实训管理员 + EDU_SHIXUN_MEMBER = 4 # 实训成员 + EDU_CERTIFICATION_TEACHER = 5 # 平台认证的老师 + EDU_GAME_MANAGER = 6 # TPI的创建者 + EDU_TEACHER = 7 # 平台老师,但是未认证 + EDU_NORMAL = 8 # 普通用户 + + VALID_EMAIL_REGEX = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/i + VALID_PHONE_REGEX = /^1\d{10}$/ + + LOGIN_LENGTH_LIMIT = 30 + MAIL_LENGTH_LMIT = 60 + + MIX_PASSWORD_LIMIT = 8 + + has_one :user_extension, dependent: :destroy + accepts_nested_attributes_for :user_extension, update_only: true + + has_many :memos, foreign_key: 'author_id' + has_many :shixun_members, :dependent => :destroy + has_many :shixuns, :through => :shixun_members + has_many :myshixuns, :dependent => :destroy + has_many :study_shixuns, through: :myshixuns, source: :shixun # 已学习的实训 + has_many :course_messages + has_many :courses, dependent: :destroy + + #试卷 + has_many :exercise_banks, :dependent => :destroy + has_many :exercise_users, :dependent => :destroy + has_many :exercise_answers, :dependent => :destroy #针对每个题目学生的答案 + has_many :exercise_shixun_answers, :dependent => :destroy #针对每个实训题目学生的答案 + has_many :exercise_answer_comments, :dependent => :destroy + has_many :exercises, :dependent => :destroy #创建的试卷 + + has_many :homework_banks, dependent: :destroy + + has_many :graduation_works, dependent: :destroy + + # 关注 + has_many :relationships, foreign_key: "follower_id", dependent: :destroy + has_many :followed_users, through: :relationships, source: :followed + # 粉丝 + has_many :reverse_relationships, foreign_key: "followed_id", + class_name: "Relationship", + dependent: :destroy + has_many :followers, through: :reverse_relationships, source: :follower + has_many :students_for_courses, foreign_key: :student_id, dependent: :destroy + has_one :onclick_time, :dependent => :destroy + + # 新版私信 + has_many :private_messages, :dependent => :destroy + has_many :tidings, :dependent => :destroy + + has_many :games, :dependent => :destroy + has_many :subjects, :through => :subject_members + has_many :subject_members, :dependent => :destroy + has_many :grades, :dependent => :destroy + has_many :experiences, :dependent => :destroy + has_many :student_works, :dependent => :destroy + has_many :student_works_scores + has_many :student_works_evaluation_distributions + + # 毕业设计 + has_many :graduation_topics, :dependent => :destroy + has_many :student_graduation_topics, :dependent => :destroy + + # 题库 + has_many :question_banks, :dependent => :destroy + # 毕设任务题库 + has_many :gtask_banks, dependent: :destroy + has_many :gtopic_banks, dependent: :destroy + + #问卷 + has_many :course_members, :dependent => :destroy + has_many :poll_votes, :dependent => :destroy + has_many :poll_users, :dependent => :destroy + + has_many :messages,foreign_key: 'author_id',:dependent => :destroy + + has_many :journals_for_messages, :as => :jour, :dependent => :destroy + has_many :teacher_course_groups, :dependent => :destroy + + has_many :attachments,foreign_key: :author_id, :dependent => :destroy + + # 工程认证 + has_many :ec_school_users,:dependent => :destroy + has_many :schools, :through => :ec_school_users + + has_many :ec_major_school_users, :dependent => :destroy + has_many :ec_major_schools, :through => :ec_major_school_users + + has_many :ec_course_users + + has_many :department_members, dependent: :destroy #部门管理员 + + # 课堂 + has_many :student_course_members, -> { course_students }, class_name: 'CourseMember' + has_many :as_student_courses, through: :student_course_members, source: :course + has_many :manage_course_members, -> { teachers_and_admin }, class_name: 'CourseMember' + has_many :manage_courses, through: :manage_course_members, source: :course + + # 关注 + has_many :be_watchers, foreign_key: :user_id, dependent: :destroy # 我的关注 + has_many :be_watcher_users, through: :be_watchers, dependent: :destroy # 我关注的用户 + + # 认证 + has_many :apply_user_authentication + has_one :process_real_name_apply, -> { processing.real_name_auth.order(created_at: :desc) }, class_name: 'ApplyUserAuthentication' + has_one :process_professional_apply, -> { processing.professional_auth.order(created_at: :desc) }, class_name: 'ApplyUserAuthentication' + has_many :apply_actions, dependent: :destroy + has_many :trail_auth_apply_actions, -> { where(container_type: 'TrialAuthorization') }, class_name: 'ApplyAction' + + has_many :attendances + + # Groups and active users + scope :active, lambda { where(status: STATUS_ACTIVE) } + + attr_accessor :password, :password_confirmation + + before_save :update_hashed_password + + # + # validations + # + validates_presence_of :login, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }, case_sensitive: false + validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false + validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, case_sensitive: false + validates_uniqueness_of :phone, :if => Proc.new { |user| user.phone_changed? && user.phone.present? }, case_sensitive: false + validates_length_of :login, maximum: LOGIN_LENGTH_LIMIT + validates_length_of :mail, maximum: MAIL_LENGTH_LMIT + # validates_format_of :mail, with: VALID_EMAIL_REGEX, multiline: true + # validates_format_of :phone, with: VALID_PHONE_REGEX, multiline: true + validate :validate_password_length + + # validates :nickname, presence: true, length: { maximum: 10 } + # validates :lastname, presence: true + + # 删除自动登录的token,一旦退出下次会提示需要登录 + def delete_autologin_token(value) + Token.where(:user_id => id, :action => 'autologin', :value => value).delete_all + end + + def delete_session_token(value) + Token.where(:user_id => id, :action => 'session', :value => value).delete_all + end + + + # 学号 + def student_id + self.user_extension.try(:student_id) + end + + # 关注总数 + def following?(other_user) + relationships.find_by(followed_id: other_user) + end + + # 关注 + def follow!(other_user) + relationships.create!(followed_id: other_user) + end + + # 取消关注 + def unfollow!(other_user) + relationships.find_by(followed_id: other_user.id).destroy + end + + # 判断当前用户是否为老师 + def is_teacher? + self.user_extension.teacher? + end + + # 平台认证的老师 + def is_certification_teacher + self.user_extension.teacher? && self.professional_certification + end + + def certification_teacher? + professional_certification? && user_extension.teacher? + end + + # 判断用户的身份 + def identity + ue = self.user_extension + unless ue.blank? + if ue.teacher? + ue.technical_title ? ue.technical_title : "老师" + elsif ue.student? + "学生" + else + ue.technical_title ? ue.technical_title : "专业人士" + end + end + end + + # 判断当前用户是否通过职业认证 + def pro_certification? + professional_certification + end + + # 用户的学校名称 + def school_name + user_extension&.school&.name || '' + end + + def school_id + user_extension&.school_id + end + + # 课堂的老师(创建者、老师、助教) + def teacher_of_course?(course) + course.course_members.exists?(user_id: id, role: [1,2,3], is_active: 1) || admin? + end + + # 课堂的老师(创建者、老师、助教),不用考虑当前身份 + def teacher_of_course_non_active?(course) + course.course_members.exists?(user_id: id, role: [1,2,3]) || admin? + end + + # 是否是教师,课堂管理员或者超级管理员 + def teacher_or_admin?(course) + course.course_members.exists?(user_id: id, role: [1,2], is_active: 1) || admin? + end + + # 课堂的创建者(考虑到多重身份的用户) + def creator_of_course?(course) + course.course_members.exists?(user_id: id, role: 1, is_active: 1) || admin? + end + + # 课堂的学生 + def student_of_course?(course) + course.course_members.exists?(user_id: id, role: %i[STUDENT]) + end + + # 课堂成员 + def member_of_course?(course) + course.course_members.exists?(user_id: id) + end + + # 实训路径管理员:创建者或admin + def creator_of_subject?(subject) + subject.user_id == id || admin? + end + + # 实训路径:合作者、admin + def manager_of_subject?(subject) + subject.subject_members.exists?(user_id: id, role: [1,2]) || admin? + end + + # 实训管理员:实训合作者、admin + def manager_of_shixun?(shixun) + shixun.shixun_members.exists?(role: [1,2], user_id: id) || admin? + end + + # 实训管理员 + def creator_of_shixun?(shixun) + id == shixun.user_id + end + + # 实训的合作者 + def member_of_shixun?(shixun) + #self.shixun_members.where(:role => 2, :shixun_id => shixun.id).present? + shixun.shixun_members.exists?(role: 2, user_id: id) + end + + # TPI的创建者 + def creator_of_game?(game) + id == game.user_id + end + + # 用户账号状态 + def active? + status == STATUS_ACTIVE + end + + def registered? + status == STATUS_REGISTERED + end + + def locked? + status == STATUS_LOCKED + end + + def activate + self.status = STATUS_ACTIVE + end + + def register + self.status = STATUS_REGISTERED + end + + def lock + self.status = STATUS_LOCKED + end + + def activate! + update_attribute(:status, STATUS_ACTIVE) + end + + def register! + update_attribute(:status, STATUS_REGISTERED) + end + + def lock! + update_attribute(:status, STATUS_LOCKED) + end + + # 课程用户身份 + def course_identity(course) + if !logged? + Course::Anonymous + elsif admin? + Course::ADMIN + elsif business? + Course::BUSINESS + else + role = course.course_members.find_by(user_id: id, is_active: 1)&.role + case role + when nil then Course::NORMAL + when 'CREATOR' then Course::CREATOR + when 'PROFESSOR' then Course::PROFESSOR + when 'STUDENT' then Course::STUDENT + when 'ASSISTANT_PROFESSOR' then Course::ASSISTANT_PROFESSOR + end + end + end + + # 实训用户身份 + def shixun_identity(shixun) + @identity = + if admin? + User::EDU_ADMIN + elsif business? + User::EDU_BUSINESS + elsif creator_of_shixun?(shixun) + User::EDU_SHIXUN_MANAGER + elsif member_of_shixun?(shixun) + User::EDU_SHIXUN_MEMBER + elsif is_certification_teacher + User::EDU_CERTIFICATION_TEACHER + elsif is_teacher? + User::EDU_TEACHER + else + User::EDU_NORMAL + end + return @identity + end + + # tpi的用户身份 + def game_identity(game) + shixun = game.myshixun.shixun + @identity = + if admin? + User::EDU_ADMIN + elsif creator_of_shixun?(shixun) + User::EDU_SHIXUN_MANAGER + elsif member_of_shixun?(shixun) + User::EDU_SHIXUN_MEMBER + elsif is_certification_teacher + User::EDU_CERTIFICATION_TEACHER + elsif creator_of_game?(game) + User::EDU_GAME_MANAGER + elsif is_teacher? + User::EDU_TEACHER + else + User::EDU_NORMAL + end + return @identity + end + + # 我的实训 + def my_shixuns + shixun_ids = shixun_members.pluck(:shixun_id) + myshixuns.pluck(:shixun_id) + Shixun.where(:id => shixun_ids).visible + end + + # 用户是否有权限查看实训 + def shixun_permission(shixun) + # 性能优化:先处理不需要权限的实训(已发布并且没有单位权限限制的实训) + return true if manager_of_shixun?(shixun) # 实训管理员 + return false if shixun.status != 2 || shixun.hidden # 隐藏或者未发布的实训:false + return true if shixun.use_scope == 0 # 对所有学校公开 + return true if shixun.use_scope == 1 && shixun.shixun_schools.exists?(school_id: school_id) # 对部分高校公开 + return false + end + + # 用户在平台名称的显示方式 + def full_name + return '游客' unless logged? + + name = show_realname? ? lastname + firstname : nickname + name.blank? ? (nickname.blank? ? login : nickname) : name + end + + # 用户的真实姓名(不考虑用户是否隐藏了真实姓名,课堂模块都用真实姓名) + def real_name + return '游客' unless logged? + + name = lastname + firstname + name.blank? ? (nickname.blank? ? login : nickname) : name + name.gsub(/\s+/, '').strip #6.11 -hs + end + + # 用户是否选题毕设课题 + def selected_topic?(topic) + student_graduation_topics.where(graduation_topic_id: topic.id).last.try(:status) + end + + def click_time + click_time = OnclickTime.find_by(user_id: id) || OnclickTime.create(user_id: id, onclick_time: created_on) + click_time.onclick_time + end + + def manager_of_memo?(memo) + id == memo.author_id || admin? + end + + # 是否是项目管理者 + def manager_of_project?(project) + project.project_members.where(user_id: id).count > 0 + end + + def logged? + true + end + + def active? + status == STATUS_ACTIVE + end + + def locked? + status == STATUS_LOCKED + end + + def phone_binded? + phone.present? + end + + def self.current=(user) + Thread.current[:current_user] = user + end + + def self.current + Thread.current[:current_user] ||= User.anonymous + end + + def self.anonymous + anonymous_user = AnonymousUser.unscoped.take + if anonymous_user.nil? + anonymous_user = AnonymousUser.unscoped.create(lastname: 'Anonymous', firstname: '', login: '', + mail: '358551897@qq.com', phone: '13333333333', status: 0) + raise "Unable to create the anonymous user: error_info:#{anonymous_user.errors.messages}" if anonymous_user.new_record? + end + anonymous_user + end + + # Returns the user who matches the given autologin +key+ or nil + def self.try_to_autologin(key) + user = Token.find_active_user('autologin', key) + user.update(last_login_on: Time.now) if user + user + end + + def self.hash_password(clear_password) + Digest::SHA1.hexdigest(clear_password || "") + end + + def check_password?(clear_password) + # Preventing Timing Attack + ActiveSupport::SecurityUtils.secure_compare( + User.hash_password("#{salt}#{User.hash_password clear_password}"), + hashed_password + ) + end + + # 登录,返回用户名与密码匹配的用户 + def self.try_to_login(login, password) + login = login.to_s.strip + password = password.to_s + + # Make sure no one can sign in with an empty login or password + return nil if login.empty? || password.empty? + if (login =~ VALID_EMAIL_REGEX) + user = find_by_mail(login) + elsif (login =~ VALID_PHONE_REGEX) + user = find_by_phone(login) + else + user = find_by_login(login) + end + + if user + # user is already in local database + raise("账号已被注销,请联系管理员") if user.locked? + raise("密码错误") unless user.check_password?(password) + else + raise("账号未注册") + end + + user + rescue => text + raise text + end + + def show_real_name + name = lastname + firstname + if name.blank? + nickname.blank? ? login : nickname + else + name + end + end + + def update_hashed_password + if password + salt_password(password) + end + end + + def salt_password(clear_password) + self.salt = User.generate_salt + self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}") + end + + def self.generate_salt + Educoder::Utils.random_hex(16) + end + + protected + def validate_password_length + # 管理员的初始密码是5位 + if password.present? && password.size < MIX_PASSWORD_LIMIT && !User.current.admin? + raise("密码长度不能低于#{MIX_PASSWORD_LIMIT}位") + end + end +end + + +class AnonymousUser < User + validate :validate_anonymous_uniqueness, :on => :create + + def validate_anonymous_uniqueness + # There should be only one AnonymousUser in the database + errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists? + end + + def available_custom_fields + [] + end + + # Overrides a few properties + def logged?; false end + def admin; false end + def name(*args); I18n.t(:label_user_anonymous) end + # def mail=(*args); nil end + # def mail; nil end + def time_zone; nil end + def rss_key; nil end + + + def membership(*args) + nil + end + + def member_of?(*args) + false + end + + # Anonymous user can not be destroyed + def destroy + false + end + + protected + + def instantiate_email_address + end + +end diff --git a/app/models/user_action.rb b/app/models/user_action.rb new file mode 100644 index 000000000..d3d70a66d --- /dev/null +++ b/app/models/user_action.rb @@ -0,0 +1,2 @@ +class UserAction < ApplicationRecord +end diff --git a/app/models/user_day_certification.rb b/app/models/user_day_certification.rb new file mode 100644 index 000000000..18da0fd12 --- /dev/null +++ b/app/models/user_day_certification.rb @@ -0,0 +1,2 @@ +class UserDayCertification < ApplicationRecord +end diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb new file mode 100644 index 000000000..3d8457ce3 --- /dev/null +++ b/app/models/user_extension.rb @@ -0,0 +1,12 @@ +class UserExtension < ApplicationRecord + # identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者 + enum identity: { teacher: 0, student: 1, professional: 2, developer: 3 } + + belongs_to :user + belongs_to :school + belongs_to :department + + def identity_text + I18n.t("user.identity.#{identity}") + end +end diff --git a/app/models/verification_code.rb b/app/models/verification_code.rb new file mode 100644 index 000000000..452e637a7 --- /dev/null +++ b/app/models/verification_code.rb @@ -0,0 +1,5 @@ +class VerificationCode < ApplicationRecord + def effective? + created_at + 10.minute > Time.current + end +end diff --git a/app/models/watcher.rb b/app/models/watcher.rb new file mode 100644 index 000000000..d9426e03c --- /dev/null +++ b/app/models/watcher.rb @@ -0,0 +1,4 @@ +class Watcher < ApplicationRecord + belongs_to :user + belongs_to :watchable, polymorphic: true +end \ No newline at end of file diff --git a/app/models/zip_pack.rb b/app/models/zip_pack.rb new file mode 100644 index 000000000..b6c0d08d4 --- /dev/null +++ b/app/models/zip_pack.rb @@ -0,0 +1,17 @@ +class ZipPack < ApplicationRecord + + def self.packed?(bid, user_id, digests) + zip_pack = ZipPack.where(container_id: bid.id, container_type: bid.class.to_s, user_id: user_id).first + return false unless zip_pack && zip_pack.digests == digests + zip_pack + end + + def file_valid? + return false unless File.exist?(self.file_path) + Educoder::Utils.digest(self.file_path) == self.file_digest + end + + def digests + self.file_digests.split(',').sort + end +end diff --git a/app/services/application_service.rb b/app/services/application_service.rb new file mode 100644 index 000000000..c6f66c098 --- /dev/null +++ b/app/services/application_service.rb @@ -0,0 +1,3 @@ +class ApplicationService + include Callable +end \ No newline at end of file diff --git a/app/services/batch_export_shixun_report_service.rb b/app/services/batch_export_shixun_report_service.rb new file mode 100644 index 000000000..6ea38b23f --- /dev/null +++ b/app/services/batch_export_shixun_report_service.rb @@ -0,0 +1,55 @@ +class BatchExportShixunReportService + Error = Class.new(StandardError) + + MAX_BATCH_LIMIT = 20 + + attr_reader :homework, :student_work_ids + + def initialize(homework, student_work_ids) + @homework = homework + @student_work_ids = student_work_ids + end + + def filename + @_filename ||= "#{Time.now.strftime('%Y%m%d%H%M%S')}-#{homework.name}.zip" + end + + def zip + validate! + student_works = homework.student_works.where(id: student_work_ids).includes(:myshixun, user: :user_extension) + + if student_works.count.zero? + raise Error, '请选择要导出的学生实训报告' + end + pdfs = [] + zip_file = Tempfile.new(filename) + Zip::File.open(zip_file.path, Zip::File::CREATE) do |zip| + student_works.find_each.map do |student_work| + export = ExportShixunReportService.new(homework, student_work) + pdf = export.to_pdf + pdfs << pdf + begin + zip.add(export.filename, pdf.path) + rescue => ex + Rails.logger.error(ex.message) + + zip.get_output_stream('FILE_NOTICE.txt'){|os| os.write('文件重复') } + next + end + end + zip_file + end + end + + private + + def validate! + if student_work_ids.size.zero? + raise Error, '请选择学生实训作业' + end + + if student_work_ids.size > MAX_BATCH_LIMIT + raise Error, '导出实训报告太多,请分批导出' + end + end +end diff --git a/app/services/concerns/accepts_nested_attributes_helper.rb b/app/services/concerns/accepts_nested_attributes_helper.rb new file mode 100644 index 000000000..7cee7cca1 --- /dev/null +++ b/app/services/concerns/accepts_nested_attributes_helper.rb @@ -0,0 +1,27 @@ +module AcceptsNestedAttributesHelper + extend ActiveSupport::Concern + + def build_accepts_nested_attributes(obj, relations, data) + # 新记录,全部为创建 + return data if obj.new_record? + + # 更新时,需要处理删除数据 + old_ids = relations.loaded? ? relations.map(&:id) : relations.pluck(:id) + new_ids = + data.map do |item| + yield(item) if block_given? + + # 处理参数中错误的ID + item[:id] = item[:id].to_i + item[:id] = nil if item[:id].zero? || !old_ids.include?(item[:id]) + item[:id] + end + new_ids.compact! + + # 被删除的子项ID数组 + destroy_ids = old_ids - new_ids + destroy_attributes = destroy_ids.map { |id| { id: id, _destroy: true } } + + data.concat(destroy_attributes) + end +end \ No newline at end of file diff --git a/app/services/concerns/callable.rb b/app/services/concerns/callable.rb new file mode 100644 index 000000000..8c2fc75d1 --- /dev/null +++ b/app/services/concerns/callable.rb @@ -0,0 +1,9 @@ +module Callable + extend ActiveSupport::Concern + + module ClassMethods + def call(*parameters) + new(*parameters).call + end + end +end \ No newline at end of file diff --git a/app/services/courses_service.rb b/app/services/courses_service.rb new file mode 100644 index 000000000..8229c7c32 --- /dev/null +++ b/app/services/courses_service.rb @@ -0,0 +1,2 @@ +class CoursesService +end \ No newline at end of file diff --git a/app/services/discusses_service.rb b/app/services/discusses_service.rb new file mode 100644 index 000000000..91fa523c9 --- /dev/null +++ b/app/services/discusses_service.rb @@ -0,0 +1,200 @@ +# encoding=utf-8 +class DiscussesService + include ApplicationHelper + include GamesHelper + + # “讨论区”的所有评论 + def self.index params, current_user + page = params[:page].to_i + offset = page * 15 + search = params[:search] + tag = params[:tag_repertoire_id] + sql, sql1, sq2 = '', '', '' + tidding_count = unviewed_tiddings(current_user) if current_user.present? + sql1 = + if search + "and d.content like '%#{search}%'" + end + sql2 = + if tag + shixun_ids = ShixunTagRepertoire.where(:tag_repertoire_id => tag).pluck(:shixun_id) + "and d.dis_id in(#{shixun_ids.join(",")})" + end + sql = "select d.id from discusses d join shixuns s on d.dis_id = s.id where s.status = 2 and s.hidden = false and d.root_id is null + and d.hidden = false #{sql1} #{sql2}" + + memo_ids = Discuss.find_by_sql(sql).map(&:id) + Rails.logger.info("############memo_ids: #{memo_ids}") + memos = Discuss.field_for_list.where(:id => memo_ids).order("created_at desc") + memo_count = memos.count + memos = memos.offset(offset).limit(15) + # 实训标签使用最多的9个 + hot_tags = TagRepertoire.find_by_sql("select distinct(a.name), a.id from + (select tr.id, tr.name, count(d.dis_id) cnt + from tag_repertoires tr join (shixun_tag_repertoires str + left join (shixuns s join discusses d on d.dis_id = s.id) + on s.id = str.shixun_id) on tr.id = str.tag_repertoire_id + group by d.dis_id order by cnt desc) a limit 9").map{|ht| ht.attributes.dup} + memos = memo_list memos + user_info = format_for_current_user current_user + hot_memos = Memo.field_for_recommend.posts.hot.limit(4) + hot_memos = + hot_memos.map do |hm| + replies_count = Memo.where(:root_id => hm.id).count + hm.attributes.dup.merge({replies_count: replies_count}) + end + + my_memos_count = Memo.user_posts(current_user.id).count + {memo_list: memos, memo_count: memo_count, hot_memos: hot_memos, hot_tags: hot_tags, + my_memos_count: my_memos_count, tidding_count: tidding_count, current_user: user_info, + recommend_shixuns: recommends} + end + + # 添加评论 + def create(params, current_user) + begin + Discuss.create!( + dis_id: params[:shixun_id], dis_type: 'Shixun', content: params[:content].gsub(' \;', '').strip, user_id: current_user.id, + praise_count: 0, position: params[:position], challenge_id: params[:challenge_id], hidden: !current_user.admin? + ) + # 发送手机通知 + Trustie::Sms.send(mobile:'18173242757', send_type:'discuss', name:'管理员') + rescue Exception => e + raise(e.message) + end + end + + # 回复评论 + def reply(params, current_user) + begin + base_dicuss params[:id] + Discuss.create!( + content: params[:content].gsub(' \;', '').strip, user_id: current_user.id, parent_id: params[:id], + root_id: @discuss.root_id || params[:id], praise_count: 0, challenge_id: @discuss.challenge_id, + dis_id: @discuss.dis_id, dis_type: @discuss.dis_type, position: @discuss.position, hidden: !current_user.admin? + ) + rescue Exception => e + raise(e.message) + end + end + + # 隐藏评论功能 + def hidden(params, current_user) + discuss = Discuss.select([:id, :hidden, :dis_id]).find(params[:id]) + shixun = Shixun.find(discuss.try(:dis_id)) + if current_user.manager_of_shixun?(shixun) + if params[:hidden] == "1" + discuss.update_attribute(:hidden, true) + elsif params[:hidden] == "0" + discuss.update_column("hidden", false) + end + else + raise("你没有权限") + end + end + + # 点/取消赞 + # 一个用户只能一次 + def plus params, current_user + pt = PraiseTread.where(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type], + :user_id => current_user, :praise_or_tread => 1).first + # 如果当前用户已赞过,则不能重复赞 + if params[:type] == 1 && pt.blank? + PraiseTread.create!(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type], + :user_id => current_user.id, :praise_or_tread => 1) if pt.blank? + else + pt.destroy if pt.present? # 如果已赞过,则删掉这条赞(取消);如果没赞过,则为非法请求不处理 + end + + return {:praise_count => PraiseTread.where(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type], + :praise_or_tread => 1).count} + end + + # 奖励金币 + def reward_code params, current_user + # 仅admin操作 + unless current_user.admin? + raise("403") + end + + ActiveRecord::Base.transaction do + container_id = params[:id] + container_type = params[:container_type] + score = params[:score] + user_id = params[:user_id] + user = User.select([:id, :login, :grade]).find(user_id) + + # 金币来源记录 + Grade.create(:user_id => user_id, :container_id => container_id, :container_type => container_type, :score => score) + # 更新用户总金币数 + user.update_column(:grade, (score.to_i + user.grade.to_i)) + # 多种类型都可以奖励金币 + case container_type + when 'Memo', 'Post' + container = Memo.find(container_id) + score = score.to_i + container.reward.to_i + container.update_attribute(:reward, score) + when 'Discusses' + container = Discuss.select([:id, :reward]).find(params[:id]) + score = score.to_i + container.reward.to_i + container.update_attribute(:reward, score) + end + return {:code => score} + end + end + + # 基本查询 + def base_dicuss id + @discuss = Discuss.select([:id, :hidden, :reward, :dis_type, :dis_id, :position, :challenge_id, :root_id]).find(id) + end + + protected + def memo_list memos + memos.map do |m| + user = User.find(m.user_id) + praise_count = m.praise_tread.where(:praise_or_tread => 1).count + replies_count = Discuss.where(:root_id => m.id).count + shixun_tag = m.dis.tag_repertoires.map(&:name) + m.attributes.dup.except("user_id", "dis_id", "dis_type", "root_id").merge({ + subject: (message_content m.content), + username: user.show_name, + login: user.login, + praise_count: praise_count, + replies_count: replies_count, + image_url: url_to_avatar(user), + shixun_tag: shixun_tag, + tpm_url: "/shixuns/#{m.dis.identifier}/shixun_discuss" + }) + end + end + + def format_for_current_user current_user + {username: current_user.show_name, login: current_user.login, user_id: current_user.id, image_url: url_to_avatar(current_user), admin: current_user.admin?} + end + + def recommends + hot_shixuns = Shixun.field_for_recommend.published.order("myshixuns_count desc").limit(2) + newest_shixuns = Shixun.field_for_recommend.published.order("created_at desc").limit(2) + recommend_shixuns = [] + hot_shixuns.each do |hs| + recommend_shixuns << {:id => hs.id, :name => hs.name, :identifier => hs.identifier, :myshixuns_count => hs.myshixuns_count, :image_url => url_to_avatar(hs)} + end + newest_shixuns.each do |ns| + recommend_shixuns << {:id => ns.id, :name => ns.name, :identifier => ns.identifier, :myshixuns_count => ns.myshixuns_count, :image_url => url_to_avatar(ns)} + end + return recommend_shixuns + end + + # 将数据库对象转换成哈希对象 + def object_to_hash objects + objects.map{|o| o.attributes.dup} + end + + def unviewed_tiddings current_user + new_tidings_count = current_user.tidings.where("created_at > '#{current_user.onclick_time.onclick_time}'").count + new_pri_message_count = current_user.private_messages.where("created_at > '#{current_user.onclick_time.onclick_time}'").count + count = new_tidings_count + new_pri_message_count + return count + end + +end \ No newline at end of file diff --git a/app/services/duplicate_course_service.rb b/app/services/duplicate_course_service.rb new file mode 100644 index 000000000..c9e991d7f --- /dev/null +++ b/app/services/duplicate_course_service.rb @@ -0,0 +1,147 @@ +class DuplicateCourseService < ApplicationService + attr_reader :origin_course, :user, :course + + def initialize(origin_course, user) + @user = user + @origin_course = origin_course + end + + def call + ActiveRecord::Base.transaction do + @course = copy_course! + + copy_course_modules! + + join_course! + + copy_homework_commons! + + copy_exercises! + + copy_polls! + + copy_attachments! + + course + end + end + + private + + def copy_course! + create_attrs = origin_course.as_json(only: %i[name class_period credit course_list_id]) + create_attrs.merge!(tea_id: user.id, school_id: user.school_id, is_public: 0, is_copy: 1) + + Course.create!(create_attrs) + end + + def copy_course_modules! + origin_course.course_modules.each do |course_module| + attrs = course_module.as_json(only: %i[module_type position hidden module_name]) + CourseModule.create!(attrs.merge(course_id: course.id)) + end + end + + def join_course! + CourseMember.create!(course_id: course.id, user_id: user.id, role: 1) + end + + def copy_homework_commons! + origin_course.homework_commons.where(homework_type: %i[normal group practice]).find_each do |origin_homework| + homework_attrs = origin_homework.as_json(only: %i[name description homework_type homework_bank_id reference_answer]) + + homework = HomeworkCommon.create!(homework_attrs.merge(user_id: user.id, course_id: course.id)) + + origin_homework.attachments.find_each do |origin_attachment| + attachment = origin_attachment.copy + attrs = { container: homework, author_id: origin_homework.user_id, copy_from: origin_attachment.id } + attachment.assign_attributes(attrs) + attachment.save! + + origin_attachment.increment!(:quotes) + end + + homework.create_homework_detail_manual! + + if homework.group_homework_type? + attrs = origin_homework.homework_detail_group.as_json(only: %i[min_num max_num base_on_project]) + homework.create_homework_detail_group!(attrs) + elsif homework.practice_homework_type? + HomeworkCommonsShixun.create!(homework_common_id: homework.id, shixun_id: origin_homework.homework_commons_shixun.shixun_id) + HomeworksService.new.create_shixun_homework_cha_setting(homework, origin_homework.shixuns.first) + end + + origin_homework.increment!(:quotes) + origin_homework.homework_bank.increment!(:quotes) if origin_homework.homework_bank + end + end + + def copy_exercises! + origin_course.exercises.find_each do |origin_exercise| + attrs = origin_exercise.as_json(only: %i[exercise_name exercise_description exercise_bank_id]) + exercise = course.exercises.create!(attrs.merge(user_id: user.id)) + + origin_exercise.exercise_questions.find_each do |origin_question| + question_attrs = origin_question.as_json(only: %i[question_title question_type question_number question_score]) + question_attrs[:question_type] ||= 1 + question = exercise.exercise_questions.create!(question_attrs) + + exercise_choice_map = {} + origin_question.exercise_choices.each_with_index do |origin_choice, index| + choice_attrs = { choice_position: index + 1, choice_text: origin_choice.choice_text } + choice = question.exercise_choices.create!(choice_attrs) + + exercise_choice_map[origin_choice.id] = choice.id + end + + origin_question.exercise_standard_answers.find_each do |origin_answer| + question.exercise_standard_answers.create!( + exercise_choice_id: exercise_choice_map[origin_answer.exercise_choice_id], + answer_text: origin_answer.answer_text + ) + end + end + + origin_exercise.exercise_bank.increment!(:quotes) if exercise.exercise_bank + end + end + + def copy_polls! + origin_course.polls.includes(poll_questions: :poll_answers).find_each do |origin_poll| + poll_attrs = origin_poll.as_json(only: %i[polls_name polls_description exercise_bank_id]) + poll = course.polls.create!(poll_attrs.merge(user_id: user.id)) + + origin_poll.poll_questions.each do |origin_question| + attr_names = %i[question_title question_type is_necessary question_number max_choices min_choices] + question_attrs = origin_question.as_json(only: attr_names) + question_attrs[:question_type] ||= 1 + + question = poll.poll_questions.create!(question_attrs) + + origin_question.poll_answers.each_with_index do |origin_answer, index| + question.poll_answers.create!(answer_position: index + 1, answer_text: origin_answer.answer_text) + end + end + + origin_poll.exercise_bank.increment!(:quotes) if origin_poll.exercise_bank + end + end + + def copy_attachments! + origin_course.attachments.each do |origin_attachment| + attachment = origin_attachment.copy + attachment.tag_list.add(origin_attachment.tag_list) # tag关联 + attachment.container = course + attachment.created_on = Time.now + attachment.publish_time = nil + attachment.author_id = User.current.id + attachment.copy_from = origin_attachment.copy_from || origin_attachment.id + attachment.is_publish = 0 + attachment.attachtype ||= 4 + + attachment.save! + + origin_course.update_quotes(attachment) + end + end +end \ No newline at end of file diff --git a/app/services/ecs/calculate_course_evaluation_service.rb b/app/services/ecs/calculate_course_evaluation_service.rb new file mode 100644 index 000000000..bd551dbf4 --- /dev/null +++ b/app/services/ecs/calculate_course_evaluation_service.rb @@ -0,0 +1,124 @@ +class Ecs::CalculateCourseEvaluationService < ApplicationService + attr_reader :ec_course + + def initialize(ec_course) + @ec_course = ec_course + end + + def call + ActiveRecord::Base.transaction do + clear_student_score! + + calculate_student_score_target! + + calculate_graduation_requirement! + end + end + + private + + def clear_student_score! + ec_course.ec_course_student_scores.destroy_all + end + + def requirement_passed?(standard_value, real_value) + standard_value && real_value && real_value >= standard_value ? 1 : 0 + end + + def calculate_student_score_target! + complete_target_count = 0 + course_targets = ec_course.ec_course_targets.includes(ec_achievement_evaluation_relates: :ec_course_achievement_method) + course_targets.find_each do |target| + target.ec_achievement_evaluation_relates.each do |relate| + achievement_method = relate.ec_course_achievement_method + + total = achievement_method.ec_achievement_evaluation_relates.count + percentage = total.zero? ? 0 : achievement_method.percentage.fdiv(total) + + achievements = EcStudentAchievement.where(ec_course_evaluation_id: achievement_method.ec_course_evaluation_id) + + achievements = + if relate.ec_course_evaluation_subitem_id.blank? || relate.ec_course_evaluation_subitem_id == -1 + achievements.where(position: relate.position) + else + achievements.where(ec_course_evaluation_subitem_id: relate.ec_course_evaluation_subitem_id) + end + + # 遍历学生成绩统计数据 + achievements.find_each do |achievement| + student_score = EcCourseStudentScore.find_or_initialize_by( + ec_course_id: ec_course.id, + ec_year_student_id: achievement.ec_year_student_id + ) + + score = achievement_method.score.zero? || achievement.score.nil? ? 0 : (achievement.fdiv(achievement_method.score) * percentage).round(3) + + if student_score.new_record? + student_score.student_name = achievement.student_name + student_score.student_number = achievement.student_number + student_score.save! + + create_params = { + ec_course_id: ec_course.id, ec_year_student_id: achievement.ec_year_student_id, + ec_course_target_id: target.id, eaer_id: relate.id, + ec_target_position: target.position, score: score + } + student_score.ec_student_score_targets.create!(create_params) + else + score_target = EcStudentScoreTarget.find_or_initialize_by( + ec_course_id: ec_course.id, + ec_year_student_id: achievement.ec_year_student_id, + ec_course_student_score_id: student_score.id, + ec_course_target_id: target.id, + ec_target_position: target.position, + eaer_id: relate.id + ) + + score_target.score = score_target.score.to_f + score + score_target.save! + end + end + end + + # 计算该课程目标是否完成 + count = target.ec_student_score_targets.count + score = target.ec_student_score_targets.sum(:score) + average = count.zero? ? 0 : score.fdiv(count) + complete_target_count += 1 if target.standard_grade && target.standard_grade <= average + end + + ec_course.update!(complete_target_count: complete_target_count) + end + + def calculate_graduation_requirement! + student_scores = ec_course.ec_course_student_scores.joins(:ec_course_target).group(:ec_course_target_id) + student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id') + student_score_map = student_scores.group_by { |item| item.ec_course_target_id } + + subitem_targets = ec_course.ec_graduation_subitem_course_targets.includes(:ec_graduation_subitem, :ec_course_target) + subitem_targets.group_by { |subitem_target| subitem_target.ec_graduation_subitem }.each do |subitem, subitem_target_arr| + support = subitem.ec_course_supports.find_by(ec_course_id: ec_course.id) + next if support.blank? + + total_weight = 0.0 + total_score = 0.0 + subitem_target_arr.each do |subitem_target| + target = subitem_target.ec_course_target + student_score = student_score_map[target.id].first + + total_weight += target.weigths.to_f + total_score += student_score.average_score.round(2) * target.weigths.to_f + end + + target_value = support.weights.to_f * ec_course.ec_year.calculation_value.to_f + real_value = total_weight.zero? ? 0 : (total_score * support.weights.to_f) / (total_weight * 100) + + cal = support.ec_graduation_requirement_calculation || support.build_ec_graduation_requirement_calculation + + cal.target_value = target_value.round(3) + cal.real_value = real_value.round(3) + cal.status = requirement_passed?(target_value, real_value) + cal.save! + end + end +end diff --git a/app/services/ecs/copy_ec_year_service.rb b/app/services/ecs/copy_ec_year_service.rb new file mode 100644 index 000000000..87cbe0845 --- /dev/null +++ b/app/services/ecs/copy_ec_year_service.rb @@ -0,0 +1,344 @@ +class CopyEcYearService < ApplicationService + attr_reader :major_school, :to_year + + def initialize(major_school, year) + @major_school = major_school + @to_year = major_school.ec_years.new(year: year) + end + + def call + if from_year.blank? + to_year.save! + return to_year + end + + # 专业第一次创建届别时,复制示例专业2017届 + ActiveRecord::Base.transaction do + copy_ec_year! + + copy_graduation_requirement! + + copy_training_objective! + + new_major_school? ? copy_template_ec_course! : copy_ec_courses! + end + + to_year + end + + private + + def new_major_school? + @_new_major ||= major_school.ec_years.count.zero? + end + + def from_year + @_from_year ||= new_major_school? ? template_major_year : to_year.prev_year + end + + def template_major_year + EcYear.joins(:ec_major_school).where(ec_major_schools: { template_major: true }).find_by_year('2017') + end + + def copy_ec_year! + to_year.calculation_value = from_year.calculation_value + to_year.save! + end + + def copy_graduation_requirement! + requirements = from_year.ec_graduation_requirements.includes(ec_graduation_subitems: :ec_require_sub_vs_standards) + + requirements.each do |requirement| + to_requirement = to_year.ec_graduation_requirements.new + to_requirement.attributes = requirement.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at') + to_requirement.save! + + # 记录对应关系,创建支撑时使用 + graduation_requirement_map[requirement.id] = to_requirement.id + + copy_graduation_subitems(requirement, to_requirement) + end + end + + def copy_graduation_subitems(requirement, to_requirement) + requirement.ec_graduation_subitems.each do |item| + to_item = to_requirement.ec_graduation_subitems.new + to_item.attributes = item.attributes.except('id', 'ec_graduation_requirement_id', 'created_at', 'updated_at') + to_item.save! + + # 记录对应关系,创建支撑时使用 + graduation_subitem_map[item.id] = to_item.id + + copy_requirement_standard_supports!(item, to_item) + end + end + + def copy_requirement_standard_supports!(graduation_subitem, to_graduation_subitem) + graduation_subitem.ec_require_sub_vs_standards.each do |support| + to_support = to_graduation_subitem.ec_require_sub_vs_standards.new + to_support.attributes = support.attributes.except('id', 'ec_graduation_subitem_id', 'created_at', 'updated_at') + to_support.save! + end + end + + def copy_training_objective! + training_objective = from_year.ec_training_objective + return if training_objective.blank? + + attributes = training_objective.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at') + to_training_objective = to_year.create_ec_training_objective!(attributes) + + copy_training_subitems!(training_objective, to_training_objective) + end + + def copy_training_subitems!(training_objective, to_training_objective) + training_subitems = training_objective.ec_training_subitems.includes(:ec_requirement_vs_objectives) + + training_subitems.each do |item| + to_item = to_training_objective.ec_training_subitems.new + to_item.attributes = item.attributes.except('id', 'ec_training_objective_id', 'created_at', 'updated_at') + to_item.save! + + copy_requirement_vs_objectives!(item, to_item) + end + end + + def copy_requirement_vs_objectives!(training_item, to_training_item) + training_item.ec_requirement_vs_objectives.each do |support| + to_support = to_training_item.ec_requirement_vs_objectives.new(status: support.status) + to_support.ec_graduation_requirement_id = graduation_requirement_map[support.ec_graduation_requirement_id] + to_support.save! + end + end + + def copy_template_ec_course! + course = from_year.ec_courses.includes( + :ec_score_levels, + ec_course_evaluations: :ec_course_evaluation_subitems, + ec_course_targets: :ec_graduation_subitem_course_targets, + ec_course_achievement_methods: :ec_achievement_evaluation_relates, + ec_course_supports: :ec_graduation_subitem_courses + ).find_by_name('数据库原理') + + to_course = to_year.ec_courses.new + to_course.attributes = course.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at') + to_course.save! + + course_map[course.id] = to_course.id + + copy_course_evaluations!(course, to_course) + copy_course_targets!(course, to_course) + copy_course_achievement_methods!(course, to_course) + copy_ec_course_supports!(course, to_course) + copy_score_levels!(course, to_course) + + # 复制示例时需要复制学生和成绩数据 + copy_year_students! + end + + def copy_ec_courses! + courses = from_year.ec_courses.includes( + :ec_score_levels, + ec_course_evaluations: :ec_course_evaluation_subitems, + ec_course_targets: :ec_graduation_subitem_course_targets, + ec_course_achievement_methods: :ec_achievement_evaluation_relates, + ec_course_supports: :ec_graduation_subitem_courses + ) + + courses.each do |course| + to_course = to_year.ec_courses.new + to_course.attributes = course.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at') + to_course.save! + + course_map[course.id] = to_course.id + + copy_course_evaluations!(course, to_course) + copy_course_targets!(course, to_course) + copy_course_achievement_methods!(course, to_course) + copy_ec_course_supports!(course, to_course) + copy_score_levels!(course, to_course) + end + end + + def copy_course_evaluations!(course, to_course) + course.ec_course_evaluations.each do |evaluation| + to_evaluation = to_course.ec_course_evaluations.new + to_evaluation.attributes = evaluation.attributes.except('id', 'ec_course_id', 'created_at', 'updated_at') + to_evaluation.save! + + course_evaluation_map[evaluation.id] = to_evaluation.id + + copy_course_evaluation_subitems!(evaluation, to_evaluation) + end + end + + def copy_course_evaluation_subitems!(evaluation, to_evaluation) + evaluation.ec_course_evaluation_subitems.each do |item| + to_item = to_evaluation.ec_course_evaluation_subitems.new + to_item.attributes = item.attributes.except('id', 'ec_course_evaluation_id', 'created_at', 'updated_at') + to_item.save! + + course_evaluation_subitem_map[item.id] = to_item.id + end + end + + def copy_course_targets!(course, to_course) + course.ec_course_targets.each do |target| + to_target = to_course.ec_course_targets.new + to_target.attributes = target.attributes.except('id', 'ec_course_id', 'created_at', 'updated_at') + to_target.save! + + course_target_map[target.id] = to_target.id + + copy_graduation_subitem_course_targets!(target, to_target) + end + end + + def copy_graduation_subitem_course_targets!(target, to_target) + target.ec_graduation_subitem_course_targets.each do |support| + to_support = to_target.ec_graduation_subitem_course_targets.new + to_support.attributes = support.attributes.except('id', 'ec_course_target_id', 'ec_graduation_subitem_id', 'created_at', 'updated_at') + to_support.ec_graduation_subitem_id = graduation_subitem_map[support.ec_graduation_subitem_id] + to_support.save! + end + end + + def copy_course_achievement_methods!(course, to_course) + course.ec_course_achievement_methods.each do |from| + to = to_course.ec_course_achievement_methods.new + to.attributes = from.attributes.except('id', 'ec_course_id', 'ec_course_target_id', 'ec_course_evaluation_id', + 'ec_course_evaluation_subitem_id', 'created_at', 'updated_at') + + to.ec_course_target_id = course_target_map[from.ec_course_target_id] + to.ec_course_evaluation_id = course_evaluation_map[from.ec_course_evaluation_id] + to.ec_course_evaluation_subitem_id = course_evaluation_subitem_map[from.ec_course_evaluation_subitem_id] + to.save! + + copy_achievement_evaluation_relates!(from, to) + end + end + + def copy_achievement_evaluation_relates!(method, to_method) + method.ec_achievement_evaluation_relates.each do |relate| + to_relate = to_method.ec_achievement_evaluation_relates.new + to_relate.attributes = relate.attributes.except('id', 'ec_course_achievement_method_id', 'ec_course_target_id', + 'ec_course_evaluation_subitem_id', 'created_at', 'updated_at') + to_relate.ec_course_target_id = course_target_map[relate.ec_course_target_id] + # 可能不存在,所以为 -1 + to_relate.ec_course_evaluation_subitem_id = course_evaluation_subitem_map[relate.ec_course_evaluation_subitem_id] || -1 + to_relate.save! + + achievement_evaluation_relates_map[relate.id] = to_relate.id + end + end + + def copy_ec_course_supports!(course, to_course) + course.ec_course_supports.each do |support| + to_support = to_course.ec_course_supports.new + to_support.attributes = support.attributes.except('id', 'ec_course_id', 'created_at', 'updated_at') + to_support.save! + + copy_graduation_subitem_courses!(support, to_support) + end + end + + def copy_graduation_subitem_courses!(course_support, to_course_support) + course_support.ec_graduation_subitem_courses.each do |item| + to_item = to_course_support.ec_graduation_subitem_courses.new + to_item.attributes = item.attributes.except('id', 'ec_course_support_id', 'ec_graduation_subitem_id', + 'created_at', 'updated_at') + to_item.ec_graduation_subitem_id = graduation_subitem_map[item.ec_graduation_subitem_id] + to_item.save! + end + end + + def copy_score_levels!(course, to_course) + course.ec_score_levels.each do |level| + to_level = to_course.ec_score_levels.new + to_level.attributes = level.attributes.except('id', 'ec_course_id', 'created_at', 'updated_at') + to_level.save! + end + end + + def copy_year_students! + students = from_year.ec_year_students.includes(:ec_student_achievements, :ec_course_student_scores, :ec_student_score_targets) + + students.each do |student| + to_student = to_year.ec_year_students.new + to_student.attributes = student.attributes.except('id', 'ec_year_id', 'created_at', 'updated_at') + to_student.save! + + copy_student_achievements!(student, to_student) + copy_course_student_scores!(student, to_student) + copy_student_score_targets!(student, to_student) + end + end + + def copy_student_achievements!(student, to_student) + student.ec_student_achievements.each do |achievement| + to_achievement = to_student.ec_student_achievements.new + to_achievement.attributes = achievement.attributes.except('id', 'ec_year_student_id', 'ec_course_evaluation_id', + 'ec_course_evaluation_subitem_id', 'created_at', 'updated_at') + to_achievement.ec_course_evaluation_id = course_evaluation_map[achievement.ec_course_evaluation_id] + to_achievement.ec_course_evaluation_subitem_id = course_evaluation_subitem_map[achievement.ec_course_evaluation_subitem_id] + to_achievement.save! + end + end + + def copy_course_student_scores!(student, to_student) + student.ec_course_student_scores.each do |score| + to_score = to_student.ec_course_student_scores.new + to_score.attributes = score.attributes.except('id', 'ec_year_student_id', 'ec_course_id', 'created_at', 'updated_at') + to_score.ec_course_id = course_map[score.ec_course_id] + to_score.save! + + course_student_score_map[score.id] = to_score.id + end + end + + def copy_student_score_targets!(student, to_student) + student.ec_student_score_targets.each do |target| + to_target = to_student.ec_student_score_targets.new + to_target.attributes = target.attributes.except('id', 'ec_course_id', 'ec_course_student_score_id', + 'ec_course_target_id', 'ec_year_student_id', 'eaer_id', + 'created_at', 'updated_at') + to_target.ec_course_id = course_map[target.ec_course_id] + to_target.ec_course_student_score_id = course_student_score_map[target.ec_course_student_score_id] + to_target.ec_course_target_id = course_target_map[target.ec_course_target_id] + to_target.eaer_id = achievement_evaluation_relates_map[target.eaer_id] + to_target.save! + end + end + + def graduation_requirement_map + @_graduation_requirement_map ||= {} + end + + def graduation_subitem_map + @_graduation_subitem_map ||= {} + end + + def course_map + @_course_map ||= {} + end + + def course_evaluation_map + @_course_evaluation_map ||= {} + end + + def course_evaluation_subitem_map + @_course_evaluation_subitem_map ||= {} + end + + def achievement_evaluation_relates_map + @_achievement_evaluation_relates_map ||= {} + end + + def course_target_map + @_course_target_map ||= {} + end + + def course_student_score_map + @_course_student_score_map ||= {} + end +end \ No newline at end of file diff --git a/app/services/ecs/create_course_achievement_method_service.rb b/app/services/ecs/create_course_achievement_method_service.rb new file mode 100644 index 000000000..01f09ff2b --- /dev/null +++ b/app/services/ecs/create_course_achievement_method_service.rb @@ -0,0 +1,66 @@ +class Ecs::CreateCourseAchievementMethodsService < ApplicationService + include AcceptsNestedAttributesHelper + + attr_reader :course_target, :params + + def initialize(course_target, params) + @course_target = course_target + @params = params + end + + def call + Ecs::CreateCourseAchievementMethodsForm.new( + ec_course: course_target.ec_course, + course_achievement_methods: params[:course_achievement_methods] + ).validate! + + accepts_attributes = build_accepts_nested_attributes( + course_target, course_target.ec_course_achievement_methods, + params[:course_achievement_methods], + &method(:deal_course_achievement_method_attribute!) + ) + + course_target.assign_attributes(ec_course_achievement_methods_attributes: accepts_attributes) + course_target.save! + course_target + end + + private + + def deal_course_achievement_method_attribute!(item) + # 创建新的评价方法时,全部为新建 + if item[:id].blank? || course_target.ec_course_achievement_methods.find_by(id: item[:id]).blank? + item[:ec_achievement_evaluation_relates_attributes] = + Array(*item[:course_evaluation_subitem_ids]).uniq.map do |subitem_id| + { ec_course_evaluation_subitem_id: subitem_id.to_i } + end + return + end + + achievement_method = course_target.ec_course_achievement_methods.find_by(id: item[:id]) + relates = achievement_method.ec_achievement_evaluation_relates + + # 获取传入的 subitem id数组和已存在的 subitem id数组 + old_subitem_ids = relates.map(&:ec_course_evaluation_subitem_id).uniq + new_subitem_ids = Array(*item[:course_evaluation_subitem_ids]).map(&:to_i).uniq + + # 分别得到需要移除的 subitem ID数组和需要创建的 subitem ID数组 + destroy_subitem_ids = old_subitem_ids - new_subitem_ids + create_subitem_ids = new_subitem_ids - old_subitem_ids + + # 生成需要创建关系的 subitem id 数据 + create_attributes = create_subitem_ids.map { |item_id| { ec_course_evaluation_subitem_id: item_id } } + + # 处理需要更新或者删除的记录 + exists_attributes = relates.map do |relate| + if destroy_subitem_ids.include?(relate.ec_course_evaluation_subitem_id) + { id: relate.id, _destroy: true } + else + relate.as_json(only: %i[id ec_course_evaluation_subitem_id ec_course_achievement_method_id]) + end + end + + # 相加得到accepts_nested_attributes + item[:ec_achievement_evaluation_relates_attributes] = create_attributes + exists_attributes + end +end \ No newline at end of file diff --git a/app/services/ecs/create_course_manager_service.rb b/app/services/ecs/create_course_manager_service.rb new file mode 100644 index 000000000..58e803bcf --- /dev/null +++ b/app/services/ecs/create_course_manager_service.rb @@ -0,0 +1,29 @@ +class Ecs::CreateCourseManagerService < ApplicationService + Error = Class.new(StandardError) + + COURSE_MANAGER_COUNT_LIMIT = 2 # 课程管理员数量限制 + + attr_reader :ec_course, :user_id + + def initialize(ec_course, user_id) + @ec_course = ec_course + @user_id = user_id + end + + def call + user = User.find_by(id: params[:user_id]) + raise Error, '该用户不存在' if user.blank? + + if ec_course.ec_course_users.exists?(user_id: user.id) + raise Error, '该用户已经是该课程的管理员了' + end + + if ec_course.ec_course_users.count >= COURSE_MANAGER_COUNT_LIMIT + raise Error, '该课程管理员数量已达上限' + end + + ec_course.ec_course_users.create!(user: user) + + user + end +end \ No newline at end of file diff --git a/app/services/ecs/create_course_service.rb b/app/services/ecs/create_course_service.rb new file mode 100644 index 000000000..dba162189 --- /dev/null +++ b/app/services/ecs/create_course_service.rb @@ -0,0 +1,42 @@ +class Ecs::CreateCourseService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :ec_year, :params + + def initialize(ec_year, params) + @ec_year = ec_year + @params = params + end + + def call + name = params[:name].to_s.strip + if ec_year.ec_courses.exists?(name: name) + raise Error, '课程名称重复' + end + + ec_course = nil + ActiveRecord::Base.transaction do + ec_course = ec_year.ec_courses.create!(name: name) + + create_default_score_levels!(ec_course) + end + + ec_course + end + + private + + def create_default_score_levels!(ec_course) + EcScoreLevel.bulk_insert(:ec_course_id, :score, :level, :position) do |worker| + [ + { ec_course_id: ec_course.id, score: 90, level: '优秀', position: 1 }, + { ec_course_id: ec_course.id, score: 80, level: '良好', position: 2 }, + { ec_course_id: ec_course.id, score: 70, level: '中等', position: 3 }, + { ec_course_id: ec_course.id, score: 60, level: '及格', position: 4 }, + { ec_course_id: ec_course.id, score: 60, level: '不及格', position: 5 }, + ].each do |attributes| + worker.add attributes + end + end + end +end diff --git a/app/services/ecs/create_course_targets_service.rb b/app/services/ecs/create_course_targets_service.rb new file mode 100644 index 000000000..8ef3afea7 --- /dev/null +++ b/app/services/ecs/create_course_targets_service.rb @@ -0,0 +1,31 @@ +class Ecs::CreateCourseTargetsService < ApplicationService + include AcceptsNestedAttributesHelper + + attr_reader :ec_course, :params + + def initialize(ec_course, params) + @ec_course = ec_course + @params = params + end + + def call + accepts_attributes = build_accepts_nested_attributes( + ec_course, ec_course.ec_course_targets, + params[:course_targets], + &method(:deal_course_target_attribute!) # 相当于方法后面写代码块,然后把参数传入方法: a(&method(:b)) == a { |c| b(c) } + ) + + ec_course.assign_attributes(ec_course_targets_attributes: accepts_attributes) + ec_course.save! + ec_course + end + + private + + def deal_course_target_attribute!(target) + target[:content] = target[:content].to_s.strip + target[:weight] = target[:weight].to_f.round(2) + target[:ec_graduation_subitem_course_targets_attributes] = + [{ ec_graduation_subitem_id: target.delete(:graduation_subitem_id) }] + end +end \ No newline at end of file diff --git a/app/services/ecs/create_major_manager_service.rb b/app/services/ecs/create_major_manager_service.rb new file mode 100644 index 000000000..befe80706 --- /dev/null +++ b/app/services/ecs/create_major_manager_service.rb @@ -0,0 +1,31 @@ +class Ecs::CreateMajorManagerService < ApplicationService + Error = Class.new(StandardError) + + MAJOR_MANAGER_COUNT_LIMIT = 5 # 专业管理员数量限制 + + attr_reader :major_school, :user_id + + def initialize(major_school, user_id) + @major_school = major_school + @user_id = user_id + end + + def call + raise Error, '示例专业不能添加管理员' if major_school.template_major? + + user = User.find_by(id: params[:user_id]) + raise Error, '该用户不存在' if user.blank? + + if major_school.ec_major_school_users.exists?(user_id: user.id) + raise Error, '该用户已经是该专业的管理员了' + end + + if major_school.ec_major_school_users.count >= MAJOR_MANAGER_COUNT_LIMIT + raise Error, '该专业管理员数量已达上限' + end + + major_school.ec_major_school_users.create!(user: user) + + user + end +end \ No newline at end of file diff --git a/app/services/ecs/create_score_levels_service.rb b/app/services/ecs/create_score_levels_service.rb new file mode 100644 index 000000000..031bead1c --- /dev/null +++ b/app/services/ecs/create_score_levels_service.rb @@ -0,0 +1,45 @@ +class Ecs::CreateScoreLevelsService < ApplicationService + include AcceptsNestedAttributesHelper + + attr_reader :ec_course, :params + + def initialize(ec_course, params) + @ec_course = ec_course + @params = params + end + + def call + check_score_orderly! + + deal_score_levels_params! + + accepts_attributes = build_accepts_nested_attributes(ec_course, ec_course.ec_score_levels, params[:score_levels]) + + ec_course.assign_attributes(ec_score_levels_attributes: accepts_attributes) + ec_course.save! + ec_course + end + + private + + def check_score_orderly! + size = params[:score_levels].size + return if size < 2 + + score = nil + params[:score_levels].each_with_index do |item, index| + if score && item.score.to_i > score || (index + 1 == size && item.score.to_i >= score) + raise Error, '分数必须降序排列' + end + + score = item.score.to_i + end + end + + def deal_score_levels_params! + params[:score_levels].each_with_index do |item, index| + item[:position] = index + 1 + item[:level] = item[:level].to_s.strip + end + end +end \ No newline at end of file diff --git a/app/services/ecs/create_training_objective_service.rb b/app/services/ecs/create_training_objective_service.rb new file mode 100644 index 000000000..c3dc3c8a6 --- /dev/null +++ b/app/services/ecs/create_training_objective_service.rb @@ -0,0 +1,31 @@ +class Ecs::CreateTrainingObjectiveService < ApplicationService + include AcceptsNestedAttributesHelper + + attr_reader :training_objective, :params + + def initialize(ec_year, params) + @params = params + @training_objective = ec_year.ec_training_objective || ec_year.build_ec_training_objective + end + + def call + training_objective.content = params[:content].to_s.strip + + attributes = build_accepts_nested_attributes( + training_objective, + training_objective.ec_training_subitems, + params[:training_subitems], + &method(:training_subitem_param_handler) + ) + training_objective.assign_attributes(ec_training_subitems_attributes: attributes) + + training_objective.save! + training_objective + end + + private + + def training_subitem_param_handler(item) + item[:content] = item[:content].to_s.strip + end +end \ No newline at end of file diff --git a/app/services/ecs/import_course_service.rb b/app/services/ecs/import_course_service.rb new file mode 100644 index 000000000..016336940 --- /dev/null +++ b/app/services/ecs/import_course_service.rb @@ -0,0 +1,31 @@ +class Ecs::ImportCourseService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :ec_year, :attachment + + def initialize(ec_year, attachment_id) + @ec_year = ec_year + @attachment = Attachment.find_by(id: attachment_id) + end + + def call + raise_import_error('文件不存在') if attachment.blank? + + path = attachment.diskfile + excel = Ecs::ImportCourseExcel.new(path) + + created_count = 0 + EcCourse.bulk_insert(:name, :created_at, :updated_at) do |worker| + excel.read_each do |course_name| + next if ec_year.ec_courses.exists?(name: course_name) + + worker.add(name: course_name) + created_count += 1 + end + end + + created_count + rescue BaseImportExcel::Error => ex + raise Error, ex.message + end +end \ No newline at end of file diff --git a/app/services/ecs/import_course_student_achievement_service.rb b/app/services/ecs/import_course_student_achievement_service.rb new file mode 100644 index 000000000..b4c9e6bc5 --- /dev/null +++ b/app/services/ecs/import_course_student_achievement_service.rb @@ -0,0 +1,81 @@ +class Ecs::ImportCourseStudentAchievementService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :ec_year, :course_evaluation, :attachment + + def initialize(course_evaluation, attachment_id) + @course_evaluation = course_evaluation + @ec_year = course_evaluation.ec_course.ec_year + @attachment = Attachment.find_by(id: attachment_id) + end + + def call + raise Error, '文件不存在' if attachment.blank? + raise Error, '请先导入学生数据' if ec_year.ec_year_students.count.zero? + + path = attachment.diskfile + excel = Ecs::ImportAchievementExcel.new(path) + + ActiveRecord::Base.transaction do + course_evaluation.ec_student_achievements.delete_all + + handler = excel.average_score_template? ? :average_score_handler : :detail_score_handler + EcStudentAchievement.bulk_insert(*achievement_columns) do |worker| + excel.read_each do |arr| + send(handler, worker, arr) + end + end + + score_type = excel.average_score_template? ? :average : :detail + current_course_evaluation.update!(import_status: true, score_type: score_type) + end + rescue BaseImportExcel::Error => ex + raise Error, ex.message + end + + private + + def achievement_columns + %i[ + score student_name student_number position ec_year_student_id + ec_course_evaluation_id ec_course_evaluation_subitem_id created_at updated_at + ] + end + + def average_score_handler(worker, arr) + items_size = course_evaluation.ec_course_evaluation_subitems.size + + ec_year.ec_year_students.find_each do |student| + course_evaluation.ec_course_evaluation_subitems.each_with_index do |evaluation_subitem, index| + course_evaluation.evaluation_count.times do |times| + score = arr[times * items_size + index].to_i # 共4个分项:第一次考核的第三项下标为 0 * 4 + 2,即 2 + attrs = { + score: score, student_name: student.name, student_number: student.student_id, + position: times + 1, ec_year_student_id: student.id, ec_course_evaluation_id: course_evaluation.id, + ec_course_evaluation_subitem_id: evaluation_subitem.id + } + worker.add(attrs) + end + end + end + end + + def detail_score_handler(worker, arr) + student = ec_year_students.find_by(student_id: arr[0].is_a?(Float) ? arr[0].to_i : arr[0].to_s.strip) + return if student.blank? + + items_size = course_evaluation.ec_course_evaluation_subitems.size + course_evaluation.ec_course_evaluation_subitems.each_with_index do |evaluation_subitem, index| + course_evaluation.evaluation_count.times do |times| + # 因为0和1是学号和姓名,所以下标要 + 2 + score = arr[times * items_size + 2 + index].to_i # 共4个分项:第一次考核的第三项下标为 0 * 4 + 2 + 2,即 arr[4] + attrs = { + score: score, student_name: student.name, student_number: student.student_id, + position: times + 1, ec_year_student_id: student.id, ec_course_evaluation_id: course_evaluation.id, + ec_course_evaluation_subitem_id: evaluation_subitem.id + } + worker.add(attrs) + end + end + end +end diff --git a/app/services/ecs/import_student_service.rb b/app/services/ecs/import_student_service.rb new file mode 100644 index 000000000..daa384d58 --- /dev/null +++ b/app/services/ecs/import_student_service.rb @@ -0,0 +1,36 @@ +class Ecs::ImportStudentService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :ec_year, :attachment + + def initialize(ec_year, attachment_id) + @ec_year = ec_year + @attachment = Attachment.find_by(id: attachment_id) + end + + def call + raise_import_error('文件不存在') if attachment.blank? + + path = attachment.diskfile + excel = Ecs::ImportStudentExcel.new(path) + + success_count = 0 + EcYearStudent.bulk_insert(:student_id, :name, :created_at, :updated_at) do |worker| + excel.read_each do |student_id, name| + success_count += 1 + + student = ec_year.ec_year_students.find_by(student_id: student_id) + if student.present? + student.update!(name: name) + next + end + + worker.add(student_id: student_id, name: name) + end + end + + success_count + rescue BaseImportExcel::Error => ex + raise Error, ex.message + end +end \ No newline at end of file diff --git a/app/services/ecs/link_course_service.rb b/app/services/ecs/link_course_service.rb new file mode 100644 index 000000000..18ba8fd15 --- /dev/null +++ b/app/services/ecs/link_course_service.rb @@ -0,0 +1,17 @@ +class Ecs::LinkCourseService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :ec_course, :params + + def initialize(ec_course, params) + @ec_course = ec_course + @params = params + end + + def call + course = Course.find_by(id: params[:course_id]) + raise Error, '课程不存在' if course.blank? + + ec_course.ec_major_courses.create!(course: course) + end +end \ No newline at end of file diff --git a/app/services/ecs/query_course_evaluation_service.rb b/app/services/ecs/query_course_evaluation_service.rb new file mode 100644 index 000000000..8c76da438 --- /dev/null +++ b/app/services/ecs/query_course_evaluation_service.rb @@ -0,0 +1,114 @@ +class Ecs::QueryCourseEvaluationService < ApplicationService + attr_reader :ec_course, :evaluation_status + + def initialize(ec_course) + @ec_course = ec_course + @_course_achievement = 0 + end + + def course_targets + @_course_targets ||= calculate_course_targets + end + + def course_achievement + course_targets + + @_course_achievement.round(2) + end + + def graduation_subitem_evaluations + student_scores = ec_course.ec_course_student_scores.joins(:ec_course_target).group(:ec_course_target_id) + student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id') + student_score_map = student_scores.group_by { |item| item.ec_course_target_id } + + subitem_targets = ec_course.ec_graduation_subitem_course_targets + .includes(ec_graduation_subitem: :ec_graduation_requirement) + + subitem_targets.group_by(&:ec_graduation_subitem_id).map do |_id, arr| + subitem = arr.first.ec_graduation_subitem + + support = subitem.ec_course_supports.find_by(ec_course_id: ec_course.id) + + weight = support.weights.to_f + objective_achievement = (weight * ec_course.ec_year.calculation_value.to_f).round(3) + + target_total_rates = 0 + reach_real_target = 0 + + arr.map(&:ec_course_target).uniq.each do |target| + target_total_rates += target.weight.to_f + student_score = student_score_map[target.id] + + reach_real_target += student_score.average_score.to_f * target.weight.to_f if student_score + end + + actually_achievement = target_total_rates.zero? ? 0 : (reach_real_target * weight) / (target_total_rates.round(3) * 100) + + { + graduation_subitem_id: subitem.id, + content: subitem.content, + position: subitem.position, + graduation_requirement_position: subitem.ec_graduation_requirement.position, + weights: format('%.02f', weight), + support_course_target_ids: arr.map(&:ec_course_target_id), + objective_achievement: format('%.03f', objective_achievement), + actually_achievement: format('%.03f', actually_achievement), + status: achieve_status(objective_achievement, actually_achievement) + } + end + end + + def score_levels_map + @_score_levels_map ||= begin + ec_course.ec_score_levels.each_with_object({}) do |level, obj| + obj[level.id.to_s] = level.as_json(only: %i[id position score level]) + end + end + end + + private + + def calculate_course_targets + score_levels = ec_course.ec_score_levels.to_a + + ec_course.ec_course_targets.includes(:ec_student_score_targets).map do |course_target| + data = course_target.as_json(only: %i[id position content standard_grade]) + data[:weight] = course_target.weight + + score_targets = course_target.ec_student_score_targets.to_a + data[:average_score] = score_targets.size.zero? ? 0 : score_targets.sum(&:score).fdiv(score_targets.size).round(2) + data[:maximum_score] = score_targets.max_by(&:score)&.score + data[:minimum_score] = score_targets.min_by(&:score)&.score + data[:actually_grade] = data[:average_score] + + data[:status] = achieve_status(course_target.standard_grade, data[:average_score]) + + # 计算总评成绩 + @_course_achievement += data[:average_score].to_f * course_target.weight.to_f + + # 计算学生成绩分布区间 + data[:score_levels] = score_levels.map do |score_level| + level_condition_proc = + if (score_level.position - 1).zero? # 第一区间 + -> (score_target){ score_target.score >= score_level.score ? 1 : 0 } + elsif score_levels.position == score_levels.size # 末尾区间 + -> (score_target){ score_target.score < score_level.score ? 1 : 0 } + else + # 中间区间 + -> (score_target){ score_target.score >= score_level.score && score_target.score < score_targets[score_level.position - 1] ? 1 : 0 } + end + + # 计算该成绩区间人数 + count = score_targets.sum(&level_condition_proc) + + { id: score_level.id, count: count } + end + + data + end + end + + def achieve_status(standard_value, real_value) + standard_value && real_value && real_value >= standard_value ? 'achieved' : 'not_achieved' + end +end \ No newline at end of file diff --git a/app/services/ecs/save_course_evaluation_service.rb b/app/services/ecs/save_course_evaluation_service.rb new file mode 100644 index 000000000..1e5af8756 --- /dev/null +++ b/app/services/ecs/save_course_evaluation_service.rb @@ -0,0 +1,34 @@ +class Ecs::SaveCourseEvaluationService < ApplicationService + include AcceptsNestedAttributesHelper + + attr_reader :ec_course, :course_evaluation, :params + + def initialize(course_evaluation, params) + @course_evaluation = course_evaluation + @ec_course = course_evaluation.ec_course + @params = params + end + + def call + Ecs::SaveCourseEvaluationForm.new(params).validate! + + subitem_attributes = build_accepts_nested_attributes( + course_evaluation, + course_evaluation.ec_course_evaluation_subitems, + params.delete(:course_evaluation_subitems), + &method(:course_evaluation_subitem_param_handler!) + ) + + course_evaluation.assign_attributes(params) + course_evaluation.assign_attributes(ec_course_evaluation_subitems_attributes: subitem_attributes) + + course_evaluation.save! + course_evaluation + end + + private + + def course_evaluation_subitem_param_handler!(item) + item[:name] = item[:name].to_s.strip + end +end diff --git a/app/services/ecs/save_graduation_course_supports_service.rb b/app/services/ecs/save_graduation_course_supports_service.rb new file mode 100644 index 000000000..bfbdb997f --- /dev/null +++ b/app/services/ecs/save_graduation_course_supports_service.rb @@ -0,0 +1,23 @@ +class Ecs::SaveGraduationCourseSupportsService < ApplicationService + include AcceptsNestedAttributesHelper + + attr_reader :graduation_subitem, :params + + def initialize(graduation_subitem, params) + @params = params + @graduation_subitem = graduation_subitem + end + + def call + Ecs::SaveGraduationCourseSupportForm.new(params).validate! + + accepts_attributes = build_accepts_nested_attributes( + graduation_subitem, graduation_subitem.ec_course_supports, + params[:course_supports] + ) + + graduation_subitem.assign_attributes(ec_course_supports_attributes: accepts_attributes) + graduation_subitem.save! + graduation_subitem + end +end \ No newline at end of file diff --git a/app/services/ecs/save_graduation_requiremente_service.rb b/app/services/ecs/save_graduation_requiremente_service.rb new file mode 100644 index 000000000..043a9bca7 --- /dev/null +++ b/app/services/ecs/save_graduation_requiremente_service.rb @@ -0,0 +1,69 @@ +class Ecs::SaveGraduationRequirementeService < ApplicationService + include AcceptsNestedAttributesHelper + + attr_reader :ec_year, :graduation_requirement, :params + + def initialize(graduation_requirement, params) + @graduation_requirement = graduation_requirement + @ec_year = graduation_requirement.ec_year + @params = params + end + + def call + set_graduation_subitems_position! + + graduation_requirement.position = params[:position].presence || ec_year.ec_graduation_requirements.count + 1 + graduation_requirement.content = params[:content].to_s.strip + + attributes = build_accepts_nested_attributes( + graduation_requirement, + graduation_requirement.ec_graduation_subitems, + params[:graduation_subitems], + &method(:graduation_subitem_params_handler!) + ) + + ActiveRecord::Base.transaction do + graduation_requirement.assign_attributes(ec_graduation_subitems_attributes: attributes) + + resort_graduation_requirements_position! + + graduation_requirement.save! + end + + graduation_requirement + end + + private + + def set_graduation_subitems_position! + params[:graduation_subitems].each_with_index do |item, index| + item[:position] = index + 1 + end + end + + def resort_graduation_requirements_position! + # 新增时 + if graduation_requirement.new_record? + # 插入数据时只需要后移 + ec_year.ec_graduation_requirements.where('position >= ?', graduation_requirement.position) + .update_all('position = position + 1') + return + end + + # 编辑时 + new_position = graduation_requirement.position + old_position = graduation_requirement.position_in_database + + if new_position > old_position # 前移 + ec_year.ec_graduation_requirements.where('position <= ? AND position > ?', new_position, old_position) + .update_all('position = position - 1') + elsif new_position < old_position # 后移 + ec_year.ec_graduation_requirements.where('position >= ? AND position < ?', new_position, old_position) + .update_all('position = position + 1') + end + end + + def graduation_subitem_params_handler!(subitem) + subitem[:content] = subitem[:content].to_s.strip + end +end diff --git a/app/services/exercise_user_pdf_service.rb b/app/services/exercise_user_pdf_service.rb new file mode 100644 index 000000000..5f92aee9c --- /dev/null +++ b/app/services/exercise_user_pdf_service.rb @@ -0,0 +1,90 @@ +class ExerciseUserPdfService + include ExercisesHelper + include ApplicationHelper + include StudentWorksHelper + + attr_reader :exercise, :ex_user + + def initialize(exercise, ex_user) + @exercise = exercise + @ex_user = ex_user + @ex_user_user = @ex_user.user + @course = @exercise.course + end + + def filename + user_course = @course.course_members.find_by(user_id:@ex_user_user.id).course_group_name + exercise_user_name = user_course + "_" + exercise.exercise_name + "_" + @ex_user_user.real_name + "#{exercise_user_name.strip}.pdf" + end + + def prepare_binding + load_data + + binding + end + + def ex_pdf + generate_pdf + end + + private + + def generate_pdf + file = File.open(Rails.root.join('app/templates/exercise_export/exercise_user.html.erb')) + html = ERB.new(file.read).result(prepare_binding) + + kit = PDFKit.new(html) + base_css = %w(app/templates/exercise_export/exercise_export.css) + base_css.each { |css| kit.stylesheets << Rails.root.join(css) } + #-----正式需删掉 + # aa = File.open(Rails.root.join("public/123.html"),"w+") + # aa.syswrite(kit.source) + #正式需删掉------- + + file = Tempfile.new(filename) + kit.to_pdf(file.path) + file + end + + def load_data + @exercise_questions = exercise.exercise_questions + @exercise_ques_count = @exercise_questions.count # 全部的题目数 + @exercise_ques_scores = @exercise_questions.pluck(:question_score).sum + + #单选题的数量及分数 + exercise_single_ques = @exercise_questions.find_by_custom("question_type",0) + @exercise_single_ques_count = exercise_single_ques.all.count + @exercise_single_ques_scores = exercise_single_ques.pluck(:question_score).sum + + #多选题的数量及分数 + exercise_double_ques = @exercise_questions.find_by_custom("question_type",1) + @exercise_double_ques_count = exercise_double_ques.all.count + @exercise_double_ques_scores = exercise_double_ques.pluck(:question_score).sum + + # 判断题数量及分数 + exercise_ques_judge = @exercise_questions.find_by_custom("question_type",2) + @exercise_ques_judge_count = exercise_ques_judge.all.count + @exercise_ques_judge_scores = exercise_ques_judge.pluck(:question_score).sum + + #填空题数量及分数 + exercise_ques_null = @exercise_questions.find_by_custom("question_type",3) + @exercise_ques_null_count = exercise_ques_null.all.count + @exercise_ques_null_scores = exercise_ques_null.pluck(:question_score).sum + + #简答题数量及分数 + exercise_ques_main = @exercise_questions.find_by_custom("question_type",4) + @exercise_ques_main_count = exercise_ques_main.all.count + @exercise_ques_main_scores = exercise_ques_main.pluck(:question_score).sum + + #实训题数量及分数 + exercise_ques_shixun = @exercise_questions.find_by_custom("question_type",5) + @exercise_ques_shixun_count = exercise_ques_shixun.all.count + @exercise_ques_shixun_scores = exercise_ques_shixun.pluck(:question_score).sum + + challenge_ids = @exercise_questions.joins(:exercise_shixun_challenges).pluck("exercise_shixun_challenges.challenge_id") + + get_each_student_exercise(exercise.id,@exercise_questions,@ex_user_user.id) + @games = @exercise_user.user.games.ch_games(challenge_ids) + end +end \ No newline at end of file diff --git a/app/services/export_exercises_service.rb b/app/services/export_exercises_service.rb new file mode 100644 index 000000000..12b5501f9 --- /dev/null +++ b/app/services/export_exercises_service.rb @@ -0,0 +1,35 @@ +class ExportExercisesService + include ExercisesHelper + include StudentWorksHelper + attr_reader :exercise, :ex_users + + def initialize(exercise, ex_users) + @exercise = exercise + @ex_users = ex_users + end + + def filename + exercise_export_name = exercise.user.real_name + "_" + exercise.exercise_name + "_" + Time.now.strftime('%Y%m%d_%H%M%S') + "#{exercise_export_name.strip}.zip" + end + + def ex_zip + zip_file = Tempfile.new(filename) + pdfs = [] + Zip::File.open(zip_file.path, Zip::File::CREATE) do |zip| + ex_users.each do |ex_user| + export = ExerciseUserPdfService.new(exercise, ex_user) + pdf = export.ex_pdf + pdfs << pdf + begin + zip.add(export.filename, pdf.path) + rescue => ex + Rails.logger.error(ex.message) + zip.get_output_stream('FILE_NOTICE.txt'){|os| os.write("文件重复:#{export.filename}") } + end + end + zip_file + end + end + +end \ No newline at end of file diff --git a/app/services/export_shixun_report_service.rb b/app/services/export_shixun_report_service.rb new file mode 100644 index 000000000..8358d422e --- /dev/null +++ b/app/services/export_shixun_report_service.rb @@ -0,0 +1,54 @@ +class ExportShixunReportService + include ApplicationHelper + include StudentWorksHelper + + attr_reader :homework, :work + + def initialize(homework, work) + @homework = homework + @work = work + end + + def filename + @_filename ||= "#{homework.name}-#{work.user.user_extension&.student_id}-#{work.user.real_name}.pdf".gsub(' ', '-').gsub('/', '_') + end + + def prepare_binding + load_data + + binding + end + + def to_pdf + @_pdf ||= generate_pdf + end + + private + + def generate_pdf + file = File.open(Rails.root.join('app/templates/shixun_work/shixun_work.html.erb')) + html = ERB.new(file.read).result(prepare_binding) + kit = PDFKit.new(html) + + base_css = %w(app/templates/shared/main.css app/templates/shixun_work/shixun_work.css app/templates/shared/codemirror.css) + base_css.each { |css| kit.stylesheets << Rails.root.join(css) } + + file = Tempfile.new(filename) + kit.to_pdf(file.path) + file + end + + def load_data + @course = homework.course + @user = @work.user + @shixun = homework.shixuns.take + @games = @work.myshixun.games.includes(:challenge, :game_codes,:outputs) if @work.myshixun + + # 用户最大评测次数 + @user_evaluate_count = @games.inject(0){|sum, g| sum + g.outputs.pluck(:query_index).first } if @games + # 图形效率图的数据 + @echart_data = student_efficiency(homework, @work) + @myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id } + @myself_consume = @echart_data[:consume_list].find { |item| item.last == @user.id } + end +end \ No newline at end of file diff --git a/app/services/git_service.rb b/app/services/git_service.rb new file mode 100644 index 000000000..4b6bf17ef --- /dev/null +++ b/app/services/git_service.rb @@ -0,0 +1,43 @@ +#coding=utf-8 +# +# 文档在 https://www.showdoc.cc/127895880302646?page_id=1077512172693249 +# +class GitService + + class << self + + ['add_repository', 'fork_repository', 'delete_repository', 'file_tree', 'update_file', 'file_content', 'commits'].each do |method| + define_method method do |params| + post(method, params) + end + end + + private + + def root_url + new_git_address = EduSetting.find_by_name('git_address_domain').try(:value) + raise 'error: new_git_address not configuration' unless new_git_address.present? + new_git_address + end + + def logger + Rails.logger + end + + def post(action, params) + uri = URI.parse("#{root_url}/api/#{action}") + https = Net::HTTP.new(uri.host, uri.port) + https.use_ssl = root_url.start_with?('https') + req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' => 'text/plain;charset=utf-8'}) + req.body = params.to_json + res = https.request(req) + body = res.body + logger.info("--uri_exec: .....res is #{body}") + content = JSON.parse(body) + #raise content["msg"] if content["code"] != 0 + + content["data"] + end + end + +end \ No newline at end of file diff --git a/app/services/homeworks_service.rb b/app/services/homeworks_service.rb new file mode 100644 index 000000000..536d62c66 --- /dev/null +++ b/app/services/homeworks_service.rb @@ -0,0 +1,275 @@ +class HomeworksService + + # 创建实训作业 + def create_homework shixun, course, category, current_user + ActiveRecord::Base.transaction do + homework = HomeworkCommon.new(name: shixun.name, description: shixun.description, homework_type: 4, + user_id: current_user.id, course_id: course.id, + course_second_category_id: category.try(:id).to_i) + + homework_detail_manual = HomeworkDetailManual.new + homework.homework_detail_manual = homework_detail_manual + + if homework.save! + homework_detail_manual.save! if homework_detail_manual + HomeworkCommonsShixun.create!(homework_common_id: homework.id, shixun_id: shixun.id) + HomeworksService.new.create_shixun_homework_cha_setting(homework, shixun) + HomeworksService.new.create_works_list(homework, course) + end + homework + end + end + + #更新实训作业的状态 + def update_shixun_work_status homework + shixun = homework.shixuns.first + student_works = homework.student_works.unfinished + homework_challenge_settings = homework.homework_challenge_settings + challeng_ids = homework_challenge_settings.map(&:challenge_id) + # 取已发布的作品 + if homework.unified_setting + student_works = student_works + else + setting = homework.homework_group_settings.group_published + if setting.blank? + student_works = student_works.none + else + users = homework.course.course_members.course_find_by_ids("course_group_id",setting.map(&:course_group_id)) + student_works = student_works.homework_by_user(users.map(&:user_id)) + end + end + # 已发布作品且状态为未提交的作品 如果有开启过实训则更新状态 + myshixuns = Myshixun.where(:shixun_id => shixun.id, :user_id => student_works.map(&:user_id)) + myshixuns.each do |myshixun| + work = student_works.homework_by_user(myshixun.user_id).first + setting_time = homework.homework_group_setting myshixun.user_id + games = myshixun.games.where(:challenge_id => challeng_ids) + myshixun_endtime = games.select{|game| game.status == 2}.size == games.size ? games.map(&:end_time).max : nil + compelete_status = 0 + if myshixun_endtime.present? && myshixun_endtime < setting_time.end_time + if myshixun_endtime < setting_time.publish_time + compelete_status = 2 + else + compelete_status = 1 + end + end + if setting_time.end_time > Time.now + work.update_attributes(:work_status => 1, :late_penalty => 0, :commit_time => myshixun.updated_at, :update_time => myshixun.updated_at, :myshixun_id => myshixun.id, :compelete_status => compelete_status) + else + work.update_attributes(:work_status => ((myshixun.is_complete? && (myshixun.done_time < setting_time.end_time)) ? 1 : 2), :late_penalty => (myshixun.is_complete? && (myshixun.done_time < setting_time.end_time) ? 0 : homework.late_penalty), :commit_time => myshixun.updated_at, :update_time => myshixun.updated_at, :myshixun_id => myshixun.id, :compelete_status => compelete_status) + end + set_shixun_final_score work + end + # 更新所有学生的效率分 + HomeworksService.new.update_student_eff_score HomeworkCommon.where(:id => homework.id).first + end + + # 实训作业的评分 + def set_shixun_final_score student_work + homework = student_work.homework_common + answer_open_evaluation = homework.homework_detail_manual.answer_open_evaluation + myshixun = student_work.myshixun + if student_work.work_status != 0 && myshixun.present? + final_score = 0 + compelete = true + max_endtime = "" + user_total_score = 0 + pass_consume_time = 0 + homework.homework_challenge_settings.each do |setting| + game = myshixun.games.find_by(challenge_id: setting.challenge_id, status: 2) + unless game.nil? + pass_consume_time += (game.cost_time / 60.0).to_f + user_total_score += game.final_score.to_i < 0 ? 0 : game.challenge.score.to_i + adjust_score = student_work.challenge_work_scores.where(challenge_id: setting.challenge_id).last + final_score += adjust_score.present? ? adjust_score.score : (answer_open_evaluation ? setting.score : (game.final_score >= 0 ? setting.score : 0)) + max_endtime = max_endtime == "" ? game.end_time : (game.end_time > max_endtime ? game.end_time : max_endtime) + else + compelete = false + end + end + + if compelete && max_endtime != "" + homework = student_work.homework_common + setting_time = homework.homework_group_setting student_work.user_id + if setting_time.publish_time.present? && setting_time.end_time.present? + if max_endtime < setting_time.publish_time + student_work.compelete_status = 2 + else + if max_endtime < setting_time.end_time || (homework.allow_late && (homework.course.end_date.nil? || + max_endtime < homework.course.end_date.end_of_day)) + student_work.compelete_status = 1 + student_work.cost_time = max_endtime.to_i - setting_time.publish_time.to_i + else + student_work.compelete_status = 0 + end + end + end + + efficiency = (pass_consume_time == 0 ? 0 : Math.log((user_total_score / pass_consume_time.to_f) + 1.0)) + student_work.efficiency = efficiency < 0 ? 0 : format("%.2f", efficiency) + + if homework.work_efficiency + if homework.max_efficiency < student_work.efficiency + # homework.max_efficiency = student_work.efficiency + homework.update_column("max_efficiency", homework.max_efficiency) + end + # eff_score = homework.max_efficiency == 0 ? 0 : student_work.efficiency / homework.max_efficiency * homework.eff_score + # student_work.eff_score = format("%.2f", eff_score) + # else + # student_work.eff_score = 0 + end + elsif !compelete + student_work.compelete_status = 0 + end + student_work.final_score = format("%.2f", final_score.to_f) + student_work.late_penalty = student_work.work_status == 1 ? 0 : homework.late_penalty + score = student_work.final_score + student_work.eff_score - student_work.late_penalty + student_work.work_score = format("%.2f", score < 0 ? 0 : score.to_f) unless student_work.ultimate_score + student_work.save! + end + end + + # 计算实训作品学生的效率分 + def update_student_eff_score homework + if homework.work_efficiency && homework.max_efficiency != 0 + homework.student_works.where("compelete_status != 0").each do |student_work| + eff_score = student_work.efficiency / homework.max_efficiency * homework.eff_score + student_work.eff_score = format("%.2f", eff_score) + student_work.late_penalty = student_work.work_status == 1 ? 0 : homework.late_penalty + unless student_work.ultimate_score + work_score = student_work.final_score.to_f + student_work.eff_score - student_work.late_penalty + student_work.work_score = format("%.2f", work_score < 0 ? 0 : work_score) + end + student_work.save! + end + else + homework.student_works.where("compelete_status != 0").each do |student_work| + student_work.eff_score = 0 + student_work.late_penalty = student_work.work_status == 1 ? 0 : homework.late_penalty + unless student_work.ultimate_score + work_score = student_work.final_score.to_f + student_work.eff_score - student_work.late_penalty + student_work.work_score = format("%.2f", work_score < 0 ? 0 : work_score) + end + student_work.save! + end + end + end + + # 用户评测时更新实训作业成绩 + def update_myshixun_work_score myshixun + ActiveRecord::Base.transaction do + student_works = myshixun.student_works.where(user_id: myshixun.user_id) + #logger.info("#############student_works_count: #{student_works.count}") + if student_works.count > 0 + student_works.each do |work| + homework = work.homework_common + #logger.info("#############member_course_group_id: #{member.try(:course_group_id)}") + setting_time = homework.homework_group_setting work.user_id + if setting_time.end_time.present? && (setting_time.end_time > Time.now || (homework.allow_late && !homework.course.is_end)) + #logger.info("#############setting_time: #{setting_time.end_time}") + + user_total_score = 0 + pass_consume_time = 0 + final_score = 0 + homework.homework_challenge_settings.each do |setting| + game = myshixun.games.where(:challenge_id => setting.challenge_id, :status => 2).first + unless game.nil? + pass_consume_time += (game.cost_time / 60.0).to_f + user_total_score += game.final_score.to_i < 0 ? 0 : game.challenge.score.to_i + adjust_score = work.challenge_work_scores.where(:challenge_id => setting.challenge_id).last + final_score += adjust_score.present? ? adjust_score.score : (homework.homework_detail_manual.answer_open_evaluation ? setting.score : (game.final_score >= 0 ? setting.score : 0)) + end + end + if work.work_status == 0 + is_complete = myshixun.is_complete? && (myshixun.done_time < setting_time.end_time) + work.work_status = setting_time.end_time > Time.now ? 1 : (is_complete ? 1 : 2) + work.late_penalty = setting_time.end_time > Time.now ? 0 : (is_complete ? 0 : homework.late_penalty) + work.commit_time = myshixun.created_at > setting_time.publish_time ? setting_time.publish_time : myshixun.created_at + work.myshixun_id = myshixun.id + end + + games = myshixun.games.where(:challenge_id => homework.homework_challenge_settings.map(&:challenge_id)) + myshixun_endtime = games.select{|game| game.status == 2}.size == games.size ? games.map(&:end_time).max : nil + if myshixun_endtime.present? + min_efficiency_changed = min_efficiency_changed.present? ? min_efficiency_changed : false + work.compelete_status = 1 + work.cost_time = myshixun_endtime.to_i - setting_time.publish_time.to_i + + efficiency = (pass_consume_time == 0 ? 0 : Math.log((user_total_score / pass_consume_time.to_f) + 1.0)) + work.efficiency = format("%.2f", efficiency) + + # 如果作业的最大效率值有变更则更新所有作品的效率分 + if homework.work_efficiency && homework.max_efficiency < work.efficiency + homework.update_column("max_efficiency", homework.max_efficiency) + end + end + + work.update_time = Time.now + + work.final_score = final_score + score = work.final_score + work.eff_score - work.late_penalty + work.work_score = format("%.2f",(score < 0 ? 0 : score).to_f) unless work.ultimate_score + #logger.info("#############work_score: #{score}") + work.save! + end + end + end + end + end + + # 用户开启实训时更新作品状态 + def update_myshixun_work_status myshixun + student_works = StudentWork.find_by_sql("SELECT sw.* FROM student_works sw, homework_commons_shixuns hcs WHERE + sw.user_id = #{myshixun.user_id} AND sw.`homework_common_id` = hcs.`homework_common_id` + AND hcs.`shixun_id` = #{myshixun.shixun_id} and sw.work_status = 0") + Rails.logger.info("#############student_works_count: #{student_works.count}") + if student_works.count > 0 + student_works.each do |work| + homework = work.homework_common + setting_time = homework.homework_group_setting work.user_id + if setting_time.end_time.present? && + (setting_time.end_time > Time.now || (homework.allow_late && homework.late_time && homework.late_time > Time.now)) + + work.work_status = setting_time.end_time > Time.now ? 1 : 2 + work.late_penalty = setting_time.end_time > Time.now ? 0 : homework.late_penalty + work.update_time = Time.now + work.commit_time = Time.now + work.myshixun_id = myshixun.id + work.save! + end + end + end + end + + # 实训作业的关卡设置 + def create_shixun_homework_cha_setting homework, shixun + if shixun.present? + sum_score = 0 + shixun.challenges.each_with_index do |challeng, index| + if index < shixun.challenges.length - 1 + score = ((100.0 / shixun.challenges.length) * 100).floor / 100.0 + sum_score += score + else + score = 100 - sum_score + end + HomeworkChallengeSetting.create!(homework_common_id: homework.id, challenge_id: challeng.id, + shixun_id: shixun.id, score: score) + end + end + end + + # 为课堂学生创建作品 + def create_works_list homework, course + if course.present? && CourseMember.students(course).size > 0 + str = "" + CourseMember.students(course).each do |student| + str += "," if str != "" + str += "(#{homework.id},#{student.user_id}, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if str != "" + sql = "insert into student_works (homework_common_id, user_id, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + end +end \ No newline at end of file diff --git a/app/services/review_service.rb b/app/services/review_service.rb new file mode 100644 index 000000000..7602aa51b --- /dev/null +++ b/app/services/review_service.rb @@ -0,0 +1,231 @@ +#coding=utf-8 +# +require 'net/http' +require 'uri' + +class ReviewService + @review_server_url = EduSetting.find_by_name('review_server_url').try(:value) + + + def self.logger + @logger ||= Logger.new(File.join(Rails.root, "log", "review.log"), 'daily') + end + + def self.root_url + @review_server_url.presence || 'http://10.9.79.221:80' + end + + def self.postForm(action, map) + Rails.logger.info("##################------action: #{action}") + Rails.logger.info("##################------action: #{map}") + begin + uri = URI.parse("#{root_url}/api/v1/#{action}") + + Rails.logger.info "请求url: #{uri}" + Rails.logger.info "参数: " + map.each do |k, v| + Rails.logger.info "#{k}=>#{v}" + end + + res = Net::HTTP.post_form uri, map + body = res.body + Rails.logger.info("返回: #{body}") + content = JSON.parse(body) + content + rescue => e + Rails.logger.error("post #{action}: exception #{e.message}") + end + end + + def self.postJson(action, params) + begin + uri = URI.parse("#{root_url}/api/v1/#{action}") + https = Net::HTTP.new(uri.host, uri.port) + https.use_ssl = root_url.start_with?('https') + req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' => 'application/x-www-form-urlencoded;charset=utf-8'}) + req.body = params.to_json + res = https.request(req) + body = res.body + logger.info("--uri_exec: .....res is #{body}") + content = JSON.parse(body) + raise content["msg"] if content["code"] != 0 + + content["data"] + rescue Exception => e + logger.error("--uri_exec: exception #{e.message}") + end + end + + + class CheckResponse + attr_accessor :status, :msg, :query_id + + def initialize(status, msg, query_id) + @status = status + @msg = msg + @query_id = query_id + end + end + + #查重 + # 参数说明 + # user_list [ + # { + # user_id: 1, + # code_info: [ + # { + # "path": "src/step1/HelloWorld.java", + # "content: "ADAGWDSSAS22", + # "passed_time": "2016-01-08 00:00:00" + # }, + # ] + # }, + # ] + # + # 返回说明 + # + # { + # code: 0, 0 成功,其他失败 + # msg: '', //失败时的错误消息 + # query_id: '123123123', //本次查重的查询号 + # } + # + # + def self.check(user_list = [], language='java') + File.open("/tmp/check_codes_#{Time.now}.json", 'w+') do |f| + f.write(user_list.to_json) + end + + data = postForm('check_codes', {user_data: user_list.to_json, language: language}) + if data.nil? + return CheckResponse.new(-1, "系统调用出错", "") + end + Rails.logger.info("@@@@@@@@@@@@@@@@------------#{data}") + CheckResponse.new(data["status"], data["msg"], data["query_id"]) + end + + + class QueryResultResponse + UserList = Struct.new(:user_id, :target_user_id, :origin_path, :target_path, :rate) + attr_accessor :status, :msg, :user_lists + + def initialize(status, msg, user_lists) + @status, @msg, @user_lists = status, msg, [] + + if user_lists.present? + user_lists.each do |info| + user = find_by_user_id_and_origin_path(info["user_id"], info["path"]["origin"]) + if !user.present? + add_user_list(info) + elsif user.rate < info["rate"] + set_user_list(user, info) + end + end + end + end + + def set_user_list(user, obj) + user.user_id = obj["user_id"] + user.target_user_id = obj["target_user_id"] + user.origin_path = obj["path"]["origin"] + user.target_path = obj["path"]["target"] + user.rate = obj["rate"] + end + + def add_user_list(obj) + user_list = UserList.new + set_user_list(user_list, obj) + @user_lists << user_list + end + + def find_by_user_id_and_origin_path(user_id, origin_path) + self.user_lists.each do |user| + return user if user.user_id == user_id and user.origin_path == origin_path + end + nil + end + + end + + + class QueryDetailResultResponse + CodeInfo = Struct.new(:origin_path, :target_path, :origin_content, :target_content, :target_user_id, :rate) + + + attr_accessor :status, :msg, :code_info + + def initialize(status, msg, code_info) + @status, @msg, @code_info = status, msg, [] + + if code_info.present? + code_info.each do |code| + info = find_by_path(code["path"]["origin"]) + if !info.present? + add_code_info(code) + elsif info.rate < code["rate"] + set_code_info(info, code) + end + end + end + end + + def set_code_info(info, obj) + info.origin_path = obj["path"]["origin"] + info.target_path = obj["path"]["target"] + info.origin_content = obj["content"]["origin"] + info.target_content = obj["content"]["target"] + info.target_user_id = obj["target_user_id"] + info.rate = obj["rate"] + end + + def add_code_info(obj) + info = CodeInfo.new + set_code_info(info, obj) + @code_info << info + end + + def find_by_path(path) + self.code_info.each do |code_info| + return code_info if code_info.origin_path == path + end + nil + end + end + + + #查询查重的结果 + # + # 输入参数 + # query_id 待查询的ID + # user_id 传入则查详情 + # + # 文档参考 https://www.showdoc.cc/127895880302646?page_id=1271144663669096 + # + def self.query_result(opt = {}) + unless opt[:query_id].present? + logger.error "query_id没有传" + return + end + + if opt[:user_id].present? + data = postForm('check_info', query_id: opt[:query_id], user_id: opt[:user_id]) + if data.nil? + return QueryDetailResultResponse.new(-1, "系统调用出错", []) + end + + response = QueryDetailResultResponse.new(data['status'], data['msg'], data["code_info"]) + return response + + else + data = postForm('check_lists', query_id: opt[:query_id]) + if data.nil? + return CheckResponse.new(-1, "系统调用出错", "") + end + + response = QueryResultResponse.new(data['status'], data['msg'], data["user_lists"]) + return response + + end + end + +end \ No newline at end of file diff --git a/app/services/reward_experience_service.rb b/app/services/reward_experience_service.rb new file mode 100644 index 000000000..70b47d1a3 --- /dev/null +++ b/app/services/reward_experience_service.rb @@ -0,0 +1,24 @@ +class RewardExperienceService + attr_reader :user, :attrs + + def initialize(user, **attrs) + @user = user + @attrs = attrs.slice(*%i[container_id container_type score]) + end + + def call + return if user.experiences.exists?(attrs.except(:score)) + + ActiveRecord::Base.transaction do + experience = user.experiences.create!(attrs) + + user.increment!(:experience, experience.score) + + experience + end + end + + def self.call(user, **attrs) + new(user, attrs).call + end +end \ No newline at end of file diff --git a/app/services/reward_grade_service.rb b/app/services/reward_grade_service.rb new file mode 100644 index 000000000..7642e1967 --- /dev/null +++ b/app/services/reward_grade_service.rb @@ -0,0 +1,18 @@ +class RewardGradeService < ApplicationService + attr_reader :user, :attrs + + def initialize(user, **attrs) + @user = user + @attrs = attrs.slice(*%i[container_id container_type score]) + end + + def call + return if user.grades.exists?(attrs) + + ActiveRecord::Base.transaction do + grade = user.grades.create!(attrs) + + user.increment!(:grade, grade.score) + end + end +end \ No newline at end of file diff --git a/app/services/shixuns_service.rb b/app/services/shixuns_service.rb new file mode 100644 index 000000000..83d61b352 --- /dev/null +++ b/app/services/shixuns_service.rb @@ -0,0 +1,156 @@ +# encoding=utf-8 +class ShixunsService + include ApplicationHelper + include GamesHelper + LIMIT = 10 + + # reuturn star_info打星情况 + def show_shixun params, current_user + shixun = Shixun.select([:id, :identifier, :name, :fork_from, :user_id, :myshixuns_count, :trainee, :can_copy, :status, :propaedeutics]).find_by_identifier(params[:identifier]) + star_info = shixun.shixun_preference_info + image_url = url_to_avatar(current_user) + username = current_user.try(:show_name) + is_certification_teacher = current_user.is_certification_teacher + manager = current_user.manager_of_shixun?(shixun, current_user) + owner = shixun.owner + watched = owner.watched_by?(current_user) + myshixun = Myshixun.select([:id, :user_id, :identifier, :shixun_id, :status]).where(:user_id => current_user, :shixun_id => shixun.id).first + if shixun.fork_from + fork_shixun = Shixun.select([:id, :name, :user_id]).find(shixun.fork_from) + fork_info = {:name => fork_shixun.name, :username => fork_shixun.owner.try(:show_name)} + end + current_user = {:image_url => image_url, :username => username, :is_certification_teacher=> is_certification_teacher, :manager => manager, + :admin => current_user.admin?, :mail => current_user.try(:mail), :login => current_user.try(:login)} + creator = {:owner_id => owner.id, :image_url => url_to_avatar(owner), :username => owner.show_name, :watching => owner.watcher_users.count, + :shixun_count => owner.shixuns.count, :login => owner.login} + fork_count = Shixun.where(:fork_from => shixun.id).count + + recommends = [] + recommend_shixuns = recommend_shixun(shixun) + recommend_shixuns.each do |rec| + recommends << {:name => rec.name, :myshixuns_count => rec.myshixuns_count, :trainee => rec.trainee, :image_url => url_to_avatar(rec), :identifier => rec.identifier} + end + + return {:current_user => current_user, :shixun => shixun.try(:attributes), :fork_info => fork_info, :creator => creator, :star_info => star_info, + :myshixuns_count => shixun.myshixuns_count, :shixun_score => shixun.shixun_score, :shixun_level => shixun.shixun_level, + :fork_count => fork_count, :recommend_shixuns => recommends, :myshixun => myshixun.try(:attributes), :watched => watched} + end + + # 实训讨论帖子 + def shixun_discuss params, current_user + page = params[:page].to_i + offset = page * LIMIT + dis_id = params[:container_id] # 如:shixun_id + dis = Shixun.select([:id, :user_id]).find(dis_id) + dis_type = params[:container_type] # 如:"Shixun" + # 总数,分页使用 + if current_user.admin? + disscuss_count = Discuss.where(dis_id: dis_id, dis_type: dis_type, root_id: nil).count + discusses = Discuss.where(dis_id: dis_id, dis_type: dis_type, root_id: nil) + .includes(:user, :praise_tread).limit(LIMIT).offset(offset) + else + disscusses = Discuss.where( + 'dis_id = :dis_id and dis_type = :dis_type and root_id is null and (hidden = :hidden or user_id = :user_id)', + dis_id: dis_id, dis_type: dis_type, hidden: false, user_id: current_user.id + ) + + disscuss_count = disscusses.count + discusses = disscusses.includes(:user, :praise_tread).limit(LIMIT).offset(offset) + end + + base_data discusses, dis, current_user + + { children_list: @children_list, disscuss_count: disscuss_count } + end + + # 获取某条消息的具体位置(比如在分页中的某一页) + def anchor params, current_user + discuss_id = params[:discuss_id].to_i + dis_id = params[:container_id] # 如:shixun_id + dis = Shixun.select([:id, :user_id]).find(dis_id) + dis_type = params[:container_type] # 如:"Shixun" + # 注意:此处查询的条件必须和列表的条件一致,否则结果定位可能会有问题 + position_discusses = Discuss.find_by_sql("SELECT @rowno:=@rowno+1 as rowno, r.id from discusses r,(select @rowno:=0) m where root_id is null and + dis_id=#{dis_id} and dis_type='#{dis_type}' order by created_at desc") + disscuss_count = position_discusses.size + # 标记是否找到评论 + find_status = false + if disscuss_count > 0 + position = position_discusses.select{|discuss| discuss.id == discuss_id}.first.try(:rowno) + page = position.to_i / LIMIT + offset = page * LIMIT + find_status = true if position + end + discusses = Discuss.limit(LIMIT).where(:dis_id => dis_id, :dis_type => dis_type, :root_id => nil).includes(:user, :praise_tread).offset(offset) + + base_data discusses, dis, current_user + Myshixun.find(params[:myshixun_id]).update_attribute(:onclick_time, Time.now) + return {:children_list => @children_list, :disscuss_count => disscuss_count, :page => page.to_i, :find_status => find_status} + end + + # 判断当前用户是否有新的评论消息 + def new_message params, current_user + onclick_time = Myshixun.find(params[:myshixun_id]).try(:onclick_time) + dis_id = params[:container_id] + dis_type = params[:container_type] + # 获取当前用户发布的帖子,如果帖子有非自己的回复则通知我 + ids = Discuss.where("user_id =? and dis_id =? and dis_type =? and root_id is null", current_user.id, dis_id, dis_type).pluck(:id) + user_discuss = Discuss.where("user_id !=? and created_at >?", current_user.id, onclick_time).where(:root_id => ids, :dis_id => dis_id, :dis_type => dis_type).first + + return {:new_message => user_discuss} + end + + # 公共数据结构 + # 注意:shixun_id如果是非实训类型的,一定要主要其中的权限判断(目前只适用于实训) + def base_data discusses, dis, current_user + @children_list = [] + # 目前只取十个,不多N+1问题不大 + # 需要彻底解决则需要改数据路结构,比如Nested算法可以解决 + if discusses.present? + discusses.each do |d| + # 总点赞数 + praise_count = d.praise_tread.where(:praise_or_tread => 1).count + user_praise= d.praise_tread.select{|pt| pt.user_id == current_user.id}.length > 0 ? true : false + manager = current_user.manager_of_shixun?(dis, current_user) + game_url = + if manager + position = d.position.nil? ? 1 : d.position + challenge_id = dis.challenges.where(position: position).pluck(:id).first + game_identifier = Game.where(user_id: current_user, + challenge_id: challenge_id).pluck(:identifier).first + "/tasks/#{game_identifier}" + else + "" + end + p_content = + if d.hidden + manager ? d.content : "违规评论已被屏蔽!" + else + d.content + end + # 实训(TPM)的管理员可以看到隐藏的评论 + parents = {:id => d.id, :content => p_content, :time => time_from_now(d.created_at), :position => d.position, + :reward => d.reward, :user => d.user, :shixun_id => dis.id, :hidden => d.hidden, game_url: game_url, + :manager => manager, :praise_count => praise_count, :user_praise => user_praise, :admin => current_user.admin?} + + # 现在没有二级回复,所以查询的时候直接从root_id取 + children = + if current_user.admin? + Discuss.where(root_id: d.id).includes(:user).reorder("created_at asc") + else + Discuss.where('root_id = :root_id and (hidden = :hidden or user_id = :user_id)', + root_id: d.id, hidden: false, user_id: current_user.id).includes(:user).reorder("created_at asc") + end + + @children_list << parents.merge( + {:children => (children.map{|child| + [:content => (child.hidden ? (manager ? child.content : "违规评论已被屏蔽!") : child.content), + :time => time_from_now(child.created_at), :position => child.position , + :reward => child.reward,:hidden => child.hidden, :user => d.user, + :can_delete => child.can_deleted?(current_user), + :id => child.id]}.flatten if children.present?) + }) + end + end + end +end \ No newline at end of file diff --git a/app/services/users/apply_trail_service.rb b/app/services/users/apply_trail_service.rb new file mode 100644 index 000000000..61563c301 --- /dev/null +++ b/app/services/users/apply_trail_service.rb @@ -0,0 +1,56 @@ +class Users::ApplyTrailService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :user, :remote_ip, :params + + def initialize(user, params) + @user = user + @remote_ip = params.delete(:remote_ip) + @params = params + end + + def call + Users::ApplyTrailForm.new(params.merge(user: user)).validate! + + ActiveRecord::Base.transaction do + bind_user_phone! unless user.phone_binded? + + apply = ApplyAction.find_or_initialize_by(user_id: user.id, container_type: 'TrialAuthorization', status: 0) + apply.assign_attributes(ip_addr: remote_ip, apply_reason: params[:reason]) if apply.new_record? + + # 自动授权 + if auto_authorization_school_student? + user.update!(certification: 1) + + apply.status = 1 + else + send_trial_apply_notify! + end + apply.save! + end + + user + end + + private + + def bind_user_phone! + code = VerificationCode.where(phone: params[:phone], code: params[:code], code_type: 4).last + + raise Error, '无效的验证码' if code.blank? || !code.effective? + + user.update!(phone: params[:phone]) + end + + def auto_authorization_school_student? + user.user_extension&.student? && School.exists?(auto_users_trial: true, id: user.user_extension&.school_id) + end + + def send_trial_apply_notify! + Educoder::Sms.notify_admin(send_type:'user_apply_auth') + rescue => ex + Rails.logger.error('发送通知管理员短信失败') + Rails.logger.error(ex.message) + ex.backtrace.each { |msg| Rails.logger.error(msg) } + end +end \ No newline at end of file diff --git a/app/services/users/attendance_service.rb b/app/services/users/attendance_service.rb new file mode 100644 index 000000000..a42e77a80 --- /dev/null +++ b/app/services/users/attendance_service.rb @@ -0,0 +1,27 @@ +class Users::AttendanceService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :user + + def initialize(user) + @user = user + end + + def call + nearly_attendance = Attendance.find_by(user_id: user.id) + raise Error, '您已签到过了' if nearly_attendance&.today? + + attendance = nil + ActiveRecord::Base.transaction do + gold = nearly_attendance&.next_gold || 50 + + user.increment!(:grade, gold) + + attendance = user.attendances.create!(score: gold) + + Grade.create!(user_id: user.id, score: gold, container_id: user.id, container_type: 'Attendance') + end + + attendance + end +end diff --git a/app/services/users/bind_email_service.rb b/app/services/users/bind_email_service.rb new file mode 100644 index 000000000..02cf8b91a --- /dev/null +++ b/app/services/users/bind_email_service.rb @@ -0,0 +1,28 @@ +class Users::BindEmailService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + Users::BindEmailForm.new(params).validate! + + raise Error, '该邮箱已被绑定' if User.where.not(id: user.id).exists?(mail: params[:email]) + + code = VerificationCode.where(mail: params[:email], code: params[:code], code_type: 4).last + raise Error, '验证码无效' unless code&.effective? + + ActiveRecord::Base.transaction do + if user.mail.blank? + RewardGradeService.call(user, container_id: user.id, container_type: 'Mail', score: 500) + end + + user.mail = params[:email] + user.save! + end + end +end \ No newline at end of file diff --git a/app/services/users/bind_phone_service.rb b/app/services/users/bind_phone_service.rb new file mode 100644 index 000000000..0ea39ae9b --- /dev/null +++ b/app/services/users/bind_phone_service.rb @@ -0,0 +1,28 @@ +class Users::BindPhoneService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + Users::BindPhoneForm.new(params).validate! + + raise Error, '该手机号已被绑定' if User.where.not(id: user.id).exists?(phone: params[:phone]) + + code = VerificationCode.where(phone: params[:phone], code: params[:code], code_type: 5).last + raise Error, '验证码无效' unless code&.effective? + + ActiveRecord::Base.transaction do + if user.phone.blank? + RewardGradeService.call(user, container_id: user.id, container_type: 'Phone', score: 500) + end + + user.phone = params[:phone] + user.save! + end + end +end \ No newline at end of file diff --git a/app/services/users/course_service.rb b/app/services/users/course_service.rb new file mode 100644 index 000000000..6271db17b --- /dev/null +++ b/app/services/users/course_service.rb @@ -0,0 +1,52 @@ +class Users::CourseService + include CustomSortable + + sort_columns :updated_at, default_by: :updated_at, default_direction: :desc + + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + courses = category_scope_courses.deleted(false) + + courses = status_filter(courses) + + custom_sort(courses, :updated_at, params[:sort_direction]) + end + + private + + def category_scope_courses + case params[:category] + when 'study' then + user.as_student_courses + when 'manage' then + user.manage_courses + else + ids = user.as_student_courses.pluck(:id) + user.manage_courses.pluck(:id) + Course.where(id: ids) + end + end + + def status_filter(relations) + # 只有自己查看才有过滤 + return relations unless observed_logged_user? + + case params[:status] + when 'processing' then + relations.ended(false) + when 'end' then + relations.ended(true) + else + relations + end + end + + def observed_logged_user? + User.current.id == user.id + end +end diff --git a/app/services/users/project_service.rb b/app/services/users/project_service.rb new file mode 100644 index 000000000..7296c0a58 --- /dev/null +++ b/app/services/users/project_service.rb @@ -0,0 +1,51 @@ +class Users::ProjectService + include CustomSortable + + sort_columns :updated_on, default_by: :updated_on, default_direction: :desc + + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + projects = Project.joins(members: :member_roles).where(members: { user_id: user.id }) + + keyword = params[:keyword].to_s.strip + projects = projects.where('name LIKE ?', "%#{keyword}%") if keyword.present? + + projects = projects.where.not(status: 9) # without archived status + + projects = category_filter(projects) + projects = status_filter(projects) + + custom_sort(projects, :updated_on, params[:sort_direction]) + end + + private + + def category_filter(relations) + roles = case params[:category] + when 'study' then [4, 5] + when 'manage' then 3 + else [3, 4, 5] + end + relations.where(member_roles: { role_id: roles }) + end + + def status_filter(relations) + return relations unless self_or_admin? + + case params[:status] + when 'publicly' then relations.where(is_public: true) + when 'personal' then relations.where(is_public: false) + else relations + end + end + + def self_or_admin? + User.current.id == user.id || User.current.admin? + end +end \ No newline at end of file diff --git a/app/services/users/question_bank_service.rb b/app/services/users/question_bank_service.rb new file mode 100644 index 000000000..b17073a4f --- /dev/null +++ b/app/services/users/question_bank_service.rb @@ -0,0 +1,99 @@ +class Users::QuestionBankService + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + relations = class_name.classify.constantize.all + + relations = category_filter(relations) + relations = type_filter(relations) if params[:type].present? + + relations = relations.where(course_list_id: params[:course_list_id]) if params[:course_list_id].present? + + custom_sort(relations, params[:sort_by], params[:sort_direction]) + end + + def course_lists + relation_name = class_name.underscore.pluralize.to_sym + course_lists = CourseList.joins(relation_name).where.not(relation_name => { id: nil }) + + category_condition = + case params[:category] + when 'common' then { homework_type: 1 } + when 'group' then { homework_type: 3 } + when 'exercise' then { container_type: 'Exercise' } + when 'poll' then { container_type: 'Poll' } + when 'gtask', 'gtopic' then {} + else raise ArgumentError + end + course_lists = course_lists.where(relation_name => category_condition) if category_condition.present? + + type_condition = + case params[:type] + when 'personal' then { user_id: user.id } + when 'publicly' then { is_public: true } + else {} + end + course_lists = course_lists.where(relation_name => type_condition) if type_condition.present? + + course_lists.distinct.select(:id, :name) + end + + private + + def class_name + @_class_name ||= begin + case params[:category] + when 'common', 'group' then 'HomeworkBank' + when 'exercise', 'poll' then 'ExerciseBank' + when 'gtask' then 'GtaskBank' + when 'gtopic' then 'GtopicBank' + else raise ArgumentError + end + end + end + + def category_filter(relations) + case params[:category] + when 'common' then + relations.where(homework_type: 1) + when 'group' then + relations.where(homework_type: 3) + when 'exercise' then + relations.where(container_type: 'Exercise') + when 'poll' then + relations.where(container_type: 'Poll') + when 'gtask', 'gtopic' then + relations.all + else + raise ArgumentError + end + end + + def type_filter(relations) + case params[:type] + when 'personal' then relations.where(user_id: user.id) + when 'publicly' then relations.where(is_public: true) + else relations + end + end + + def custom_sort(relations, sort_by, sort_direction) + case sort_by + when 'updated_at' then + relations.order(updated_at: sort_direction) + when 'name' then + relations.order("CONVERT(name USING gbk) COLLATE gbk_chinese_ci #{sort_direction}") + when 'contributor' then + order_sql = "CONVERT (users.lastname USING gbk) COLLATE gbk_chinese_ci #{sort_direction},"\ + " CONVERT (users.firstname USING gbk) COLLATE gbk_chinese_ci #{sort_direction}" + relations.joins(:user).where(users: { status: 1 }).order(order_sql) + else + relations + end + end +end diff --git a/app/services/users/shixun_service.rb b/app/services/users/shixun_service.rb new file mode 100644 index 000000000..b5e5586f1 --- /dev/null +++ b/app/services/users/shixun_service.rb @@ -0,0 +1,97 @@ +class Users::ShixunService + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + shixuns = category_scope_shixuns + + shixuns = user_policy_filter(shixuns) + + custom_order(shixuns, params[:sort_by], params[:sort_direction]) + end + + private + + def category_scope_shixuns + case params[:category] + when 'study' then + user.study_shixuns + when 'manage' then + user.shixuns + else + ids = user.study_shixuns.pluck(:id) + user.shixuns.pluck(:id) + Shixun.where(id: ids) + end + end + + def status_filter(relations) + case params[:category] + when 'study' then + study_shixun_status_filter(relations) + when 'manage' then + manage_shixun_status_filter(relations) + else + relations + end + end + + def user_policy_filter(relations) + # 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能 + if self_or_admin? + relations = relations.where.not(status: -1) + status_filter(relations) + else + relations.where(status: [2, 3], hidden: false) + end + end + + def self_or_admin? + User.current.id == user.id || User.current.admin? + end + + def study_shixun_status_filter(relations) + status = case params[:status] + when 'passed' then 1 + when 'processing' then 0 + end + relations.where(myshixuns: { status: status }) if status + relations + end + + def manage_shixun_status_filter(relations) + status = case params[:status] + when 'editing' then 0 + when 'applying' then 1 + when 'published' then 2 + when 'closed' then 3 + end + relations = relations.where(status: status) if status + relations + end + + def custom_order(relations, sort_by, sort_direction) + sort_by = sort_by&.downcase + sort_direction = sort_direction&.downcase + + if sort_direction.blank? || !%w(desc asc).include?(sort_direction) + sort_direction = 'desc' + end + + if sort_by == 'language' + return relations.left_joins(:tag_repertoires).order("tag_repertoires.name #{sort_direction}") + end + + case params[:category] + when 'study' then + relations.order("myshixuns.updated_at #{sort_direction}") + when 'manage' then + relations.order("shixuns.updated_at #{sort_direction}") + else + relations.order("shixuns.created_at #{sort_direction}") + end + end +end diff --git a/app/services/users/subject_service.rb b/app/services/users/subject_service.rb new file mode 100644 index 000000000..e0d8377c2 --- /dev/null +++ b/app/services/users/subject_service.rb @@ -0,0 +1,85 @@ +class Users::SubjectService + include CustomSortable + + sort_columns :updated_at, default_by: :updated_at, default_direction: :desc + + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + subjects = category_scope_subjects + subjects = user_policy_filter(subjects) + + custom_sort(subjects, :updated_at, params[:sort_direction]) + end + + private + + def category_scope_subjects + case params[:category] + when 'study' then + Subject.joins(stage_shixuns: { shixun: :myshixuns }).where(myshixuns: { user_id: user.id }) + when 'manage' then + Subject.joins(:subject_members).where(subject_members: { user_id: user.id }) + else + study_subject_ids = StageShixun.where(shixun_id: user.myshixuns.pluck(:shixun_id)).pluck(:subject_id) + manage_subject_ids = user.subject_members.pluck(:subject_id) + Subject.where(id: study_subject_ids + manage_subject_ids) + end + end + + def user_policy_filter(relations) + # 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能 + if self_or_admin? + status_filter(relations) + else + relations.where(status: 2, hidden: false) + end + end + + def status_filter(relations) + return relations unless self_or_admin? + + case params[:category] + when 'study' then + study_subject_status_filter(relations) + when 'manage' then + manage_subject_status_filter(relations) + else + relations + end + end + + def study_subject_status_filter(relations) + subjects = Subject.joins(shixuns: :myshixuns) + .where(myshixuns: { user_id: user.id }) + .select('subjects.id, (COUNT(IF(myshixuns.status=1, 1, 0)) = subjects.stages_count) finished') + .group('subjects.id') + subject_ids = + case params[:status] + when 'unfinished' then subjects.having('finished = 0').map(&:id) + when 'finished' then subjects.having('finished = 1').map(&:id) + end + + relations.where(id: subject_ids) if subject_ids.present? + relations + end + + def manage_subject_status_filter(relations) + status = case params[:status] + when 'editing' then 0 + when 'applying' then 1 + when 'published' then 2 + end + relations.where(status: status) if status + relations + end + + def self_or_admin? + User.current.id == user.id || User.current.admin? + end +end diff --git a/app/services/users/update_account_service.rb b/app/services/users/update_account_service.rb new file mode 100644 index 000000000..6a8588dee --- /dev/null +++ b/app/services/users/update_account_service.rb @@ -0,0 +1,61 @@ +class Users::UpdateAccountService < ApplicationService + + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + form = Users::UpdateAccountForm.new(params.merge(user: user)) + form.validate! + + first_full_reward = false + ActiveRecord::Base.transaction do + first_full_reward = user.nickname.blank? + + extension = user.user_extension || user.build_user_extension + + user.assign_attributes(user_attributes) + extension.assign_attributes(user_extension_attributes) + + # 未认证下才能修改姓名 + if !user.authentication? && user.process_real_name_apply.blank? + user.lastname = params[:name] + user.firstname = '' + extension.gender = params[:gender] + end + + if extension.student? + extension.student_id = params[:student_id] + extension.technical_title = nil + else + extension.student_id = nil + extension.technical_title = params[:technical_title] + end + + # 表示资料完整 + user.profile_completed = true + + extension.save! + user.save! + end + + if first_full_reward + RewardGradeService.call(user, container_id: user.id, container_type: 'Account', score: 500) + end + + user + end + + private + + def user_attributes + params.slice(*%i[nickname show_realname]) + end + + def user_extension_attributes + params.slice(*%i[location location_city identity student_id technical_title school_id department_id]) + end +end \ No newline at end of file diff --git a/app/services/users/update_password_service.rb b/app/services/users/update_password_service.rb new file mode 100644 index 000000000..0df32eb76 --- /dev/null +++ b/app/services/users/update_password_service.rb @@ -0,0 +1,32 @@ +class Users::UpdatePasswordService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + Users::UpdatePasswordForm.new(params).validate! + + raise Error, '旧密码不匹配' unless user.check_password?(params[:old_password]) + + ActiveRecord::Base.transaction do + user.update!(password: params[:password]) + + if user.gid.present? + # 同步修改gitlab密码 + begin + Gitlab.client.edit_user(user.gid, password: params[:password]) + rescue Exception => ex + Rails.logger.error(ex.message) + raise Error, '修改失败' + end + end + end + + user + end +end \ No newline at end of file diff --git a/app/templates/exercise_export/blank_exercise.html.erb b/app/templates/exercise_export/blank_exercise.html.erb new file mode 100644 index 000000000..61bde0d27 --- /dev/null +++ b/app/templates/exercise_export/blank_exercise.html.erb @@ -0,0 +1,129 @@ + + + + + + + +
+
+
+
+

<%= @exercise.try(:exercise_name) %>

+
+
+

+ <%= @exercise.try(:exercise_description).nil? ? "" : @exercise.try(:exercise_description).html_safe %> +

+
+
+
+
+
+ <% if @exercise_single_ques_count > 0 %> + 单选题<%= @exercise_single_ques_count %>题, + 共<%= @exercise_single_ques_scores %> + <% end %> + <% if @exercise_double_ques_count > 0 %> + 多选题<%= @exercise_double_ques_count %>题, + 共<%= @exercise_double_ques_scores %> + <% end %> + <% if @exercise_ques_judge_count > 0 %> + 判断题<%= @exercise_ques_judge_count %>题, + 共<%= @exercise_ques_judge_scores %> + <% end %> + <% if @exercise_ques_null_count > 0 %> + 填空题<%= @exercise_ques_null_count %>题, + 共<%= @exercise_ques_null_scores %> + <% end %> + <% if @exercise_ques_main_count > 0 %> + 主观题<%= @exercise_ques_main_count %>题, + 共<%= @exercise_ques_main_scores %> + <% end %> + <% if @exercise_ques_shixun_count > 0 %> + 实训题<%= @exercise_ques_shixun_count %>题, + 共<%= @exercise_ques_shixun_scores %> + <% end %> +
+
合计<%= @exercise_ques_count %>题, + 共<%= @exercise_ques_scores %>分 +
+
+
+
+ <% @exercise_questions.each do |q| %> +
+
+
+ <%= q.question_number %>、 + + <%= q.question_type_name %> + + (<%= q&.question_score %>分) +
+
+ <% if q.question_type == 5 %> + <%= q.shixun_name.present? ? q.shixun_name.html_safe : "" %> +
+ <%= q.question_title.present? ? q.question_title.html_safe : "" %> +
+ <% else %> + <%= q.question_title.present? ? q.question_title.html_safe : "" %> + <% end %> +
+
+ <% if q.question_type == 0 %> + <% q.exercise_choices.each_with_index do |s,index| %> +

+ + <%= convert_to_char((index+1).to_s)%><%= s.choice_text%> +

+ <% end %> + <% elsif q.question_type == 1 %> + <% q.exercise_choices.each_with_index do |s,index| %> +

+ + <%= convert_to_char((index+1).to_s)%><%= s.choice_text%> +

+ <% end %> + <% elsif q.question_type == 2 %> +

+ <% q.exercise_choices.each_with_index do |s,index| %> + + + <%= s.choice_text %> + + <% end %> +

+ <% elsif q.question_type == 3 %> + <% st_counts = q.exercise_standard_answers.pluck(:exercise_choice_id).uniq %> + <% st_counts.each_with_index do |s,index| %> +

+ 答案(填空<%= index+1 %>): + +

+ <% end %> + <% elsif q.question_type == 4 %> +

+ +

+ <% else %> + <% q.exercise_shixun_challenges.each_with_index do |c,index| %> +

+ 第<%= index+1 %>关 + <%= c.challenge.subject %> + + <%= c&.question_score %> 分 + +

+ <% end %> + <% end %> +
+
+
+ <% end %> +
+
+
+ + \ No newline at end of file diff --git a/app/templates/exercise_export/exercise_export.css b/app/templates/exercise_export/exercise_export.css new file mode 100644 index 000000000..91f25e45e --- /dev/null +++ b/app/templates/exercise_export/exercise_export.css @@ -0,0 +1,308 @@ +body{ + font-size:14px;} +p{ + margin:0; +} +.fs13{ + font-size:13px; +} +.fs16{ + font-size:16px; +} +.position-relative{ + position:relative; +} +.text-center{ + text-align:center; +} +.bdc{ + border-bottom:1px solid #eee; +} +.plr15{ + padding:0 15px; +} +.pd10{ + padding:10px; +} +.pbt10{ + padding:10px 0; +} +.pbt5{ + padding:5px 0; +} +.mbt20{ + margin: 20px 0; +} +.mb10{ + margin-bottom: 10px; +} +.mt8{ + margin-top:8px; +} +.mbt10{ + margin: 10px 0; +} +.pull-right{ + float:right; +} +.line-34{ + line-height:34px; +} +.pull-left{ + float:left; +} +.text-orange{ + color: #FC7033; +} +.text-red{ + color:#ff3756; +} +.text-green{ + color: #29BD8B; +} +.bgc{ + background-color:rgb(250, 250, 250); +} +.text-black{color:#333;} +.flex-nowrap{ + display:flex; + white-space: nowrap; +} +.text-blue{ + color:#1890ff; +} +.text-gray{ + color:#999 !important; +} +.mlr5{ + margin:0 5px; +} +.ml20{ + margin-left:20px; +} +.mr3{ + margin-right:3px; +} +.mr15{ + margin-right:15px; +} +.main-height{ + min-height:60px !important; +} +.null-answer{ + background: #eee; + width: 100%; + display: inline-block; + padding: 8px 10px; + border-radius: 2px; + white-space: normal; + min-height:12px; +} +.choose-radio{ + display: inline-block; + width: 12px; + height: 12px; + border-radius: 50%; + border: 1px solid #d9d9d9; + background-color: #fff; + vertical-align: middle; + margin: 0 5px 5px 0 ; +} +.choose-checkbox{ + display: inline-block; + width: 12px; + height: 12px; + border-radius:2px; + border: 1px solid #d9d9d9; + background-color: #fff; + vertical-align: middle; + margin: 0 5px 5px 0 ; +} +.ques-title p:first-child{ + display:inline-block; + margin-bottom:10px; +} +.choose-answer{ + position: relative; + border-color: #1890ff; +} +.choose-answer:after{ + position: absolute; + width: 6px; + height: 6px; + left: 3px; + top: 3px; + border-radius: 8px; + display: table; + border-top: 0; + border-left: 0; + content: " "; + background-color: #1890ff; +} +.choose-answer-multi{ + background-color: #1890ff; + border-color: #1890ff; + position: relative; + width:12px; + height: 12px; +} +.choose-answer-multi:after{ + content: "\2713"; + color:#fff; + height: 9px; + width: 7px; + position: absolute; + display: inline-block; + bottom: 6px; + /*left: 1px;*/ +} + +.line-line { + width:15px; + height: 7px; + border-radius:6px; + margin-right:5px; + display:inline-block; +} +.bd-ee{ + border:1px solid #eee; + padding:5px; +} +.bg-red{ + background-color:#ff3756; +} +.bg-orange{ + background-color:#FC7033; +} +.bg-green{ + background-color:#29BD8B; +} +.bg-gray{ + background-color: #ccc; +} +.bg-e{ + background-color:#eee; +} +.right-status{ + width:28px; + height:28px; + border-radius: 50%; + text-align:center; + margin:5px 3px; +} +.right-status span{ + color:#fff; + font-size:13px; + line-height: 28px; +} +.inline-block{ + display:inline-block; +} +.circle-review{ + width:12px; + height:12px; + border-radius: 50%; + border:1px solid #ccc; + margin-right:5px; + display:inline-block; +} +.bd-radius{ + border:1px solid #ccc +} +.user-score{ + float:right; +} +.circle-score{ + width:14px; + height:14px; + border-radius:50%; + position: relative; + display:inline-block; + vertical-align: middle; + margin-bottom: 2px; +} +.circle-wrong:after{ + color:#fff; + content: "\2715"; + height: 7px; + width: 7px; + position: absolute; + display: inline-block; + bottom: 9px; + left: 3px; +} +.circle-right:after{ + color:#fff; + content: "\2713"; + height: 7px; + width: 7px; + position: absolute; + display: inline-block; + bottom: 9px; + left: 0; +} +table{ + width:100%; + text-align:center; +} + +table, tr, td, th, tbody, thead, tfoot,textarea{ + page-break-inside: avoid; +} +table th{ + padding:10px 0; +} +table td{ + padding: 10px 0; + border-bottom: 1px solid #eee; +} +.shixun-detail td{ + border:1px solid #eee; +} +.code_content_show{ + width:95%; + height:100%; + line-height:1.8; + border:none; + padding-left:10px; + resize:none; + overflow: hidden; +} +.test-code{ + position: relative; + width:100%; + display:inline-block; +} +.line-no{ + width: 28px; + display: inline-block; +} +.line-no p{ + line-height:1.8; + text-align: center; + color:#999; +} +.pull-left{ + float:left; +} +.avatar-32{ + width:32px; + height:32px; + border-radius:50%; +} +.ml38{ + margin-left:38px; +} +/*.shixun-detail{*/ + /*max-height:100%;*/ +/*}*/ +textarea{ + width:100%; + resize:none; + border:none; + background-color:#eee; + line-height:2; +} + + + diff --git a/app/templates/exercise_export/exercise_user.html.erb b/app/templates/exercise_export/exercise_user.html.erb new file mode 100644 index 000000000..713f09ee4 --- /dev/null +++ b/app/templates/exercise_export/exercise_user.html.erb @@ -0,0 +1,348 @@ + + + + + + + +
+
+
+
+

<%= @exercise.try(:exercise_name) %>

+
+
+

+ <%= @exercise.try(:exercise_description).nil? ? "" : @exercise.try(:exercise_description).html_safe %> +

+
+
+
+
+
+ <% if @exercise_single_ques_count > 0 %> + 单选题<%= @exercise_single_ques_count %>题, + 共<%= @exercise_single_ques_scores %> + <% end %> + <% if @exercise_double_ques_count > 0 %> + 多选题<%= @exercise_double_ques_count %>题, + 共<%= @exercise_double_ques_scores %> + <% end %> + <% if @exercise_ques_judge_count > 0 %> + 判断题<%= @exercise_ques_judge_count %>题, + 共<%= @exercise_ques_judge_scores %> + <% end %> + <% if @exercise_ques_null_count > 0 %> + 填空题<%= @exercise_ques_null_count %>题, + 共<%= @exercise_ques_null_scores %> + <% end %> + <% if @exercise_ques_main_count > 0 %> + 主观题<%= @exercise_ques_main_count %>题, + 共<%= @exercise_ques_main_scores %> + <% end %> + <% if @exercise_ques_shixun_count > 0 %> + 实训题<%= @exercise_ques_shixun_count %>题, + 共<%= @exercise_ques_shixun_scores %> + <% end %> +
+
+ 合计<%= @exercise_ques_count %>题, + 共<%= @exercise_ques_scores %>分 +
+
+
+
+ <% if @ex_obj_array.size > 0 %> +
+

+ 客观题 + 正确 + 错误 + 部分得分 + 总分:<%= @exercise_user.score %>分 +

+
+
+ <% @ex_obj_array.each do |s| %> + <% if s[:stand_status] == 1 %> +
+ <%= s[:q_position] %> +
+ <% elsif s[:stand_status] == 0 %> +
+ <%= s[:q_position] %> +
+ <% else %> +
+ <%= s[:q_position] %> +
+ <% end %> + <% end %> +
+ <% end %> + <% if @ex_sub_array.size > 0 %> +
+

+ 主观题 + 已评 + 未评 + 开始答题时间:<%= @exercise_user.start_at.present? ? @exercise_user.start_at.strftime("%Y-%m-%d %H:%M") : "--" %> +

+
+
+ <% @ex_sub_array.each do |s| %> + <% if s[:stand_status] == 0 %> +
+ <%= s[:q_position] %> +
+ <% else %> +
+ <%= s[:q_position] %> +
+ <% end %> + <% end %> +
+ <% end %> +
+
+ <% @exercise_questions.each do |q| %> + <% q_type = q.question_type %> + <% user_answer = (q_type == 5 ? q.exercise_shixun_answers.where(user_id: @ex_user_user.id) : q.exercise_answers.where(user_id: @ex_user_user.id)) %> + <% this_ques_status = @ex_obj_array.detect{|f| f[:q_id] == q.id} %> + <% main_ques_status = @ex_sub_array.detect{|f| f[:q_id] == q.id} %> + <% ques_comment = q.exercise_answer_comments.where("exercise_answer_id",user_answer.first&.id) %> +
+
+
+
+ <%= q.question_number %>、  + + <%= q.question_type_name %> + + (<%= q&.question_score %>分) + <% if q_type == 5 %> + + <% if this_ques_status.present? && this_ques_status[:stand_status] == 1 %> + + <%= this_ques_status[:user_score] %>分 + <% elsif this_ques_status.present? && this_ques_status[:stand_status] == 2 %> + + <%= this_ques_status[:user_score] %>分 + <% else %> + + 0.0分 + <% end %> + + <% elsif q_type == 4 %> + + <% if main_ques_status.present? && main_ques_status[:stand_status] == 1 %> + + <%= main_ques_status[:user_score] %>分 + <% elsif main_ques_status.present? && main_ques_status[:stand_status] == 2 %> + + <%= main_ques_status[:user_score] %>分 + <% else %> + 未批 + <% end %> + + <% else %> + + <% if this_ques_status.present? && this_ques_status[:stand_status] == 1 %> + + <%= this_ques_status[:user_score] %>分 + <% elsif this_ques_status.present? && this_ques_status[:stand_status] == 2 %> + + <%= this_ques_status[:user_score] %>分 + <% else %> + + 0.0分 + <% end %> + + <% end %> +
+
+ <% if q_type == 5 %> + <%= q.shixun_name.html_safe %> +
+ <%= q.question_title.html_safe %> +
+ <% elsif q_type == 4 %> + <%= q.question_title.html_safe %> + <% else %> + <%= q.question_title.html_safe %> + <% end %> +
+
+
+ <% if q_type == 0 %> + <% q.exercise_choices.each_with_index do |s,index| %> + <% check_answer = (user_answer.present? && (s.id == user_answer.first.exercise_choice_id)) ? "choose-answer" : '' %> +

+ + <%= convert_to_char((index+1).to_s)%><%= s.choice_text%> +

+ <% end %> + <% elsif q_type == 1 %> + <% q.exercise_choices.each_with_index do |s,index| %> + <% check_answer = (user_answer.present? && (user_answer.pluck(:exercise_choice_id).include?(s.id))) ? true : false %> +

+ <% if check_answer %> + + <% else %> + + <% end %> + <%= convert_to_char((index+1).to_s)%><%= s.choice_text%> +

+ <% end %> + <% elsif q_type == 2 %> +

+ <% q.exercise_choices.each do |s| %> + <% if user_answer.present? && (s.id == user_answer.first.exercise_choice_id) %> + <% check_answer = 'choose-answer' %> + <% else %> + <% check_answer = '' %> + <% end %> + + + <%= s.choice_text %> + + <% end %> +

+ <% elsif q_type == 3 %> + <% st_counts = q.exercise_standard_answers.pluck(:exercise_choice_id).uniq %> + <% st_counts.each_with_index do |s,index| %> + <% if user_answer.present? && user_answer.where(exercise_choice_id:s).present? %> + <% check_answer = user_answer.where(exercise_choice_id:s).first.answer_text %> + <% else %> + <% check_answer = "--" %> + <% end %> +

+ 答案(填空<%= index+1 %>): + <%= check_answer.html_safe %> +

+ <% end %> + <% elsif q_type == 4 %> + <% check_answer = (user_answer.present? ? user_answer.first.answer_text : '--') %> +

+ <%= check_answer.html_safe %> +

+ <% else %> +
+

+ 阶段成绩 +

+ + + + + + + + + + + + <% if @games.size > 0 %> + <% @games.each_with_index do |game, index| %> + <% user_score = q.exercise_shixun_answers.where(exercise_shixun_challenge_id:game.challenge.id,user_id: @ex_user_user.id) %> + <% game_score = q.exercise_shixun_challenges.where(challenge_id:game.challenge.id) %> + + + + + + + + + + <% end %> + <% else %> + <% q.exercise_shixun_challenges.each_with_index do |game, index| %> + <% game_score = q.exercise_shixun_challenges.where(challenge_id:game.challenge.id) %> + + + + + + + + + + <% end %> + <% end %> + +
关卡任务名称评测次数完成时间耗时经验值得分/满分
<%= index + 1 %> + <%= game.challenge.subject %> + <%= game.evaluate_count %><%= game.end_time.present? ? game.end_time.strftime("%Y-%m-%d %H:%M") : "--" %><%= ApplicationController.helpers.time_consuming game %><%= game.final_score %> / <%= game.challenge.all_score %><%= user_score.present? ? user_score.first.score : 0.0 %> / <%= game_score.present? ? game_score.first.question_score : 0.0 %>
<%= index + 1 %> + <%= game.challenge.subject %> + 0----0.0 / <%= game.challenge.all_score %>0.0 / <%= game_score.present? ? game_score.first.question_score : 0.0 %>
+
+
+

+ 实训详情 +

+ <% @games.each_with_index do |game, index| %> +
+

+ 第<%= index+1 %>关<%= game.challenge.subject %> +

+
+ <% if game.outputs.present? %> + + + + + + + <% outputs = game.outputs.group("query_index") %> + <% outputs.reverse.try(:each) do |output| %> + + + + + <% end %> + +
评测次数评测信息
<%= "第#{output.query_index}次" %><%= output_detail(game, output) %>
+ <% end %> + <% if game.try(:lastest_code).present? && game.challenge.st == 0 %> + <% con_rows = content_line(game.lastest_code) %> +
+

+ + 最近通过的代码 + <%= game.challenge.path %> + +

+
+ +
+
+ <% end %> +
+
+ <% end %> +
+ <% end %> +
+
+
+ <% if ques_comment.present? && ques_comment.first.comment.present? %> + <% ques_user = ques_comment.first.user %> +
+
+
+ +
+
+

<%= ques_user.real_name %><%= ques_comment.first.updated_at.strftime('%Y-%m-%d %H:%M') %>

+

<%= ques_comment.first.comment %>

+
+
+
+ <% end %> + <% end %> +
+
+
+ + diff --git a/app/templates/shared/codemirror.css b/app/templates/shared/codemirror.css new file mode 100644 index 000000000..8d8aa2b6b --- /dev/null +++ b/app/templates/shared/codemirror.css @@ -0,0 +1,892 @@ +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + color: black; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror-cursor { + border-left: 1px solid black; + border-right: none; + width: 0; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.cm-fat-cursor .CodeMirror-cursor { + width: auto; + border: 0; + background: #7e7; +} +.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} + +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + background-color: #7e7; +} +@-moz-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@-webkit-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} + +/* Can style cursor different in overwrite (non-insert) mode */ +.CodeMirror-overwrite .CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3 {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +.CodeMirror-composing { border-bottom: 2px solid; } + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + min-height: 100%; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -30px; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + background: none !important; + border: none !important; +} +.CodeMirror-gutter-background { + position: absolute; + top: 0; bottom: 0; + z-index: 4; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} +.CodeMirror-gutter-wrapper { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + -webkit-font-variant-ligatures: none; + font-variant-ligatures: none; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; +} + +.CodeMirror-widget {} + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.CodeMirror-cursor { position: absolute; } +.CodeMirror-measure pre { position: static; } + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +div.CodeMirror-dragcursors { + visibility: visible; +} + +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { *vertical-align: text-bottom; } + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } + +/* + + Name: dracula + Author: Michael Kaminsky (http://github.com/mkaminsky11) + + Original dracula color scheme by Zeno Rocha (https://github.com/zenorocha/dracula-theme) + +*/ + + +.cm-s-dracula.CodeMirror, .cm-s-dracula .CodeMirror-gutters { + background-color: #282a36 !important; + color: #f8f8f2 !important; + border: none; +} +.cm-s-dracula .CodeMirror-gutters { color: #282a36; } +.cm-s-dracula .CodeMirror-cursor { border-left: solid thin #f8f8f0; } +.cm-s-dracula .CodeMirror-linenumber { color: #6D8A88; } +.cm-s-dracula.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); } +.cm-s-dracula .CodeMirror-line::selection, .cm-s-dracula .CodeMirror-line > span::selection, .cm-s-dracula .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); } +.cm-s-dracula .CodeMirror-line::-moz-selection, .cm-s-dracula .CodeMirror-line > span::-moz-selection, .cm-s-dracula .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); } +.cm-s-dracula span.cm-comment { color: #6272a4; } +.cm-s-dracula span.cm-string, .cm-s-dracula span.cm-string-2 { color: #f1fa8c; } +.cm-s-dracula span.cm-number { color: #bd93f9; } +.cm-s-dracula span.cm-variable { color: #50fa7b; } +.cm-s-dracula span.cm-variable-2 { color: white; } +.cm-s-dracula span.cm-def { color: #ffb86c; } +.cm-s-dracula span.cm-keyword { color: #ff79c6; } +.cm-s-dracula span.cm-operator { color: #ff79c6; } +.cm-s-dracula span.cm-keyword { color: #ff79c6; } +.cm-s-dracula span.cm-atom { color: #bd93f9; } +.cm-s-dracula span.cm-meta { color: #f8f8f2; } +.cm-s-dracula span.cm-tag { color: #ff79c6; } +.cm-s-dracula span.cm-attribute { color: #50fa7b; } +.cm-s-dracula span.cm-qualifier { color: #50fa7b; } +.cm-s-dracula span.cm-property { color: #66d9ef; } +.cm-s-dracula span.cm-builtin { color: #50fa7b; } +.cm-s-dracula span.cm-variable-3 { color: #50fa7b; } + +.cm-s-dracula .CodeMirror-activeline-background { background: rgba(255,255,255,0.1); } +.cm-s-dracula .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } + +.cm-s-eclipse span.cm-meta { color: #FF1717; } +.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; } +.cm-s-eclipse span.cm-atom { color: #219; } +.cm-s-eclipse span.cm-number { color: #164; } +.cm-s-eclipse span.cm-def { color: #00f; } +.cm-s-eclipse span.cm-variable { color: black; } +.cm-s-eclipse span.cm-variable-2 { color: #0000C0; } +.cm-s-eclipse span.cm-variable-3 { color: #0000C0; } +.cm-s-eclipse span.cm-property { color: black; } +.cm-s-eclipse span.cm-operator { color: black; } +.cm-s-eclipse span.cm-comment { color: #3F7F5F; } +.cm-s-eclipse span.cm-string { color: #2A00FF; } +.cm-s-eclipse span.cm-string-2 { color: #f50; } +.cm-s-eclipse span.cm-qualifier { color: #555; } +.cm-s-eclipse span.cm-builtin { color: #30a; } +.cm-s-eclipse span.cm-bracket { color: #cc7; } +.cm-s-eclipse span.cm-tag { color: #170; } +.cm-s-eclipse span.cm-attribute { color: #00c; } +.cm-s-eclipse span.cm-link { color: #219; } +.cm-s-eclipse span.cm-error { color: #f00; } + +.cm-s-eclipse .CodeMirror-activeline-background { background: #e8f2ff; } +.cm-s-eclipse .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } + +.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom { color: #762; } +.cm-s-elegant span.cm-comment { color: #262; font-style: italic; line-height: 1em; } +.cm-s-elegant span.cm-meta { color: #555; font-style: italic; line-height: 1em; } +.cm-s-elegant span.cm-variable { color: black; } +.cm-s-elegant span.cm-variable-2 { color: #b11; } +.cm-s-elegant span.cm-qualifier { color: #555; } +.cm-s-elegant span.cm-keyword { color: #730; } +.cm-s-elegant span.cm-builtin { color: #30a; } +.cm-s-elegant span.cm-link { color: #762; } +.cm-s-elegant span.cm-error { background-color: #fdd; } + +.cm-s-elegant .CodeMirror-activeline-background { background: #e8f2ff; } +.cm-s-elegant .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } + +/* Based on Sublime Text's Monokai theme */ + +.cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; } +.cm-s-monokai div.CodeMirror-selected { background: #49483E; } +.cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); } +.cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); } +.cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; } +.cm-s-monokai .CodeMirror-guttermarker { color: white; } +.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; } + +.cm-s-monokai span.cm-comment { color: #75715e; } +.cm-s-monokai span.cm-atom { color: #ae81ff; } +.cm-s-monokai span.cm-number { color: #ae81ff; } + +.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; } +.cm-s-monokai span.cm-keyword { color: #f92672; } +.cm-s-monokai span.cm-builtin { color: #66d9ef; } +.cm-s-monokai span.cm-string { color: #e6db74; } + +.cm-s-monokai span.cm-variable { color: #a6e22e; } +.cm-s-monokai span.cm-variable-2 { color: #9effff; } +.cm-s-monokai span.cm-variable-3 { color: #66d9ef; } +.cm-s-monokai span.cm-def { color: #fd971f; } +.cm-s-monokai span.cm-bracket { color: #f8f8f2; } +.cm-s-monokai span.cm-tag { color: #f92672; } +.cm-s-monokai span.cm-header { color: #ae81ff; } +.cm-s-monokai span.cm-link { color: #ae81ff; } +.cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; } + +.cm-s-monokai .CodeMirror-activeline-background { background: #373831; } +.cm-s-monokai .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} + +/* + + Name: Railscasts + Author: Ryan Bates (http://railscasts.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-railscasts.CodeMirror {background: #2b2b2b; color: #f4f1ed;} +.cm-s-railscasts div.CodeMirror-selected {background: #214283 !important;} +.cm-s-railscasts .CodeMirror-gutters {background: #2b2b2b; border-right: 0px;} +.cm-s-railscasts .CodeMirror-linenumber {color: #5a647e;} +.cm-s-railscasts .CodeMirror-cursor {border-left: 1px solid #d4cfc9 !important;} + +.cm-s-railscasts span.cm-comment {color: #bc9458;} +.cm-s-railscasts span.cm-atom {color: #b6b3eb;} +.cm-s-railscasts span.cm-number {color: #b6b3eb;} + +.cm-s-railscasts span.cm-property, .cm-s-railscasts span.cm-attribute {color: #a5c261;} +.cm-s-railscasts span.cm-keyword {color: #da4939;} +.cm-s-railscasts span.cm-string {color: #ffc66d;} + +.cm-s-railscasts span.cm-variable {color: #a5c261;} +.cm-s-railscasts span.cm-variable-2 {color: #6d9cbe;} +.cm-s-railscasts span.cm-def {color: #cc7833;} +.cm-s-railscasts span.cm-error {background: #da4939; color: #d4cfc9;} +.cm-s-railscasts span.cm-bracket {color: #f4f1ed;} +.cm-s-railscasts span.cm-tag {color: #da4939;} +.cm-s-railscasts span.cm-link {color: #b6b3eb;} + +.cm-s-railscasts .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} +.cm-s-railscasts .CodeMirror-activeline-background { background: #303040; } + +/* +Solarized theme for code-mirror +http://ethanschoonover.com/solarized +*/ + +/* +Solarized color pallet +http://ethanschoonover.com/solarized/img/solarized-palette.png +*/ + +.solarized.base03 { color: #002b36; } +.solarized.base02 { color: #073642; } +.solarized.base01 { color: #586e75; } +.solarized.base00 { color: #657b83; } +.solarized.base0 { color: #839496; } +.solarized.base1 { color: #93a1a1; } +.solarized.base2 { color: #eee8d5; } +.solarized.base3 { color: #fdf6e3; } +.solarized.solar-yellow { color: #b58900; } +.solarized.solar-orange { color: #cb4b16; } +.solarized.solar-red { color: #dc322f; } +.solarized.solar-magenta { color: #d33682; } +.solarized.solar-violet { color: #6c71c4; } +.solarized.solar-blue { color: #268bd2; } +.solarized.solar-cyan { color: #2aa198; } +.solarized.solar-green { color: #859900; } + +/* Color scheme for code-mirror */ + +.cm-s-solarized { + line-height: 1.45em; + color-profile: sRGB; + rendering-intent: auto; +} +.cm-s-solarized.cm-s-dark { + color: #839496; + background-color: #002b36; + text-shadow: #002b36 0 1px; +} +.cm-s-solarized.cm-s-light { + background-color: #fdf6e3; + color: #657b83; + text-shadow: #eee8d5 0 1px; +} + +.cm-s-solarized .CodeMirror-widget { + text-shadow: none; +} + +.cm-s-solarized .cm-header { color: #586e75; } +.cm-s-solarized .cm-quote { color: #93a1a1; } + +.cm-s-solarized .cm-keyword { color: #cb4b16; } +.cm-s-solarized .cm-atom { color: #d33682; } +.cm-s-solarized .cm-number { color: #d33682; } +.cm-s-solarized .cm-def { color: #2aa198; } + +.cm-s-solarized .cm-variable { color: #839496; } +.cm-s-solarized .cm-variable-2 { color: #b58900; } +.cm-s-solarized .cm-variable-3 { color: #6c71c4; } + +.cm-s-solarized .cm-property { color: #2aa198; } +.cm-s-solarized .cm-operator { color: #6c71c4; } + +.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; } + +.cm-s-solarized .cm-string { color: #859900; } +.cm-s-solarized .cm-string-2 { color: #b58900; } + +.cm-s-solarized .cm-meta { color: #859900; } +.cm-s-solarized .cm-qualifier { color: #b58900; } +.cm-s-solarized .cm-builtin { color: #d33682; } +.cm-s-solarized .cm-bracket { color: #cb4b16; } +.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; } +.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; } +.cm-s-solarized .cm-tag { color: #93a1a1; } +.cm-s-solarized .cm-attribute { color: #2aa198; } +.cm-s-solarized .cm-hr { + color: transparent; + border-top: 1px solid #586e75; + display: block; +} +.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; } +.cm-s-solarized .cm-special { color: #6c71c4; } +.cm-s-solarized .cm-em { + color: #999; + text-decoration: underline; + text-decoration-style: dotted; +} +.cm-s-solarized .cm-strong { color: #eee; } +.cm-s-solarized .cm-error, +.cm-s-solarized .cm-invalidchar { + color: #586e75; + border-bottom: 1px dotted #dc322f; +} + +.cm-s-solarized.cm-s-dark div.CodeMirror-selected { background: #073642; } +.cm-s-solarized.cm-s-dark.CodeMirror ::selection { background: rgba(7, 54, 66, 0.99); } +.cm-s-solarized.cm-s-dark .CodeMirror-line::-moz-selection, .cm-s-dark .CodeMirror-line > span::-moz-selection, .cm-s-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(7, 54, 66, 0.99); } + +.cm-s-solarized.cm-s-light div.CodeMirror-selected { background: #eee8d5; } +.cm-s-solarized.cm-s-light .CodeMirror-line::selection, .cm-s-light .CodeMirror-line > span::selection, .cm-s-light .CodeMirror-line > span > span::selection { background: #eee8d5; } +.cm-s-solarized.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-ligh .CodeMirror-line > span::-moz-selection, .cm-s-ligh .CodeMirror-line > span > span::-moz-selection { background: #eee8d5; } + +/* Editor styling */ + + + +/* Little shadow on the view-port of the buffer view */ +.cm-s-solarized.CodeMirror { + -moz-box-shadow: inset 7px 0 12px -6px #000; + -webkit-box-shadow: inset 7px 0 12px -6px #000; + box-shadow: inset 7px 0 12px -6px #000; +} + +/* Gutter border and some shadow from it */ +.cm-s-solarized .CodeMirror-gutters { + border-right: 1px solid; +} + +/* Gutter colors and line number styling based of color scheme (dark / light) */ + +/* Dark */ +.cm-s-solarized.cm-s-dark .CodeMirror-gutters { + background-color: #002b36; + border-color: #00232c; +} + +.cm-s-solarized.cm-s-dark .CodeMirror-linenumber { + text-shadow: #021014 0 -1px; +} + +/* Light */ +.cm-s-solarized.cm-s-light .CodeMirror-gutters { + background-color: #fdf6e3; + border-color: #eee8d5; +} + +/* Common */ +.cm-s-solarized .CodeMirror-linenumber { + color: #586e75; + padding: 0 5px; +} +.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; } +.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; } +.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; } + +.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text { + color: #586e75; +} + +.cm-s-solarized .CodeMirror-cursor { border-left: 1px solid #819090; } + +/* +Active line. Negative margin compensates left padding of the text in the +view-port +*/ +.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background { + background: rgba(255, 255, 255, 0.10); +} +.cm-s-solarized.cm-s-light .CodeMirror-activeline-background { + background: rgba(0, 0, 0, 0.10); +} + +.CodeMirror-foldmarker { + color: blue; + text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; + font-family: arial; + line-height: .3; + cursor: pointer; +} +.CodeMirror-foldgutter { + width: .7em; +} +.CodeMirror-foldgutter-open, +.CodeMirror-foldgutter-folded { + cursor: pointer; +} +.CodeMirror-foldgutter-open:after { + content: "\25BE"; +} +.CodeMirror-foldgutter-folded:after { + content: "\25B8"; +} + +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 2px; + + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + border-radius: 3px; + border: 1px solid silver; + + background: white; + font-size: 90%; + font-family: monospace; + + max-height: 20em; + overflow-y: auto; +} + +.CodeMirror-hint { + margin: 0; + padding: 0 4px; + border-radius: 2px; + max-width: 19em; + overflow: hidden; + white-space: pre; + color: black; + cursor: pointer; +} + +li.CodeMirror-hint-active { + background: #08f; + color: white; +} + +/* The lint marker gutter */ +.CodeMirror-lint-markers { + width: 16px; +} + +.CodeMirror-lint-tooltip { + background-color: infobackground; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: infotext; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px 5px; + position: fixed; + white-space: pre; + white-space: pre-wrap; + z-index: 100; + max-width: 600px; + opacity: 0; + transition: opacity .4s; + -moz-transition: opacity .4s; + -webkit-transition: opacity .4s; + -o-transition: opacity .4s; + -ms-transition: opacity .4s; +} + +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { + background-position: left bottom; + background-repeat: repeat-x; +} + +.CodeMirror-lint-mark-error { + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") +; +} + +.CodeMirror-lint-mark-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + width: 16px; + vertical-align: middle; + position: relative; +} + +.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { + padding-left: 18px; + background-position: top left; + background-repeat: no-repeat; +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-multiple { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); + background-repeat: no-repeat; + background-position: right bottom; + width: 100%; height: 100%; +} + +.CodeMirror-search-match { + background: gold; + border-top: 1px solid orange; + border-bottom: 1px solid orange; + -moz-box-sizing: border-box; + box-sizing: border-box; + opacity: .5; +} + +.cm-s-liquibyte.CodeMirror { + background-color: #000; + color: #fff; + line-height: 1.2em; + font-size: 1em; +} +.CodeMirror-focused .cm-matchhighlight { + text-decoration: underline; + text-decoration-color: #0f0; + text-decoration-style: wavy; +} +.cm-trailingspace { + text-decoration: line-through; + text-decoration-color: #f00; + text-decoration-style: dotted; +} +.cm-tab { + /*text-decoration: line-through;*/ + text-decoration-color: #404040; + text-decoration-style: dotted; +} +.cm-s-liquibyte .CodeMirror-gutters { background-color: #262626; border-right: 1px solid #505050; padding-right: 0.8em; } +.cm-s-liquibyte .CodeMirror-gutter-elt div{ font-size: 1.2em; } +.cm-s-liquibyte .CodeMirror-guttermarker { } +.cm-s-liquibyte .CodeMirror-guttermarker-subtle { } +.cm-s-liquibyte .CodeMirror-linenumber { color: #606060; padding-left: 0;} +.cm-s-liquibyte .CodeMirror-cursor { border-left: 1px solid #eee !important; } + +.cm-s-liquibyte span.cm-comment { color: #008000; } +.cm-s-liquibyte span.cm-def { color: #ffaf40; font-weight: bold; } +.cm-s-liquibyte span.cm-keyword { color: #c080ff; font-weight: bold; } +.cm-s-liquibyte span.cm-builtin { color: #ffaf40; font-weight: bold; } +.cm-s-liquibyte span.cm-variable { color: #5967ff; font-weight: bold; } +.cm-s-liquibyte span.cm-string { color: #ff8000; } +.cm-s-liquibyte span.cm-number { color: #0f0; font-weight: bold; } +.cm-s-liquibyte span.cm-atom { color: #bf3030; font-weight: bold; } + +.cm-s-liquibyte span.cm-variable-2 { color: #007f7f; font-weight: bold; } +.cm-s-liquibyte span.cm-variable-3 { color: #c080ff; font-weight: bold; } +.cm-s-liquibyte span.cm-property { color: #999; font-weight: bold; } +.cm-s-liquibyte span.cm-operator { color: #fff; } + +.cm-s-liquibyte span.cm-meta { color: #0f0; } +.cm-s-liquibyte span.cm-qualifier { color: #fff700; font-weight: bold; } +.cm-s-liquibyte span.cm-bracket { color: #cc7; } +.cm-s-liquibyte span.cm-tag { color: #ff0; font-weight: bold; } +.cm-s-liquibyte span.cm-attribute { color: #c080ff; font-weight: bold; } +.cm-s-liquibyte span.cm-error { color: #f00; } + +.cm-s-liquibyte .CodeMirror-selected { background-color: rgba(255, 0, 0, 0.25) !important; } + +.cm-s-liquibyte span.cm-compilation { background-color: rgba(255, 255, 255, 0.12); } + +.cm-s-liquibyte .CodeMirror-activeline-background {background-color: rgba(0, 255, 0, 0.15) !important;} + +/* Default styles for common addons */ +div.CodeMirror span.CodeMirror-matchingbracket { color: #0f0; font-weight: bold; } +div.CodeMirror span.CodeMirror-nonmatchingbracket { color: #f00; font-weight: bold; } +.CodeMirror-matchingtag { background-color: rgba(150, 255, 0, .3); } +/* Scrollbars */ +/* Simple */ +div.CodeMirror-simplescroll-horizontal div:hover, div.CodeMirror-simplescroll-vertical div:hover { + background-color: rgba(80, 80, 80, .7); +} +div.CodeMirror-simplescroll-horizontal div, div.CodeMirror-simplescroll-vertical div { + background-color: rgba(80, 80, 80, .3); + border: 1px solid #404040; + border-radius: 5px; +} +div.CodeMirror-simplescroll-vertical div { + border-top: 1px solid #404040; + border-bottom: 1px solid #404040; +} +div.CodeMirror-simplescroll-horizontal div { + border-left: 1px solid #404040; + border-right: 1px solid #404040; +} +div.CodeMirror-simplescroll-vertical { + background-color: #262626; +} +div.CodeMirror-simplescroll-horizontal { + background-color: #262626; + border-top: 1px solid #404040; +} +/* Overlay */ +div.CodeMirror-overlayscroll-horizontal div, div.CodeMirror-overlayscroll-vertical div { + background-color: #404040; + border-radius: 5px; +} +div.CodeMirror-overlayscroll-vertical div { + border: 1px solid #404040; +} +div.CodeMirror-overlayscroll-horizontal div { + border: 1px solid #404040; +} \ No newline at end of file diff --git a/app/templates/shared/main.css b/app/templates/shared/main.css new file mode 100644 index 000000000..48fd91b15 --- /dev/null +++ b/app/templates/shared/main.css @@ -0,0 +1,781 @@ +/*整体公用样式--------------主题颜色为蓝色#459be5,字体颜色为#05101a*/ +@charset "utf-8"; +body{font-size:14px; line-height:2.0;background:#fafafa!important;font-family: "微软雅黑","宋体"; color:#05101a;height: 100%;position: relative; +} +html,body{height:100%;} +body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td,span{ margin:0; padding:0;} +table,input,textarea,select,button {outline: none;border-radius: 3px; font-family: "微软雅黑","宋体"; font-size:14px;line-height:1.9;border:1px solid #eaeaea;background: #FFFFff; color:#05101A;} +textarea{resize: none;} +/*设置input框的placehoder的字体颜色*/ +input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color: #cccccc} +input::-moz-placeholder,textarea::-moz-placeholder { color:#cccccc;} +input::-moz-placeholder,textarea::-moz-placeholder { color:#cccccc;} +input::-ms-input-placeholder,textarea::-ms-input-placeholder {color:#cccccc;} + +div,img,tr,td,table{ border:0;} +a:link,a:visited{text-decoration:none; color:#05101a;} +a:hover {color:#459be5;} +ol, ul, li {list-style-type: none;} +select:disabled,input:disabled{background-color: #EEEEEE;} +/*万能清除浮动*/ +.clearfix:after{clear:both;content:".";display:block;font-size:0;height:0;line-height:0;visibility:hidden;} +.clearfix{clear:both;zoom:1} +.cl{ clear: both; overflow: hidden;} +/*通用浮动*/ +.fl{ float: left!important;} +.fr{ float: right!important;} +/*pre标签换行*/ +.break-word{word-break: break-all;word-wrap: break-word;} +.break-word-firefox{white-space: pre-wrap !important;word-break: break-all;} +/*文字左右两端对齐*/ +.justify{text-align: justify} +.indent{text-indent: 2em;} + +.edu-name-dark{ max-width:100px; display: block; } +.edu-info-dark{ max-width:345px; display: block; } +.edu-max-h200{ height:200px; overflow: auto;} +.edu-h260{ height:260px;} +.edu-h270{ height:270px;} +.edu-h310{ height:310px;} +.edu-position{ position: relative;} +.edu-h200-auto{ max-height:200px; overflow:auto;} +.edu-h300-auto{ max-height:300px; overflow:auto;} +.edu-h350-auto{ max-height:350px; overflow:auto;} +.edu-h280-auto{ height:280px; overflow:auto;} +.edu-txt-w240{ width:240px; display: block;} +.edu-txt-w280{ width:280px; display: block;} +.edu-txt-w320{ width:320px; display: block;} +.edu-txt-w200{ width:200px; display: block;} +a.edu-txt-w280,.edu-txt-w280{ width:280px; display: inline-block;text-align: center} +a.edu-txt-w190,.edu-txt-w190{ width:190px; display: inline-block;text-align: center} +a.edu-txt-w160,.edu-txt-w160{ width:160px; display: inline-block;text-align: center} +a.edu-txt-w140,.edu-txt-w140{ width:141px; display: inline-block;text-align: center} +a.edu-txt-w130,.edu-txt-w130{ width:130px; display: inline-block;text-align: center} +a.edu-txt-w120,.edu-txt-w120{ width:120px; display: inline-block;text-align: center} +a.edu-txt-w100,.edu-txt-w100{ width:100px; display: inline-block;text-align: center} +a.edu-txt-w90,.edu-txt-w90{ width:90px; display: inline-block;text-align: center} +a.edu-txt-w80,.edu-txt-w80{ width:80px; display: inline-block;text-align: center} + +/*超过隐藏*/ +.overellipsis{overflow: hidden;white-space: nowrap;text-overflow: ellipsis;} +.task-hide{overflow:hidden; white-space: nowrap; text-overflow:ellipsis;} +.task-hide-2{overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;} +/*隐藏*/ +.none{display: none} +.block{ display:block;} + +.boxsizing{box-sizing: border-box} + + +/*字体icon均为18px*/ +.iconfont{font-size: 18px!important;} +/*通用文字大小样式*/ +.font-n{font-weight: normal!important;} +.font-bd{font-weight: bold;} +.font-n{font-weight: normal;} +.font-12{ font-size: 12px!important;} +.font-13{ font-size: 13px!important;} +.font-14{ font-size: 14px!important;} +.font-15{ font-size: 15px!important;} +.font-16{ font-size: 16px!important;} +.font-17{ font-size: 17px!important;} +.font-18{ font-size: 18px!important;} +.font-20{ font-size: 20px!important;} +.font-22{ font-size: 22px!important;} +.font-24{ font-size: 24px!important;} +.font-26{ font-size: 26px!important;} +.font-28{ font-size: 28px!important;} +.font-30{ font-size: 30px!important;} +.font-32{ font-size: 32px!important;} +.font-36{ font-size: 36px!important;} +.font-50{ font-size: 50px!important;} +.font-60{ font-size: 60px!important;} +.font-70{ font-size: 70px!important;} + +/*a标签的下划线*/ +a.decoration{text-decoration: underline} + +/*表单*/ +.panel-form-label{ display:inline-block; width:10%; min-width:90px; text-align:right; line-height:40px; font-weight: normal; } + +/*通用内外边距*/ +.mt-10{ margin-top:-10px;}.mt-3{ margin-top:-3px;}.mt0{ margin-top:0px!important;} .mt1{ margin-top:1px;}.mt2{ margin-top:2px;}.mt3{ margin-top:3px;}.mt4{ margin-top:4px;}.mt5{ margin-top:5px!important;}.mt6{ margin-top:6px;}.mt7{ margin-top:7px!important;}.mt8{ margin-top:8px;}.mt9{ margin-top:9px;}.mt10{ margin-top:10px!important;}.mt12{ margin-top:12px;}.mt13{ margin-top:13px;}.mt14{ margin-top:14px;}.mt15{ margin-top:15px!important;}.mt16{ margin-top:16px;}.mt17{ margin-top:17px;}.mt18{ margin-top:18px;}.mt20{ margin-top:20px!important;}.mt22{ margin-top:22px!important;}.mt23{ margin-top:23px!important;}.mt24{ margin-top:24px!important;}.mt25{ margin-top:25px;}.mt28{ margin-top:28px;}.mt30{ margin-top:30px!important;}.mt34{ margin-top:34px!important;}.mt35{ margin-top:35px!important;}.mt36{ margin-top:36px!important;}.mt40{ margin-top:40px;}.mt45{ margin-top:45px;}.mt46{ margin-top:46px;}.mt50{ margin-top:50px;!important;}.mt56{ margin-top:56px;!important;}.mt60{ margin-top:60px;}.mt70{ margin-top:70px;}.mt80{ margin-top:80px;}.mt95{ margin-top:95px;}.mt100{ margin-top:100px;}.mt110{ margin-top:110px;}.mt120{ margin-top:120px;}.mt130{ margin-top:130px;}.mt140{ margin-top:140px;}.mt150{ margin-top:150px;}.mt160{ margin-top:160px;} +.mb0{margin-bottom: 0px!important;}.mb3{ margin-bottom: 3px;}.mb5{ margin-bottom: 5px;}.mb7{ margin-bottom: 7px;}.mb10{ margin-bottom: 10px;}.mb11{ margin-bottom: 11px;}.mb14{ margin-bottom: 14px;}.mb15{ margin-bottom: 15px;}.mb16{ margin-bottom: 16px;}.mb20{ margin-bottom: 20px!important;}.mb25{ margin-bottom: 25px;}.mb26{ margin-bottom: 26px;}.mb28{ margin-bottom: 28px;}.mb30{ margin-bottom: 30px!important;}.mb40{ margin-bottom: 40px!important;}.mb50{ margin-bottom: 50px!important;}.mb60{ margin-bottom: 60px!important;}.mb70{ margin-bottom: 70px!important;}.mb80{ margin-bottom: 80px!important;}.mb90{ margin-bottom: 90px!important;}.mb100{ margin-bottom: 100px!important;}.mb110{ margin-bottom: 110px;} +.ml-3{ margin-left: -3px;}.ml1{margin-left: 1px;}.ml2{margin-left: 2px;}.ml3{margin-left: 3px;}.ml4{margin-left: 4px;}.ml5{ margin-left: 5px;}.ml6{ margin-left: 6px;}.ml10{ margin-left: 10px;}.ml12{ margin-left:12px!important;}.ml13{ margin-left:13px!important;}.ml15{ margin-left: 15px;}.ml18{ margin-left: 18px;}.ml20{ margin-left: 20px;}.ml22{ margin-left: 22px;}.ml25{ margin-left: 25px;}.ml30{ margin-left: 30px;}.ml33{ margin-left: 33px;}.ml35{ margin-left:35px;}.ml40{margin-left:40px;}.ml42{margin-left:42px;}.ml45{ margin-left: 45px;}.ml50{ margin-left: 50px;}.ml55{ margin-left: 55px;}.ml60{ margin-left: 60px;}.ml72{ margin-left: 72px;}.ml73{ margin-left: 73px;}.ml75{ margin-left: 75px;}.ml80{ margin-left: 80px;}.ml85{margin-left:85px;}.ml95{ margin-left: 95px;}.ml115{margin-left: 115px}.ml123{ margin-left: 123px;}.ml150{ margin-left: 150px;}.ml180{ margin-left: 180px;}.ml230{ margin-left: 230px;}.ml240{margin-left: 240px;}.ml250{ margin-left: 250px;}.ml290{ margin-left: 290px;} +.mr3{margin-right: 3px}.mr4{margin-right: 4px}.mr5{ margin-right: 5px;}.mr8{ margin-right: 8px;}.mr10{ margin-right: 10px;}.mr12{ margin-right:12px!important;}.mr15{ margin-right: 15px;}.mr18{ margin-right: 18px;}.mr20{ margin-right: 20px;}.mr24{ margin-right: 24px;}.mr25{ margin-right: 25px;}.mr30{ margin-right:30px;}.mr35{margin-right:35px;}.mr40{margin-right:40px;}.mr45{margin-right:45px;}.mr50{ margin-right: 50px;}.mr60{ margin-right:60px;}.mr70{ margin-right: 70px;}.mr75{ margin-right: 75px;}.mr80{ margin-right:80px;}.mr90{ margin-right:90px;}.mr100{ margin-right: 100px;}.mr110{ margin-right:110px;}.mr350{ margin-right:350px;} + +.pt1{ padding-top:1px;}.pt3{ padding-top:3px!important;}.pt5{ padding-top:5px!important;}.pt10{ padding-top:10px;}.pt15{ padding-top:15px;}.pt17{ padding-top:17px;}.pt20{ padding-top:20px!important;}.pt25{ padding-top:25px;}.pt30{ padding-top:30px;}.pt35{ padding-top:35px;}.pt37{ padding-top:37px;}.pt40{ padding-top:40px;}.pt47{ padding-top:47px;}.pt49{ padding-top:49px;}.pt50{ padding-top:50px;}.pt60{ padding-top:60px;}.pt70{ padding-top:70px;}.pt80{ padding-top:80px;}.pt90{ padding-top:90px;}.pt100{padding-top:100px;}.pt110{ padding-top:110px;}.pt120{ padding-top:120px;}.pt130{padding-top:130px;} +.pb3{ padding-bottom:3px!important;}.pb5{ padding-bottom:5px!important;}.pb10{ padding-bottom:10px;}.pb15{ padding-bottom:15px;}.pb20{ padding-bottom:20px;}.pb25{ padding-bottom:20px;}.pb25{ padding-bottom:20px;}.pb30{ padding-bottom:30px;}.pb35{ padding-bottom:35px;}.pb40{ padding-bottom:40px;}.pb47{ padding-bottom:47px;}.pb50{ padding-bottom:50px;}.pb60{ padding-bottom:60px;}.pb70{ padding-bottom:70px;}.pb80{ padding-bottom:80px;}.pb90{ padding-bottom:90px;}.pb100{ padding-bottom:100px;}.pb110{ padding-bottom:110px;}.pb155{ padding-bottom:155px;} +.pr2{ paddding-right:2px;}.pr5{ padding-right:5px;}.pr10{ padding-right:10px;}.pr15{ padding-right:15px;}.pr20{ padding-right:20px!important;}.pr30{ padding-right:30px!important;}.pr35{ padding-right:35px!important;}.pr42{ padding-right:42px;}.pr45{ padding-right:45px;}.pr48{ padding-right:48px;}.pr57{ padding-right:57px;}.pr60{ padding-right:60px;}.pr70{ padding-right:70px;}.pr72{ padding-right:72px;}.pr75{ padding-right:75px;}.pr88{ padding-right:88px;} + +.pl0{ padding-left:0px!important;}.pl2{ padding-left:2px;}.pl5{ padding-left:5px;}.pl7{ padding-left:7px;}.pl8{ padding-left:8px;}.pl10{ padding-left:10px;}.pl15{ padding-left:15px;}.pl20{ padding-left:20px;}.pl22{ padding-left:22px;}.pl25{ padding-left:25px;}.pl28{ padding-left:28px;}.pl30{ padding-left:30px !important;}.pl33{padding-left: 33px}.pl35{ padding-left:35px;}.pl40{ padding-left:40px;}.pl42{ padding-left:42px;}.pl45{ padding-left:45px;}.pl50{ padding-left:50px;}.pl60{ padding-left:60px;}.pl70{padding-left:70px;}.pl75{padding-left:75px;}.pl80{padding-left:80px;}.pl88{ padding-left:88px;}.pl92{padding-left:92px;}.pl100{ padding-left:100px;} +.pr2{ paddding-right:2px;}.pr5{ padding-right:5px;}.pr7{ padding-right:7px;}.pr10{ padding-right:10px;}.pr15{ padding-right:15px;}.pr20{ padding-right:20px!important;}.pr25{ padding-right:25px!important;}.pr30{ padding-right:30px!important;}.pr40{ padding-right:40px;}.pr42{ padding-right:42px;}.pr45{ padding-right:45px;}.pr60{padding-right:60px;}.pr75{padding-right:75px;} + + +.padding5-10{padding:5px 10px;box-sizing: border-box} +.padding5-20{padding:5px 20px;box-sizing: border-box} +.padding10{padding: 10px;box-sizing: border-box} +.padding15{padding: 15px;box-sizing: border-box} +.padding20{padding: 20px;box-sizing: border-box} +.padding10-20{padding: 10px 20px;box-sizing: border-box} +.padding10-15{padding: 10px 15px;box-sizing: border-box} +.padding10-25{padding: 10px 25px;box-sizing: border-box} +.padding10-30{padding: 10px 30px;box-sizing: border-box} + +.padding15-20{padding: 15px 20px;box-sizing: border-box} +.padding15-25{padding: 15px 25px;box-sizing: border-box} + +.padding20-40{padding: 20px 40px;box-sizing: border-box} +.padding20-30{padding: 20px 30px;box-sizing: border-box} +.padding20-15{padding: 20px 15px;box-sizing: border-box} +.padding20-10{padding: 20px 10px;box-sizing: border-box} + +.padding30{padding: 30px;box-sizing: border-box} +.padding30-20{padding: 30px 20px;box-sizing: border-box} +.padding30-40{padding: 30px 40px;box-sizing: border-box} + +.padding40{padding: 40px;box-sizing: border-box} +.padding40-30{padding: 40px 30px;box-sizing: border-box} +.padding40-20{padding: 40px 20px;box-sizing: border-box} + +.margin10{margin:10px;} +.margin15{margin:15px;} +.margin20{margin:20px;} + +/*行高*/ +.lineh-12{line-height: 12px} +.lineh-15{line-height: 15px} +.lineh-17{line-height: 17px} +.lineh-20{line-height: 20px} +.lineh-25{line-height: 25px} +.lineh-30{line-height: 30px} +.lineh-35{line-height: 35px} +.lineh-40{line-height: 40px} + +/*pre标签换行*/ +.break_word{word-break: break-all;word-wrap: break-word;} +.break_word_firefox{white-space: pre-wrap !important;word-break: break-all;} +/*定位*/ +.pr{position: relative} +.df {display:flex;display: -webkit-flex;display: -ms-flex;} +.flex1{flex: 1;} +/*去掉IE input框输入时自带的清除按钮*/ +input::-ms-clear{display:none;} +/*自定义滚动条宽度*/ +::-webkit-scrollbar {width:7px;height:10px;background-color: #F5F5F5; } +::-webkit-scrollbar-track {-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);background-color: #F5F5F5;} +::-webkit-scrollbar-thumb {-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);background-color: #dadada;} + + +.newContainer{ min-height:100%; height: auto !important; height: 100%; /*IE6不识别min-height*/position: relative;} +.educontent{width: 1200px;margin:0px auto;box-sizing: border-box}/*中间部分宽度固定为1200*/ +.newMain{ margin: 0 auto; padding-bottom: 235px; min-width:1200px;padding-top: 60px}/*padding-bottom根据底部的高度而定*/ + +/*高度*/ +.height-100{height: 100%;} +/*文本位置*/ +.edu-txt-center{ text-align: center!important;} +.edu-txt-left{ text-align: left!important;} +.edu-txt-right{ text-align: right!important;} + +/*背景颜色*/ +.edu-back-white{background-color:#FFFFff; } +.edu-back-greyf5{background-color: #f5f5f5!important;} +.edu-back-skyblue{background: #F4FAFF;} +.edu-back-blue{background-color:#459be6!important; } +.edu-back-blue-txt{background-color:#F7FBFF!important; } +.edu-bg-light-blue{ background:#f7f9fd; padding:5px;}/*发送实训弹框*/ +/*常用字体*/ +/*红色*/ +.color-red{color: #FF0000!important;} +/*白色*/ +.color-white{color: #ffffff!important;} +/*黑色*/ +.color-dark{color: #05101a!important;} +/*灰色*/ +.color-grey-name{color: #1A0B00!important;} +.color-grey-fa{color: #FAFAFA!important;} +.color-grey-3{color: #333!important;} +.color-grey-eb{color: #EBEBEB!important;} +.color-grey-c{color: #ccc!important;} +.color-grey-cd{color: #cdcdcd!important;} +.color-grey-9{color: #999999!important;} +.color-grey-98{color: #989898!important;} +.color-grey-8{color: #888!important;} +.color-grey-6{color: #666!important;} +.color-grey-4d{color: #4d4d4d!important;} +.color-grey-B2{color: #B2B2B2!important;} +.color-grey-B3{color: #B3B3B3!important;} +.color-grey-B4{color: #B4B4B4!important;} +.color-grey-74{color: #747A7F!important;} + + +a.color-grey-name:hover,a.color-dark:hover,a.color-grey-6:hover,a.color-grey-3:hover{color: #4cacff!important;} +a.color-grey-9:hover,a.color-grey-8:hover,a.color-grey-c:hover{color: #111C24!important;} +/*蓝色*/ +.color-blue{color: #4CACFF!important;}/*主*/ +.color-blue_4C{color: #4CACFF!important;} +a.color-blue:hover,a.color-blue_4C:hover{color: #459BE6!important;} +/*橙色*/ +.color-orange{color: #ff6800!important;}/*辅助文字*/ +.color-orange-tip{color: #FF954C!important;}/*提示文字*/ +a.color-orange:hover,a.color-orange-tip:hover{color: #F06200!important;} +/*黄色*/ +.color-yellow{color: #EFC003!important;} +.color-yellow-ff{color: #FFA800!important} +/*绿色*/ +.color-green{color: #29BD8B!important;} +a.color-green:hover{color: #28AC7F!important;} +/*红色*/ +.color-red-dd{color: #DD1717!important;} +a.color-red-dd:hover{color: #C61616!important;} +/*圆角*/ +.radius{border-radius: 50%;} +.radius4{border-radius: 4px;} +.radius2{border-radius: 2px;} + + +/*绿色圆形--例如:实训路径详情的编辑icon的背景*/ +.ring-green{width: 18px;height: 18px;display: block;border-radius: 50%;background-color: #29BD8B;text-align: center;} +.ring-op-green{width: 18px;height: 18px;display: block;border-radius: 50%;background-color: rgba(41,189,139,0.6);text-align: center;} +.ring-grey{width: 18px;height: 18px;line-height: 18px;display: block;border-radius: 50%;background-color:rgba(204,204,204,0.5);text-align: center;} +.ring-blue{width: 18px;height: 18px;display: block;border-radius: 50%;background-color: #4CACFF;text-align: center;} + +.ring-orange{background-color: #FF6800;display: block;padding: 0px 3px;height: 18px;box-sizing: border-box;min-width: 18px;text-align: center;line-height: 18px;border-radius: 50%;color:#fff;font-size: 12px;} + +/*左侧label内容右对齐*/ +.label-right{min-width:75px;text-align: right;height: 35px;line-height: 35px;float: left; } + + +/*输入框样式---------宽度为百分比*/ +.input-flex-30{flex: 1;height: 30px;padding: 5px;box-sizing: border-box;} +.input-flex-35{flex: 1;height: 35px;padding: 5px;box-sizing: border-box;} +.input-flex-40{flex: 1;height: 40px;padding: 5px;box-sizing: border-box;} +.input-100-35{width: 100%;height: 35px;padding: 5px;box-sizing: border-box;} +.input-100-40{width: 100%;height: 40px;padding: 5px;box-sizing: border-box;} +.input-100-45{width: 100%;height: 45px;padding: 5px;box-sizing: border-box;} +.input-90-35{width: 90%;height: 35px;padding: 5px;box-sizing: border-box;} +.input-60-40{width: 60%;height: 40px;padding: 5px;box-sizing: border-box;} +.input-60-35{width: 60%;height: 35px;padding: 5px;box-sizing: border-box;} +.input-50-35{width: 50%;height: 35px;padding: 5px;box-sizing: border-box;} +.input-50-40{width: 50%;height: 40px;padding: 5px;box-sizing: border-box;} +.input-50-45{width: 50%;height: 45px;padding: 5px;box-sizing: border-box;} +.input-48-45{width: 48%;height: 45px;padding: 5px;box-sizing: border-box;} +/*输入框为灰色背景,获取焦点时背景变白色*/ +.greyInput{background-color: #F5F5F5;outline: none} +.greyInput:focus{background-color: #fff; border: 1px solid #ddd;} + +/*输入框样式---------宽度为固定长度*/ +.winput-240-45{width: 240px;height: 45px;padding: 5px;box-sizing: border-box;} +.winput-240-40{width: 240px;height: 40px;padding: 5px;box-sizing: border-box;} +.winput-240-35{width: 240px;height: 35px;padding: 5px;box-sizing: border-box;} +.winput-240-30{width: 240px;height: 30px;padding: 5px;box-sizing: border-box;} +.winput-190-45{width: 190px;height: 45px;padding: 5px;box-sizing: border-box;} +.winput-200-35{width: 200px;height: 35px;padding: 5px;box-sizing: border-box;} +.winput-120-40{width: 120px;height: 40px;padding: 5px;box-sizing: border-box;} +.winput-120-35{width: 120px;height: 35px;padding: 5px;box-sizing: border-box;} +.winput-120-30{width: 120px;height: 30px;padding: 5px;box-sizing: border-box;} +.winput-115-40{width: 115px;height: 40px;padding: 5px;box-sizing: border-box;} +.winput-90-40{width: 90px;height: 40px;padding: 5px;box-sizing: border-box;} +.winput-90-35{width: 90px;height: 35px;padding: 5px;box-sizing: border-box;} +.winput-240-100{width: 240px;height: 100px;padding: 5px;box-sizing: border-box;} +/*输入框样式---------高度固定*/ +.winput-90-100{width: 90%;height: 100px;padding: 5px;box-sizing: border-box;} +.winput-100-130{width: 100%;height: 130px;padding: 5px;box-sizing: border-box;} +.winput-100-150{width: 100%;height: 150px;padding: 5px;box-sizing: border-box;} +.winput-100-200{width: 100%;height: 200px;padding: 5px;box-sizing: border-box;} +.winput-90-100{width: 90%;height: 100px;padding: 5px;box-sizing: border-box;} +/*百分比宽度*/ +.width100{width: 100%;} +.width90{width: 90%;} +.width89{width: 89%;} +.width80{width: 80%;} +.width70{width: 70%;} +.width60{width: 60%;} +.width50{width: 50%;} +.width40{width: 40%;} +.width30{width: 30%;} +.width20{width: 20%;} +.width15{width: 15%;} +.width10{width: 10%;} + +/*固定大小的宽度*/ +.wid100{width: 100px;display: block} +.wid120{width: 120px;display: block} +.wid90{min-width: 90px!important;display: block} +a.edu-txt-w280,.edu-txt-w280{ width:280px; display: inline-block;text-align: center} +a.edu-txt-w200,.edu-txt-w200{ width:200px; display: inline-block;text-align: center} +a.edu-txt-w190,.edu-txt-w190{ width:190px; display: inline-block;text-align: center} +a.edu-txt-w160,.edu-txt-w160{ width:160px; display: inline-block;text-align: center} +a.edu-txt-w140,.edu-txt-w140{ width:141px; display: inline-block;text-align: center} +a.edu-txt-w130,.edu-txt-w130{ width:130px; display: inline-block;text-align: center} +a.edu-txt-w120,.edu-txt-w120{ width:120px; display: inline-block;text-align: center} +a.edu-txt-w100,.edu-txt-w100{ width:100px; display: inline-block;text-align: center} +a.edu-txt-w90,.edu-txt-w90{ width:90px; display: inline-block;text-align: center} +a.edu-txt-w80,.edu-txt-w80{ width:80px; display: inline-block;text-align: center} +a.edu-txt-w40,.edu-txt-w40{ width:40px; display: inline-block;text-align: center} + +/*最小高度*/ +.minH-40{min-height: 490px;} +.minH-280{min-height: 280px;} +.minH-400{min-height: 400px;} +.minH-440{min-height: 440px;} +.minH-500{min-height: 500px;} +.minH-560{min-height: 560px;} +/*超出高度出现滚动条--纵向*/ +.over260{max-height: 260px;overflow-y: auto} +.over210{height: 210px;overflow-y: auto} +.over280{height: 280px;overflow-y: auto} +.over170{min-height: 170px;max-height: 170px;overflow-y: auto} + +/*---------------tab公用边框-----------------*/ +.border-bottom-orange{border-bottom: 2px solid #FC7033!important;} +.bor-bottom-orange{border-bottom: 1px solid #FF9e6a!important;} +.bor-bottom-greyE{border-bottom: 1px solid #EEEEEE!important;} +.bor-left-greyE{border-left: 1px solid #EEEEEE!important;} +.bor-top-greyE{border-top: 1px solid #EEEEEE!important;} +.bor-right-greyE{border-right: 1px solid #EEEEEE!important;} +.bor-left-greyC{border-left: 1px solid #CCC!important;} +.bor-top-greyC{border-top: 1px solid #CCC!important;} +/*---------------边框-----------------*/ +.bor-gray-c{border:1px solid #ccc;} +.bor-grey-e{border:1px solid #eee;} +.bor-grey-d{border:1px solid #ddd;} +.bor-grey01{border:1px solid #E6EAEB;} +.bor-orange{border:1px solid #FF7500;} +.bor-blue{border:1px solid #5faee3;} +.bor-red{border:1px solid #db0505;} +.bor-none{border:none;} +.bor-outnone{outline:none; border:0px;} + +a.decoration{text-decoration: underline!important;} + +/*下拉菜单*/ +.edu-menu-panel{position: relative;cursor: pointer} +.edu-menu-list{position: absolute;padding: 5px 0px;box-shadow: 0 2px 8px 0 rgba(0,0,0,.2);display: none;width: 120px;background: #FFFFff;right: -5px;border-radius:0px 0px 4px 4px;color: #05101a; font-size: 14px;z-index: 9} +.edu-menu-list li{width: 100%;padding:0px 15px;box-sizing: border-box;height: 35px;line-height: 35px;cursor: pointer;} + +.edu-menuSmall-list{position: absolute;padding: 5px 0px;box-shadow: 0 2px 8px 0 rgba(0,0,0,.2);display: none;width: 100px;background: #FFFFff;right: -5px;border-radius:0px 0px 4px 4px;color: #05101a; font-size: 14px;z-index: 9} +.edu-menuSmall-list li{width: 100%;padding:0px 10px;box-sizing: border-box;height: 30px;line-height: 30px;cursor: pointer;font-size: 12px;} + +.edu-menu-list li a,.edu-menuSmall-list li a{width: 100%;height: 100%;display: block;color: #323232;} +.edu-menu-panel:hover i,.edu-menu-panel:hover{color: #4cacff;} +.edu-menu-panel:hover .edu-menu-list,.edu-menu-panel:hover .edu-menuSmall-list{display: block} +.edu-menu-list li:hover,.edu-menuSmall-list li:hover{background: #4CACFF;} +.edu-menu-list li:hover a,.edu-menuSmall-list li:hover a{color: #fff!important;} +.currentName{display: block;width: 100%;padding:0px 15px;height: 40px;line-height: 40px;font-size: 16px;box-sizing: border-box;cursor: default} +.ul-leftline:after{position: absolute;top:0px;content: "";width: 1px;background-color: #eee;height: 100%;right: 0px;} +.overPart{width: 240px;height: 30px;position: absolute;right: 0;top: -27px;background: transparent;} +/*滑块验证*/ +.drag_slider{ position: relative; background-color: #e8e8e8; width:100%; height: 45px;color: #999999; line-height: 45px; text-align: center;border-radius: 4px;} +.drag_slider .handler{ border-radius: 4px 0px 0px 4px;position: absolute; top: 0px; left: 0px; width: 50px; height: 43px; border: 1px solid #eee; cursor: move;} +.handler_bg{ background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==") no-repeat center;} +.handler_ok_bg{ background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAAASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMCy4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQNTNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgGFMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJggg==") no-repeat center;} +.drag_slider .drag_bg{ background-color: #29bd8b; height: 45px; width: 0px;} +.drag_slider .drag_text{border-radius: 4px 0px 0px 4px;position: absolute; top: 0px; width: 100%; -moz-user-select: none; -webkit-user-select: none; user-select: none; -o-user-select:none; -ms-user-select:none;} + +/*tip公共样式的设置:*/ +.-task-title{opacity:0;position:absolute;left:0;top:0;display:none;z-index:100000;} /*1*/ +.data-tip-down,.data-tip-left,.data-tip-right,.data-tip-top{ position:relative; box-shadow:0px 0px 8px #000; background:#000; color:#fff; max-width:300px;/*2*/ + word-wrap: break-word; text-align:center; border-radius:4px; padding:0 10px; border:1px solid #000; display:none; }/*3*/ +.data-tip-down:after,.data-tip-down:before,.data-tip-left:before,.data-tip-right:before,.data-tip-left:after,.data-tip-right:after,.data-tip-top:after,.data-tip-top:before{/*4*/ + position: absolute;content:''; width:0; height:0;}/*5*/ +.data-tip-down:after,.data-tip-down:before{left: 45%;top:-10px;/*6*/ + border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 10px solid #000; }/*7*/ +.data-tip-down:before{top:-11px;border-bottom:10px solid #000;}/*8*/ +.data-tip-left:after,.data-tip-left:before{left: -10px;top:50%; margin-top:-5px;/*9*/ + border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-right: 10px solid #000; }/*10*/ +.data-tip-left:before{ left: -12px;border-right: 10px solid #000; }/*11*/ +.data-tip-right:after,.data-tip-right:before{right: -10px; top:50%; margin-top:-5px;/*12*/ + border-top: 5px solid transparent;border-bottom: 5px solid transparent; border-left: 10px solid #000; }/*13*/ +.data-tip-right:before{ right: -10px;border-left: 10px solid #000; }/*14*/ +.data-tip-top:after,.data-tip-top:before{left: 45%;bottom:-10px;border-left: 5px solid transparent; + border-right: 5px solid transparent;border-top: 10px solid #000;} +.data-tip-top:before{bottom:-11px;} + + +/*左右两栏排列、固定左右宽度----------ul*/ +ul.abouttable{margin: 0px auto;width: 440px;} +ul.abouttable li{width: 100%;} +ul.abouttable li .rz-label{min-width: 150px;height: 45px;line-height: 45px;text-align: right;color: #adadad;} +ul.abouttable li .second-label{min-width: 150px;height: 40px;line-height: 40px;text-align: right;color: #adadad;} +ul.abouttable li .minh-label{min-width: 150px;height: 28px;line-height: 28px;text-align: right;color: #adadad;} + + + +/* table--------------------------------*/ + +/* table-1底部边框 */ +.edu-pop-table{ width: 100%; border:1px solid #eee; border-bottom:none; background:#fff; color:#888;cursor: default} +.edu-pop-table tr{ height:40px; } +.edu-pop-table tr.edu-bg-grey{ background:#f5f5f5;} +.edu-txt-center{ text-align: center;}.edu-txt-left{ text-align: left;}.edu-txt-right{ text-align: right;} +.edu-pop-table tr th{ color:#333;border-bottom:1px solid #eee; } +.edu-pop-table tr td{border-bottom:1px solid #eee;} +.edu-pop-table.table-line tr td,.edu-pop-table.table-line tr th{ border-right:1px solid #eee;} +.edu-pop-table.table-line tr td:last-child,.edu-pop-table.table-line tr th:last-child{border-right:none;} +/*th行有背景颜色且table无边框*/ +.edu-pop-table.head-color thead tr{background: #fafbfb} +.edu-pop-table.head-color{border: none} +.edu-pop-table.head-color tr:last-child td {border: none} +/*--表格行间隔背景颜色-*/ +.edu-pop-table.interval-td{border-bottom: 1px solid #eee;} +.edu-pop-table.interval-td thead tr{background: #fafbfb} +.edu-pop-table.interval-td tbody tr:nth-child(even){background: #fafbfb} +.edu-pop-table.interval-td tbody tr td{border: none} +/*--表格行间隔背景颜色(th也没有边框)-*/ +.edu-pop-table.interval-all{border:none;border-bottom: 1px solid #eee;} +.edu-pop-table.interval-all thead th{border: none} +.edu-pop-table.interval-all thead tr{background: #fafbfb} +.edu-pop-table.interval-all tbody tr:nth-child(even){background: #fafbfb} +.edu-pop-table.interval-all tbody tr td{border: none;padding:5px 0px} +/*--表格行移入背景颜色-*/ +.edu-pop-table.hover-td tbody tr:hover{background: #EFF9FD}/*悬浮颜色为天蓝色*/ +.edu-pop-table.hover-td_1 tbody tr:hover{background:#FCF2EC}/*悬浮颜色为浅橙色*/ +/* table-2全边框 */ +.edu-pop-table-all{ width: 100%; border:1px solid #eee; background:#fff; color:#888;border-collapse: collapse} +.edu-pop-table-all tr{ height:30px; } +.edu-pop-table-all tr.edu-bg-grey{ background:#f5f5f5;} +.edu-pop-table-all tr th{ color:#333;border:1px solid #eee; } +.edu-pop-table-all tr td{border:1px solid #eee;padding: 5px} +/*table无边框、无背景颜色*/ +.allNone{background: none!important;cursor: default;border-bottom:none!important;} +.allNone tr{height: 30px!important;} + +/*数据为空公共页面*/ +img.edu-nodata-img{ width:300px; margin:50px auto 20px; display: block;} +.edu-nodata-p{ font-size: 20px; text-align: center; color:#999;border-bottom:none!important;padding-left: 18px;box-sizing: border-box;} + +/*输入为空或者错误的提示*/ +.input-none{box-shadow: 0px 0px 2px rgba(0,0,0,0.1);} +.notice{height: 25px;margin-left: 150px;} +.input-none + .notice span{display: block} + +/*列表里菜单icon移入*/ +.edu-position-hide{ position: absolute; top:15px; left:-20px; box-shadow: 0px 2px 8px rgba(146, 153, 169, 0.5); background:#fff;z-index:1001; padding:5px 0;z-index: 999999;} +.edu-position-hide li a{ display:inline-block; height: 30px; width: 100px; line-height: 30px; text-align: center; font-size:12px!important; } +.edu-position-hide li a:hover{ background:#F1F1F1; color:#05101A;} +.edu-position-hidebox i{ color:#bcbcbc;} +.edu-position-hidebox i:hover{ color:#4CACFF;} +.edu-position-hidebox a{ color:#05101A;} +.edu-position-hidebox:hover .edu-position-hide{ display: block;} + +/*搜索(灰色背景、点击变白色)*/ +.seekPanel > input{width: 100%;height: 30px;line-height: 30px;background-color: #f4f4f4;border:1px solid #eaeaea;padding: 0px 30px 0px 5px ;box-sizing: border-box;outline: none;} +.seekPanel > input:focus{background-color: #fff;} +.seekPanel > i{position: absolute;right: 7px;top: -1px;} +/*-------------------------------------------公用按钮:以white-btn(或者edu-default-btn无padding)为基础,宽度和高度可以用padding填充,颜色用edu-color-btn,begin-----------------------------------------*/ +/*按钮*/ +/*默认按钮*/ +/*长条形按钮*/ +.default_btn{display: block;border-radius: 5px ;background: #f4f4f4;color: #cfcfcf!important;text-align: center;width: 102px;box-sizing: border-box} +/*正常按钮*/ +.white-btn{text-align:center;cursor: pointer;display: inline-block;padding: 0px 8px;border: 1px solid #ccc;color: #666;letter-spacing: 1px;font-size: 14px;height: 26px;line-height: 26px;border-radius: 3px;} +a.white-btn.orange-btn{border: 1px solid #FF7500;color: #FF7500!important;} +a.white-btn.orange-btn:hover{border: 1px solid #F06200;color: #F06200!important;} + +.defalutGreyBorder{display: block;padding: 0px 10px;border:1px solid #ccc;height: 30px;line-height: 30px;border-radius: 4px;} +a.task-btn{cursor: pointer;display: inline-block;border: none;padding: 0 12px;color: #fff;background: #CDCDCD !important;letter-spacing: 1px;text-align: center;font-size: 14px;height: 30px;line-height: 30px;border-radius: 2px; font-weight: 400;} +/*最新按钮:以个人主页为例-------------因高度和宽度都已经固定,后续不再支持使用,*/ +.user_default_btn{cursor: pointer;font-size: 14px;display: block;width: 120px;text-align: center;height: 40px;line-height: 40px!important;border-radius: 4px;box-sizing: border-box} +.user_orange_btn{color: #fff!important;background-color: #FF6800;}/*橙色签到按钮*/ +.user_orange_btn:hover{background-color:#F06200;} +.user_grey_btn{color: #fff!important;background-color: #CCCCCC;cursor: default}/*灰色已经签到按钮*/ +.user_private_btn{color:#646464!important;background-color: #fff;border: 1px solid #989898}/*灰色私信、互相关注按钮*/ +.user_private_btn:hover{color: #B2B2B2!important;border: 1px solid #B2B2B2;} +.btn_auto{border-radius: 5px ;background: #fff;padding: 0px 18px;} + +/*可共用按钮,需添加padding或者边框*/ +.edu-default-btn{display: block;border-radius: 4px;} +a.edu-focus-btn{padding: 0px 10px;height: 30px;line-height: 30px;border: 1px solid #b2b2b2;color: #b2b2b2!important;} +a.edu-focus-btn:hover{border: 1px solid #666;color: #666!important;} + +a.edu-greenback-btn{padding: 0px 10px;background: #29BD8B;color: #fff!important;border: 1px solid #29BD8B;} +a.edu-greenline-btn{padding: 0px 10px;color: #29BD8B!important;border: 1px solid #29BD8B;} +a.edu-greenback-btn:hover{background-color: #28AC7F;} +a.edu-greenline-btn:hover{border:1px solid #28AC7F;color: #28AC7F!important;} + +a.edu-blueback-btn{padding: 0px 10px;background: #4CACFF;color: #fff!important;border: 1px solid #4CACFF;} +a.edu-blueline-btn{padding: 0px 10px;color: #4CACFF!important;border: 1px solid #4CACFF;} +a.edu-blueback-btn:hover{background-color: #459BE6;} +a.edu-blueline-btn:hover{border:1px solid #459BE6;color: #459BE6!important;} + +a.edu-orangeback-btn{background-color: #ff7500;color: #fff!important;border:1px solid #FF7500} +a.edu-orangeback-btn:hover{background-color: #F06200;} +a.edu-orangeline-btn{color: #FF7500!important;border:1px solid #FF7500} +a.edu-orangeline-btn:hover{color: #F06200!important;border:1px solid #F06200} + +a.edu-greyback-btn{padding: 0px 10px;background: #CCCCCC;color: #fff!important;border: 1px solid #CCCCCC;} +a.edu-greyback-btn:hover{background-color: #B2B2B2;} +a.edu-greyshallowline-btn{padding: 0px 10px;color: #999!important;border:1px solid #CFCFCF} +a.edu-greyline-btn{padding: 0px 10px;background: #fff;color: #666!important;border: 1px solid #eaeaea;line-height: 33px;height: 33px;} +a.edu-greyline-btn:hover,a.edu-greyshallowline-btn:hover{border:1px solid #B2B2B2;color:#B2B2B2!important;} + +/*新建页面的提交和取消按钮*/ +.defalutCancelbtn{display: block;border: 1px solid #CDCDCD;background-color: #fafafa;color: #999!important;width: 120px;text-align: center;height: 30px;line-height: 30px;border-radius: 2px; + width: 130px; + height: 40px; + background: rgba(77,124,254,0); + border: 1px solid rgba(76, 172, 255, 1); + border-radius: 4px; + line-height: 40px; + font-size: 16px; + font-family: MicrosoftYaHei; + font-weight: 400; + color: rgba(76,172,255,1) !important; +} +.defalutCancelbtn:hover{border:1px solid #B2B2B2;color: #B2B2B2!important;} +.defalutSubmitbtn{ + display: block;border: 1px solid #4CACFF;background-color: #4CACFF;color: #fff!important;width: 120px;text-align: center;line-height: 40px;border-radius: 2px; + width: 130px; + height: 40px; + background: rgba(76,172,255,1); + border-radius: 4px; + font-size: 16px; + font-family: MicrosoftYaHei; + font-weight: 400; + color: rgba(255,255,255,1); +} +.defalutSubmitbtn:hover{background-color: #459BE6;border: 1px solid #459BE6;} +/*-------------------------------------------公用按钮:以white-btn(或者edu-default-btn无padding)为基础,宽度和高度可以用padding填充,颜色用edu-color-btn,end-----------------------------------------*/ + +/*可点击按钮---蓝色*/ +.use_btn{background: #4cacff;color:#fff!important;} +a.task-btn-orange{background: #4CACFF!important; color:#fff!important;} +a:hover.task-btn-orange{background: #459BE6;} +/*可点击按钮---蓝色---蓝色边框*/ +.user_blue_btn{border: 1px solid #4CACFF;color: #4CACFF!important;} +/*可点击按钮---蓝色---蓝色背景*/ +a.user_bluebg_btn{background-color:#4CACFF;color: #fff;} +a.user_orangebg_btn{background-color:#FF6800;color: #fff;} +a.user_greybg_btn{background-color:#747A7F;color: #fff;} + + +.pointer{cursor: pointer} +.cdefault{cursor: default} + + +/*md编辑器恢复被覆盖样式*/ +.new_li li{ list-style-type: disc!important; } +.new_li ol li{ list-style-type: decimal!important; } +.new_li li{ margin-bottom: 0!important; } + +/*搜索框*/ +#pollingPanel{position: relative;width: 248px;height: 32px;} +#pollingPanel > input{width: 100%;height: 100%;border:1px solid #eaeaea;border-radius: 4px;padding: 0px 30px 0px 5px;box-sizing: border-box;background-color: #F4F4F4;} +#pollingPanel > input:focus{background-color: #fff;outline: none;} +#pollingPanel > a{position: absolute;right: 10px;top:0px;} + +/* 弹框 */ +.popupAll{width: 100%;height: 100%;position: fixed;z-index: 99998;background-color: rgba(5,16,26,0.6);left: 0;top:0;} +.task-popup{ width: 30%;background: #fff; border:1px solid #e8e8e8; border-radius:10px;} +.task-popup-text-center{ text-align: center; color: #333;} +.task-popup-title{ border-bottom: 1px solid #eee; padding:0px 15px;text-align: center;box-sizing: border-box;line-height: 70px;height: 70px; border-radius: 10px 10px 0px 0px;font-size: 16px;font-weight: bold; } +.task-popup-content{ padding:15px;} +.task-popup-submit{ margin:0px auto 15px; width: 160px;} +.task-popup-sure{ margin:0px auto 15px; width: 54px;} +.task-popup-right-sure{margin:0px auto 15px;text-align: center} +.task-popup-OK{ margin:15px auto; text-align: center} +.task-popup-bggrey{ background:#fff; color:#333;} +#closeIcon{position: absolute;color:#fefefe} +/* 模板弹框 20170407byLB */ +#task_popup_box{ background:#fff;padding-bottom:15px;-webkit-border-radius:5px;-moz-border-radius:5px;-o-border-radius:5px;border-radius:5px;box-shadow: 0px 2px 8px rgba(146, 153, 169, 0.5);} +.task_popup_top{background:#ccc;height:40px;-webkit-border-radius: 5px 5px 0px 0px;-moz-border-radius: 5px 5px 0px 0px;-o-border-radius: 5px 5px 0px 0px;border-radius: 5px 5px 0px 0px;} +.task_popup_top h3{ font-size:14px; color:#333; line-height:40px; padding-left:10px; } +a.task_icons_close{width:20px; height:20px;display:block;background: url(../images/popup/sy_icons_close.png) 0 0px no-repeat; margin:8px 10px 0 0;} +a:hover.task_icons_close{background: url(../images/popup/sy_icons_close.png) -40px 0px no-repeat;} +.task_popup_con{ padding:20px;} +/* 模板弹框 20161013byLB */ +#muban_popup_box{ background:#fff;padding-bottom:15px;-webkit-border-radius:5px;-moz-border-radius:5px;-o-border-radius:5px;border-radius:5px;box-shadow: 0px 2px 8px rgba(146, 153, 169, 0.5);} +.muban_popup_top{background:#3b94d6;height:40px;-webkit-border-radius: 5px 5px 0px 0px;-moz-border-radius: 5px 5px 0px 0px;-o-border-radius: 5px 5px 0px 0px;border-radius: 5px 5px 0px 0px;} +.muban_popup_top h3{ font-size:16px; color:#fff; font-weight:normal; line-height:40px; padding-left:10px; } +a.muban_icons_close{width:20px; height:20px;display:block;background: url(/images/sy/sy_icons_close.png) 0 0px no-repeat; margin:8px 10px 0 0;} +a:hover.muban_icons_close{background: url(/images/sy/sy_icons_close.png) -40px 0px no-repeat;} +#muban_popup_box input,#muban_pwopup_box select{ border:1px solid #c8c8c8; height: 28px; color: #888;} +#muban_popup_box label.pop_box_label{width: 100px; text-align: right; display: inline-block;} +input.radio-width90{ width: 90px; } +#muban_popup_box label.pop_box_label_l {width: 100px; text-align: left; display: inline-block;} + + +/*提示条*/ +.alert{ padding:10px;border: 1px solid transparent; text-align: center;} +.alert-blue{ background-color: #d9edf7;border-color: #bce8f1; color: #3a87ad;} +.alert-orange{ background-color: #fff9e9;border-color: #f6d0b1; color:#ee4a20;} +.task-close{padding: 0;cursor: pointer; background: transparent; border: 0; -webkit-appearance: none; font-size: 21px; font-weight: bold;line-height: 1; color: #000000; text-shadow: 0 1px 0 #ffffff; opacity: 0.3;} +.taskclose:hover{opacity: 0.5;} +.alert-red{background-color: #f2dede;border-color: #eed3d7; color: #d14f4d; text-align: left!important;} + +/*搜索的下拉列表*/ +.search_down_list a{display: block;height: 28px;line-height: 28px;padding: 0px 5px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;} +.search_down_list a:hover{background: #fafafa;} + +/*白色色块--类似个人主页-学习-里面的tab*/ +.white-panel{border-radius: 2px;width: 100%;margin: 0px auto;box-sizing: border-box;padding-left: 25px;} +.white-panel li{width: 118px;height: 48px;line-height: 48px;text-align: center;color: #05101A;float: left;cursor: pointer;border:1px solid #fff;} +.white-panel li a{display: block;width: 100%;} +.white-panel li.active{border-radius: 24px;border:1px solid #4CACFF;color:#4CACFF; } +.white-panel li.active a{color:#4CACFF; } + + +/* 个人主页翻页 */ +.pages_user_show a:hover,.pages_user_show li.active a{ background-color:#4CACFF; color:#fff;border: 1px solid #4CACFF;} +.pages_user_show a{border-radius: 2px; display: inline-block;border:1px solid #d1d1d1;background-color:#fff; color:#888; float:left;text-align:center; padding:2px 10px; line-height:1.9; margin: 0 5px;} +.pages_user_show li{float: left; list-style-type: none;} +.pages_user_show ul li{list-style-type: none !important;} +.pages_user_show ul li a{color:#888} +.page_GO{text-align:center;width: 80px;border-radius: 2px;margin-left: 5px;height: 33px;padding: 0px 5px;box-sizing: border-box;float: left;border:1px solid #d1d1d1;} +/* 小翻页 */ +.pages_little_show a:hover,.pages_little_show li.active a{ background-color:#4CACFF;; color:#fff!important;border:1px solid #4CACFF} +.pages_little_show a{ display: inline-block;border:1px solid #d1d1d1; color:#888!important; float:left;text-align:center; padding:3px 3px; line-height:1.9; margin: 0 2px; font-size: 12px;} +.pages_little_show li{float: left;} + +/*左右排版结构:参考个人主页的经验值和金币等页面*/ +.leftPanel{width: 22%;float: left;} +.leftPanel li.nav{padding:10px 0px;box-sizing: border-box;} +.leftPanel li.nav a{padding-left: 40px;display: block;width: 100%;box-sizing: border-box;border-left: 2px solid #fff;height: 24px;line-height: 24px;} +.leftPanel li.nav.active a{border-left: 2px solid #4CACFF;} +.rightPanel{width:78%;float: right;} + +/*个人主页,认证的圆圈*/ +.ringauto{width: 20px;height: 20px;line-height: 20px;text-align: center;border-radius: 50%;background-color: #F4FAFF;margin-right:5px;} + +/*-------------------个人主页:右侧提示区域--------------------------*/ +.-task-sidebar{position:fixed;width:40px;height:180px;right:0;bottom:30px;z-index: 10;} +.-task-sidebar div{height: 40px;line-height: 40px;box-sizing: border-box;width:40px;background:#4CACFF;color:#fff;font-size:20px;text-align:center;margin-bottom:5px;border-radius: 4px;} +.-task-sidebar div i{ color:#fff;} +.-task-sidebar div i:hover{color: #fff!important;} +.gotop{background-color: rgba(208,207,207,0.5)!important;padding: 0px!important;} +.-task-desc{background:#494949;width:90px;line-height: 36px;text-align: center; + position: absolute;color: #fff;font-size: 13px;z-index: 999999;opacity: 0;} +.-task-desc div{position: absolute;top:10px;right: -7px;height: 13px;} +.-task-desc div img{float: left} + + +/***** loading ******/ +/*****载入中******/ +#ajax-indicator { + position: absolute; /* fixed not supported by IE*/ + background-color:#eee; + border: 1px solid #bbb; + top:35%; + left:40%; + width:20%; + /*height:5%;*/ + font-weight:bold; + text-align:center; + padding:0.6em; + z-index:100000; + opacity: 0.5; +} + +html>body #ajax-indicator { position: fixed; } + +#ajax-indicator span{ + color:#fff; + color: #333333; + background-position: 0% 40%; + background-repeat: no-repeat; + background-image: url(/images/loading.gif); + padding-left: 26px; + vertical-align: bottom; + z-index:100000; +} +/*最新、最热*/ +.bestChoose.active{color: #4CACFF;} + + +/*实训路径选择实训*/ +.edu-filter-cir-grey{color: #666!important;width: auto;padding:0px 15px; font-size:14px !important; text-align: center;background: #f3f3f3;border-radius: 10px;display: block; height:25px; line-height:25px;} +.edu-filter-cir-grey:hover{background: #4cacff; color: #ffffff!important;} +.edu-filter-cir-grey.active{background: #4cacff; color: #ffffff!important; font-size: 14px !important;} + + +.with10{ width: 10%;box-sizing: border-box}.with12{ width: 12%;box-sizing: border-box}.with13{ width: 13%;box-sizing: border-box}.with14{ width: 14%;box-sizing: border-box}.with15{ width: 15%;box-sizing: border-box} +.with20{ width: 20%;box-sizing: border-box}.with22{ width: 22%;box-sizing: border-box}.with23{ width: 23%;box-sizing: border-box}.with25{ width: 25%;box-sizing: border-box} +.with30{ width: 30%;box-sizing: border-box}.with35{ width: 35%;box-sizing: border-box} +.with40{ width: 40%;box-sizing: border-box}.with45{ width: 45%;box-sizing: border-box}.with49{ width: 49%;box-sizing: border-box} +.with50{ width: 50%;box-sizing: border-box}.with55{ width: 55%;box-sizing: border-box} +.with52{ width: 52%;box-sizing: border-box}.with48{ width: 48%;box-sizing: border-box} +.with60{ width: 60%;box-sizing: border-box}.with65{ width: 65%;box-sizing: border-box} +.with70{ width: 70%;box-sizing: border-box}.with73{ width: 73%;box-sizing: border-box}.with75{ width: 75%;box-sizing: border-box}.with77{ width: 77%;box-sizing: border-box}.with78{ width: 78%;box-sizing: border-box} +.with80{ width: 80%;box-sizing: border-box}.with85{ width: 85%;box-sizing: border-box} +.with87{ width: 87%;box-sizing: border-box}.with90{ width: 90%;box-sizing: border-box}.with95{ width: 95%;box-sizing: border-box} +.with100{ width: 100%;} + +.transform-90{ + transform:rotate(-90deg); + -ms-transform:rotate(-90deg); /* IE 9 */ + -moz-transform:rotate(-90deg); /* Firefox */ + -webkit-transform:rotate(-90deg); /* Safari 和 Chrome */ + -o-transform:rotate(-90deg); +} + +.newplayVedio{ + font-size: 86px !important; +} +.icon-qizhi{ + font-size:30px !important; +} +.icon-31{ + font-size: 68px !important; +} + +/*置顶*/ +.btn-cir {display: inline-block;padding: 0px 5px;border-radius: 25px;line-height: 20px;font-size: 12px;} +.btn-cir-red{background:red;color: #fff; font-weight: normal;cursor: default} +.btn-cir-red:hover{background:red;color: #fff!important;} +.btn-cir-grey{background: #e1e1e1;color: #8c8c8c;font-weight: normal;border: 1px solid #e1e1e1} + +/*动态标签*/ +.edu-filter-btn{cursor: default;display: inline-block; padding:0px 9px; color:#666; background:#fff; text-align: center; border-radius:10px; font-size:12px; height:18px; line-height:18px;} +.edu-filter-btn-blue{border:1px solid #3498db; color:#3498db;} +.edu-filter-btn-orange{border:1px solid #ff6800; color:#ff6800!important;}/*提交中、评阅中*/ +.edu-filter-btn-red{border:1px solid #DD1717; color:#DD1717;}/*已截止、未开启补交*/ +.edu-filter-btn-green{border:1px solid #29BD8B; color:#29BD8B!important;}/*申诉中、已开启补交*/ +.edu-filter-btn-appeal{border:1px solid #FF4343; color:#FF4343!important;}/*申诉中*/ +.edu-filter-btn-yellow{border:1px solid #ef9324; color:#ef9324;} +.edu-filter-btn-danger{background:#d72e36; color:#fff;} +.edu-filter-btn-late{border:1px solid #3fbcff; color: #3fbcff;} +.edu-filter-btn-no-late{border:1px solid #747A7F;color: #747A7F;}/*未发布*/ +.edu-filter-btn-end{border: 1px solid #999999;color: #999999;}/*已结束*/ +/*动态按钮*/ +.edu-activity-orange{background-color:#FF6800;color:#fff!important;cursor: pointer;border: 1px solid #ff6800;}/*修改作品、补交作品、立即补交、补交附件*/ +.edu-activity-blue{background-color:#4CACFF;color:#fff!important;cursor: pointer;border: 1px solid #4CACFF;}/*开始实战、开始答题、继续答题、继续实战、提交作品*/ +.edu-activity-grey{background-color:#747A7F;color:#fff!important;cursor: pointer;border: 1px solid #747A7F;}/*匿评作品*/ +.edu-activity-green{background-color:#29BD8B;color:#fff!important;cursor: pointer;border: 1px solid #29BD8B;}/*查看作品、查看实战、查看答题*/ +.edu-activity-light-grey{background-color:#cbcbcb;color:#fff!important;cursor: pointer;border: 1px solid #cbcbcb;}/*取消关联*/ +/*课堂设置页面*/ +.course-ul-nav{width: 100%;border-bottom: 1px solid #EBEBEB;} +.course-ul-nav a{display: inline-block;padding: 20px;font-size: 18px;text-align: center;width: 94px;position: relative} +.course-ul-nav a.active,.course-ul-nav a:hover{color: #4CACFF;} +.course-ul-nav a.active:after{content: '';width: 94px;left: 20px;bottom: 0px;height: 2px;background-color: #4CACFF;position: absolute} + +/*-----下拉框--------*/ +.down-select{display:none;position: absolute;z-index: 10;left: 0px;width: 100%;overflow-y: auto;background: #fff;max-height: 200px;border:1px solid #eee;} +.down-select p{height: 35px;line-height: 35px;padding-left: 5px;cursor: pointer} +.down-select p:hover{background: #f3f4f6} + + + +.paddingLeft28{padding-left:28px;} + +.ant-modal-header{ + border-radius: 10px; +} + +.color656565{ + color:#656565; +} + +.colorC8161D{ + color:#C8161D; +} + +.bor-reds{ + border:1px solid #FF0000!important; + border-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} \ No newline at end of file diff --git a/app/templates/shixun_work/shixun_work.css b/app/templates/shixun_work/shixun_work.css new file mode 100644 index 000000000..e69de29bb diff --git a/app/templates/shixun_work/shixun_work.html.erb b/app/templates/shixun_work/shixun_work.html.erb new file mode 100644 index 000000000..f4aec2ea6 --- /dev/null +++ b/app/templates/shixun_work/shixun_work.html.erb @@ -0,0 +1,467 @@ + + + + + + + +
+

+ <%= @course.name %> > + <%= @homework.course_second_category&.name || '实训作业'%> > + <% homework_ids = @homework.course.homework_commons.where(homework_type: 4, course_homework_category_id: @homework.course_homework_category_id) + .order(Arel.sql('IF(ISNULL(publish_time),0,1),publish_time DESC, created_at DESC')).pluck(:id) %> + #<%= homework_ids.index(@homework.id) + 1 %>> + <%= @user.real_name %> +

+
+

+ + <%= @shixun.name %> +

+
+
+

+ 总体评价 + +

+ + + + + + + + + + + + + + + + + +
总评总经验值作业成绩耗时评测次数
<%= @work.overall_appraisal %><%= @work.myshixun&.total_score %> / <%= @shixun.all_score %><%= ApplicationController.helpers.number_with_precision(@work.work_score, precision: 1) %> / 100<%= @work.myshixun_consume %><%= @user_evaluate_count.to_i %>
+
+ + <% if @work.description.present? %> +
+

+ 个人总结 +

+
+ <%= @work.description.html_safe %> +
+
+ <% end %> + +
+

+ 阶段成绩 +

+ + + + + + + + + + + + <% @games.each_with_index do |game, index| %> + + + + + + + + + + <% end %> + +
关卡任务名称开启时间评测次数完成时间耗时经验值
<%= index + 1 %> + <%= game.challenge.subject %> + <% if ((Time.now > @homework.end_time) && game.end_time.blank?) || (game.end_time.present? && game.end_time > @homework.end_time) %> + 延时 + <% end %> + <%= myshixun_open_time(game) %><%= game.evaluate_count %><%= finished_time game.end_time %><%= ApplicationController.helpers.time_consuming game %><%= game.final_score %> / <%= game.challenge.all_score %>
+
+ +
+

+ 图形统计 +

+
+ +
+ +
+
+
+
+
+ +
+
+
+
  • 姓名
  • +
  • 学号
  • +
  • 工作效率
  • +
    +
    +
  • <%= @user.real_name %>
  • +
  • <%= @user.student_id %>
  • +
  • <%= @myself_eff[1] %>
  • +
    +
    +
    + +
    +
    +
    +
  • 姓名
  • +
  • 学号
  • +
  • 能力
  • +
    +
    +
  • <%= @user.real_name %>
  • +
  • <%= @user.student_id %>
  • +
  • <%= @myself_consume[1] %>
  • +
    +
    + +
    + +
    +
    +
    + +
    +

    + 实训详情 +

    + <%#= ApplicationController.helpers.javascript_include_tag "/codemirror/lib/codemirror", "/codemirror/mode/javascript/javascript", "/codemirror/addon/hint/show-hint", "/codemirror/addon/hint/javascript-hint", "/codemirror/addon/selection/active-line", "/codemirror/addon/lint/javascript-lint", "/codemirror/addon/lint/css-lint", "/codemirror/addon/lint/lint", "/codemirror/addon/lint/json-lint", "/editormd/lib/codemirror/addon/lint/css-lint" %> + <% @games.each_with_index do |game, index| %> +
    +

    + + <% if game.challenge.st == 1 %> + + <% else %> + + <% end %> + + 第<%= index+1 %>关<%= game.challenge.subject %> +

    +
    + <% if game.outputs.present? %> + + + + + + + <% outputs = game.outputs.group("query_index") %> + <% max_query = outputs.map(&:query_index).max %> + <% outputs.reverse.try(:each) do |output| %> + + + + + <% end %> + +
    评测次数评测信息
    <%= max_query == output.query_index ? "最后一次" : "第#{output.query_index}次" %><%= output_detail(game, output) %>
    + <% end %> + <% if game.try(:lastest_code).present? && game.challenge.st == 0 %> +
    +

    + 最近通过的代码 +

    +
    +
  • + +
  • +
    +
    + <% end %> +
    +
    + <% end %> +
    + +
    + + + <%= ApplicationController.helpers.pdf_load_sources(*%w(editormd/lib/codemirror/lib/codemirror.js editormd/lib/codemirror/mode/javascript/javascript.js + editormd/lib/codemirror/addon/hint/show-hint.js editormd/lib/codemirror/addon/hint/javascript-hint.js + editormd/lib/codemirror/addon/selection/active-line.js editormd/lib/codemirror/addon/lint/javascript-lint.js + editormd/lib/codemirror/addon/lint/css-lint.js editormd/lib/codemirror/addon/lint/lint.js + editormd/lib/codemirror/addon/lint/json-lint.js editormd/lib/codemirror/addon/lint/css-lint.js + echart/echarts.min.js))%> + + diff --git a/app/views/accounts/login.json.jbuilder b/app/views/accounts/login.json.jbuilder new file mode 100644 index 000000000..8b275cf58 --- /dev/null +++ b/app/views/accounts/login.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'users/user', user: @user \ No newline at end of file diff --git a/app/views/accounts/register.json.jbuilder b/app/views/accounts/register.json.jbuilder new file mode 100644 index 000000000..9a3dba175 --- /dev/null +++ b/app/views/accounts/register.json.jbuilder @@ -0,0 +1 @@ +json.redirect_uri subjects_url \ No newline at end of file diff --git a/app/views/accounts/verify.json.jbuilder b/app/views/accounts/verify.json.jbuilder new file mode 100644 index 000000000..f56389049 --- /dev/null +++ b/app/views/accounts/verify.json.jbuilder @@ -0,0 +1,2 @@ +json.status 0 +json.message "邮箱或者手机号码可用" \ No newline at end of file diff --git a/app/views/attachment_histories/_attachment_history.json.jbuilder b/app/views/attachment_histories/_attachment_history.json.jbuilder new file mode 100644 index 000000000..37b8b95c1 --- /dev/null +++ b/app/views/attachment_histories/_attachment_history.json.jbuilder @@ -0,0 +1,9 @@ +json.id attachment.id +json.title attachment.title +json.is_public attachment.publiced? +json.is_publish attachment.published? +json.publish_time attachment.publish_time +json.quotes attachment.quotes_count +json.downloads_count attachment.downloads_count +json.created_on attachment.created_on +json.url attachment_path(attachment, type: 'history') diff --git a/app/views/attachment_histories/_list.json.jbuilder b/app/views/attachment_histories/_list.json.jbuilder new file mode 100644 index 000000000..1d2212a6a --- /dev/null +++ b/app/views/attachment_histories/_list.json.jbuilder @@ -0,0 +1,3 @@ +json.attachment_histories do + json.array! attachment_histories, partial: 'attachment_histories/attachment_history', as: :attachment +end \ No newline at end of file diff --git a/app/views/attachments/_attachment.json.jbuilder b/app/views/attachments/_attachment.json.jbuilder new file mode 100644 index 000000000..01a7f4163 --- /dev/null +++ b/app/views/attachments/_attachment.json.jbuilder @@ -0,0 +1,13 @@ +json.id attachment.id +json.title attachment.title +json.is_public attachment.publiced? +json.is_lock attachment.locked?(@is_member) +json.is_publish attachment.published? +json.publish_time attachment.publish_time +json.unified_setting attachment.unified_setting +json.filesize number_to_human_size(attachment.filesize) +json.quotes attachment.quotes_count +json.description attachment.description +json.downloads_count attachment.downloads_count +json.created_on attachment.created_on +json.url download_url(attachment) unless attachment.locked?(@is_member) diff --git a/app/views/attachments/_attachment_simple.json.jbuilder b/app/views/attachments/_attachment_simple.json.jbuilder new file mode 100644 index 000000000..ad98fadb5 --- /dev/null +++ b/app/views/attachments/_attachment_simple.json.jbuilder @@ -0,0 +1,6 @@ +json.id attachment.id +json.title attachment.title +json.filesize number_to_human_size attachment.filesize +json.description attachment.description +json.url download_url(attachment) +json.set! :delete, delete.nil? ? true : delete if defined? delete \ No newline at end of file diff --git a/app/views/attachments/_attachment_small.json.jbuilder b/app/views/attachments/_attachment_small.json.jbuilder new file mode 100644 index 000000000..d9a976bde --- /dev/null +++ b/app/views/attachments/_attachment_small.json.jbuilder @@ -0,0 +1,5 @@ +json.id attachment.id +json.title attachment.title +json.filesize number_to_human_size(attachment.filesize) +json.url download_url(attachment) +json.created_on attachment.created_on \ No newline at end of file diff --git a/app/views/attachments/create.json.jbuilder b/app/views/attachments/create.json.jbuilder new file mode 100644 index 000000000..3c0ef3559 --- /dev/null +++ b/app/views/attachments/create.json.jbuilder @@ -0,0 +1,2 @@ +json.id @attachment.id +json.filesize @attachment.filesize diff --git a/app/views/attachments/destroy.json.jbuilder b/app/views/attachments/destroy.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/attachments/destroy.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/boards/destroy.json.jbuilder b/app/views/boards/destroy.json.jbuilder new file mode 100644 index 000000000..a9d8fbdaf --- /dev/null +++ b/app/views/boards/destroy.json.jbuilder @@ -0,0 +1,2 @@ +json.status 0 +json.right_url course_board_messages_path(@course, @course_board) \ No newline at end of file diff --git a/app/views/boards/index.json.jbuilder b/app/views/boards/index.json.jbuilder new file mode 100644 index 000000000..726a1da80 --- /dev/null +++ b/app/views/boards/index.json.jbuilder @@ -0,0 +1,12 @@ +json.array! @boards do |board| + json.id board.id + json.name board.name + # json.messages board.messages do |msg| + # json.id msg.id + # json.board_id msg.board_id + # json.replies_count msg.replies_count + # json.subject msg.subject + # json.author msg.author, :id, :full_name + # json.last_reply msg.last_reply + # end +end \ No newline at end of file diff --git a/app/views/challenges/_challenge.json.jbuilder b/app/views/challenges/_challenge.json.jbuilder new file mode 100644 index 000000000..ea105ad2c --- /dev/null +++ b/app/views/challenges/_challenge.json.jbuilder @@ -0,0 +1,3 @@ +json.name challenge.subject +json.position challenge.position +json.tag_count challenge.challenge_tags_count diff --git a/app/views/challenges/_top_common_data.jbuilder b/app/views/challenges/_top_common_data.jbuilder new file mode 100644 index 000000000..b3715b656 --- /dev/null +++ b/app/views/challenges/_top_common_data.jbuilder @@ -0,0 +1,19 @@ +# 新建关卡 +json.choice_url new_shixun_challenge_path(shixun_identifier, st: 1) if @power == 0 +json.practice_url new_shixun_challenge_path(shixun_identifier, st: 0) if @power == 0 +json.go_back_url shixun_challenges_path +if @prev_challenge + json.prev_challenge do + json.id @prev_challenge.id + json.st @prev_challenge.st + end +end +if @next_challenge + json.next_challenge do + json.id @next_challenge.id + json.st @next_challenge.st + end +end +json.position @position +json.name @challenge.try(:subject) + diff --git a/app/views/challenges/answer.json.jbuilder b/app/views/challenges/answer.json.jbuilder new file mode 100644 index 000000000..0a3c01ccf --- /dev/null +++ b/app/views/challenges/answer.json.jbuilder @@ -0,0 +1,3 @@ +json.array! @answers do |answer| + json.(answer, :id, :name, :contents, :level, :score) +end \ No newline at end of file diff --git a/app/views/challenges/create.json.jbuilder b/app/views/challenges/create.json.jbuilder new file mode 100644 index 000000000..534873669 --- /dev/null +++ b/app/views/challenges/create.json.jbuilder @@ -0,0 +1,3 @@ +json.status 1 +json.messages "新建成功" +json.challenge_id @challenge.id \ No newline at end of file diff --git a/app/views/challenges/create_choose_question.json.jbuilder b/app/views/challenges/create_choose_question.json.jbuilder new file mode 100644 index 000000000..a6a512e19 --- /dev/null +++ b/app/views/challenges/create_choose_question.json.jbuilder @@ -0,0 +1 @@ +json.challenge_choose_id @challenge_choose.id \ No newline at end of file diff --git a/app/views/challenges/crud_answer.json.jbuilder b/app/views/challenges/crud_answer.json.jbuilder new file mode 100644 index 000000000..b11268d99 --- /dev/null +++ b/app/views/challenges/crud_answer.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "创建参考答案成功" \ No newline at end of file diff --git a/app/views/challenges/destroy.json.jbuilder b/app/views/challenges/destroy.json.jbuilder new file mode 100644 index 000000000..edd1290f0 --- /dev/null +++ b/app/views/challenges/destroy.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "删除成功!" \ No newline at end of file diff --git a/app/views/challenges/destroy_challenge_choose.json.jbuilder b/app/views/challenges/destroy_challenge_choose.json.jbuilder new file mode 100644 index 000000000..d5dc043ea --- /dev/null +++ b/app/views/challenges/destroy_challenge_choose.json.jbuilder @@ -0,0 +1,2 @@ +json.status @status +json.challenge_id @challenge.id \ No newline at end of file diff --git a/app/views/challenges/edit.json.jbuilder b/app/views/challenges/edit.json.jbuilder new file mode 100644 index 000000000..64848a4e6 --- /dev/null +++ b/app/views/challenges/edit.json.jbuilder @@ -0,0 +1,23 @@ +json.partial! "challenges/top_common_data", shixun_identifier: @shixun.identifier +json.chooses do + json.array! @chooses do |choose| + json.choose_id choose.id + json.type choose.category + end +end +if @tab == 0 + # 本关任务tab的编辑模式 + json.(@challenge, :id, :subject, :task_pass, :difficulty, :score) + json.tags @challenge.challenge_tags.map(&:name) +elsif @tab == 1 + # 评测设置的编辑模式 + json.(@challenge, :id, :path, :exec_path, :show_type, :original_picture_path, :expect_picture_path, :picture_path, + :web_route, :test_set_score, :test_set_average) + json.test_sets @challenge.test_sets do |set| + json.hidden (set.is_public ? 0 : 1) + json.(set, :input, :output, :score) + end +elsif @tab == 2 + # 参考答案 + json.(@challenge, :answer) +end \ No newline at end of file diff --git a/app/views/challenges/edit_choose_question.json.jbuilder b/app/views/challenges/edit_choose_question.json.jbuilder new file mode 100644 index 000000000..663f27d7f --- /dev/null +++ b/app/views/challenges/edit_choose_question.json.jbuilder @@ -0,0 +1,11 @@ +json.(@challenge_choose, :challenge_id, :subject, :answer, + :standard_answer, :score, :difficult, + :position, :category) + +# 选项的参数 +json.choose_contents @challenge_choose.challenge_questions do |question| + json.(question, :option_name, :position, :right_key) +end + +json.tags @challenge_choose.challenge_tags.map(&:name) + diff --git a/app/views/challenges/index.json.jbuilder b/app/views/challenges/index.json.jbuilder new file mode 100644 index 000000000..0b90b5ca5 --- /dev/null +++ b/app/views/challenges/index.json.jbuilder @@ -0,0 +1,30 @@ +# 公共接口,新建关卡任务 +# json.partial! 'challenges/new_link', shixun_identifier: @shixun.identifier +json.description @shixun.description +json.power @editable +json.shixun_identifier @shixun.identifier +json.shixun_status @shixun.status +json.allow_skip @shixun.task_pass + +# 列表 +if @challenges.present? + json.challenge_list @challenges do |challenge| + json.challenge_id challenge.id + json.position challenge.position + json.st challenge.st + json.name challenge.subject + json.score challenge.score + json.passed_count challenge.user_passed_count + json.playing_count challenge.playing_count + json.name_url shixun_challenge_path(challenge, shixun_identifier: @shixun.identifier) + json.open_game challenge.open_game(@user.id) + if @editable + json.edit_url edit_shixun_challenge_path(challenge, shixun_identifier: @shixun.identifier) + json.delete_url shixun_challenge_path(challenge, shixun_identifier: @shixun.identifier) + json.up_url index_up_shixun_challenge_path(challenge, :shixun_identifier => @shixun.identifier) unless challenge.position < 2 + json.down_url index_down_shixun_challenge_path(challenge, :shixun_identifier => @shixun.identifier) if @shixun.challenges_count != challenge.position + end + #json.passed challenge.has_passed?(@user.id) + json.status challenge.user_tpi_status @user.id + end +end diff --git a/app/views/challenges/index_down.json.jbuilder b/app/views/challenges/index_down.json.jbuilder new file mode 100644 index 000000000..d0530a9be --- /dev/null +++ b/app/views/challenges/index_down.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "下移成功" \ No newline at end of file diff --git a/app/views/challenges/index_up.json.jbuilder b/app/views/challenges/index_up.json.jbuilder new file mode 100644 index 000000000..b91f30a75 --- /dev/null +++ b/app/views/challenges/index_up.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "上移成功" \ No newline at end of file diff --git a/app/views/challenges/new.json.jbuilder b/app/views/challenges/new.json.jbuilder new file mode 100644 index 000000000..b2d079960 --- /dev/null +++ b/app/views/challenges/new.json.jbuilder @@ -0,0 +1,13 @@ +# 导航栏公共数据 +json.partial! "challenges/top_common_data", shixun_identifier: @shixun.identifier + +# st: 0 实践任务, 1 选择题任务 +json.st @st + +# 过关任务的默认值 +json.task_pass_default @task_pass_default + +json.submit_url shixun_challenges_path(@shixun, :st => @st) + + + diff --git a/app/views/challenges/show.json.jbuilder b/app/views/challenges/show.json.jbuilder new file mode 100644 index 000000000..332879eac --- /dev/null +++ b/app/views/challenges/show.json.jbuilder @@ -0,0 +1,10 @@ +# 导航栏公共数据 +json.partial! "challenges/top_common_data", shixun_identifier: @shixun.identifier +json.(@challenge, :id, :subject, :task_pass, :difficulty, :score) +json.tags @challenge.challenge_tags.map(&:name) + + + + + + diff --git a/app/views/challenges/show_choose_question.json.jbuilder b/app/views/challenges/show_choose_question.json.jbuilder new file mode 100644 index 000000000..5513d8e1b --- /dev/null +++ b/app/views/challenges/show_choose_question.json.jbuilder @@ -0,0 +1,3 @@ +json.(@challenge_choose, :challenge_id, :subject, :answer, + :standard_answer, :score, :difficult, + :position, :category) \ No newline at end of file diff --git a/app/views/challenges/update.json.jbuilder b/app/views/challenges/update.json.jbuilder new file mode 100644 index 000000000..d927bd450 --- /dev/null +++ b/app/views/challenges/update.json.jbuilder @@ -0,0 +1,3 @@ +json.status 1 +json.messages "更新成功!" +json.challenge_id @challenge.id \ No newline at end of file diff --git a/app/views/challenges/update_choose_question.json.jbuilder b/app/views/challenges/update_choose_question.json.jbuilder new file mode 100644 index 000000000..3ee5d377c --- /dev/null +++ b/app/views/challenges/update_choose_question.json.jbuilder @@ -0,0 +1 @@ +json.challenge_choose_id @challenge_choose.try(:id) \ No newline at end of file diff --git a/app/views/commons/_data.json.jbuilder b/app/views/commons/_data.json.jbuilder new file mode 100644 index 000000000..739feaa11 --- /dev/null +++ b/app/views/commons/_data.json.jbuilder @@ -0,0 +1,3 @@ +json.data do + json.id object.id +end \ No newline at end of file diff --git a/app/views/commons/_like.json.jbuilder b/app/views/commons/_like.json.jbuilder new file mode 100644 index 000000000..436f70b7a --- /dev/null +++ b/app/views/commons/_like.json.jbuilder @@ -0,0 +1,3 @@ +unless @current_user.nil? + json.liked by_user_liked?(message, @current_user) +end \ No newline at end of file diff --git a/app/views/commons/_success.json.jbuilder b/app/views/commons/_success.json.jbuilder new file mode 100644 index 000000000..3e44db1d7 --- /dev/null +++ b/app/views/commons/_success.json.jbuilder @@ -0,0 +1,2 @@ +json.set! :status, 0 +json.set! :message, "响应成功" \ No newline at end of file diff --git a/app/views/commons/delete.json.jbuilder b/app/views/commons/delete.json.jbuilder new file mode 100644 index 000000000..af46ec565 --- /dev/null +++ b/app/views/commons/delete.json.jbuilder @@ -0,0 +1,2 @@ +json.partial! "commons/success" +json.partial! "commons/data", object: @object \ No newline at end of file diff --git a/app/views/commons/hidden.json.jbuilder b/app/views/commons/hidden.json.jbuilder new file mode 100644 index 000000000..af46ec565 --- /dev/null +++ b/app/views/commons/hidden.json.jbuilder @@ -0,0 +1,2 @@ +json.partial! "commons/success" +json.partial! "commons/data", object: @object \ No newline at end of file diff --git a/app/views/commons/unhidden.json.jbuilder b/app/views/commons/unhidden.json.jbuilder new file mode 100644 index 000000000..af46ec565 --- /dev/null +++ b/app/views/commons/unhidden.json.jbuilder @@ -0,0 +1,2 @@ +json.partial! "commons/success" +json.partial! "commons/data", object: @object \ No newline at end of file diff --git a/app/views/course_groups/_course_group.json.jbuilder b/app/views/course_groups/_course_group.json.jbuilder new file mode 100644 index 000000000..972891e96 --- /dev/null +++ b/app/views/course_groups/_course_group.json.jbuilder @@ -0,0 +1,3 @@ +json.course_group_id attachment_group_setting.course_group.id +json.course_group_name attachment_group_setting.course_group.name +json.course_group_publish_time attachment_group_setting.publish_time \ No newline at end of file diff --git a/app/views/course_groups/destroy.json.jbuilder b/app/views/course_groups/destroy.json.jbuilder new file mode 100644 index 000000000..0fbd93d7f --- /dev/null +++ b/app/views/course_groups/destroy.json.jbuilder @@ -0,0 +1,3 @@ +json.status 0 +json.message "删除成功" +json.right_url "/courses/#{@course.id}/students" \ No newline at end of file diff --git a/app/views/course_second_categories/destroy.json.jbuilder b/app/views/course_second_categories/destroy.json.jbuilder new file mode 100644 index 000000000..c1726ab8e --- /dev/null +++ b/app/views/course_second_categories/destroy.json.jbuilder @@ -0,0 +1,2 @@ +json.status 0 +json.right_url @right_url \ No newline at end of file diff --git a/app/views/courses/_course.json.jbuilder b/app/views/courses/_course.json.jbuilder new file mode 100644 index 000000000..3c109f8b4 --- /dev/null +++ b/app/views/courses/_course.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! course, :id, :created_at, :updated_at +json.url course_url(course, format: :json) diff --git a/app/views/courses/add_teacher_popup.json.jbuilder b/app/views/courses/add_teacher_popup.json.jbuilder new file mode 100644 index 000000000..a77d05b47 --- /dev/null +++ b/app/views/courses/add_teacher_popup.json.jbuilder @@ -0,0 +1,13 @@ +json.school_name @school_name +json.graduation_groups do + json.array! @graduation_groups do |graduation_group| + json.id graduation_group.id + json.name graduation_group.name + end +end +json.course_groups do + json.array! @course_groups do |course_group| + json.id course_group.id + json.name course_group.name + end +end \ No newline at end of file diff --git a/app/views/courses/all_course_groups.json.jbuilder b/app/views/courses/all_course_groups.json.jbuilder new file mode 100644 index 000000000..e64b9929a --- /dev/null +++ b/app/views/courses/all_course_groups.json.jbuilder @@ -0,0 +1,7 @@ +json.course_groups do + json.array! @course_groups_array do |course_group| + json.id course_group.id + json.name course_group.name + end +end +json.course_groups_count @course_groups_array.size \ No newline at end of file diff --git a/app/views/courses/attahcment_category_list.json.jbuilder b/app/views/courses/attahcment_category_list.json.jbuilder new file mode 100644 index 000000000..217b1092e --- /dev/null +++ b/app/views/courses/attahcment_category_list.json.jbuilder @@ -0,0 +1,10 @@ +json.has_course_groups @has_course_groups +json.course_modules do + json.array! @course_modules do |course_module| + json.id course_module.id + json.module_name course_module.module_name + json.course_second_categories do + json.array! course_module.course_second_categories, :id, :name + end + end +end diff --git a/app/views/courses/base_info.json.jbuilder b/app/views/courses/base_info.json.jbuilder new file mode 100644 index 000000000..c32617968 --- /dev/null +++ b/app/views/courses/base_info.json.jbuilder @@ -0,0 +1,2 @@ +json.course_id @course.id +json.course_name @course.name \ No newline at end of file diff --git a/app/views/courses/board_list.json.jbuilder b/app/views/courses/board_list.json.jbuilder new file mode 100644 index 000000000..e8961e380 --- /dev/null +++ b/app/views/courses/board_list.json.jbuilder @@ -0,0 +1,9 @@ +json.partial! 'commons/success' + +json.data do + json.course_id @course.id + json.user_course_identity @current_user.course_identity(@course) + json.boards do + json.array! @boards, :id, :name + end +end diff --git a/app/views/courses/course_group_list.json.jbuilder b/app/views/courses/course_group_list.json.jbuilder new file mode 100644 index 000000000..8c30a6b20 --- /dev/null +++ b/app/views/courses/course_group_list.json.jbuilder @@ -0,0 +1,7 @@ +json.course_groups do + json.array! @all_course_groups do |course_group| + json.id course_group.id + json.name course_group.name + json.checked @existed_course_group_ids.include? course_group.id + end +end \ No newline at end of file diff --git a/app/views/courses/create.json.jbuilder b/app/views/courses/create.json.jbuilder new file mode 100644 index 000000000..baf14da46 --- /dev/null +++ b/app/views/courses/create.json.jbuilder @@ -0,0 +1 @@ +json.course_id @course.id \ No newline at end of file diff --git a/app/views/courses/export_member_scores_excel.xlsx.axlsx b/app/views/courses/export_member_scores_excel.xlsx.axlsx new file mode 100644 index 000000000..da8c05f7a --- /dev/null +++ b/app/views/courses/export_member_scores_excel.xlsx.axlsx @@ -0,0 +1,181 @@ +wb = xlsx_package.workbook +wb.use_shared_strings = true +wb.styles do |s| + no_wrap_sz = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: false,:horizontal => :center,:vertical => :center } + sz_all = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center } + row_cell = s.add_style :bg_color=> "FAEBDC",:border => { :style => :thin, :color =>"000000" },alignment: {wrap_text: true,:horizontal => :center,:vertical => :center } + blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 20,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center} + + #课堂信息摘要 + wb.add_worksheet(name:course_info[0]) do |sheet| + sheet.sheet_view.show_grid_lines = false + course_main_info = course_info[1] + course_group_info = course_info[2] + group_info_d = course_group_info[0] + group_info_detail = course_group_info[1] + course_main_info.each do |c| + sheet.add_row c, :style => sz_all #用户id + end + sheet["A1:A7"].each { |c| c.style = row_cell } + sheet.add_row [],:style => sz_all + if group_info_detail.count > 0 + sheet.add_row group_info_d, :style => blue_cell + group_info_detail.each do |group| + sheet.add_row group, :style => sz_all #用户id + end + sheet.column_info.second.width = 40 + end + end #add_worksheet + + #课堂活跃度统计 + wb.add_worksheet(name:activity_level[0]) do |sheet| + sheet.sheet_view.show_grid_lines = false + sheet_title = activity_level[1] + sheet_content = activity_level[2] + sheet.add_row sheet_title, :style => blue_cell + if sheet_content.count > 0 + sheet_content.each_with_index do |c,index| + c_1 = (index+1) + c_2 = [c_1] + c.values + sheet.add_row c_2, :style => sz_all #用户id + end + sheet.column_widths *([20]*sheet.column_info.count) + sheet.column_info.first.width = 8 + end + end #add_worksheet + + #学生总成绩 + wb.add_worksheet(name:course_scores[0]) do |sheet| + sheet.sheet_view.show_grid_lines = false + sheet_title = course_scores[1] #头部标题 + sheet_title_counts = course_scores[2] #总成绩的作业数(包含每一项的总得分)如实训作业的作业数+总成绩 + sheet_content = course_scores[3] + sheet_length = sheet_title.count + sheet.add_row [""]*sheet_length, :style => blue_cell + sheet.add_row [""]*sheet_length, :style => blue_cell + sheet.merge_cells("A1:A2") + sheet.merge_cells("B1:B2") + sheet.merge_cells("C1:C2") + sheet.merge_cells("D1:D2") + sheet.merge_cells("E1:E2") + sheet.merge_cells("F1:F2") + sheet.merge_cells (Axlsx::cell_r(sheet_length-1,0) + ':' + Axlsx::cell_r(sheet_length-1,1)) #最后一行的合并 + sheet_first = sheet.rows.first #第一行 + sheet_second = sheet.rows.second #第二行 + work_head_title = %w(实训作业 普通作业 分组作业 毕设任务 试卷) + (0..(sheet_length-1)).each do |i| + if i <= 5 || i == sheet_length-1 + sheet_first.cells[i].value = sheet_title[i] + else + sheet_second.cells[i].value = sheet_title[i] + end + end + st_col = 6 + sheet_title_counts.each_with_index do |c,index| + end_col = (st_col + c - 1) + sheet.merge_cells sheet_first.cells[(st_col..end_col)] + sheet_first.cells[st_col].value = work_head_title[index.to_i] + st_col = end_col + 1 + end + + if sheet_content.count > 0 + sheet_content.each_with_index do |c,index| + c_1 = (index+1) + c_2 = [c_1] + c + sheet.add_row c_2, :style => sz_all #用户id + end + end + sheet.column_widths *([15]*sheet.column_info.count) + sheet.column_info.first.width = 8 + sheet.rows[1].height = 40 + end #add_worksheet + + #实训作业 + if shixun_works.count > 0 + shixun_works.each do |shixun| + wb.add_worksheet(name:shixun[0]) do |sheet| + head_title = shixun[1] + content_shixun = shixun[2] + sheet.sheet_view.show_grid_lines = false + sheet.add_row head_title, :style => blue_cell + if content_shixun.count > 0 + content_shixun.each do |user| + sheet.add_row user, :style => sz_all + end #each_widh_index + end + sheet.column_widths *([20]*sheet.column_info.count) + sheet.column_info.first.width = 12 + end #add_worksheet + end + end + + #普通作业 + if common_works.count > 0 + common_works.each do |work| + wb.add_worksheet(name:work[0]) do |sheet| + head_title = work[1] + content_ = work[2] + sheet.sheet_view.show_grid_lines = false + sheet.add_row head_title, :style => blue_cell + if content_.count > 0 + content_.each do |user| + sheet.add_row user, :style => no_wrap_sz + end #each_widh_index + end + sheet.column_widths *([20]*sheet.column_info.count) + sheet.column_info.first.width = 12 + end #add_worksheet + end + end + + #分组作业 + if group_works.count > 0 + group_works.each do |work| + wb.add_worksheet(name:work[0]) do |sheet| + head_title = work[1] + content_ = work[2] + sheet.sheet_view.show_grid_lines = false + sheet.add_row head_title, :style => blue_cell + if content_.count > 0 + content_.each do |user| + sheet.add_row user, :style => sz_all + end #each_widh_index + end + sheet.column_widths *([20]*sheet.column_info.count) + sheet.column_info.first.width = 12 + end #add_worksheet + end + end + + #毕设任务 + if task_works.count > 0 + task_works.each do |task| + wb.add_worksheet(name:task[0]) do |sheet| + sheet.sheet_view.show_grid_lines = false + content_ = task[2] + sheet.add_row task[1], :style => blue_cell + content_.each do |user| + sheet.add_row user, :style => sz_all + end #each_widh_index + sheet.column_widths *([20]*sheet.column_info.count) + sheet.column_info.first.width = 12 + end #add_worksheet + end + end + + #试卷 + if exercise_works.count > 0 + exercise_works.each do |ex| + wb.add_worksheet(name: ex[0]) do |sheet| + sheet.sheet_view.show_grid_lines = false + content_ = ex[2] + sheet.add_row ex[1], :style => blue_cell + content_.each do |user| + sheet.add_row user, :style => sz_all #用户id + end #each_widh_index + sheet.column_widths *([20]*sheet.column_info.count) + sheet.column_info.first.width = 12 + end #add_worksheet + end + end +end diff --git a/app/views/courses/get_historical_course_students.json.jbuilder b/app/views/courses/get_historical_course_students.json.jbuilder new file mode 100644 index 000000000..a2d3a3f57 --- /dev/null +++ b/app/views/courses/get_historical_course_students.json.jbuilder @@ -0,0 +1,9 @@ +json.students do + json.array! @students do |student| + json.course_member_id student.id + json.name student.user.real_name + json.student_id student.user.user_extension.try(:student_id) + json.school_name student.user.user_extension.school.try(:name) + end +end +json.students_count @students_count \ No newline at end of file diff --git a/app/views/courses/get_historical_courses.json.jbuilder b/app/views/courses/get_historical_courses.json.jbuilder new file mode 100644 index 000000000..74b190d8e --- /dev/null +++ b/app/views/courses/get_historical_courses.json.jbuilder @@ -0,0 +1,14 @@ +json.courses do + json.array! @courses do |course| + if course.course_groups.present? + course.course_groups.each do |course_group| + json.name course.name + "-" + course_group.name + json.course_id course.id + json.course_group_id course_group.id + end + else + json.name course.name + json.course_id course.id + end + end +end \ No newline at end of file diff --git a/app/views/courses/graduation_group_list.json.jbuilder b/app/views/courses/graduation_group_list.json.jbuilder new file mode 100644 index 000000000..e9036bce2 --- /dev/null +++ b/app/views/courses/graduation_group_list.json.jbuilder @@ -0,0 +1,7 @@ +json.graduation_group_list do + json.array! @graduation_group_list do |graduation_group| + json.id graduation_group.id + json.name graduation_group.name + end +end +json.graduation_groups_count @graduation_group_list.size \ No newline at end of file diff --git a/app/views/courses/index.json.jbuilder b/app/views/courses/index.json.jbuilder new file mode 100644 index 000000000..ec9ebfc3f --- /dev/null +++ b/app/views/courses/index.json.jbuilder @@ -0,0 +1,18 @@ +json.courses do + json.array! @courses do |course| + json.id course.id + json.name course.name + json.avatar_url url_to_avatar(course.teacher) + json.creator course.teacher.real_name + json.school course.teacher.school_name + json.technical_title course.teacher.user_extension.technical_title + json.course_members_count course.course_members_count + json.tasks_count get_tasks_count course + json.visits course.visits + json.is_public course.is_public + json.is_accessible @user.present? ? @user.member_of_course?(course) || @user.creator_of_course?(course) : course.is_public == 1 + json.is_end course.is_end + json.first_category_url module_url(course.course_modules.where.not(module_type: "activity").where(hidden: 0).order(position: :desc).first, course) + end +end +json.courses_count @courses_count diff --git a/app/views/courses/left_banner.json.jbuilder b/app/views/courses/left_banner.json.jbuilder new file mode 100644 index 000000000..681145769 --- /dev/null +++ b/app/views/courses/left_banner.json.jbuilder @@ -0,0 +1,45 @@ +json.is_teacher @is_teacher +json.course_modules @course_modules.each do |mod| + json.id mod.id + json.name mod.module_name + json.type mod.module_type + json.position mod.position + json.task_count course_task_count(@course, mod.module_type) + json.main_id mod.module_type == "board" ? @course.course_board.try(:id) : @course.id + json.category_url module_url(mod, @course) + if @second_category_type.include?(mod.module_type) + case mod.module_type + when "course_group" + # json.none_group_count @course.none_group_count + json.second_category left_group_info @course + when "board" + course_board = @course.course_board + if course_board.present? + json.second_category course_board.children.each do |board| + json.category_id board.id + json.category_name board.name + json.position board.position + json.category_count board.messages_count + json.category_type "messages" + json.second_category_url "/courses/#{@course.id}/boards/#{board.id}" + end + end + else + json.second_category mod.course_second_categories.each do |category| + json.category_id category.id + json.category_name category.name + json.position category.position + json.category_count category_task_count(@course, category, @user) + json.category_type category.category_type_str + json.second_category_url category_url(category, @course) + end + end + end +end + +json.hidden_modules @hidden_modules.each do |mod| + json.id mod.id + json.name mod.module_name + json.type mod.module_type + json.position mod.position +end \ No newline at end of file diff --git a/app/views/courses/mine.json.jbuilder b/app/views/courses/mine.json.jbuilder new file mode 100644 index 000000000..c82e31f6b --- /dev/null +++ b/app/views/courses/mine.json.jbuilder @@ -0,0 +1,5 @@ +json.partial! "commons/success" +json.data do + json.array! @courses, :id, :name, :updated_at +end + diff --git a/app/views/courses/search_course_list.json.jbuilder b/app/views/courses/search_course_list.json.jbuilder new file mode 100644 index 000000000..be751e064 --- /dev/null +++ b/app/views/courses/search_course_list.json.jbuilder @@ -0,0 +1,5 @@ +json.course_lists @course_lists do |course_list| + json.id course_list.id + json.name course_list.name +end +json.search_count @search_count \ No newline at end of file diff --git a/app/views/courses/search_teacher_candidate.json.jbuilder b/app/views/courses/search_teacher_candidate.json.jbuilder new file mode 100644 index 000000000..33bed4100 --- /dev/null +++ b/app/views/courses/search_teacher_candidate.json.jbuilder @@ -0,0 +1,11 @@ +json.candidates do + json.array! @users do |user| + json.id user.id + json.name user.firstname + user.lastname + json.nickname user.nickname + json.school_name user.user_extension.school.try(:name) + json.school_id user.user_extension.school.try(:id) + json.added @course.course_member?(user.id, [1, 2, 3]) + end +end +json.candidates_count @users_size \ No newline at end of file diff --git a/app/views/courses/search_users.json.jbuilder b/app/views/courses/search_users.json.jbuilder new file mode 100644 index 000000000..d735de970 --- /dev/null +++ b/app/views/courses/search_users.json.jbuilder @@ -0,0 +1,10 @@ +json.users do + json.array! @users do |user| + json.id user.id + json.name user.real_name + json.student_id user.user_extension.try(:student_id) + json.school_name user.user_extension.school.name + json.added @course.course_member?(user.id, 4) + end +end +json.users_count @users_count \ No newline at end of file diff --git a/app/views/courses/settings.json.jbuilder b/app/views/courses/settings.json.jbuilder new file mode 100644 index 000000000..8c82d15ea --- /dev/null +++ b/app/views/courses/settings.json.jbuilder @@ -0,0 +1,12 @@ +json.course_list_id @course.course_list.id +json.course_list_name @course.course_list.name +json.name @course.name +json.course_id @course.id +json.school @course.school&.name +json.class_period @course.class_period +json.credit @course.credit +json.end_date @course.end_date +json.is_public @course.is_public +json.course_module_types @course.course_modules.where(hidden: 0).pluck(:module_type) +json.authentication @course.authentication +json.professional_certification @course.professional_certification \ No newline at end of file diff --git a/app/views/courses/show.json.jbuilder b/app/views/courses/show.json.jbuilder new file mode 100644 index 000000000..2ea056fa8 --- /dev/null +++ b/app/views/courses/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "courses/course", course: @course diff --git a/app/views/courses/students.json.jbuilder b/app/views/courses/students.json.jbuilder new file mode 100644 index 000000000..a7585672f --- /dev/null +++ b/app/views/courses/students.json.jbuilder @@ -0,0 +1,16 @@ +json.students do + json.array! @students do |student| + json.user_id student.user_id + json.login student.user.try(:login) + json.name student.user.try(:real_name) + json.name_link user_path(student.user) + json.student_id student.user.try(:student_id) + json.course_group_name student.course_group.try(:name) + json.course_member_id student.id + end +end +json.students_count @students_count +if @course_group.present? + json.course_group_name @course_group.name + json.invite_code @course_group.invite_code +end \ No newline at end of file diff --git a/app/views/courses/teachers.json.jbuilder b/app/views/courses/teachers.json.jbuilder new file mode 100644 index 000000000..25df05097 --- /dev/null +++ b/app/views/courses/teachers.json.jbuilder @@ -0,0 +1,30 @@ +json.teacher_list do + json.array! @teacher_list do |teacher| + json.course_member_id teacher.id + json.name teacher.user.real_name + json.name_link user_path(teacher.user.login) + json.login teacher.user.login + json.user_id teacher.user.id + json.role teacher.role == "CREATOR" ? "管理员" : teacher.role == "PROFESSOR" ? "教师" : "助教" + json.course_groups do + json.array! CourseGroup.where(id: TeacherCourseGroup.where(course_member_id: teacher.id, user_id: teacher.user.id, course_id: @course.id).pluck(:course_group_id)) do |course_group| + json.name course_group.name + json.id course_group.id + end + end + json.graduation_group teacher.graduation_group.try(:name) + json.graduation_group_id teacher.graduation_group.try(:id) + end +end +json.teacher_list_size @teacher_list_size +json.application_list do + json.array! @applications do |application| + json.application_id application.id + json.user_id application.course_message_id + json.name application.application_user.real_name + json.name_link user_path(application.application_user) + json.login application.application_user.login + json.role application.content.to_i == 3 || application.content.to_i == 7 ? "助教" : application.content.to_i == 2 || application.content.to_i == 9 ? "教师" : "" + end +end +json.is_admin @is_admin diff --git a/app/views/courses/top_banner.json.jbuilder b/app/views/courses/top_banner.json.jbuilder new file mode 100644 index 000000000..ddf860709 --- /dev/null +++ b/app/views/courses/top_banner.json.jbuilder @@ -0,0 +1,27 @@ +json.name @course.name +json.teacher_name @course.teacher.real_name +json.teacher_login @course.teacher.login +json.teacher_img url_to_avatar(@course.teacher) +json.teacher_school @course.school.try(:name) +json.teacher_count @course.course_member_count([1, 2, 3]) +json.student_count @course.course_member_count(4) +json.course_group_count @course.course_groups_count +json.credit @course.credit +json.course_end @course.is_end +json.deadline course_end_date @course.end_date +json.educoder_teacher @user.is_teacher? +#json.is_student @is_student +json.is_admin @user.creator_of_course?(@course) +json.is_public @course.is_public == 1 +json.code_halt @course.invite_code_halt == 1 +json.invite_code @course.invite_code_halt == 0 ? @course.generate_invite_code : "" +json.switch_to_student switch_student_role(@is_teacher, @course, @user) +json.switch_to_teacher switch_teacher_role(@is_student, @course, @user) +json.switch_to_assistant switch_assistant_role(@is_student, @course, @user) +#json.join_course !@user.member_of_course?(@course) +#json.copy_course !@user.member_of_course?(@course) && @user.is_teacher? +json.course_identity @user.course_identity(@course) +if @course.is_end == 0 + json.days_remaining (@course.end_date.to_date - Time.now.to_date).to_i +end + diff --git a/app/views/discusses/_discuss.json.jbuilder b/app/views/discusses/_discuss.json.jbuilder new file mode 100644 index 000000000..1fcf150bc --- /dev/null +++ b/app/views/discusses/_discuss.json.jbuilder @@ -0,0 +1,21 @@ +json.author do + json.partial! 'users/user', user: discuss.user +end +json.id discuss.id +json.content discuss.contents(container, current_user) +json.time time_from_now(discuss.created_at) +json.position discuss.position +json.shixun_id discuss.dis_id +json.hidden discuss.hidden +json.manage current_user.manager_of_shixun?(container) +json.reward discuss.reward +json.game_url discuss.game_url(container, current_user) +# 主贴和回复有一些不同点 +if discuss.parent_id + json.can_delete discuss.can_deleted?(current_user) +else + json.praise_count discuss.praise_tread.where(praise_or_tread: 1).count + json.user_praise discuss.praise_tread.select{|pt| pt.user_id == current_user.id}.length > 0 ? true : false +end + + diff --git a/app/views/discusses/create.json.jbuilder b/app/views/discusses/create.json.jbuilder new file mode 100644 index 000000000..d9cfe0254 --- /dev/null +++ b/app/views/discusses/create.json.jbuilder @@ -0,0 +1,5 @@ +# 这个地方没有跳入到partial可能性能更好,因为发表评论的瞬间,点赞什么的肯定都没有的 +json.discuss @discuss +json.author do + json.partial! 'users/user', user: @discuss.user +end \ No newline at end of file diff --git a/app/views/discusses/index.json.jbuilder b/app/views/discusses/index.json.jbuilder new file mode 100644 index 000000000..3d0ee9fc9 --- /dev/null +++ b/app/views/discusses/index.json.jbuilder @@ -0,0 +1,9 @@ +json.disscuss_count @disscuss_count +json.all @current_user.admin? +json.comments @discusses do |discuss| + json.partial! 'discusses/discuss', locals: { discuss: discuss, container: @container, current_user: @current_user } + child_discuss = Discuss.children(discuss.id) + json.children child_discuss do |c_d| + json.partial! 'discusses/discuss', locals: { discuss: c_d, container: @container, current_user: @current_user } + end +end diff --git a/app/views/discusses/new_message.json.jbuilder b/app/views/discusses/new_message.json.jbuilder new file mode 100644 index 000000000..4fd3f2a68 --- /dev/null +++ b/app/views/discusses/new_message.json.jbuilder @@ -0,0 +1 @@ +json.new_message @user_discuss \ No newline at end of file diff --git a/app/views/discusses/plus.json.jbuilder b/app/views/discusses/plus.json.jbuilder new file mode 100644 index 000000000..d24dbb655 --- /dev/null +++ b/app/views/discusses/plus.json.jbuilder @@ -0,0 +1 @@ +json.praise_count @praise_count \ No newline at end of file diff --git a/app/views/discusses/reply.json.jbuilder b/app/views/discusses/reply.json.jbuilder new file mode 100644 index 000000000..4024ee7ea --- /dev/null +++ b/app/views/discusses/reply.json.jbuilder @@ -0,0 +1 @@ +json.discuss @discuss \ No newline at end of file diff --git a/app/views/discusses/reward_code.json.jbuilder b/app/views/discusses/reward_code.json.jbuilder new file mode 100644 index 000000000..e5e0e9152 --- /dev/null +++ b/app/views/discusses/reward_code.json.jbuilder @@ -0,0 +1 @@ +json.code @code \ No newline at end of file diff --git a/app/views/discusses/show.json.jbuilder b/app/views/discusses/show.json.jbuilder new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/ecs/course_achievement_methods/shared/_ec_course_achievement_method.json.jbuilder b/app/views/ecs/course_achievement_methods/shared/_ec_course_achievement_method.json.jbuilder new file mode 100644 index 000000000..5cc3220a4 --- /dev/null +++ b/app/views/ecs/course_achievement_methods/shared/_ec_course_achievement_method.json.jbuilder @@ -0,0 +1,9 @@ +json.extract! ec_course_achievement_method, :id, :score, :percentage + +json.course_evaluation do + json.partial! 'ecs/course_evaluations/shared/ec_course_evaluation_only', + ec_course_evaluation: ec_course_achievement_method.ec_course_evaluation +end + +json.course_evaluation_subitems ec_course_achievement_method.ec_course_evaluation_subitems, + partial: 'ecs/shared/ec_course_evaluation_subitem', as: :ec_course_evaluation_subitem diff --git a/app/views/ecs/course_achievement_methods/show.json.jbuilder b/app/views/ecs/course_achievement_methods/show.json.jbuilder new file mode 100644 index 000000000..9105c9615 --- /dev/null +++ b/app/views/ecs/course_achievement_methods/show.json.jbuilder @@ -0,0 +1,3 @@ +json.course_targets @course_targets, + partial: 'ecs/course_targets/shared/ec_course_target_with_achievement_methods', + as: :ec_course_target diff --git a/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx b/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx new file mode 100644 index 000000000..900ff5888 --- /dev/null +++ b/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx @@ -0,0 +1,28 @@ +course_evaluation = @course_evaluation + +wb = xlsx_package.workbook +wb.styles do |style| + base_style_attr = { + sz: 11, height: 16, alignment: { horizontal: :center }, + border: { style: :thin, color: '000000' } + } + bg_style = style.add_style(base_style_attr.merge(bg_color: '90EE90')) + normal_style = style.add_style(base_style_attr) + + wb.add_worksheet(name: "#{course_evaluation.name}成绩导入模板") do |sheet| + name = course_evaluation.name + items_size = course_evaluation.ec_course_evaluation_subitems.count + + sheet.add_row name, style: bg_style + sheet.merge_cells wb.rows.first.cells[(1..(items_size * course_evaluation.evaluation_count))] + + data = [] + item_names = course_evaluation.ec_course_evaluation_subitems.pluck(:name) + course_evaluation.evaluation_count.times do |times| + data += item_names.map { |str| "#{name}#{times + 1}#{str}" } + end + sheet.add_row data, style: bg_style + + sheet.add_row [''] * (items_size * course_evaluation.evaluation_count), style: normal_style + end +end \ No newline at end of file diff --git a/app/views/ecs/course_evaluations/detail_score_import_template.xlsx.axlsx b/app/views/ecs/course_evaluations/detail_score_import_template.xlsx.axlsx new file mode 100644 index 000000000..8803ef65c --- /dev/null +++ b/app/views/ecs/course_evaluations/detail_score_import_template.xlsx.axlsx @@ -0,0 +1,33 @@ +course_evaluation = @course_evaluation + +wb = xlsx_package.workbook +wb.styles do |style| + base_style_attr = { + sz: 11, height: 16, alignment: { horizontal: :center }, + border: { style: :thin, color: '000000' } + } + bg_style = style.add_style(base_style_attr.merge(bg_color: '90EE90')) + normal_style = style.add_style(base_style_attr) + + wb.add_worksheet(name: "#{course_evaluation.name}成绩导入模板") do |sheet| + name = course_evaluation.name + items_size = course_evaluation.ec_course_evaluation_subitems.count + + sheet.add_row ['学号', '姓名', name], style: bg_style + sheet.merge_cells('A1:A2') + sheet.merge_cells('B1:B2') + sheet.merge_cells wb.rows.first.cells[(3..(3 + items_size * course_evaluation.evaluation_count))] + + data = ['', ''] + item_names = course_evaluation.ec_course_evaluation_subitems.pluck(:name) + course_evaluation.evaluation_count.times do |times| + data += item_names.map { |str| "#{name}#{times + 1}#{str}" } + end + sheet.add_row data, style: bg_style + + empty_data = [''] * (3 + items_size * course_evaluation.evaluation_count) + 60.times do + sheet.add_row empty_data, style: normal_style + end + end +end \ No newline at end of file diff --git a/app/views/ecs/course_evaluations/index.json.jbuilder b/app/views/ecs/course_evaluations/index.json.jbuilder new file mode 100644 index 000000000..e1c63d44d --- /dev/null +++ b/app/views/ecs/course_evaluations/index.json.jbuilder @@ -0,0 +1 @@ +json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation', as: :ec_course_evaluation diff --git a/app/views/ecs/course_evaluations/shared/_ec_course_evaluation.json.jbuilder b/app/views/ecs/course_evaluations/shared/_ec_course_evaluation.json.jbuilder new file mode 100644 index 000000000..daef8cea1 --- /dev/null +++ b/app/views/ecs/course_evaluations/shared/_ec_course_evaluation.json.jbuilder @@ -0,0 +1,4 @@ +json.extract! ec_course_evaluation, :id, :name, :evaluation_count, :status, :import_status, :score_type + +json.course_evaluation_subitems ec_course_evaluation.ec_course_evaluation_subitems, + partial: 'ecs/shared/ec_course_evaluation_subitem', as: :ec_course_evaluation_subitem diff --git a/app/views/ecs/course_evaluations/shared/_ec_course_evaluation_only.json.jbuilder b/app/views/ecs/course_evaluations/shared/_ec_course_evaluation_only.json.jbuilder new file mode 100644 index 000000000..776d446f7 --- /dev/null +++ b/app/views/ecs/course_evaluations/shared/_ec_course_evaluation_only.json.jbuilder @@ -0,0 +1 @@ +json.extract! ec_course_evaluation, :id, :name, :evaluation_count, :status diff --git a/app/views/ecs/course_evaluations/shared/_ec_course_evaluation_slim.json.jbuilder b/app/views/ecs/course_evaluations/shared/_ec_course_evaluation_slim.json.jbuilder new file mode 100644 index 000000000..e0c49f00e --- /dev/null +++ b/app/views/ecs/course_evaluations/shared/_ec_course_evaluation_slim.json.jbuilder @@ -0,0 +1,4 @@ +json.extract! ec_course_evaluation, :id, :name, :evaluation_count, :status + +json.course_evaluation_subitems ec_course_evaluation.ec_course_evaluation_subitems, + partial: 'ecs/shared/ec_course_evaluation_subitem', as: :ec_course_evaluation_subitem diff --git a/app/views/ecs/course_evaluations/show.json.jbuilder b/app/views/ecs/course_evaluations/show.json.jbuilder new file mode 100644 index 000000000..b03ddc076 --- /dev/null +++ b/app/views/ecs/course_evaluations/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'shared/ec_course_evaluation', ec_course_evaluation: @course_evaluation diff --git a/app/views/ecs/course_evaluations/slimmer.json.jbuilder b/app/views/ecs/course_evaluations/slimmer.json.jbuilder new file mode 100644 index 000000000..929cfe7be --- /dev/null +++ b/app/views/ecs/course_evaluations/slimmer.json.jbuilder @@ -0,0 +1 @@ +json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation_slim', as: :ec_course_evaluation diff --git a/app/views/ecs/course_managers/create.json.jbuilder b/app/views/ecs/course_managers/create.json.jbuilder new file mode 100644 index 000000000..ff7ff01e5 --- /dev/null +++ b/app/views/ecs/course_managers/create.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'ecs/shared/user', user: @user diff --git a/app/views/ecs/course_targets/index.json.jbuilder b/app/views/ecs/course_targets/index.json.jbuilder new file mode 100644 index 000000000..6590ecc10 --- /dev/null +++ b/app/views/ecs/course_targets/index.json.jbuilder @@ -0,0 +1,2 @@ + +json.course_targets @course_targets, partial: 'shared/course_target', as: :ec_course_target diff --git a/app/views/ecs/course_targets/index.xlsx.axlsx b/app/views/ecs/course_targets/index.xlsx.axlsx new file mode 100644 index 000000000..a188ad95c --- /dev/null +++ b/app/views/ecs/course_targets/index.xlsx.axlsx @@ -0,0 +1,71 @@ +course_targets = @course_targets.includes( + ec_course_achievement_methods: :ec_course_evaluation, + ec_graduation_subitems: :ec_graduation_requirement +) +ec_year = @_current_year +major = ec_year.ec_major_school.ec_major + +wb = xlsx_package.workbook +wb.styles do |style| + title_style = style.add_style(sz: 16, height: 20, b: true) + ec_year_style = style.add_style(sz: 10, height: 14) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', + alignment: { horizontal: :center }, border: { style: :thin, color: '000000' }) + content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) + + name = "#{@_current_course.name}课程目标" + wb.add_worksheet(name: name) do |sheet| + sheet.add_row name, style: title_style + + sheet.add_row [] + sheet.add_row [] + + sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业名称', major.name], style: ec_year_style + sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style + + sheet.add_row [] + sheet.add_row [] + + index = 9 + course_targets.each do |target| + sheet.add_row ['课程目标', "目标#{target.position}:#{target.content}"], style: [label_style, content_style] + end + sheet.merge_cells("A#{index}:A#{index + course_targets.size}") + + sheet.add_row [] + sheet.add_row [] + + sheet.add_row %w(毕业要求 二级指标点 权重(∑=1) 课程目标), style: label_style + course_targets.each do |target| + target.ec_graduation_subitems.each do |item| + requirement = item.ec_graduation_requirement + + data = [ + "#{requirement.position}:#{requirement.content}", + "#{requirement.position}-#{item.position}:#{item.content}", + target.weight, + "目标#{target.position}" + ] + sheet.add_row data, style: content_style + end + end + + sheet.add_row [] + sheet.add_row [] + + sheet.add_row %w(教学目标 评价方法 评价依据 达成标准(分)), style: label_style + course_targets.each do |target| + achievement_methods = [] + names = [] + + target.ec_course_achievement_methods.each do |achievement| + names << achievement.ec_course_evaluation.name + achievement_methods << "#{achievement.ec_course_evaluation.name}(#{achievement.percentage}%)" + end + + data = ["目标#{target.position}", achievement_methods.join('+'), names.join('+'), target.standard_grade] + sheet.add_row data, style: content_style + end + end +end \ No newline at end of file diff --git a/app/views/ecs/course_targets/shared/_course_target.json.jbuilder b/app/views/ecs/course_targets/shared/_course_target.json.jbuilder new file mode 100644 index 000000000..a5646ac7e --- /dev/null +++ b/app/views/ecs/course_targets/shared/_course_target.json.jbuilder @@ -0,0 +1,8 @@ +json.extract! ec_course_target, :id, :position, :content, :standard_grade, :weight + +json.graduation_subitem do + graduation_subitem = ec_course_target.ec_graduation_subitems.take + + json.partial! 'ecs/shared/ec_graduation_subitem', ec_graduation_subitem: graduation_subitem + json.graduation_requirement_position graduation_subitem.ec_graduation_requirement.position +end diff --git a/app/views/ecs/course_targets/shared/_ec_course_target_with_achievement_methods.json.jbuilder b/app/views/ecs/course_targets/shared/_ec_course_target_with_achievement_methods.json.jbuilder new file mode 100644 index 000000000..ce82b669c --- /dev/null +++ b/app/views/ecs/course_targets/shared/_ec_course_target_with_achievement_methods.json.jbuilder @@ -0,0 +1,5 @@ +json.extract! ec_course_target, :id, :position, :content + +json.course_achievement_methods ec_course_target.ec_course_achievement_methods, + partial: 'ecs/course_achievement_methods/shared/ec_course_achievement_method', + as: :ec_course_achievement_method \ No newline at end of file diff --git a/app/views/ecs/ec_courses/create.json.jbuilder b/app/views/ecs/ec_courses/create.json.jbuilder new file mode 100644 index 000000000..9281ed71d --- /dev/null +++ b/app/views/ecs/ec_courses/create.json.jbuilder @@ -0,0 +1,23 @@ +json.extract! @ec_course, :id, :name, :ec_year_id, :complete_target_count + +course_target_count = @ec_course.ec_course_targets.count +json.course_target_count course_target_count +json.course_evaluation_count @ec_course.ec_course_evaluations.count +json.course_achievement_method_count @ec_course.ec_course_achievement_methods.count + +json.graduation_subitem_count EcGraduationSubitemCourseTarget.joins(:ec_course_target) + .where(ec_course_targets: { ec_course_id: @ec_course.id }) + .count('distinct ec_graduation_subitem_id') +json.completed_graduation_subitem_count EcCourseSupport.joins(:ec_graduation_requirement_calculation) + .where(ec_course_id: @ec_course.id) + .where(ec_graduation_requirement_calculations: { status: 1 }) + .count('distinct ec_graduation_subitem_id') +# 达成状态 +status = if course_target_count.zero? + '' + else + ec_course.complete_target_count == course_target_count ? 'achieved' : 'not_achieved' + end +json.status status + +json.course_managers @ec_course.course_managers, partial: 'ecs/shared/user', as: :user diff --git a/app/views/ecs/ec_courses/index.json.jbuilder b/app/views/ecs/ec_courses/index.json.jbuilder new file mode 100644 index 000000000..084034aa5 --- /dev/null +++ b/app/views/ecs/ec_courses/index.json.jbuilder @@ -0,0 +1,25 @@ +json.count @count +json.ec_courses do + json.array! @ec_courses do |ec_course| + json.extract! ec_course, :id, :name, :ec_year_id + + json.course_evaluation_count @evaluation_count_map[ec_course.id] + json.course_achievement_method_count @achievement_method_count_map[ec_course.id] + # 课程目标 + json.course_target_count ec_course.complete_target_count + json.course_target_count @target_count_map[ec_course.id] + # 毕业要求指导点 + json.graduation_subitem_count @graduation_subitem_count_map[ec_course.id] + json.completed_graduation_subitem_count @completed_subitem_count_map[ec_course.id] + + # 达成状态 + status = if @target_count_map[ec_course.id].to_i.zero? + '' + else + ec_course.complete_target_count == @target_count_map[ec_course.id].to_i ? 'achieved' : 'not_achieved' + end + json.status status + + json.course_managers ec_course.course_managers, partial: 'ecs/shared/user', as: :user + end +end diff --git a/app/views/ecs/ec_courses/search.json.jbuilder b/app/views/ecs/ec_courses/search.json.jbuilder new file mode 100644 index 000000000..fc22586d7 --- /dev/null +++ b/app/views/ecs/ec_courses/search.json.jbuilder @@ -0,0 +1,2 @@ +json.count @count +json.ec_courses @ec_courses, partial: 'shared/ec_course_slim', as: :ec_course \ No newline at end of file diff --git a/app/views/ecs/ec_courses/shared/_ec_course_slim.json.jbuilder b/app/views/ecs/ec_courses/shared/_ec_course_slim.json.jbuilder new file mode 100644 index 000000000..1d43b5a8d --- /dev/null +++ b/app/views/ecs/ec_courses/shared/_ec_course_slim.json.jbuilder @@ -0,0 +1 @@ +json.extract! ec_course, :id, :name diff --git a/app/views/ecs/ec_graduation_requirements/index.json.jbuilder b/app/views/ecs/ec_graduation_requirements/index.json.jbuilder new file mode 100644 index 000000000..6fbbf249b --- /dev/null +++ b/app/views/ecs/ec_graduation_requirements/index.json.jbuilder @@ -0,0 +1,3 @@ + +json.count @graduation_requirements.size +json.graduation_requirements @graduation_requirements, partial: 'shared/ec_graduation_requirement', as: :ec_graduation_requirement diff --git a/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx b/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx new file mode 100644 index 000000000..aeb802329 --- /dev/null +++ b/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx @@ -0,0 +1,43 @@ +graduation_requirements = @graduation_requirements +ec_year = @_current_year +major = ec_year.ec_major_school.ec_major + +wb = xlsx_package.workbook +wb.styles do |style| + title_style = style.add_style(sz: 16, height: 20, b: true) + ec_year_style = style.add_style(sz: 10, height: 14) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) + + wb.add_worksheet(:name => '毕业要求及指标点') do |sheet| + sheet.add_row '毕业要求及指标点', style: title_style + + sheet.add_row [] + + sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业名称', major.name], style: ec_year_style + sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style + + sheet.add_row [] + + sheet.add_row %w(毕业要求 分解指标项), style: label_style + + index = 7 + + graduation_requirements.each do |requirement| + requirement_content = "#{requirement.position}. #{requirement.content}" + requirement.ec_graduation_subitems.each do |item| + item_content = "#{requirement.position}-#{item.position}. #{item.content}" + sheet.add_row [requirement_content, item_content], style: content_style + end + + items_size = requirement.ec_graduation_subitems.size + sheet.merge_cells("A#{index}:A#{index + items_size}") + sheet.merge_cells("B#{index}:B#{index + items_size}") + + index += items_size + end + + sheet.column_widths [400, 400] + end +end \ No newline at end of file diff --git a/app/views/ecs/ec_graduation_requirements/shared/_ec_graduation_requirement.json.jbuilder b/app/views/ecs/ec_graduation_requirements/shared/_ec_graduation_requirement.json.jbuilder new file mode 100644 index 000000000..6ed5baa3e --- /dev/null +++ b/app/views/ecs/ec_graduation_requirements/shared/_ec_graduation_requirement.json.jbuilder @@ -0,0 +1,4 @@ +json.extract! ec_graduation_requirement, :id, :position, :content + +json.ec_graduation_subitems ec_graduation_requirement.ec_graduation_subitems, + partial: 'ecs/shared/ec_graduation_subitem', as: :ec_graduation_subitem diff --git a/app/views/ecs/ec_graduation_requirements/show.json.jbuilder b/app/views/ecs/ec_graduation_requirements/show.json.jbuilder new file mode 100644 index 000000000..562c255a9 --- /dev/null +++ b/app/views/ecs/ec_graduation_requirements/show.json.jbuilder @@ -0,0 +1,2 @@ + +json.partial! 'shared/ec_graduation_requirement', ec_graduation_requirement: @graduation_requirement diff --git a/app/views/ecs/ec_major_schools/index.json.jbuilder b/app/views/ecs/ec_major_schools/index.json.jbuilder new file mode 100644 index 000000000..0924b71ea --- /dev/null +++ b/app/views/ecs/ec_major_schools/index.json.jbuilder @@ -0,0 +1,15 @@ + +json.count @count + +# 示例专业 +json.template_ec_major_school do + json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: @template_major_school +end + +# 专业 +json.ec_major_schools @major_schools do |ec_major_school| + json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: ec_major_school + + # 专业管理员 + json.major_managers ec_major_school.users, partial: 'ecs/ec_major_schools/shared/ec_major_school', as: :user +end diff --git a/app/views/ecs/ec_major_schools/shared/_ec_major_school.json.jbuilder b/app/views/ecs/ec_major_schools/shared/_ec_major_school.json.jbuilder new file mode 100644 index 000000000..ce0447a54 --- /dev/null +++ b/app/views/ecs/ec_major_schools/shared/_ec_major_school.json.jbuilder @@ -0,0 +1,6 @@ + +ec_major = ec_major_school.ec_major + +json.id ec_major_school.id +json.code ec_major.code +json.name ec_major.name diff --git a/app/views/ecs/ec_majors/index.json.jbuilder b/app/views/ecs/ec_majors/index.json.jbuilder new file mode 100644 index 000000000..34ee9a907 --- /dev/null +++ b/app/views/ecs/ec_majors/index.json.jbuilder @@ -0,0 +1,2 @@ +json.count @count +json.es_majors @ec_majors, partial: 'ecs/majors/shared/ec_major', as: :ec_major diff --git a/app/views/ecs/ec_majors/shared/_ec_major.json.jbuilder b/app/views/ecs/ec_majors/shared/_ec_major.json.jbuilder new file mode 100644 index 000000000..1b6f08262 --- /dev/null +++ b/app/views/ecs/ec_majors/shared/_ec_major.json.jbuilder @@ -0,0 +1 @@ +json.extract! ec_major, :id, :code, :name diff --git a/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder b/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder new file mode 100644 index 000000000..83414d2f4 --- /dev/null +++ b/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder @@ -0,0 +1,3 @@ +json.extract! ec_training_objective, :id, :content + +json.ec_training_items ec_training_objective.ec_training_subitems, partial: 'ec_training_subitem', as: :ec_training_subitem diff --git a/app/views/ecs/ec_training_objectives/shared/_ec_training_subitem.json.jbuilder b/app/views/ecs/ec_training_objectives/shared/_ec_training_subitem.json.jbuilder new file mode 100644 index 000000000..d145e2829 --- /dev/null +++ b/app/views/ecs/ec_training_objectives/shared/_ec_training_subitem.json.jbuilder @@ -0,0 +1 @@ +json.extract! ec_training_subitem, :id, :content diff --git a/app/views/ecs/ec_training_objectives/show.json.jbuilder b/app/views/ecs/ec_training_objectives/show.json.jbuilder new file mode 100644 index 000000000..a37fa1c09 --- /dev/null +++ b/app/views/ecs/ec_training_objectives/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'shared/ec_training_objective', ec_training_objective: @training_objective diff --git a/app/views/ecs/ec_training_objectives/show.xlsx.axlsx b/app/views/ecs/ec_training_objectives/show.xlsx.axlsx new file mode 100644 index 000000000..4746be0ea --- /dev/null +++ b/app/views/ecs/ec_training_objectives/show.xlsx.axlsx @@ -0,0 +1,32 @@ +training_objective = @training_objective +ec_year = training_objective.ec_year +major = ec_year.ec_major_school.ec_major + +wb = xlsx_package.workbook +wb.styles do |style| + title_style = style.add_style(sz: 16, height: 20, b: true) + ec_year_style = style.add_style(sz: 10, height: 14) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) + + wb.add_worksheet(:name => '培养目标及目标分解') do |sheet| + sheet.add_row '培养目标及目标分解', style: title_style + + sheet.add_row [] + sheet.add_row [] + + sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业名称', major.name], style: ec_year_style + sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style + + sheet.add_row [] + + sheet.add_row ['培养目标', training_objective.content], style: [label_style, content_style] + training_objective.ec_training_subitems.each do |item| + sheet.add_row ['目标分解', item.content], style: [label_style, content_style] + end + + items_size = training_objective.ec_training_subitems.size + sheet.merge_cells("A9:A#{9 + items_size}") + end +end \ No newline at end of file diff --git a/app/views/ecs/ec_years/create.json.jbuilder b/app/views/ecs/ec_years/create.json.jbuilder new file mode 100644 index 000000000..e21a1ba0c --- /dev/null +++ b/app/views/ecs/ec_years/create.json.jbuilder @@ -0,0 +1,9 @@ + +json.extract! @ec_year, :id, :year + +json.student_count @ec_year.ec_year_students.count +json.training_subitem_count @ec_year.ec_training_subitems.count +json.graduation_requirement_count @ec_year.ec_graduation_requirements.count +json.course_count @ec_year.ec_courses.count +json.course_target_count @ec_year.ec_course_targets.count +json.graduation_subitem_count @ec_year.ec_graduation_subitems.count diff --git a/app/views/ecs/ec_years/index.json.jbuilder b/app/views/ecs/ec_years/index.json.jbuilder new file mode 100644 index 000000000..c5c89cd06 --- /dev/null +++ b/app/views/ecs/ec_years/index.json.jbuilder @@ -0,0 +1,14 @@ +json.count @count + +json.ec_years do + json.array! @ec_years do |ec_year| + json.extract! ec_year, :id, :year + + json.student_count @student_count_map.fetch(ec_year.id, 0) + json.training_subitem_count @training_subitem_count_map.fetch(ec_year.id, 0) + json.graduation_requirement_count @graduation_requirement_count_map.fetch(ec_year.id, 0) + json.course_count @course_count_map.fetch(ec_year.id, 0) + json.course_target_count @course_target_count_map.fetch(ec_year.id, 0) + json.graduation_subitem_count @graduation_subitem_count_map.fetch(ec_year.id, 0) + end +end \ No newline at end of file diff --git a/app/views/ecs/graduation_course_supports/create.json.jbuilder b/app/views/ecs/graduation_course_supports/create.json.jbuilder new file mode 100644 index 000000000..c05024911 --- /dev/null +++ b/app/views/ecs/graduation_course_supports/create.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'shared/ec_graduation_subitem', ec_graduation_subitem: @graduation_subitem diff --git a/app/views/ecs/graduation_course_supports/shared/_ec_course_support.json.jbuilder b/app/views/ecs/graduation_course_supports/shared/_ec_course_support.json.jbuilder new file mode 100644 index 000000000..7fa6ff319 --- /dev/null +++ b/app/views/ecs/graduation_course_supports/shared/_ec_course_support.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! ec_course_support, :id, :weights, :top_relation, :ec_course_id +json.ec_course_name ec_course_support.ec_course.name diff --git a/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder b/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder new file mode 100644 index 000000000..1ffe12ec4 --- /dev/null +++ b/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder @@ -0,0 +1,5 @@ +json.extract! ec_graduation_subitem, :id, :position, :content, :ec_graduation_requirement_id + +json.graduation_requirement_position ec_graduation_subitem.ec_graduation_requirement.position + +json.course_supports ec_graduation_subitem.ec_course_supports, partial: 'ec_course_support', as: :ec_course_support diff --git a/app/views/ecs/graduation_course_supports/show.json.jbuilder b/app/views/ecs/graduation_course_supports/show.json.jbuilder new file mode 100644 index 000000000..a9e4bdc22 --- /dev/null +++ b/app/views/ecs/graduation_course_supports/show.json.jbuilder @@ -0,0 +1,3 @@ +json.course_count @course_count +json.graduation_subitems @graduation_subitems, partial: 'shared/ec_graduation_subitem', as: :ec_graduation_subitem +json.count @graduation_subitems.size diff --git a/app/views/ecs/graduation_course_supports/show.xlsx.axlsx b/app/views/ecs/graduation_course_supports/show.xlsx.axlsx new file mode 100644 index 000000000..fd1a44935 --- /dev/null +++ b/app/views/ecs/graduation_course_supports/show.xlsx.axlsx @@ -0,0 +1,71 @@ +graduation_subitems = @graduation_subitems +ec_year = @_current_year +major = ec_year.ec_major_school.ec_major + +max_support_length = graduation_subitems.map { |item| item.ec_course_supports.size }.max +last_column_index = 2 + max_support_length + +wb = xlsx_package.workbook +wb.styles do |style| + title_style = style.add_style(sz: 16, height: 20, b: true) + ec_year_style = style.add_style(sz: 10, height: 14) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }, border: { style: :thin, color: '000000' }) + content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) + tip_style = style.add_style(sz: 11, height: 16, color: 'FFA07A') + + wb.add_worksheet(:name => '课程体系对毕业要求的支撑') do |sheet| + sheet.add_row '课程体系VS毕业要求', style: title_style + sheet.merge_cells wb.rows.first.cells[(1..(3 + max_support_length - 1))] + + sheet.add_row [] + + sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业名称', major.name], style: ec_year_style + sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style + + sheet.add_row ['注:有对应关系的课程名称下方为其权重系数,一个指标点的权重系数之和必须等于1'], style: tip_style + sheet.add_row ['注:“★” 表示关联度高'] + sheet.merge_cells wb.rows[5].cells[(1..(3 + max_support_length - 1))] + sheet.merge_cells wb.rows[6].cells[(1..(3 + max_support_length - 1))] + + sheet.add_row [] + + data = ['毕业要求', '', '课程名称'] + data[last_column_index] = '课程数量' + sheet.add_row data, style: label_style + course_columns = max_support_length.times.map { |i| "课程#{i + 1}" } + sheet.add_row %w('一级 二级') + course_columns + ['∑目标值'], style: label_style + sheet.merge_cells("A9:B9") + sheet.merge_cells wb.rows[8].cells[(3..(3 + max_support_length - 1))] + + current_row = 11 + graduation_subitems.group_by(&:ec_graduation_requirement).each do |requirement, items| + position = requirement.position + start_row = current_row + + items.each do |item| + course_data = [position, "#{position}.#{item.position}"] + weight_data = ['', ''] + + total_weight = item.ec_course_supports.sum do |support| + course_data << support.ec_course.name.to_s + weight_data << support.weight.to_s + + support.weight.to_f + end + + course_data[last_column_index] = item.ec_course_supports.size + weight_data[last_column_index] = total_weight.to_s + + styles = [label_style, label_style,].concat([content_style] * max_support_length) + sheet.add_row course_data, style: styles + sheet.add_row weight_data, style: styles + + sheet.merge_cells("B#{current_row - 1}:B#{current_row}") + current_row += 2 + end + + sheet.merge_cells("A#{start_row - 1}:B#{current_row - 1}") + end + end +end \ No newline at end of file diff --git a/app/views/ecs/homes/index.json.jbuilder b/app/views/ecs/homes/index.json.jbuilder new file mode 100644 index 000000000..9bf21f056 --- /dev/null +++ b/app/views/ecs/homes/index.json.jbuilder @@ -0,0 +1,16 @@ + +json.current_user do + json.id current_user.id + json.name current_user.real_name + json.admin current_user.admin? + json.manager current_school.manager?(current_user) + json.major_manager current_school.major_manager?(current_user) + json.course_manager current_school.course_manager?(current_user) +end + +json.school do + json.id current_school.id + json.name current_school.name +end + +json.school_managers @school_managers, partial: 'ecs/shared/user', as: :user diff --git a/app/views/ecs/index.json.jbuilder b/app/views/ecs/index.json.jbuilder new file mode 100644 index 000000000..a117cbc54 --- /dev/null +++ b/app/views/ecs/index.json.jbuilder @@ -0,0 +1,35 @@ +json.school_managers do + json.array! @school_managers do |u| + json.user_id u.id + json.user_name u.real_name + json.user_avatar_path url_to_avatar(u) + end +end + +json.user_permission do + json.user_permission @user_permission +end + +json.count @obj_count +json.school_majors do + json.template_major do + json.major_id @template_major.id #major_school 的id + json.major_index 0 #序号 + json.major_code @template_major.ec_major.code + json.major_name @template_major.ec_major.name + end + json.real_major do + json.array! @major_schools.each_with_index.to_a do |m, index| + ec_major = m.ec_major #专业 + json.major_id m.id + json.major_index (index+1) #序号 + json.major_code ec_major.code + json.major_name ec_major.name + json.major_managers do + json.array! m.users.each do |u| + json.major_user u.real_name + end + end + end + end +end \ No newline at end of file diff --git a/app/views/ecs/major_managers/create.json.jbuilder b/app/views/ecs/major_managers/create.json.jbuilder new file mode 100644 index 000000000..ff7ff01e5 --- /dev/null +++ b/app/views/ecs/major_managers/create.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'ecs/shared/user', user: @user diff --git a/app/views/ecs/majors.json.jbuilder b/app/views/ecs/majors.json.jbuilder new file mode 100644 index 000000000..7029d6ba0 --- /dev/null +++ b/app/views/ecs/majors.json.jbuilder @@ -0,0 +1,9 @@ +json.major_counts @count +json.major_info do + json.array! @ec_majors.each_with_index.to_a do |m,index| + json.position index+1 + json.major_id m.id + json.major_code m.code + json.major_name m.name + end +end diff --git a/app/views/ecs/reach_evaluations/show.json.jbuilder b/app/views/ecs/reach_evaluations/show.json.jbuilder new file mode 100644 index 000000000..df99ba711 --- /dev/null +++ b/app/views/ecs/reach_evaluations/show.json.jbuilder @@ -0,0 +1,48 @@ +ec_year = @_current_year + +json.reach_threshold ec_year.calculation_value +maximum_course_support_count = 0 + +json.graduation_requirements do + json.array! @graduation_requirements do |requirement| + json.extract! requirement, :id, :position + + json.graduation_subitems do + json.array! requirement.ec_graduation_subitems do |subitem| + json.extract! subitem, :id, :position + + reach_criteria_total = 0.0 + actually_reach_total = 0.0 + + json.course_supports do + json.array! subitem.ec_course_supports do |support| + json.id support.id + + json.course_id support.ec_course.id + json.course_name support.ec_course.name + + reach_criteria = support.weights.to_f * ec_year.calculation_value.to_f + actually_reach = support.ec_graduation_requirement_calculation&.real_value.to_f + + reach_criteria_total += reach_criteria + actually_reach_total += actually_reach + + json.reach_criteria format('%.03f', reach_criteria) + json.actually_reach format('%.03f', actually_reach) + end + end + + json.reach_criteria format('%.03f', reach_criteria_total) + json.actually_reach format('%.03f', actually_reach_total) + + size = subitem.ec_course_supports.size + maximum_course_support_count = size if size > maximum_course_support_count + json.course_support_count size + + json.status actually_reach_total >= reach_criteria_total ? 'achieved' : 'not_achieved' + end + end + end +end + +json.maximum_course_support_count maximum_course_support_count diff --git a/app/views/ecs/reach_evaluations/show.xlsx.axlsx b/app/views/ecs/reach_evaluations/show.xlsx.axlsx new file mode 100644 index 000000000..a62e4f6c2 --- /dev/null +++ b/app/views/ecs/reach_evaluations/show.xlsx.axlsx @@ -0,0 +1,59 @@ +graduation_requirements = @graduation_requirements +ec_year = @_current_year +major = ec_year.ec_major_school.ec_major + +wb = xlsx_package.workbook +wb.styles do |style| + title_style = style.add_style(sz: 16, height: 20, b: true) + ec_year_style = style.add_style(sz: 10, height: 14) + label_style = style.add_style(sz: 11, b: true, alignment: { horizontal: :center }) + content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) + + wb.add_worksheet(name: '达成度-毕业要求综合评价报表') do |sheet| + sheet.add_row '培养目标及目标分解', style: title_style + sheet.merge_cells("A1:D1") + + sheet.add_row [] + + sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业名称', major.name], style: ec_year_style + sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style + + sheet.add_row [] + + sheet.add_row ['毕业要求', '', '课程数量 ∑合格标准', '评价结果'], style: label_style + sheet.add_row ['一级', '二级', '∑达成值', ''], style: label_style + sheet.merge_cells("A7:B7") + sheet.merge_cells("D7:D8") + + index = 9 + + graduation_requirements.each do |requirement| + start_index = index + + requirement.ec_graduation_subitems.each do |item| + reach_criteria, actually_reach = 0.0, 0.0 + + item.ec_course_supports.each do |support| + reach_criteria += support.weights.to_f * ec_year.calculation_value.to_f + actually_reach += support.ec_graduation_requirement_calculation&.real_value.to_f + end + + size = item.ec_course_supports.size + status = actually_reach >= reach_criteria ? '已达成' : '未达成' + + base_arr = [requirement.position.to_s, "#{requirement.position}-#{item.position}", status] + sheet.add_row base_arr.dup.insert(-2, size), style: content_style + sheet.add_row base_arr.dup.insert(-2, format('%.03f', reach_criteria)), style: content_style + sheet.add_row base_arr.dup.insert(-2, format('%.03f', actually_reach)), style: content_style + + sheet.merge_cells("B#{index}:B#{index + 2}") + sheet.merge_cells("D#{index}:D#{index + 2}") + + index += 3 + end + + sheet.merge_cells("A#{start_index}:B#{index - 1}") + end + end +end \ No newline at end of file diff --git a/app/views/ecs/requirement_support_objectives/shared/_requirement_support_objective.json.jbuilder b/app/views/ecs/requirement_support_objectives/shared/_requirement_support_objective.json.jbuilder new file mode 100644 index 000000000..acd3e59df --- /dev/null +++ b/app/views/ecs/requirement_support_objectives/shared/_requirement_support_objective.json.jbuilder @@ -0,0 +1,2 @@ +json.graduation_requirement_id requirement_support_objective.ec_graduation_requirement_id +json.training_subitem_id requirement_support_objective.ec_training_objective_id diff --git a/app/views/ecs/requirement_support_objectives/show.json.jbuilder b/app/views/ecs/requirement_support_objectives/show.json.jbuilder new file mode 100644 index 000000000..1ba783304 --- /dev/null +++ b/app/views/ecs/requirement_support_objectives/show.json.jbuilder @@ -0,0 +1,4 @@ + +json.graduation_requirements @graduation_requirements, partial: 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement +json.training_subitems @training_subitems, partial: 'ecs/ec_training_subitems/shared/ec_training_subitem', as: :ec_training_subitem +json.requirement_support_objectives @requirement_support_objectives, partial: 'shared/requirement_support_objective', as: :requirement_support_objective diff --git a/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx b/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx new file mode 100644 index 000000000..934ad2941 --- /dev/null +++ b/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx @@ -0,0 +1,44 @@ +graduation_requirements = @graduation_requirements +training_subitems = @training_subitems +subitem_size = training_subitems.size +support_map = @requirement_support_objectives.group_by do |support| + [support.ec_training_objective_id, support.ec_graduation_requirememt_id] +end +ec_year = @_current_year +major = ec_year.ec_major_school.ec_major + +wb = xlsx_package.workbook +wb.styles do |style| + title_style = style.add_style(sz: 18, height: 22, b: true) + ec_year_style = style.add_style(sz: 10, height: 14) + note_style = style.add_style(sz: 11, height: 14, color: 'FF5500') + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) + + wb.add_worksheet(:name => '毕业要求对培养目标的支撑') do |sheet| + sheet.add_row '毕业要求 vs 培养目标矩阵', style: title_style + + sheet.merge_cells wb.rows.first.cells[(1..subitem_size)] + + sheet.add_row [] + + sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业名称', major.name], style: ec_year_style + sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style + + sheet.add_row ['注:“√” 表示有对应关系'], style: note_style + + objectives = subitem_size.times.map { |index| "目标#{index + 1}" } + sheet.add_row objectives.unshift('毕业要求指标点\培养目标'), style: label_style + + graduation_requirements.each do |requirement| + data = + training_subitems.map do |item| + support_map[[item.id, requirement.id]].present? ? '√' : '' + end + + data.unshift("指导点#{requirement.position.to_s}") + sheet.add_row data, style: ([content_style] * subitem_size).unshift(label_style) + end + end +end \ No newline at end of file diff --git a/app/views/ecs/score_levels/shared/_ec_score_level.json.jbuilder b/app/views/ecs/score_levels/shared/_ec_score_level.json.jbuilder new file mode 100644 index 000000000..0b8815ebf --- /dev/null +++ b/app/views/ecs/score_levels/shared/_ec_score_level.json.jbuilder @@ -0,0 +1 @@ +json.extract! ec_score_level, :id, :position, :score, :level, :compare_condition diff --git a/app/views/ecs/score_levels/show.json.jbuilder b/app/views/ecs/score_levels/show.json.jbuilder new file mode 100644 index 000000000..0c8b76d86 --- /dev/null +++ b/app/views/ecs/score_levels/show.json.jbuilder @@ -0,0 +1 @@ +json.score_levels @score_levels, partial: 'shared/ec_score_level', as: :ec_score_level diff --git a/app/views/ecs/shared/_ec_course_evaluation_subitem.json.jbuilder b/app/views/ecs/shared/_ec_course_evaluation_subitem.json.jbuilder new file mode 100644 index 000000000..a05c9a24f --- /dev/null +++ b/app/views/ecs/shared/_ec_course_evaluation_subitem.json.jbuilder @@ -0,0 +1 @@ +json.extract! ec_course_evaluation_subitem, :id, :name \ No newline at end of file diff --git a/app/views/ecs/shared/_ec_graduation_standard.json.jbuilder b/app/views/ecs/shared/_ec_graduation_standard.json.jbuilder new file mode 100644 index 000000000..3fbc55a6f --- /dev/null +++ b/app/views/ecs/shared/_ec_graduation_standard.json.jbuilder @@ -0,0 +1 @@ +json.extract! ec_graduation_standard, :id, :content diff --git a/app/views/ecs/shared/_ec_graduation_subitem.json.jbuilder b/app/views/ecs/shared/_ec_graduation_subitem.json.jbuilder new file mode 100644 index 000000000..f1bf1bb73 --- /dev/null +++ b/app/views/ecs/shared/_ec_graduation_subitem.json.jbuilder @@ -0,0 +1 @@ +json.extract! ec_graduation_subitem, :id, :position, :content diff --git a/app/views/ecs/shared/_user.json.jbuilder b/app/views/ecs/shared/_user.json.jbuilder new file mode 100644 index 000000000..04895cfb2 --- /dev/null +++ b/app/views/ecs/shared/_user.json.jbuilder @@ -0,0 +1,3 @@ +json.id user.id +json.real_name user.real_name +json.avatar_url url_to_avatar(user) diff --git a/app/views/ecs/students/shared/_ec_year_student.json.jbuilder b/app/views/ecs/students/shared/_ec_year_student.json.jbuilder new file mode 100644 index 000000000..7bd1fbf41 --- /dev/null +++ b/app/views/ecs/students/shared/_ec_year_student.json.jbuilder @@ -0,0 +1 @@ +json.extract! ec_year_student, :id, :name, :student_id, :guarantee_school, :guarantee_major diff --git a/app/views/ecs/students/show.json.jbuilder b/app/views/ecs/students/show.json.jbuilder new file mode 100644 index 000000000..352970055 --- /dev/null +++ b/app/views/ecs/students/show.json.jbuilder @@ -0,0 +1,2 @@ +json.count @count +json.students @students, partial: 'shared/ec_year_student', as: :ec_year_student \ No newline at end of file diff --git a/app/views/ecs/subitem_support_standards/shared/_subitem_support_standard.json.jbuilder b/app/views/ecs/subitem_support_standards/shared/_subitem_support_standard.json.jbuilder new file mode 100644 index 000000000..1410decd6 --- /dev/null +++ b/app/views/ecs/subitem_support_standards/shared/_subitem_support_standard.json.jbuilder @@ -0,0 +1,2 @@ +json.graduation_standard_id subitem_support_standard.ec_graduation_standard_id +json.graduation_subitem_id subitem_support_standard.ec_graduation_subitem_id diff --git a/app/views/ecs/subitem_support_standards/show.json.jbuilder b/app/views/ecs/subitem_support_standards/show.json.jbuilder new file mode 100644 index 000000000..94fd6c5a0 --- /dev/null +++ b/app/views/ecs/subitem_support_standards/show.json.jbuilder @@ -0,0 +1,4 @@ + +json.graduation_standards @graduation_standards, partial: 'ecs/shared/ec_graduation_standard', as: :ec_graduation_standard +json.graduation_subitems @graduation_subitems, partial: 'ecs/shared/ec_graduation_subitem', as: :ec_graduation_subitem +json.subitem_support_standards @subitem_support_standards, partial: 'shared/subitem_support_standard', as: :subitem_support_standard diff --git a/app/views/ecs/subitem_support_standards/show.xlsx.axlsx b/app/views/ecs/subitem_support_standards/show.xlsx.axlsx new file mode 100644 index 000000000..e12f517f3 --- /dev/null +++ b/app/views/ecs/subitem_support_standards/show.xlsx.axlsx @@ -0,0 +1,45 @@ +graduation_subitems = @graduation_subitems +graduation_standards = @graduation_standards +standards_size = graduation_standards.size +support_map = @subitem_support_standards.group_by do |support| + [support.ec_requirement_standard_id, support.ec_graduation_subitem_id] +end + +ec_year = @_current_year +major = ec_year.ec_major_school.ec_major + +wb = xlsx_package.workbook +wb.styles do |style| + title_style = style.add_style(sz: 18, height: 22, b: true) + ec_year_style = style.add_style(sz: 10, height: 14) + note_style = style.add_style(sz: 11, height: 14, color: 'FF5500') + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) + + wb.add_worksheet(:name => '毕业要求对通用标准的支撑') do |sheet| + sheet.add_row '毕业要求 vs 通用标准矩阵', style: title_style + + sheet.merge_cells wb.rows.first.cells[(1..standards_size)] + + sheet.add_row [] + + sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业名称', major.name], style: ec_year_style + sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style + + sheet.add_row ['注:“√” 表示有对应关系'], style: note_style + + objectives = standards_size.times.map { |index| "标准#{index + 1}" } + sheet.add_row objectives.unshift('毕业要求指标点\通用标准'), style: label_style + + graduation_subitems.each do |graduation| + data = + graduation_standards.map do |standard| + support_map[[standard.id, graduation.id]].present? ? '√' : '' + end + + data.unshift("指导点#{graduation.ec_graduation_requirement.position}-#{graduation.position}") + sheet.add_row data, style: ([content_style] * standards_size).unshift(label_style) + end + end +end \ No newline at end of file diff --git a/app/views/edu_settings/_edu_setting.json.jbuilder b/app/views/edu_settings/_edu_setting.json.jbuilder new file mode 100644 index 000000000..f0b01cd78 --- /dev/null +++ b/app/views/edu_settings/_edu_setting.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! edu_setting, :id, :name, :value, :created_at, :updated_at +json.url edu_setting_url(edu_setting, format: :json) diff --git a/app/views/edu_settings/_form.html.erb b/app/views/edu_settings/_form.html.erb new file mode 100644 index 000000000..3b7f09f1c --- /dev/null +++ b/app/views/edu_settings/_form.html.erb @@ -0,0 +1,27 @@ +<%= form_with(model: edu_setting, local: true) do |form| %> + <% if edu_setting.errors.any? %> +
    +

    <%= pluralize(edu_setting.errors.count, "error") %> prohibited this edu_setting from being saved:

    + +
      + <% edu_setting.errors.full_messages.each do |message| %> +
    • <%= message %>
    • + <% end %> +
    +
    + <% end %> + +
    + <%= form.label :name %> + <%= form.text_field :name %> +
    + +
    + <%= form.label :value %> + <%= form.text_field :value %> +
    + +
    + <%= form.submit %> +
    +<% end %> diff --git a/app/views/edu_settings/edit.html.erb b/app/views/edu_settings/edit.html.erb new file mode 100644 index 000000000..2a0796842 --- /dev/null +++ b/app/views/edu_settings/edit.html.erb @@ -0,0 +1,6 @@ +

    Editing Edu Setting

    + +<%= render 'form', edu_setting: @edu_setting %> + +<%= link_to 'Show', @edu_setting %> | +<%= link_to 'Back', edu_settings_path %> diff --git a/app/views/edu_settings/index.html.erb b/app/views/edu_settings/index.html.erb new file mode 100644 index 000000000..d49977254 --- /dev/null +++ b/app/views/edu_settings/index.html.erb @@ -0,0 +1,30 @@ +

    <%= notice %>

    + +

    EduCoder公共配置

    +

    说明:该界面适用于存储全局变量

    + + + + + + + + + + + + <% @edu_settings.each do |edu_setting| %> + + + + + + + + <% end %> + +
    变量名变量值
    <%= edu_setting.name %><%= edu_setting.value %><%= link_to 'Show', edu_setting %><%= link_to 'Edit', edit_edu_setting_path(edu_setting) %><%= link_to 'Destroy', edu_setting, method: :delete, data: { confirm: 'Are you sure?' } %>
    + +
    + +<%= link_to 'New Edu Setting', new_edu_setting_path %> diff --git a/app/views/edu_settings/index.json.jbuilder b/app/views/edu_settings/index.json.jbuilder new file mode 100644 index 000000000..bcc5948be --- /dev/null +++ b/app/views/edu_settings/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @edu_settings, partial: 'edu_settings/edu_setting', as: :edu_setting diff --git a/app/views/edu_settings/new.html.erb b/app/views/edu_settings/new.html.erb new file mode 100644 index 000000000..8a70e3a63 --- /dev/null +++ b/app/views/edu_settings/new.html.erb @@ -0,0 +1,5 @@ +

    New Edu Setting

    + +<%= render 'form', edu_setting: @edu_setting %> + +<%= link_to 'Back', edu_settings_path %> diff --git a/app/views/edu_settings/show.html.erb b/app/views/edu_settings/show.html.erb new file mode 100644 index 000000000..9d027373f --- /dev/null +++ b/app/views/edu_settings/show.html.erb @@ -0,0 +1,14 @@ +

    <%= notice %>

    + +

    + Name: + <%= @edu_setting.name %> +

    + +

    + Value: + <%= @edu_setting.value %> +

    + +<%= link_to 'Edit', edit_edu_setting_path(@edu_setting) %> | +<%= link_to 'Back', edu_settings_path %> diff --git a/app/views/edu_settings/show.json.jbuilder b/app/views/edu_settings/show.json.jbuilder new file mode 100644 index 000000000..7d1650e62 --- /dev/null +++ b/app/views/edu_settings/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "edu_settings/edu_setting", edu_setting: @edu_setting diff --git a/app/views/exercise_questions/_exercise_questions.json.jbuilder b/app/views/exercise_questions/_exercise_questions.json.jbuilder new file mode 100644 index 000000000..10dc46abf --- /dev/null +++ b/app/views/exercise_questions/_exercise_questions.json.jbuilder @@ -0,0 +1,94 @@ +json.question_id question.id +json.question_number question.question_number +json.question_title question.question_title +json.question_type question.question_type +json.question_score question.question_score.round(1).to_s +if question.question_type <= 2 #当为选择题或判断题时,只显示选项的位置 + standard_answers_array = question.get_standard_answer_ids + exercise_choices = choices.order("choice_position ASC") + ex_choice_random_boolean = (exercise_type.present? && exercise_type == 3 && (question.exercise.choice_random)) ? true : false #问题的选项随机打乱 + if ex_choice_random_boolean + exercise_choices = exercise_choices.order("RAND()") + end + json.question_choices do + json.array! exercise_choices.each_with_index.to_a do |a,index| + standard_answer_b = standard_answers_array.include?(a.choice_position) + user_answer_b = user_answer.include?(a.id) + json.c_position (index+1) if ex_choice_random_boolean #当选项随机时,选项位置以此为准,否则不出现 + json.choice_id a.id + json.choice_text a.choice_text + json.choice_position a.choice_position + if exercise_type == 1 || exercise_type == 4 #1为教师编辑/预览 试卷或问题,2为空白试卷,即标准答案和用户答案都不显示,3为用户开始答题的显示,4为老师评阅试卷或学生在截止后查看试卷 + json.standard_boolean standard_answer_b + end + if exercise_type == 3 || exercise_type == 4 + json.user_answer_boolean user_answer_b + end + end + end + + if exercise_type == 1 || exercise_type == 4 #1为老师,4为试卷截止且答案公开的情况 + json.standard_answer standard_answers_array + end + if exercise_type == 3 || exercise_type == 4 + json.user_answer user_answer + end + +elsif question.question_type == 3 #当为填空题时 + standard_answers_count = question.exercise_standard_answers + standard_answer_ex = standard_answers_count.pluck(:exercise_choice_id).uniq + json.is_ordered question.is_ordered + json.multi_count standard_answer_ex.size #有几个填空 + if exercise_type == 1 || exercise_type == 4 #1为老师,4为试卷截止且答案公开的情况 + json.standard_answer do + json.array! standard_answer_ex.each do |a| + s_answer_text = standard_answers_count.standard_by_ids(a).pluck(:answer_text) + json.choice_id a + json.answer_text s_answer_text + end + end + end + if exercise_type == 3 || exercise_type == 4 + json.user_answer do + json.array! user_answer.each do |e| + json.choice_id e[:choice_id] + json.answer_text e[:answer_text] + end + end + end +elsif question.question_type == 4 #简答题时 + if exercise_type == 1 || exercise_type == 4 + json.standard_answer question.exercise_standard_answers.pluck(:answer_text) + end + if exercise_type == 3 || exercise_type == 4 + json.user_answer user_answer + end +elsif question.question_type == 5 + json.shixun_id question.shixun_id + json.shixun_name question.shixun_name.present? ? question.shixun_name : "" + json.shixun_identifier question.shixun.identifier + if exercise_type == 1 || exercise_type == 2 || (shixun_type.present? && shixun_type == 0) #教师预览/新建/编辑以及导出空白试卷时,以及学生开始答题,但是还未回答实训题时 + json.shixun do + json.array! shixun_challenges do |s| + json.challenge_id s.challenge_id + json.challenge_position s.position + json.challenge_name s.challenge.subject + json.challenge_score s.question_score.round(1).to_s + end + end + end + if (exercise_type == 3 || exercise_type == 4) && (shixun_type.present? && shixun_type > 0 ) #教师评阅/试卷截止后,答案公开/试卷未截止,但学生已做了实训题 + json.shixun_details do + json.array! shixun_challenges do |s| + games_score = shixun_game_scores(s,ex_answerer,shixun_type,question.id) + user_get_score = games_score[:s_score].present? ? games_score[:s_score] : 0.0 + json.shixun_challenge_id s.id + if games_score[:games].count > 0 + json.partial! "exercises/shixun_details",games: games_score[:games], user_score: user_get_score,game_score: games_score[:game_score] + else + json.partial! "exercises/shixun_undo",games: [s], user_score: user_get_score ,game_score: s.question_score + end + end + end + end +end \ No newline at end of file diff --git a/app/views/exercise_questions/adjust_score.json.jbuilder b/app/views/exercise_questions/adjust_score.json.jbuilder new file mode 100644 index 000000000..107ec3a38 --- /dev/null +++ b/app/views/exercise_questions/adjust_score.json.jbuilder @@ -0,0 +1,7 @@ +if @exercise_comments.present? + json.question_comments do + json.partial! "exercises/exercise_comments", question_comment:@exercise_comments + end +else + json.question_comments [] +end \ No newline at end of file diff --git a/app/views/exercise_questions/create.json.jbuilder b/app/views/exercise_questions/create.json.jbuilder new file mode 100644 index 000000000..5ebb1d9d9 --- /dev/null +++ b/app/views/exercise_questions/create.json.jbuilder @@ -0,0 +1,2 @@ +json.partial! "commons/success" +json.exercise_question_id @exercise_question.id \ No newline at end of file diff --git a/app/views/exercise_questions/edit.json.jbuilder b/app/views/exercise_questions/edit.json.jbuilder new file mode 100644 index 000000000..32567d813 --- /dev/null +++ b/app/views/exercise_questions/edit.json.jbuilder @@ -0,0 +1,8 @@ +json.partial! "commons/success" + +json.partial! "exercise_questions/exercise_questions", + question: @exercise_question, + choices:@exercise_choices, + shixun_challenges: @exercise_question_shixun, + exercise_type:1, + user_answer:[] \ No newline at end of file diff --git a/app/views/exercise_questions/new.json.jbuilder b/app/views/exercise_questions/new.json.jbuilder new file mode 100644 index 000000000..f9b891601 --- /dev/null +++ b/app/views/exercise_questions/new.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" \ No newline at end of file diff --git a/app/views/exercise_questions/show.json.jbuilder b/app/views/exercise_questions/show.json.jbuilder new file mode 100644 index 000000000..e8662a611 --- /dev/null +++ b/app/views/exercise_questions/show.json.jbuilder @@ -0,0 +1,8 @@ +json.partial! "commons/success" + +json.partial! "exercise_questions/exercise_questions", + question: @exercise_question, + choices:@exercise_choices, + shixun_challenges: @exercise_question_shixun, + exercise_type:1, + user_answer:[] diff --git a/app/views/exercises/_exercise_comments.json.jbuilder b/app/views/exercises/_exercise_comments.json.jbuilder new file mode 100644 index 000000000..165f8594b --- /dev/null +++ b/app/views/exercises/_exercise_comments.json.jbuilder @@ -0,0 +1,4 @@ +user = question_comment.user +json.user_picture url_to_avatar(user) +json.user_name user.real_name +json.extract! question_comment, :id,:updated_at,:comment,:score,:exercise_question_id,:exercise_shixun_answer_id,:exercise_answer_id \ No newline at end of file diff --git a/app/views/exercises/_exercise_detail.json.jbuilder b/app/views/exercises/_exercise_detail.json.jbuilder new file mode 100644 index 000000000..5d4221eab --- /dev/null +++ b/app/views/exercises/_exercise_detail.json.jbuilder @@ -0,0 +1,8 @@ +json.extract! exercise, :id, :exercise_name,:is_public,:created_at,:exercise_status +json.lock_status lock_icon +json.publish_time exercise_publish_time # 试卷的发布时间 +json.end_time exercise_end_time # 试卷的截止时间 +json.exercise_answer exercise_answer # 已提交试卷的用户 +json.exercise_unanswer exercise_unanswer # 已查看试卷/开始答题,但是未提交试卷的用户 +json.current_status current_status #答题的状态 + diff --git a/app/views/exercises/_exercise_scores.json.jbuilder b/app/views/exercises/_exercise_scores.json.jbuilder new file mode 100644 index 000000000..af6bc33d9 --- /dev/null +++ b/app/views/exercises/_exercise_scores.json.jbuilder @@ -0,0 +1,16 @@ +json.exercise_types do + json.q_counts @exercise_ques_count #全部问题数 + json.q_scores @exercise_ques_scores.round(1).to_s #试卷总分 + json.q_singles @exercise_single_ques_count #单选题的数量 + json.q_singles_scores @exercise_single_ques_scores.round(1).to_s #单选题的分数 + json.q_doubles @exercise_double_ques_count #多选题的数量 + json.q_doubles_scores @exercise_double_ques_scores.round(1).to_s #多选题的总分 + json.q_judges @exercise_ques_judge_count #判断题的数量 + json.q_judges_scores @exercise_ques_judge_scores.round(1).to_s #判断题的分数 + json.q_nulls @exercise_ques_null_count #填空题的数量 + json.q_nulls_scores @exercise_ques_null_scores.round(1).to_s #填空题的分数 + json.q_mains @exercise_ques_main_count #简答题 + json.q_mains_scores @exercise_ques_main_scores.round(1).to_s + json.q_shixuns @exercise_ques_shixun_count #实训题 + json.q_shixuns_scores @exercise_ques_shixun_scores.round(1).to_s +end \ No newline at end of file diff --git a/app/views/exercises/_exercise_user.json.jbuilder b/app/views/exercises/_exercise_user.json.jbuilder new file mode 100644 index 000000000..d41fb9e20 --- /dev/null +++ b/app/views/exercises/_exercise_user.json.jbuilder @@ -0,0 +1,16 @@ +ex_user_info = exercise_use_info(exercise_user,user_status,exercise) + +json.user_id ex_user_info[:user_id] +json.user_name ex_user_info[:user_name] +json.login ex_user_info[:login] +json.user_group_id ex_user_info[:user_group_id] +json.user_group_name ex_user_info[:user_group_name] +json.student_id ex_user_info[:student_id] +json.commit_status ex_user_info[:commit_status] +json.end_at ex_user_info[:end_at] +if subjective_type == 1 + json.objective_score ex_user_info[:ex_object_score] + json.subjective_score ex_user_info[:ex_subject_score] +end +json.score ex_user_info[:score] +json.review_status ex_user_info[:teacher_review] #教师是否评阅,评阅则为true,否则为false \ No newline at end of file diff --git a/app/views/exercises/_question_scores.json.jbuilder b/app/views/exercises/_question_scores.json.jbuilder new file mode 100644 index 000000000..6d0e7131d --- /dev/null +++ b/app/views/exercises/_question_scores.json.jbuilder @@ -0,0 +1,6 @@ +json.array! question_scores do |q| + json.ques_id q[:q_id] + json.ques_position q[:q_position] + json.answer_status q[:stand_status] #答案状态,1为正确,0为错误/未答 + json.user_score q[:user_score] +end \ No newline at end of file diff --git a/app/views/exercises/_shixun_details.json.jbuilder b/app/views/exercises/_shixun_details.json.jbuilder new file mode 100644 index 000000000..033ac3dc1 --- /dev/null +++ b/app/views/exercises/_shixun_details.json.jbuilder @@ -0,0 +1,31 @@ + +#阶段成绩 +json.stage_list do + json.array! games do |game| + json.position game.challenge.position + json.name game.challenge.subject + json.evaluate_count game.evaluate_count + json.finished_time finished_time game.end_time + json.time_consuming time_consuming game + json.myself_experience game.final_score #经验值 + json.experience game.challenge.all_score #经验值 + json.user_score user_score.round(1).to_s #用户获得的分数 + json.game_score game_score.round(1).to_s #该关卡的总分数 + end +end + +# 实训详情 +json.shixun_detail do + json.array! games do |game| + json.position game.challenge.position + json.game_identifier game.identifier + json.path game.challenge.path + json.st game.challenge.st + json.name game.challenge.subject + json.outputs game.distinct_query_index do |output| + json.position output.query_index + json.output_detail output_detail game, output + end + json.passed_code game.try(:lastest_code) + end +end \ No newline at end of file diff --git a/app/views/exercises/_shixun_undo.json.jbuilder b/app/views/exercises/_shixun_undo.json.jbuilder new file mode 100644 index 000000000..62c84a0b9 --- /dev/null +++ b/app/views/exercises/_shixun_undo.json.jbuilder @@ -0,0 +1,14 @@ +#阶段成绩 +json.stage_list do + json.array! games do |game| + json.position game.position + json.name game.challenge.subject + json.evaluate_count 0 + json.finished_time 0 + json.time_consuming 0 + json.myself_experience 0 #经验值 + json.experience game.challenge.all_score #总经验值 + json.user_score user_score.round(1).to_s #用户获得的分数 + json.game_score game_score.round(1).to_s #该关卡的总分数 + end +end \ No newline at end of file diff --git a/app/views/exercises/_user_exercise_info.json.jbuilder b/app/views/exercises/_user_exercise_info.json.jbuilder new file mode 100644 index 000000000..a3b7b208c --- /dev/null +++ b/app/views/exercises/_user_exercise_info.json.jbuilder @@ -0,0 +1,77 @@ +json.exercise do + json.extract! exercise, :id, :exercise_name,:exercise_description,:exercise_status,:answer_open + json.student_commit_status student_status #当前为学生且已提交时 +end + +json.exercise_answer_user do + json.is_teacher is_teacher_or + json.user_name ex_answerer.real_name + json.user_id ex_answerer.id + json.login ex_answerer.login + if exercise_user.present? + json.start_at exercise_user.start_at + json.score exercise_user.score.present? ? exercise_user.score.round(1).to_s : "0.0" + end +end + +all_question_status = [] +if student_status == 2 + #试卷的全部分数 + json.exercise_scores do + json.partial! "exercises/exercise_scores" + #试卷的客观题分数及是否错误 + json.objective_scores do + json.partial! "exercises/question_scores", question_scores: ex_obj_array #客观问题正确与否的显示 + end + + #试卷的主观题及是否错误 + json.subjective_scores do + json.partial! "exercises/question_scores", question_scores: ex_sub_array #主观题正确与否的显示 + end + end + +#主观题及客观题的全部分数及正确与否的状态 + all_question_status = ex_obj_array + ex_sub_array +elsif student_status == 1 + json.question_status question_status +end + +exercise_status = exercise.get_exercise_status(ex_answerer.id) + +#当前为老师,或为学生,但在试卷截止后且答案选择公开的 +if is_teacher_or == 1 || (exercise_status == 3 && exercise.answer_open) + ex_type = 4 +else + ex_type = 3 +end + +json.exercise_questions do + json.array! exercise_questions do |q| + + user_ques_answers = user_question_answers(q,ex_answerer.id,student_status,is_teacher_or,exercise_status,q.question_type,ex_type) + user_ques_comments = user_ques_answers[:question_comment] + if all_question_status.size > 0 + this_ques_status = all_question_status.detect {|f| f[:q_id] == q.id} + json.answer_status this_ques_status[:stand_status] + end + json.user_score user_ques_answers[:user_score].to_s + json.partial! "exercise_questions/exercise_questions", + question: q, + ex_answerer: ex_answerer, + choices:q.exercise_choices, + shixun_challenges: q.exercise_shixun_challenges, + exercise_type: ex_type, + user_answer: user_ques_answers[:answered_content], + shixun_type: user_ques_answers[:shixun_type] + if user_ques_comments.count > 0 + json.question_comments do + json.partial! "exercises/exercise_comments", question_comment:user_ques_answers[:question_comment].first + end + else + json.question_comments [] + end + end +end + + +#exercise_type 表示选择公用的模板类型,1为教师预览/编辑,2为空白试卷,3表示学生开始答题/答题未截止。 \ No newline at end of file diff --git a/app/views/exercises/begin_commit.json.jbuilder b/app/views/exercises/begin_commit.json.jbuilder new file mode 100644 index 000000000..4c1aebbb5 --- /dev/null +++ b/app/views/exercises/begin_commit.json.jbuilder @@ -0,0 +1,3 @@ +json.shixun_undo @shixun_undo +json.question_undo @ques_undo +json.end_time @ex_end_time \ No newline at end of file diff --git a/app/views/exercises/blank_exercise.html.erb b/app/views/exercises/blank_exercise.html.erb new file mode 100644 index 000000000..5a27a3ab4 --- /dev/null +++ b/app/views/exercises/blank_exercise.html.erb @@ -0,0 +1,579 @@ + + + + + + + + +
    +
    +
    +
    +

    <%= @exercise.try(:exercise_name) %>

    +
    +
    +

    + <%= @exercise.try(:exercise_description).nil? ? "" : @exercise.try(:exercise_description).html_safe %> +

    +
    +
    +
    +
    +
    + <% if @exercise_single_ques_count > 0 %> + 单选题<%= @exercise_single_ques_count %>题, + 共<%= @exercise_single_ques_scores %> + <% end %> + <% if @exercise_double_ques_count > 0 %> + 多选题<%= @exercise_double_ques_count %>题, + 共<%= @exercise_double_ques_scores %> + <% end %> + <% if @exercise_ques_judge_count > 0 %> + 判断题<%= @exercise_ques_judge_count %>题, + 共<%= @exercise_ques_judge_scores %> + <% end %> + <% if @exercise_ques_null_count > 0 %> + 填空题<%= @exercise_ques_null_count %>题, + 共<%= @exercise_ques_null_scores %> + <% end %> + <% if @exercise_ques_main_count > 0 %> + 主观题<%= @exercise_ques_main_count %>题, + 共<%= @exercise_ques_main_scores %> + <% end %> + <% if @exercise_ques_shixun_count > 0 %> + 实训题<%= @exercise_ques_shixun_count %>题, + 共<%= @exercise_ques_shixun_scores %> + <% end %> +
    +
    合计<%= @exercise_ques_count %>题, + 共<%= @exercise_ques_scores %>
    +
    +
    +
    +
    +

    + 客观题 + 正确 + 错误 + 总分:<%= @exercise.exercise_users.where(user_id:31798).first.score %>分 +

    +
    +
    + <% @ex_obj_array.each do |s| %> + <% if s[:stand_status] == 1 %> +
    + <%= s[:q_position] %> +
    + <% else %> +
    + <%= s[:q_position] %> +
    + <% end %> + <% end %> +
    + <% if @ex_sub_array.size > 0 %> +
    +

    + 主观题 + 已评 + 未评 + 开始答题时间:<%= @exercise_user.start_at.present? ? @exercise_user.start_at.strftime("%Y-%m-%d %H:%M") : "--" %> +

    +
    +
    + <% @ex_sub_array.each do |s| %> + <% if s[:stand_status] == 1 %> +
    + <%= s[:q_position] %> +
    + <% else %> +
    + <%= s[:q_position] %> +
    + <% end %> + <% end %> +
    + <% end %> +
    +
    + <% @exercise_questions.each do |q| %> + <% user_answer = q.exercise_answers.where(user_id: 31798) %> + <% this_ques_status = @ex_obj_array.detect{|f| f[:q_id] == q.id} %> +
    +
    +
    + + <%= q.question_type_name %> + + (<%= q.question_score %>分) + Q<%= q.question_number %>:  + <% if q.question_type == 5 %> + <%= q.shixun_name.html_safe %> + + <% if this_ques_status.present? && this_ques_status[:stand_status] == 1 %> + + <%= this_ques_status[:user_score] %>分 + <% else %> + + 0分 + <% end %> + +
    + <%= q.question_title.html_safe %> +
    + <% else %> + <%= q.question_title.html_safe %> + + <% if this_ques_status.present? && this_ques_status[:stand_status] == 1 %> + + <%= this_ques_status[:user_score] %>分 + <% else %> + + 0分 + <% end %> + + <% end %> +
    +
    + <% if q.question_type == 0 %> + <% q.exercise_choices.each_with_index do |s,index| %> + <% check_answer = (user_answer.present? && (s.id == user_answer.first.exercise_choice_id)) ? "choose-answer" : '' %> +

    + + <%= convert_to_char((index+1).to_s)%><%= s.choice_text%> +

    + <% end %> + <% elsif q.question_type == 1 %> + <% q.exercise_choices.each_with_index do |s,index| %> + <% check_answer = (user_answer.present? && (user_answer.pluck(:exercise_choice_id).include?(s.id))) ? true : false %> +

    + <% if check_answer %> + + <% else %> + + <% end %> + <%= convert_to_char((index+1).to_s)%><%= s.choice_text%> +

    + <% end %> + <% elsif q.question_type == 2 %> +

    + <% q.exercise_choices.each_with_index do |s,index| %> + <% check_answer = (user_answer.present? && (s.id == user_answer.first.exercise_choice_id)) ? "choose-answer" : '' %> + + + <%= s.choice_text %> + + <% end %> +

    + <% elsif q.question_type == 3 %> + <% st_counts = q.exercise_standard_answers.pluck(:exercise_choice_id).uniq %> + <% st_counts.each_with_index do |s,index| %> + <% if user_answer.present? && user_answer.where(exercise_choice_id:s).present? %> + <% check_answer = user_answer.where(exercise_choice_id:s).first.answer_text %> + <% else %> + <% check_answer = "--" %> + <% end %> +

    + 答案(填空<%= index+1 %>): + <%= check_answer.html_safe %> +

    + <% end %> + <% elsif q.question_type == 4 %> + <% check_answer = user_answer.present? ? user_answer.first.answer_text : '--' %> +

    + <%= check_answer.html_safe %> +

    + <% else %> +
    +

    + 阶段成绩 +

    + + + + + + + + + + + + <% if @games.size > 0 %> + <% @games.each_with_index do |game, index| %> + <% user_score = q.exercise_shixun_answers.where(exercise_shixun_challenge_id:game.challenge.id,user_id:31798) %> + <% game_score = q.exercise_shixun_challenges.where(challenge_id:game.challenge.id) %> + + + + + + + + + + <% end %> + <% else %> + <% q.exercise_shixun_challenges.each_with_index do |game, index| %> + <% game_score = q.exercise_shixun_challenges.where(challenge_id:game.challenge.id) %> + + + + + + + + + + <% end %> + <% end %> + + +
    关卡任务名称评测次数完成时间耗时经验值得分/满分
    <%= index + 1 %> + <%= game.challenge.subject %> + <%= game.evaluate_count %><%= game.end_time.present? ? game.end_time.strftime("%Y-%m-%d %H:%M") : "--" %><%= ApplicationController.helpers.time_consuming game %><%= game.final_score %> / <%= game.challenge.all_score %><%= user_score.present? ? user_score.first.score : 0.0 %> / <%= game_score.first.question_score %>
    <%= index + 1 %> + <%= game.challenge.subject %> + 0----0.0 / <%= game.challenge.all_score %>0.0 / <%= game_score.first.question_score %>
    +
    +
    + <% @games.each_with_index do |game, index| %> +

    + 实训详情 +

    +
    +

    + 第<%= index+1 %>关<%= game.challenge.subject %> +

    +
    + <% if game.outputs.present? %> + + + + + + + <% outputs = game.outputs.group("query_index") %> + <% outputs.reverse.try(:each) do |output| %> + + + + + <% end %> + +
    评测次数评测信息
    <%= "第#{output.query_index}次" %><%= output_detail(game, output) %>
    + <% end %> + <% if game.try(:lastest_code).present? && game.challenge.st == 0 %> +
    +

    + + 最近通过的代码 + <%= game.challenge.path %> + +

    +
    +
    + <% code_len = content_line(game.try(:lastest_code).html_safe) %> + <% (1..code_len).each do |c| %> +

    <%= c %>

    + <% end %> +
    + +
    +
    + <% end %> +
    +
    + <% end %> +
    + <% end %> +
    +
    +
    + <% end %> +
    +
    +
    + + + \ No newline at end of file diff --git a/app/views/exercises/blank_exercise.json.jbuilder b/app/views/exercises/blank_exercise.json.jbuilder new file mode 100644 index 000000000..631f0dcb3 --- /dev/null +++ b/app/views/exercises/blank_exercise.json.jbuilder @@ -0,0 +1,19 @@ +json.exercise do + json.extract! @exercise, :id, :exercise_name,:exercise_description,:exercise_status +end + + +json.partial! "exercises/exercise_scores" + +json.exercise_questions do + json.array! @exercise_questions do |q| + json.partial! "exercise_questions/exercise_questions", question: q, + choices:q.exercise_choices, + shixun_challenges: q.exercise_shixun_challenges, + exercise_type:2, + user_answer:[] + end +end + + +#exercise_type 表示选择公用的模板类型,1为教师预览/编辑,2为空白试卷。 \ No newline at end of file diff --git a/app/views/exercises/choose_shixun.json.jbuilder b/app/views/exercises/choose_shixun.json.jbuilder new file mode 100644 index 000000000..5a9cd5da2 --- /dev/null +++ b/app/views/exercises/choose_shixun.json.jbuilder @@ -0,0 +1,10 @@ +json.shixun_counts @shixuns_count + +json.shixuns do + json.array! @shixuns do |s| + json.shixun_id s.id + json.shixun_name s.name + json.shixun_user s.user.real_name + json.shixun_user_count s.myshixuns_count + end +end diff --git a/app/views/exercises/commit_shixun.json.jbuilder b/app/views/exercises/commit_shixun.json.jbuilder new file mode 100644 index 000000000..236a71052 --- /dev/null +++ b/app/views/exercises/commit_shixun.json.jbuilder @@ -0,0 +1,10 @@ +json.shixun_id @shixun.id +json.shixun_name @shixun.name + +json.challenges do + json.array! @shixun_challenges do |s| + json.challenge_name s.subject + end +end + +json.challenge_counts @shixun_challenges_count \ No newline at end of file diff --git a/app/views/exercises/common_header.json.jbuilder b/app/views/exercises/common_header.json.jbuilder new file mode 100644 index 000000000..68fa45a67 --- /dev/null +++ b/app/views/exercises/common_header.json.jbuilder @@ -0,0 +1,21 @@ +json.course_is_end @course.is_end # true表示已结束,false表示未结束 +json.extract! @exercise, :id,:exercise_name,:exercise_description,:show_statistic,:time +json.exercise_status @ex_status + +json.user_permission do + json.is_teacher_or @is_teacher_or + json.current_status @user_exercise_answer + json.exercise_publish_count @exercise_publish_count #是否存在已发布的分班 + json.exercise_unpublish_count @exercise_unpublish_count #是否存在未发布的分班 + json.user_commit_counts @user_commit_counts #当前已提交的用户,如果说为null,表示当前用户为学生。如果大于0,表示有已提交的用户 + json.left_banner_id @left_banner_id + json.left_banner_name @left_banner_name +end + +exercise_url_status = ex_common_header(@is_teacher_or,@exercise) +json.common_tabs do + json.array! exercise_url_status do |p| + json.common_tab p[:common_tab].to_i + json.active_status p[:active_status] + end +end diff --git a/app/views/exercises/create.json.jbuilder b/app/views/exercises/create.json.jbuilder new file mode 100644 index 000000000..6c4888bd2 --- /dev/null +++ b/app/views/exercises/create.json.jbuilder @@ -0,0 +1,4 @@ +json.partial! "commons/success" +json.data do + json.exercise_id @exercise.id +end \ No newline at end of file diff --git a/app/views/exercises/edit.json.jbuilder b/app/views/exercises/edit.json.jbuilder new file mode 100644 index 000000000..61ec71db5 --- /dev/null +++ b/app/views/exercises/edit.json.jbuilder @@ -0,0 +1,22 @@ +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.partial! "commons/success" + +json.exercise do + json.extract! @exercise, :id, :exercise_name,:exercise_description,:exercise_status +end + +json.partial! "exercises/exercise_scores" + +json.exercise_questions do + json.array! @exercise_questions do |q| + json.partial! "exercise_questions/exercise_questions", question: q, + choices:q.exercise_choices, + shixun_challenges: q.exercise_shixun_challenges, + exercise_type:1, + user_answer:[], + shixun_type:0 + end +end + +#exercise_type 表示选择公用的模板类型,1为教师预览/编辑,2为空白试卷。 \ No newline at end of file diff --git a/app/views/exercises/end_modal.json.jbuilder b/app/views/exercises/end_modal.json.jbuilder new file mode 100644 index 000000000..81d5c816c --- /dev/null +++ b/app/views/exercises/end_modal.json.jbuilder @@ -0,0 +1,11 @@ +if @course_groups.size >0 + json.on_commiting @course_groups.size #未发布的分班 + json.course_info do + json.array! @course_groups do |group| + json.course_group_id group.id + json.course_group_name group.name + end + end +else + json.on_commiting 0 +end \ No newline at end of file diff --git a/app/views/exercises/exercise_lists.json.jbuilder b/app/views/exercises/exercise_lists.json.jbuilder new file mode 100644 index 000000000..b51e781c7 --- /dev/null +++ b/app/views/exercises/exercise_lists.json.jbuilder @@ -0,0 +1,51 @@ +json.exercise_types do + if @exercise_current_user_status == 0 #当为老师的时候,显示的全部人数 + json.published_count @exercise_publish_count + json.unpublish_count @exercise_unpublish_count + json.exercise_all_users @exercise_users_count #全部显示的人数 + json.total_users @exercise_users_size #全部人数 + json.review_counts @teacher_review_count #已评阅人数git + json.unreview_counts @teacher_unreview_count #未评阅人数 + end + json.score_open @exercise.score_open #成绩是否公开 + json.exercise_status @exercise_status #试卷的状态 + json.answer_users @exercise_answers + json.unanswer_users @exercise_unanswers + json.user_permission @exercise_current_user_status #当前用户存在且为课堂教师/管理员/超级管理员时为0 ,其他否则为1 + json.exercise_id @exercise.id + json.subjective @subjective_type #是否包含主观题,1为包括,0为不包括 + json.exercise_end_time ((@ex_user_end_time.nil? || @ex_user_end_time < Time.now) ? "--" : how_much_time(@ex_user_end_time)) +end + +if @exercise_current_user_status == 0 #当为老师的时候 + if @exercise_course_groups.present? + json.course_groups do + json.array! @exercise_course_groups do |group| + json.exercise_group_id group[:course_id] #班级id + json.exercise_group_name group[:course_name] #班级名称 + json.exercise_group_students group[:student_count] #班级人数 + end + end + else + json.course_groups [] + end + +end + +if @current_user_ex_answers.present? + json.current_answer_user do + json.partial! "exercises/exercise_user",locals: {exercise_user:@current_user_ex_answers.first, subjective_type:@subjective_type, + user_status:@exercise_current_user_status, exercise:@exercise} + end +end + +if @exercise_users_list.present? + json.exercise_users do + json.array! @exercise_users_list.each do |exercise_user| + json.partial! "exercises/exercise_user",locals: {exercise_user:exercise_user, subjective_type:@subjective_type, + user_status:@exercise_current_user_status, exercise:@exercise} + end + end +else + json.exercise_users [] +end diff --git a/app/views/exercises/exercise_lists.xlsx.axlsx b/app/views/exercises/exercise_lists.xlsx.axlsx new file mode 100644 index 000000000..922dd206e --- /dev/null +++ b/app/views/exercises/exercise_lists.xlsx.axlsx @@ -0,0 +1,14 @@ + +wb = xlsx_package.workbook +wb.styles do |s| + sz_all = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {:horizontal => :center} + blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 20,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {:horizontal => :center} + + wb.add_worksheet(:name => "学生成绩") do |sheet| + sheet.add_row table_columns, :style => blue_cell + sheet.column_info.first.width = 12 + exercise_users.each do |user| + sheet.add_row user, :style => sz_all #用户id + end #each_widh_index + end #add_worksheet +end \ No newline at end of file diff --git a/app/views/exercises/exercise_result.json.jbuilder b/app/views/exercises/exercise_result.json.jbuilder new file mode 100644 index 000000000..b0d1be9d2 --- /dev/null +++ b/app/views/exercises/exercise_result.json.jbuilder @@ -0,0 +1,65 @@ +if @exercise_course_groups.present? && @exercise_course_groups.count > 0 + json.course_groups do + json.array! @exercise_course_groups do |group| + json.exercise_group_id group[:course_id] #班级id + json.exercise_group_name group[:course_name] #班级名称 + json.exercise_group_students group[:student_count] #班级人数 + end + end +else + json.course_groups [] +end + +#试卷分数的统计 + +json.exercise_counts do + json.commit_percent @counts_array[:commit_percent] + json.min_score @counts_array[:min_score] + json.max_score @counts_array[:max_score] + json.average_score @counts_array[:average_score].to_s + json.fail_counts @counts_array[:fail_counts] + json.pass_counts @counts_array[:pass_counts] + json.good_counts @counts_array[:good_counts] + json.best_counts @counts_array[:best_counts] +end + +json.questions_count @exercise_questions_count +json.commit_results do + json.array! @question_result_hash do |q| + json.ques_title q[:ques_title] + json.ques_less_title q[:ques_less_title] + json.ques_type q[:type] + json.ques_position q[:position] + json.right_percent q[:percent] + json.effictive_counts q[:ques_effictive_counts] + if q[:type] != 5 + json.ques_details do + json.array! q[:ques_details] do |d| + json.choice_position d[:choice_position] + json.choice_text d[:choice_text] + json.choice_users_count d[:choice_users_count] + json.choice_percent d[:choice_percent] + json.choice_right_boolean d[:right_answer] + end + end + else + json.ques_details do + json.array! q[:ques_details] do |cha| + json.challenge_id cha[:cha_id] + json.challenge_name cha[:cha_name] + json.challenge_position cha[:cha_position] + json.challenge_details do + json.array! cha[:cha_details] do |ch| + json.choice_position ch[:choice_position] + json.choice_text ch[:choice_text] + json.choice_users_count ch[:choice_users_count] + json.choice_percent ch[:choice_percent] + json.choice_right_boolean ch[:right_answer] + end + end + end + end + end + end +end + diff --git a/app/views/exercises/exercise_setting.json.jbuilder b/app/views/exercises/exercise_setting.json.jbuilder new file mode 100644 index 000000000..25c6fa588 --- /dev/null +++ b/app/views/exercises/exercise_setting.json.jbuilder @@ -0,0 +1,40 @@ +json.exercise do + json.extract! @exercise, :id,:exercise_name, :exercise_status,:time,:publish_time, + :end_time,:score_open,:answer_open,:question_random,:choice_random, + :unified_setting,:show_statistic + json.course_id @course.id + json.published_count @exercise_publish_count + json.unpublish_count @exercise_unpublish_count + json.committed_count @exercise_users_count + json.user_permission @user_permission +end + +if @user_published_setting.size > 0 #老师存在已发布的分班 + total_array_groups = get_user_setting_course(@user_published_setting,@user_course_groups) + json.published_course_groups do + json.array! total_array_groups do |s| + json.course_group_id s[:course_group_id] + json.course_group_name s[:course_group_name] + json.course_publish_time s[:course_publish_time] + json.course_end_time s[:course_end_time] + end + end +else + json.published_course_groups [] +end + +if @user_course_groups.count > 0 + json.course_groups do + json.array! @user_course_groups do |group| + course_choosed = 0 + if @being_setting_course_ids.include?(group[:group_id]) + course_choosed = 1 + end + json.course_group_id group[:group_id] + json.course_group_name group[:group_name] + json.course_choosed course_choosed + end + end +else + json.course_groups [] +end diff --git a/app/views/exercises/index.json.jbuilder b/app/views/exercises/index.json.jbuilder new file mode 100644 index 000000000..661a8886d --- /dev/null +++ b/app/views/exercises/index.json.jbuilder @@ -0,0 +1,40 @@ + +json.exercises_counts do + json.exercises_total_counts @exercises_count #全部试卷数 + json.exercises_all_counts @exercises_select_count #选择后的全部试卷数 + json.exercises_unpublish_counts @exercises_unpublish_counts #未发布试卷数 + json.exercises_published_counts @exercises_published_counts #已发布试卷数 + json.exercises_ended_counts @exercises_ended_counts #已截止试卷数 + json.left_banner_id @left_banner_id + json.left_banner_name @left_banner_name +end + +json.course_types do + json.course_status @course.is_end ? 1 : 0 #课堂的当前是否结束,如结束,则为1,否则为0 + json.course_end_time @course.end_date #课堂的截止时间 + json.course_is_public @course.is_public #判断课堂是否为公开,只有公开课才有设为公开的按钮 + json.user_permission @is_teacher_or # 当前用户存在且为课堂教师/管理员/超级管理员时为1 ,课堂成员为2,否则为0 +end + + +if @exercises_count > 0 + json.exercises do + json.array! @exercises do |exercise| + ex_index = exercise_index_show(exercise,@course,@is_teacher_or,@current_user_) + json.extract! exercise, :id, :exercise_name,:is_public,:created_at,:time + json.exercise_status ex_index[:ex_status] + json.lock_status ex_index[:lock_icon] + json.publish_time ex_index[:publish_time] # 试卷的发布时间 + json.end_time ex_index[:end_time] # 试卷的截止时间 + json.exercise_answer ex_index[:exercise_answer] # 已提交试卷的用户 + json.exercise_unanswer ex_index[:exercise_unanswer] # 已查看试卷/开始答题,但是未提交试卷的用户 + json.exercise_left_time ex_index[:ex_left_time] + json.current_status ex_index[:current_status] #答题的状态 + json.unreview_count ex_index[:unreview_count] + json.exercise_tips ex_index[:ex_tips] + end + end +else + json.exercises [] +end + diff --git a/app/views/exercises/my_exercises.json.jbuilder b/app/views/exercises/my_exercises.json.jbuilder new file mode 100644 index 000000000..6cbd9dbed --- /dev/null +++ b/app/views/exercises/my_exercises.json.jbuilder @@ -0,0 +1,12 @@ +json.exercises_count @my_exercises_count +if @current_user_exercises.count > 0 + json.my_exercises do + json.array! @current_user_exercises do |exercise| + json.exercise_name exercise.name + json.exercise_description exercise.description + json.exercise_id exercise.container_id + end + end +else + json.my_exercises [] +end \ No newline at end of file diff --git a/app/views/exercises/new.json.jbuilder b/app/views/exercises/new.json.jbuilder new file mode 100644 index 000000000..8df8e29a0 --- /dev/null +++ b/app/views/exercises/new.json.jbuilder @@ -0,0 +1,3 @@ +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.partial! "commons/success" \ No newline at end of file diff --git a/app/views/exercises/public_exercises.json.jbuilder b/app/views/exercises/public_exercises.json.jbuilder new file mode 100644 index 000000000..6939a3583 --- /dev/null +++ b/app/views/exercises/public_exercises.json.jbuilder @@ -0,0 +1,16 @@ + +json.user_certification @user_certification #用户的认证,1为认证通过,0为未认证/认证未通过 +json.exercises_count @public_exercises_count +if @public_exercises_count > 0 + json.public_exercises do + json.array! @public_exercises do |exercise| + json.exercise_name exercise.name + json.exercise_description exercise.description + json.exercise_id exercise.container_id + json.exercise_user_id exercise.user_id + json.exercise_user_name exercise.user.real_name + end + end +else + json.public_exercises [] +end \ No newline at end of file diff --git a/app/views/exercises/publish_modal.json.jbuilder b/app/views/exercises/publish_modal.json.jbuilder new file mode 100644 index 000000000..253a030c2 --- /dev/null +++ b/app/views/exercises/publish_modal.json.jbuilder @@ -0,0 +1,11 @@ +if @course_groups.count > 0 + json.un_publish @course_groups.count #未发布的分班 + json.course_info do + json.array! @course_groups do |group| + json.course_group_id group.id + json.course_group_name group.name + end + end +else + json.un_publish 0 #未发布的分班 +end \ No newline at end of file diff --git a/app/views/exercises/redo_modal.json.jbuilder b/app/views/exercises/redo_modal.json.jbuilder new file mode 100644 index 000000000..3a3da797e --- /dev/null +++ b/app/views/exercises/redo_modal.json.jbuilder @@ -0,0 +1,10 @@ +json.commit_users_count @exercise_users_size #已提交用户数 +json.exercise_users do + json.array! @exercise_users do |ex| + ex_user = ex.user + json.user_id ex_user.id + json.user_name ex_user.real_name + json.student_id ex_user.user_extension.student_id + json.user_score ex.score + end +end \ No newline at end of file diff --git a/app/views/exercises/review_exercise.json.jbuilder b/app/views/exercises/review_exercise.json.jbuilder new file mode 100644 index 000000000..5d2ac875d --- /dev/null +++ b/app/views/exercises/review_exercise.json.jbuilder @@ -0,0 +1,12 @@ +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.partial! "exercises/user_exercise_info",locals:{exercise:@exercise, + is_teacher_or:@is_teacher_or, + ex_answerer:@ex_answerer, + exercise_user:@exercise_user, + ex_obj_array:@ex_obj_array, + ex_sub_array:@ex_sub_array, + exercise_questions:@exercise_questions, + student_status:@student_status, + question_status:@question_status +} diff --git a/app/views/exercises/show.json.jbuilder b/app/views/exercises/show.json.jbuilder new file mode 100644 index 000000000..8f6517c2c --- /dev/null +++ b/app/views/exercises/show.json.jbuilder @@ -0,0 +1,26 @@ +json.partial! "commons/success" + +json.exercise do + json.extract! @exercise, :id, :exercise_name,:exercise_description,:exercise_status +end + +json.user_permission do + json.is_teacher @is_teacher_or +end + +json.partial! "exercises/exercise_scores" + +json.exercise_questions do + json.array! @exercise_questions do |q| + json.partial! "exercise_questions/exercise_questions", + question: q, + choices:q.exercise_choices, + shixun_challenges: q.exercise_shixun_challenges, + exercise_type:1, + user_answer:[], + shixun_type:0 + end +end + + +#exercise_type 表示选择公用的模板类型,1为教师预览/编辑,2为空白试卷。 \ No newline at end of file diff --git a/app/views/exercises/start_answer.json.jbuilder b/app/views/exercises/start_answer.json.jbuilder new file mode 100644 index 000000000..fb9916696 --- /dev/null +++ b/app/views/exercises/start_answer.json.jbuilder @@ -0,0 +1,63 @@ +all_question_status = [] +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.exercise do + json.extract! @exercise,:id,:exercise_name,:exercise_description + json.exercise_status @t_user_exercise_status + json.left_time @user_left_time + json.user_exercise_status @user_exercise_status #当前用户的状态 + json.user_name @ex_answerer.real_name + json.commit_status @exercise_user_current.present? ? @exercise_user_current.commit_status : 0 #当前用户是否提交 + json.exercise_start_at @exercise_user_current.present? ? @exercise_user_current.start_at : nil +end +if @t_user_exercise_status == 3 + json.user_score @exercise_user_current.score.present? ? @exercise_user_current.score.round(1).to_s : "0.0" + #试卷的全部分数 + json.exercise_scores do + #试卷的客观题分数及是否错误 + json.objective_scores do + json.partial! "exercises/question_scores", question_scores: @ex_obj_array #客观问题正确与否的显示 + end + + #试卷的主观题及是否错误 + json.subjective_scores do + json.partial! "exercises/question_scores", question_scores: @ex_sub_array #主观题正确与否的显示 + end + end + + #主观题及客观题的全部分数及正确与否的状态 + all_question_status = @ex_obj_array + @ex_sub_array +else + json.question_status @question_status +end + +json.partial! "exercises/exercise_scores" + +json.exercise_questions do + json.array! @exercise_all_questions do |q| + question = q[:question] + ques_position = q[:ques_number] #问题的序号,当问题为随机时,重新更新后的问题序号 + question_info = get_exercise_question_info(question,@exercise,@exercise_user_current,@ex_answerer.id) + json.q_position ques_position + if @t_user_exercise_status == 3 + this_answer_status = "0.0" + user_score = "0.0" + if all_question_status.size > 0 + this_ques_status = all_question_status.detect {|f| f[:q_id] == question.id} + this_answer_status = this_ques_status[:stand_status] + user_score = this_ques_status[:user_score] + end + json.answer_status this_answer_status + json.user_score user_score + end + + json.partial! "exercise_questions/exercise_questions", + question: question, + ex_answerer:@ex_answerer, + shixun_challenges: question.exercise_shixun_challenges, + user_answer: question_info[:answered_content], + choices:question.exercise_choices, + exercise_type:3, + shixun_type:question_info[:shixun_type] + end +end \ No newline at end of file diff --git a/app/views/exercises/students_exercises.json.jbuilder b/app/views/exercises/students_exercises.json.jbuilder new file mode 100644 index 000000000..25c85be88 --- /dev/null +++ b/app/views/exercises/students_exercises.json.jbuilder @@ -0,0 +1,18 @@ +json.total_counts @total_exercise_counts + +json.total_user_exercises do + json.array! @all_exercise_stu_array do |a| + json.student_exercise do + json.partial! "exercises/user_exercise_info",locals:{exercise:@exercise, + is_teacher_or:a[:is_teacher], + ex_answerer:a[:ex_answerer], + exercise_user:a[:ex_user], + ex_obj_array:a[:ex_obj_array], + ex_sub_array:a[:ex_sub_array], + exercise_questions:@exercise_questions, + student_status:@student_status, + question_status:@question_status + } + end + end +end diff --git a/app/views/files/_course_groups.json.jbuilder b/app/views/files/_course_groups.json.jbuilder new file mode 100644 index 000000000..001cc9732 --- /dev/null +++ b/app/views/files/_course_groups.json.jbuilder @@ -0,0 +1,3 @@ +json.course_groups do + json.array! attachment_group_settings, partial: 'course_groups/course_group', as: :attachment_group_setting +end \ No newline at end of file diff --git a/app/views/files/_tag.json.jbuilder b/app/views/files/_tag.json.jbuilder new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/files/_tags_list.json.jbuilder b/app/views/files/_tags_list.json.jbuilder new file mode 100644 index 000000000..09c132c09 --- /dev/null +++ b/app/views/files/_tags_list.json.jbuilder @@ -0,0 +1,3 @@ +json.tags do + json.array! tags, :id, :name +end \ No newline at end of file diff --git a/app/views/files/bulk_delete.json.jbuilder b/app/views/files/bulk_delete.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/files/bulk_delete.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/files/bulk_move.json.jbuilder b/app/views/files/bulk_move.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/files/bulk_move.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/files/bulk_public.json.jbuilder b/app/views/files/bulk_public.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/files/bulk_public.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/files/bulk_send.json.jbuilder b/app/views/files/bulk_send.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/files/bulk_send.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/files/histories.json.jbuilder b/app/views/files/histories.json.jbuilder new file mode 100644 index 000000000..f30cf6b1b --- /dev/null +++ b/app/views/files/histories.json.jbuilder @@ -0,0 +1,2 @@ +json.partial! 'attachments/attachment_small', attachment: @file +json.partial! "attachment_histories/list", attachment_histories: @attachment_histories diff --git a/app/views/files/import.json.jbuilder b/app/views/files/import.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/files/import.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/files/index.json.jbuilder b/app/views/files/index.json.jbuilder new file mode 100644 index 000000000..03b4d4892 --- /dev/null +++ b/app/views/files/index.json.jbuilder @@ -0,0 +1,18 @@ +json.partial! "commons/success" +json.data do + json.id @category_id + json.name @category_name + json.total_count @total_count + json.public_count @public_count + json.private_count @private_count + json.course_is_public @course.is_public? + json.files do + json.array! @attachments do |attachment| + json.partial! "attachments/attachment", attachment: attachment + json.author do + json.partial! "users/user_simple", user: attachment.author + end + json.partial! "files/course_groups", attachment_group_settings: attachment.attachment_group_settings + end + end +end diff --git a/app/views/files/mine_with_course_and_project.json.jbuilder b/app/views/files/mine_with_course_and_project.json.jbuilder new file mode 100644 index 000000000..22597b9b7 --- /dev/null +++ b/app/views/files/mine_with_course_and_project.json.jbuilder @@ -0,0 +1,12 @@ +json.partial! "commons/success" +json.data do + json.total_count @total_count + json.files do + json.array! @attachments do |attachment| + json.partial! "attachments/attachment_small", attachment: attachment + json.author do + json.partial! "users/user_simple", user: @current_user + end + end + end +end \ No newline at end of file diff --git a/app/views/files/public_with_course_and_project.json.jbuilder b/app/views/files/public_with_course_and_project.json.jbuilder new file mode 100644 index 000000000..79fa5de26 --- /dev/null +++ b/app/views/files/public_with_course_and_project.json.jbuilder @@ -0,0 +1,12 @@ +json.partial! "commons/success" +json.data do + json.total_count @total_count + json.files do + json.array! @attachments do |attachment| + json.partial! "attachments/attachment_small", attachment: attachment + json.author do + json.partial! "users/user_simple", user: attachment.author + end + end + end +end \ No newline at end of file diff --git a/app/views/files/show.json.jbuilder b/app/views/files/show.json.jbuilder new file mode 100644 index 000000000..941e66619 --- /dev/null +++ b/app/views/files/show.json.jbuilder @@ -0,0 +1,3 @@ +json.partial! 'attachments/attachment', attachment: @file +json.partial! "files/course_groups", attachment_group_settings: @file.attachment_group_settings +json.partial! "attachment_histories/list", attachment_histories: @attachment_histories \ No newline at end of file diff --git a/app/views/files/update.json.jbuilder b/app/views/files/update.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/files/update.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/files/upload.json.jbuilder b/app/views/files/upload.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/files/upload.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/games/_testset_list.json.jbuilder b/app/views/games/_testset_list.json.jbuilder new file mode 100644 index 000000000..2111e3467 --- /dev/null +++ b/app/views/games/_testset_list.json.jbuilder @@ -0,0 +1,15 @@ +json.test_sets @qurey_test_sets do |test_set| + json.is_public test_set.is_public + json.result test_set.try(:result) + if test_set.is_public || @allowed_hidden_testset + json.input test_set.input + json.output test_set.output + json.actual_output evaluate_actual_output(test_set) + end + json.compile_success test_set.try(:compile_success) +end + +json.allowed_unlock @shixun.test_set_permission +json.last_compile_output @last_compile_output +json.test_sets_count @test_sets_count +json.sets_error_count @sets_error_count \ No newline at end of file diff --git a/app/views/games/answer.json.jbuilder b/app/views/games/answer.json.jbuilder new file mode 100644 index 000000000..8f1897502 --- /dev/null +++ b/app/views/games/answer.json.jbuilder @@ -0,0 +1,7 @@ +if @allowed + json.view_answer true + json.answer @result +else + json.is_teacher User.current.is_teacher? + json.view_answer false +end \ No newline at end of file diff --git a/app/views/games/answer_grade.json.jbuilder b/app/views/games/answer_grade.json.jbuilder new file mode 100644 index 000000000..52975731f --- /dev/null +++ b/app/views/games/answer_grade.json.jbuilder @@ -0,0 +1,3 @@ +json.answer @answer +json.final_score @final_score.to_i +json.grade @grade diff --git a/app/views/games/check_test_sets.json.jbuilder b/app/views/games/check_test_sets.json.jbuilder new file mode 100644 index 000000000..017a75aea --- /dev/null +++ b/app/views/games/check_test_sets.json.jbuilder @@ -0,0 +1,2 @@ +json.status @status +json.message @message \ No newline at end of file diff --git a/app/views/games/choose_build.json.jbuilder b/app/views/games/choose_build.json.jbuilder new file mode 100644 index 000000000..2bf528ffd --- /dev/null +++ b/app/views/games/choose_build.json.jbuilder @@ -0,0 +1,8 @@ +json.grade @result[:grade] +json.gold @result[:gold] +json.experience @result[:experience] +json.challenge_chooses_count @result[:challenge_chooses_count] +json.choose_correct_num @result[:choose_correct_num] +json.test_sets @result[:test_sets] +json.prev_game @result[:prev_game] +json.next_game @result[:next_game] \ No newline at end of file diff --git a/app/views/games/close_webssh.json.jbuilder b/app/views/games/close_webssh.json.jbuilder new file mode 100644 index 000000000..3134749b9 --- /dev/null +++ b/app/views/games/close_webssh.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "关闭成功!" \ No newline at end of file diff --git a/app/views/games/cost_time.json.jbuilder b/app/views/games/cost_time.json.jbuilder new file mode 100644 index 000000000..efe6fc949 --- /dev/null +++ b/app/views/games/cost_time.json.jbuilder @@ -0,0 +1 @@ +json.game @game \ No newline at end of file diff --git a/app/views/games/file_update.json.jbuilder b/app/views/games/file_update.json.jbuilder new file mode 100644 index 000000000..ab2741ce2 --- /dev/null +++ b/app/views/games/file_update.json.jbuilder @@ -0,0 +1,9 @@ +if @error + json.status -1 + json.message "实训平台繁忙(繁忙等级:81),请稍后刷新并重试" + #return {:status => -1, :success => "fail", :message => "实训云平台繁忙(繁忙等级:81),请稍后刷新并重试", :position => @game.challenge.position, :had_done => @game.had_done} +else + json.resubmit @resubmit + json.status 1 + json.content_modified @content_modified +end diff --git a/app/views/games/game_build.json.jbuilder b/app/views/games/game_build.json.jbuilder new file mode 100644 index 000000000..bf3f09a04 --- /dev/null +++ b/app/views/games/game_build.json.jbuilder @@ -0,0 +1,5 @@ +if @result[:status] == 1 + json.(@result, :status, :resubmit, :position, :port, :had_done) +else + json.(@result, :status, :message, :position, :had_done) +end diff --git a/app/views/games/game_status.json.jbuilder b/app/views/games/game_status.json.jbuilder new file mode 100644 index 000000000..73de75598 --- /dev/null +++ b/app/views/games/game_status.json.jbuilder @@ -0,0 +1,4 @@ +json.(@base_date, :grade, :gold, :experience, :status, :had_done, :position, :port, :record_consume_time, :mirror_name, + :picture, :web_route, :star, :next_game, :prev_game) +# # 测试集相关 +json.partial! 'games/testset_list' \ No newline at end of file diff --git a/app/views/games/get_answer_info.json.jbuilder b/app/views/games/get_answer_info.json.jbuilder new file mode 100644 index 000000000..7620a991a --- /dev/null +++ b/app/views/games/get_answer_info.json.jbuilder @@ -0,0 +1,15 @@ +index = 0 +json.status 3 +json.message do + json.array! @challenge_answers do |answer| + index += 1 + json.answer_id answer.id + json.answer_name answer.name + json.answer_score answer.score + # 高层级不给答案 + if @power || @game.answer_open >= index + json.answer_contents answer.contents + end + end +end + diff --git a/app/views/games/git_entries.json.jbuilder b/app/views/games/git_entries.json.jbuilder new file mode 100644 index 000000000..25d76f182 --- /dev/null +++ b/app/views/games/git_entries.json.jbuilder @@ -0,0 +1,8 @@ +json.array! @trees do |tree| + new_path = File.join(@path,tree.name).reverse.chomp("/").reverse + json.name tree.name + json.path new_path + json.kind tree.type == 'tree' ? 'dir' : 'file' +end + + diff --git a/app/views/games/picture_display.json.jbuilder b/app/views/games/picture_display.json.jbuilder new file mode 100644 index 000000000..0470a5c0b --- /dev/null +++ b/app/views/games/picture_display.json.jbuilder @@ -0,0 +1,28 @@ +json.type @type + +if @type == "image" + #原始图片 + json.orignal_picture do + json.array! @orignal_picture do |pic| + json.pic_url attachment_show_users_path(:file_name => pic, :path => @original_path) + end + end + json.user_picture do + json.array! @user_picture do |pic| + json.pic_url attachment_show_users_path(:file_name => pic, :path => @user_path, :time => Time.now.to_i) + end + end + json.answer_picture do + json.array! @answer_picture do |pic| + json.pic_url attachment_show_users_path(:file_name => pic, :path => @answer_path) + end + end + +elsif @type == "html" + json.iframe_src html_show_users_path(:path => "#{@user_path}/#{@user_picture[0]}") +elsif @type == "txt" + json.contents @contents.html_safe +elsif @type =="qrcode" + json.qrcode_str @qrcode_str + +end \ No newline at end of file diff --git a/app/views/games/plus_or_cancel_praise.json.jbuilder b/app/views/games/plus_or_cancel_praise.json.jbuilder new file mode 100644 index 000000000..d9b8cb535 --- /dev/null +++ b/app/views/games/plus_or_cancel_praise.json.jbuilder @@ -0,0 +1,2 @@ +json.praise_count @praise_count +json.praise @praise \ No newline at end of file diff --git a/app/views/games/rep_content.json.jbuilder b/app/views/games/rep_content.json.jbuilder new file mode 100644 index 000000000..d4cccf0a7 --- /dev/null +++ b/app/views/games/rep_content.json.jbuilder @@ -0,0 +1 @@ +json.content @content \ No newline at end of file diff --git a/app/views/games/reset_my_game.json.jbuilder b/app/views/games/reset_my_game.json.jbuilder new file mode 100644 index 000000000..7a1ce381c --- /dev/null +++ b/app/views/games/reset_my_game.json.jbuilder @@ -0,0 +1,3 @@ +json.status 1 +json.message "success" +json.shixun_url "/shixuns/#{@shixun.identifier}" \ No newline at end of file diff --git a/app/views/games/reset_original_code.json.jbuilder b/app/views/games/reset_original_code.json.jbuilder new file mode 100644 index 000000000..d4cccf0a7 --- /dev/null +++ b/app/views/games/reset_original_code.json.jbuilder @@ -0,0 +1 @@ +json.content @content \ No newline at end of file diff --git a/app/views/games/reset_passed_code.json.jbuilder b/app/views/games/reset_passed_code.json.jbuilder new file mode 100644 index 000000000..d4cccf0a7 --- /dev/null +++ b/app/views/games/reset_passed_code.json.jbuilder @@ -0,0 +1 @@ +json.content @content \ No newline at end of file diff --git a/app/views/games/show.json.jbuilder b/app/views/games/show.json.jbuilder new file mode 100644 index 000000000..acbc8c2ef --- /dev/null +++ b/app/views/games/show.json.jbuilder @@ -0,0 +1,18 @@ +json.(@base_date, :st, :discusses_count, :game_count, :record_onsume_time, :prev_game, :next_game, :praise_count, + :user_praise, :time_limit, :tomcat_url, :is_teacher, :myshixun_manager, :game, :challenge, + :shixun, :myshixun) +json.user do + json.partial! 'users/user', user: @user + json.identity @identity +end + +if @st == 0 + json.(@task_result, :tpm_modified, :tpm_cases_modified, :mirror_name, :has_answer) + + # 测试集相关 + json.partial! 'games/testset_list' +else + json.has_answer @has_answer + json.choose_test_cases @choose_test_cases + json.chooses @chooses +end diff --git a/app/views/games/star.json.jbuilder b/app/views/games/star.json.jbuilder new file mode 100644 index 000000000..e39624331 --- /dev/null +++ b/app/views/games/star.json.jbuilder @@ -0,0 +1 @@ +json.reward_coder @gold diff --git a/app/views/games/sync_codes.json.jbuilder b/app/views/games/sync_codes.json.jbuilder new file mode 100644 index 000000000..4d882e46e --- /dev/null +++ b/app/views/games/sync_codes.json.jbuilder @@ -0,0 +1 @@ +json.path @path \ No newline at end of file diff --git a/app/views/games/unlock_answer.json.jbuilder b/app/views/games/unlock_answer.json.jbuilder new file mode 100644 index 000000000..71018c7be --- /dev/null +++ b/app/views/games/unlock_answer.json.jbuilder @@ -0,0 +1 @@ +json.contents @answer.contents \ No newline at end of file diff --git a/app/views/graduation_tasks/_public_navigation.json.jbuilder b/app/views/graduation_tasks/_public_navigation.json.jbuilder new file mode 100644 index 000000000..00280c31b --- /dev/null +++ b/app/views/graduation_tasks/_public_navigation.json.jbuilder @@ -0,0 +1,5 @@ +json.partial! "graduation_topics/show_navigation", locals: {course: course, graduation: graduation} +json.task_status task_curr_status(graduation, course)[:status] +json.task_name graduation.name +json.task_id graduation.id +json.status graduation.status \ No newline at end of file diff --git a/app/views/graduation_tasks/create.json.jbuilder b/app/views/graduation_tasks/create.json.jbuilder new file mode 100644 index 000000000..3d58a10ce --- /dev/null +++ b/app/views/graduation_tasks/create.json.jbuilder @@ -0,0 +1 @@ +json.task_id @graduation_task.id \ No newline at end of file diff --git a/app/views/graduation_tasks/edit.json.jbuilder b/app/views/graduation_tasks/edit.json.jbuilder new file mode 100644 index 000000000..0c5d6f49f --- /dev/null +++ b/app/views/graduation_tasks/edit.json.jbuilder @@ -0,0 +1,8 @@ +json.partial! "public_navigation", locals: {course: @course, graduation: @task} +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.course_name @course.name +json.(@task, :task_type, :description) +json.attachments @task.attachments do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta} +end \ No newline at end of file diff --git a/app/views/graduation_tasks/index.json.jbuilder b/app/views/graduation_tasks/index.json.jbuilder new file mode 100644 index 000000000..157bde672 --- /dev/null +++ b/app/views/graduation_tasks/index.json.jbuilder @@ -0,0 +1,30 @@ +json.course_identity @identity +json.course_public @course.is_public == 1 +json.is_end @course.is_end +json.all_count @all_count +json.published_count @published_count +json.unpublished_count @all_count - @published_count +json.task_count @task_count + +json.tasks @tasks.each do |task| + task_private = @identity > Course::STUDENT && !task.is_public + json.task_id task.id + json.name task.name + json.private_icon task_private + json.task_status task.status #6.12 -hs + json.status task_curr_status(task, @course)[:status] + json.status_time task_curr_status(task, @course)[:time] + + unless task_curr_status(task, @course)[:status].include?("未发布") + json.commit_count grduationwork_count task, 1 + json.uncommit_count grduationwork_count task, 0 + end + + if @identity == Course::STUDENT + work = task.user_work(@member.user_id) + json.work_status graduation_work_status(task, @member.user_id, @course) + json.work_id work.try(:id) + json.un_commit_work !work.present? || work.work_status == 0 + end +end + diff --git a/app/views/graduation_tasks/new.json.jbuilder b/app/views/graduation_tasks/new.json.jbuilder new file mode 100644 index 000000000..ed2d9414d --- /dev/null +++ b/app/views/graduation_tasks/new.json.jbuilder @@ -0,0 +1,6 @@ +json.course_id @course.id +json.course_name @course.name +json.graduation_name "毕设任务" +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.course_name @course.name \ No newline at end of file diff --git a/app/views/graduation_tasks/settings.json.jbuilder b/app/views/graduation_tasks/settings.json.jbuilder new file mode 100644 index 000000000..e9578a48c --- /dev/null +++ b/app/views/graduation_tasks/settings.json.jbuilder @@ -0,0 +1,20 @@ +json.partial! "public_navigation", locals: {course: @course, graduation: @task} + +json.(@task, :task_type, :min_num, :max_num, :base_on_project, :status, :cross_comment, :publish_time, :end_time, + :allow_late, :late_penalty, :late_time, :comment_num, :comment_status, :comment_time, :open_work, :open_score) + +json.has_project @task.student_relate_projects +json.has_commit @task.student_commit_works + +if @user_course_identity == Course::STUDENT + json.work_id @task.user_work(@current_user.id).try(:id) + json.work_status graduation_work_status(@task, @current_user.id, @course) +end + +json.graduation_groups @course.graduation_groups do |gra_group| + json.group_id gra_group.id + json.group_name gra_group.name + json.member_count gra_group.course_members.count + json.select_name @task.task_assign_group(gra_group.id).try(:assign_group).try(:name) + json.assign_group_id @task.task_assign_group(gra_group.id).try(:assign_graduation_group_id) +end \ No newline at end of file diff --git a/app/views/graduation_tasks/show.json.jbuilder b/app/views/graduation_tasks/show.json.jbuilder new file mode 100644 index 000000000..b5cd1620b --- /dev/null +++ b/app/views/graduation_tasks/show.json.jbuilder @@ -0,0 +1,23 @@ +json.partial! "public_navigation", locals: {graduation: @task, course: @course} +json.description @task.description +json.user_id @task.user_id +# 附件 +json.attachments @attachments do |attachment| + json.partial! "attachments/attachment_simple", locals: {attachment: attachment} +end + + +if @user_course_identity == Course::STUDENT + json.work_id @task.user_work(@current_user.id).try(:id) + json.work_status graduation_work_status(@task, @current_user.id, @course) +end + +# 分组要求 +json.group_info do + if @task.task_type == 2 + json.max_number @task.max_num + json.min_number @task.min_num + json.base_on_project @task.base_on_project + end +end + diff --git a/app/views/graduation_tasks/show_comment.json.jbuilder b/app/views/graduation_tasks/show_comment.json.jbuilder new file mode 100644 index 000000000..cf4fcd914 --- /dev/null +++ b/app/views/graduation_tasks/show_comment.json.jbuilder @@ -0,0 +1,12 @@ +# 帖子信息 +json.messages_count @messages_count +json.comments @messages do |message| + json.partial! "graduation_topics/graduation_comments", locals: {message: message, current_user: @current_user, + identity: @user_course_identity} + if @parent.nil? + json.children message.children(@page, 5) do |c_message| + json.partial! 'graduation_topics/graduation_comments', locals: { message: c_message, current_user: @current_user, + identity: @user_course_identity} + end + end +end \ No newline at end of file diff --git a/app/views/graduation_tasks/tasks_list.json.jbuilder b/app/views/graduation_tasks/tasks_list.json.jbuilder new file mode 100644 index 000000000..5f1b8eb40 --- /dev/null +++ b/app/views/graduation_tasks/tasks_list.json.jbuilder @@ -0,0 +1,52 @@ +json.partial! "public_navigation", locals: {graduation: @task, course: @course} +json.user_course_identity @user_course_identity +json.course_group_count @course.course_groups_count +# 课程发布才有数据 +if @task.published? || @user_course_identity < Course::STUDENT +# 老师身份才有的分类信息 + if @user_course_identity < Course::STUDENT + json.search_assistants do + json.teacher_comment teacher_comment @task, @current_user.id + json.task_status task_status @task, @current_user.id + json.course_group_info course_group_info @course, @current_user.id + json.cross_comment cross_comment @task, @current_user + end + # 课堂下所有老师 TODO: 考虑以后在点击分配时,再获取老师列表 + json.teacher_list do + json.array! @teachers do |teacher| + json.id teacher.user.id + json.name teacher.user.full_name + end + end + elsif @user_course_identity == Course::STUDENT + json.work_id @task.user_work(@current_user.id).try(:id) + json.work_status graduation_work_status(@task, @current_user.id, @course) + end + + # 是否具有分组 + json.have_grouping @task.have_grouping? + json.work_count @work_count + json.all_work_count @all_work_count +# 学生数据 + json.work_lists do + json.array! @work_list do |work| + json.id work.id + json.user_id work.user.id + json.name work.user.full_name + json.student_id work.user.school_id + json.class_grouping_name work.class_grouping_name + if @task.have_grouping? + json.grouping_name work.grouping_name + if @task.base_on_project + json.project_info project_info work, @current_user, @user_course_identity + end + end + json.status work.work_status + json.update_time format_time work.update_time + json.teacher_comment_score work.teacher_comment_score(@current_user, @user_course_identity) + json.cross_comment_score work.cross_comment_score(@current_user, @user_course_identity) + json.final_score work_final_score work, @current_user, @user_course_identity + json.assign work.assign_power?(@user_course_identity) + end + end +end \ No newline at end of file diff --git a/app/views/graduation_tasks/tasks_list.xlsx.axlsx b/app/views/graduation_tasks/tasks_list.xlsx.axlsx new file mode 100644 index 000000000..1f4f76292 --- /dev/null +++ b/app/views/graduation_tasks/tasks_list.xlsx.axlsx @@ -0,0 +1,14 @@ + +wb = xlsx_package.workbook +wb.styles do |s| + sz_all = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {:horizontal => :center} + blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 20,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {:horizontal => :center} + + wb.add_worksheet(:name =>"学生成绩") do |sheet| + sheet.add_row table_columns, :style => blue_cell + sheet.column_info.first.width = 12 + task_users.each do |user| + sheet.add_row user, :style => sz_all + end #each_widh_index + end #add_worksheet +end \ No newline at end of file diff --git a/app/views/graduation_topics/_graduation_comments.json.jbuilder b/app/views/graduation_topics/_graduation_comments.json.jbuilder new file mode 100644 index 000000000..1d49d450f --- /dev/null +++ b/app/views/graduation_topics/_graduation_comments.json.jbuilder @@ -0,0 +1,16 @@ +json.author do + json.partial! "users/user_simple", user: message.user +end + +json.id message.id +json.content message.contents_show(identity) +json.time time_from_now(message.created_at) +json.hidden message.hidden +# 主贴与子贴不一致 +if message.m_parent_id + json.can_delete message.can_delete(identity) +else + json.praise_count message.praise_treads.liker.count + json.user_praise message.praise_treads.user_liker(current_user).count + json.child_message_count message.m_reply_count +end diff --git a/app/views/graduation_topics/_new_or_edit_data.json.jbuilder b/app/views/graduation_topics/_new_or_edit_data.json.jbuilder new file mode 100644 index 000000000..a91d63d60 --- /dev/null +++ b/app/views/graduation_topics/_new_or_edit_data.json.jbuilder @@ -0,0 +1,11 @@ +json.teacher_list do + json.array! teachers do |teacher| + json.id teacher.user.id + json.name teacher.user.real_name + end +end +json.topic_type topic_type +json.topic_source topic_source +json.topic_property_first topic_property_first +json.topic_property_second topic_property_second +json.topic_repeat topic_repeat \ No newline at end of file diff --git a/app/views/graduation_topics/_show_navigation.json.jbuilder b/app/views/graduation_topics/_show_navigation.json.jbuilder new file mode 100644 index 000000000..c01633326 --- /dev/null +++ b/app/views/graduation_topics/_show_navigation.json.jbuilder @@ -0,0 +1,5 @@ +json.course_id course.id +json.course_name course.name +json.is_end course.is_end +json.graduation_name graduation_navigation(graduation) +json.graduation_id graduation_navigation_id(course) diff --git a/app/views/graduation_topics/_topics.json.jbuilder b/app/views/graduation_topics/_topics.json.jbuilder new file mode 100644 index 000000000..7a37b666b --- /dev/null +++ b/app/views/graduation_topics/_topics.json.jbuilder @@ -0,0 +1,9 @@ +json.array! topics do |topic| + task_private = course_identity > Course::STUDENT && !topic.is_public + json.private_icon task_private + json.(topic, :id, :name, :status) + json.author topic.teacher.full_name + json.user_topic_status topic.user_status(current_user) + json.selected_count topic.student_graduation_topics.count + json.confirmation_count topic.student_graduation_topics.confirmation_count +end \ No newline at end of file diff --git a/app/views/graduation_topics/create.json.jbuilder b/app/views/graduation_topics/create.json.jbuilder new file mode 100644 index 000000000..6aa3fc4b2 --- /dev/null +++ b/app/views/graduation_topics/create.json.jbuilder @@ -0,0 +1 @@ +json.id @graduation_topic.id \ No newline at end of file diff --git a/app/views/graduation_topics/edit.json.jbuilder b/app/views/graduation_topics/edit.json.jbuilder new file mode 100644 index 000000000..7ed4a8d13 --- /dev/null +++ b/app/views/graduation_topics/edit.json.jbuilder @@ -0,0 +1,17 @@ +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.course_name @course.name +json.partial! 'new_or_edit_data', locals: {teachers: @teachers} +json.selected_data do + json.(@graduation_topic, :tea_id, :name, :topic_type, :topic_source, :topic_property_first, + :description, :topic_property_second, :status, :source_unit, :topic_repeat, + :province, :city, :is_public) +end + +json.attachments do + json.array! @attachments do |attachment| + json.partial! "attachments/attachment_simple", locals: {attachment: attachment} + end + +end + diff --git a/app/views/graduation_topics/export.xlsx.axlsx b/app/views/graduation_topics/export.xlsx.axlsx new file mode 100644 index 000000000..f1d7e8e74 --- /dev/null +++ b/app/views/graduation_topics/export.xlsx.axlsx @@ -0,0 +1,35 @@ +wb = xlsx_package.workbook +wb.use_autowidth = false +wb.use_shared_strings = true + +wb.styles do |s| + sz_all = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center } + bg_db = s.add_style :bg_color=> "DBEEF4",:border => { :style => :thick, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center } + bg_d2 = s.add_style :bg_color=> "CCC1DA",:border => { :style => :thick, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center } + bg_cc = s.add_style :bg_color=> "CCC1DA",:border => { :style => :thick, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center } + bg_ff = s.add_style :bg_color=> "FFC000",:border => { :style => :thick, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center } + bg_bb = s.add_style :bg_color=> "9BBB59",:border => { :style => :thick, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center } + bg_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 20,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {wrap_text: true,:horizontal => :center,:vertical => :center } + + wb.add_worksheet(:name => "毕设选题情况汇总") do |sheet| + sheet.sheet_view.show_grid_lines = false + sheet_title = table_columns + sheet_title_c = sheet_title.count + sheet.add_row sheet_title, :style => bg_cell + sheet["J1:L1"].each { |c| c.style = bg_db } + sheet["M1:O1"].each { |c| c.style = bg_cc } + sheet["P1:Q1"].each { |c| c.style = bg_d2 } + sheet["R1:T1"].each { |c| c.style = bg_ff } + sheet["U1:W1"].each { |c| c.style = bg_bb } + if topic_users.count > 0 + topic_users.each do |user| + sheet.add_row user, :style => sz_all + end #each_widh_index + else + sheet.add_row ["--"]*sheet_title_c + end + + sheet.column_widths *([15]*sheet.column_info.count) + sheet.column_info.first.width = 8 + end #add_worksheet +end diff --git a/app/views/graduation_topics/index.json.jbuilder b/app/views/graduation_topics/index.json.jbuilder new file mode 100644 index 000000000..e7698a58f --- /dev/null +++ b/app/views/graduation_topics/index.json.jbuilder @@ -0,0 +1,7 @@ +json.graduation_topic do + json.partial! 'topics', locals: {topics: @graduation_topic, current_user: @current_user, course_identity: @user_course_identity} +end +json.graduation_topic_count @graduation_topic_count +json.course_public @course.is_public +json.is_end @course.is_end +json.user_selected @user_selected \ No newline at end of file diff --git a/app/views/graduation_topics/new.json.jbuilder b/app/views/graduation_topics/new.json.jbuilder new file mode 100644 index 000000000..8aeccc9f4 --- /dev/null +++ b/app/views/graduation_topics/new.json.jbuilder @@ -0,0 +1,5 @@ +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.course_name @course.name +json.partial! 'new_or_edit_data', locals: {teachers: @teachers} + diff --git a/app/views/graduation_topics/show.json.jbuilder b/app/views/graduation_topics/show.json.jbuilder new file mode 100644 index 000000000..440dc776e --- /dev/null +++ b/app/views/graduation_topics/show.json.jbuilder @@ -0,0 +1,38 @@ +# 公共数据 +json.partial! "show_navigation", locals: {course: @course, graduation: @graduation_topic} +json.graduation_topic_name @graduation_topic.name +json.status_name @graduation_topic.status_name +json.back_url course_graduation_topics_path(@course) +json.edit_url edit_course_graduation_topic_path(@course, graduation_topic_id: @graduation_topic) +json.users_count @users_count +json.course_identity @current_user.course_identity(@course) +json.user_selected_topic @graduation_topic.user_status(current_user.id) + +json.group_list do + json.array! @group_list do |group| + json.course_group_id group.id + json.group_name group.name + end +end + +# 列表数据 +json.users_list do + json.array! @student_graduation_topics do |student| + json.id student.id + json.student_name student.name + json.student_id student.student_id + json.class_group_name student.class_group_name + json.selected_time student.selected_time + json.result student.status_name + if @user_course_identity < Course::STUDENT + if student.status == 0 || student.status == 1 + json.refuse_operate_api refuse_student_topic_course_graduation_topic_path(@course) + end + if student.status == 0 + json.accept_operate_api accept_student_topic_course_graduation_topic_path(@course) + end + end + end +end + + diff --git a/app/views/graduation_topics/show_comment.json.jbuilder b/app/views/graduation_topics/show_comment.json.jbuilder new file mode 100644 index 000000000..d2d2d4596 --- /dev/null +++ b/app/views/graduation_topics/show_comment.json.jbuilder @@ -0,0 +1,11 @@ +# 帖子信息 +json.messages_count @messages_count +json.user_course_identity @user_course_identity +json.comments @messages do |message| + json.partial! "graduation_comments", locals: {message: message, current_user: @current_user, identity: @user_course_identity} + if @parent.nil? + json.children message.children(@page, 5) do |c_message| + json.partial! 'graduation_comments', locals: { message: c_message, current_user: @current_user, identity: @user_course_identity} + end + end +end \ No newline at end of file diff --git a/app/views/graduation_topics/show_detail.json.jbuilder b/app/views/graduation_topics/show_detail.json.jbuilder new file mode 100644 index 000000000..28962fe62 --- /dev/null +++ b/app/views/graduation_topics/show_detail.json.jbuilder @@ -0,0 +1,8 @@ +json.(@graduation_topic, :description, :topic_type, :topic_source, :topic_property_first, + :topic_property_second, :source_unit, :topic_repeat, :province, :city, :user_id) +# 附件信息 +json.attachment_list do + json.array! @attachments do |attach| + json.partial! "attachments/attachment_simple", locals: {attachment: attach} + end +end diff --git a/app/views/graduation_topics/update.json.jbuilder b/app/views/graduation_topics/update.json.jbuilder new file mode 100644 index 000000000..6aa3fc4b2 --- /dev/null +++ b/app/views/graduation_topics/update.json.jbuilder @@ -0,0 +1 @@ +json.id @graduation_topic.id \ No newline at end of file diff --git a/app/views/graduation_works/check_project.json.jbuilder b/app/views/graduation_works/check_project.json.jbuilder new file mode 100644 index 000000000..cb1b1848d --- /dev/null +++ b/app/views/graduation_works/check_project.json.jbuilder @@ -0,0 +1,2 @@ +json.is_relate @is_relate +json.relate_user @relate_user \ No newline at end of file diff --git a/app/views/graduation_works/comment_list.json.jbuilder b/app/views/graduation_works/comment_list.json.jbuilder new file mode 100644 index 000000000..51595c55b --- /dev/null +++ b/app/views/graduation_works/comment_list.json.jbuilder @@ -0,0 +1,22 @@ +json.ultimate @work.ultimate_score + +json.last_comment do + json.last_content @last_comment.try(:comment) + json.last_score @last_comment.try(:score) +end + +json.comment_scores @comment_scores do |score| + json.user_login score.user.login + json.user_image_url url_to_avatar(score.user) + json.user_name score.user.real_name + json.comment_id score.id + json.comment_role score.reviewer_role == 1 ? "教师" : "交叉评阅" + json.comment_time score.created_at + json.score score.score + json.content score.comment + json.is_invalid score.is_invalid + json.delete @current_user == score.user && (score.is_invalid || score.score.nil?) + json.attachments score.attachments do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false} + end +end \ No newline at end of file diff --git a/app/views/graduation_works/create.json.jbuilder b/app/views/graduation_works/create.json.jbuilder new file mode 100644 index 000000000..c1c966ee9 --- /dev/null +++ b/app/views/graduation_works/create.json.jbuilder @@ -0,0 +1,3 @@ +json.status 0 +json.message "提交成功" +json.work_id @work_id \ No newline at end of file diff --git a/app/views/graduation_works/edit.json.jbuilder b/app/views/graduation_works/edit.json.jbuilder new file mode 100644 index 000000000..7fc3a9621 --- /dev/null +++ b/app/views/graduation_works/edit.json.jbuilder @@ -0,0 +1,16 @@ +json.partial! "graduation_tasks/public_navigation", locals: {course: @course, graduation: @task} +json.task_type @task.task_type +json.work_id @work.id +json.description @work.description +json.user_name @task_user.real_name + +json.attachments @work.attachments do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: @work.delete_atta(atta)} +end + +json.members @work_members do |member| + json.user_id member.user_id + json.user_name member.user.real_name + json.group_name member.course_group_name + json.student_id member.user.student_id +end \ No newline at end of file diff --git a/app/views/graduation_works/new.json.jbuilder b/app/views/graduation_works/new.json.jbuilder new file mode 100644 index 000000000..601ba02d3 --- /dev/null +++ b/app/views/graduation_works/new.json.jbuilder @@ -0,0 +1,9 @@ +json.partial! "graduation_tasks/public_navigation", locals: {course: @course, graduation: @task} +json.task_type @task.task_type +json.user_name @user.real_name + +if @task.task_type == 2 + json.user_id @user.id + json.user_student_id @user.student_id + json.group_name @course.course_member(@user.id).try(:course_group_name) +end diff --git a/app/views/graduation_works/search_member_list.json.jbuilder b/app/views/graduation_works/search_member_list.json.jbuilder new file mode 100644 index 000000000..a999ebef3 --- /dev/null +++ b/app/views/graduation_works/search_member_list.json.jbuilder @@ -0,0 +1,7 @@ +json.members @members do |member| + json.user_id member.user_id + json.user_name member.user.real_name + json.group_name member.course_group_name + json.student_id member.user.student_id + json.commit_status @task.has_commit_work(member.user_id) +end \ No newline at end of file diff --git a/app/views/graduation_works/show.json.jbuilder b/app/views/graduation_works/show.json.jbuilder new file mode 100644 index 000000000..efe0f52cc --- /dev/null +++ b/app/views/graduation_works/show.json.jbuilder @@ -0,0 +1,25 @@ +json.partial! "graduation_tasks/public_navigation", locals: {course: @course, graduation: @task} +json.task_type @task.task_type +json.(@work, :description, :commit_time, :update_time) + +json.author_name @work.user.real_name +json.is_author @is_author +json.update_user_name @work.commit_user.try(:real_name) +json.task_status @task.status #6.12 -hs +json.status task_curr_status(@task, @course)[:status] +json.update_atta (!@course.is_end && @task.end_time < Time.now && @task.allow_late && (@task.late_time.nil? || @task.late_time > Time.now) && @is_author) + +json.attachments @attachments do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false} +end + +if @task.task_type == 2 && @task.base_on_project + json.project_info project_info @work, @current_user, @user_course_identity +end + +json.work_members @work_members.each do |member| + json.user_name member.user.real_name + json.user_login member.user.login +end + + diff --git a/app/views/graduation_works/supply_attachments.json.jbuilder b/app/views/graduation_works/supply_attachments.json.jbuilder new file mode 100644 index 000000000..eae78aed6 --- /dev/null +++ b/app/views/graduation_works/supply_attachments.json.jbuilder @@ -0,0 +1,8 @@ +json.revise_reason @last_atta.try(:description) +json.atta_update_time @last_atta.try(:created_on) +json.atta_update_user @last_atta.try(:author).try(:real_name) +json.atta_update_user_login @last_atta.try(:author).try(:login) + +json.revise_attachments @revise_attachments.each do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: @work.delete_atta(atta)} +end \ No newline at end of file diff --git a/app/views/home/index.json.jbuilder b/app/views/home/index.json.jbuilder new file mode 100644 index 000000000..aa29ae7ff --- /dev/null +++ b/app/views/home/index.json.jbuilder @@ -0,0 +1,19 @@ +json.images_url @images_url + +json.reps @rep_list + +json.shixuns do + json.partial! 'shixuns/shixun', locals: {shixuns: @shixuns} +end + +json.subjects do + json.partial! 'subjects/subject', locals: {subjects: @subjects} +end + +json.teachers do + json.partial! 'users/user_small', users: @tea_users +end + +json.students do + json.partial! 'users/user_small', users: @stu_users +end diff --git a/app/views/home/search.json.jbuilder b/app/views/home/search.json.jbuilder new file mode 100644 index 000000000..f217d9d32 --- /dev/null +++ b/app/views/home/search.json.jbuilder @@ -0,0 +1,5 @@ +json.keyword @fuzzy_searchs +json.total_count @total_count +json.shixuns do + json.partial! 'shixuns/shixun', locals: {shixuns: @shixuns} +end \ No newline at end of file diff --git a/app/views/homework_commons/_homework_btn_check.json.jbuilder b/app/views/homework_commons/_homework_btn_check.json.jbuilder new file mode 100644 index 000000000..ff6e5bc0c --- /dev/null +++ b/app/views/homework_commons/_homework_btn_check.json.jbuilder @@ -0,0 +1,5 @@ +# 教师身份的立即发布、立即截止、代码查重入口的判断 +json.publish_immediately identity < Course::STUDENT && homework.publish_immediately(user) +json.end_immediately identity < Course::STUDENT && homework.end_immediately(user) +json.code_review identity < Course::STUDENT && homework.code_review if homework.homework_type == 'practice' +json.view_answer homework.view_answer(identity, user.id) if homework.homework_type != "practice" \ No newline at end of file diff --git a/app/views/homework_commons/_homework_public_navigation.json.jbuilder b/app/views/homework_commons/_homework_public_navigation.json.jbuilder new file mode 100644 index 000000000..09dd076c0 --- /dev/null +++ b/app/views/homework_commons/_homework_public_navigation.json.jbuilder @@ -0,0 +1,13 @@ +json.course_id course.id +json.course_name course.name +json.is_end course.is_end +json.category homework.category_info +member = course.course_members.find_by(user_id: user.id, is_active: 1) +json.homework_status homework_curr_status(homework, user.course_identity(course), course, member, member&.teacher_course_groups)[:status] +json.time_status homework_curr_status(homework, user.course_identity(course), course, member, member&.teacher_course_groups)[:time_status] +json.homework_name homework.name +json.homework_id homework.id +json.homework_type homework.homework_type +if homework.homework_type == "practice" + json.shixun_identifier homework.shixuns.first.try(:identifier) +end diff --git a/app/views/homework_commons/_second_category.json.jbuilder b/app/views/homework_commons/_second_category.json.jbuilder new file mode 100644 index 000000000..b584abecc --- /dev/null +++ b/app/views/homework_commons/_second_category.json.jbuilder @@ -0,0 +1,8 @@ +json.main_category main_catrgory do |category| + json.main_category_id 0 + json.main_category_name category.module_name +end +json.homework_category homework_category do |category| + json.category_id category.id + json.category_name category.name +end \ No newline at end of file diff --git a/app/views/homework_commons/_student_btn_check.json.jbuilder b/app/views/homework_commons/_student_btn_check.json.jbuilder new file mode 100644 index 000000000..efa89203d --- /dev/null +++ b/app/views/homework_commons/_student_btn_check.json.jbuilder @@ -0,0 +1,10 @@ +if identity == Course::STUDENT + if homework.homework_type == "practice" + json.task_operation task_operation_url(work.try(:myshixun), homework.shixuns.take) + json.view_report work.work_status > 0 + json.commit_des commit_des_status(work, homework) + else + json.work_statuses student_work_status(homework, work.user_id, homework.course, work) + end + json.work_id work.id +end \ No newline at end of file diff --git a/app/views/homework_commons/choose_category.json.jbuilder b/app/views/homework_commons/choose_category.json.jbuilder new file mode 100644 index 000000000..45ab4c537 --- /dev/null +++ b/app/views/homework_commons/choose_category.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'homework_commons/second_category', locals: {main_catrgory: @main_catrgory, homework_category: @homework_category} \ No newline at end of file diff --git a/app/views/homework_commons/code_review_detail.json.jbuilder b/app/views/homework_commons/code_review_detail.json.jbuilder new file mode 100644 index 000000000..4ebabf20a --- /dev/null +++ b/app/views/homework_commons/code_review_detail.json.jbuilder @@ -0,0 +1,33 @@ +json.course_id @course.id +json.course_name @course.name +json.homework_common_id @homework.id +json.homework_common_name @homework.name +json.work_name @student_work.name +json.username @user.full_name +json.user_id @user.id +json.user_login @user.login + +json.work_score @student_work.work_score +if @student_work.ultimate_score + json.adjust_score @student_work.work_score < 0 ? 0 : number_with_precision(@student_work.work_score, precision: 1) +else + json.final_score @student_work.final_score + json.late_penalty @student_work.late_penalty + json.score @student_work.work_score < 0 ? 0 : number_with_precision(@student_work.work_score, precision: 1) +end + +json.challenge_list do + json.array! @challenges do |challenge| + json.id challenge[:id] + json.position challenge[:position] + json.subject challenge[:subject] + json.end_time challenge[:end_time] + json.final_score challenge[:final_score] + json.username challenge[:username] + json.all_score challenge[:all_score] + json.copy_username challenge[:copy_username] + json.copy_end_time challenge[:copy_end_time] + json.code_rate challenge[:code_rate] + json.code_list challenge[:code_list] + end +end diff --git a/app/views/homework_commons/code_review_results.json.jbuilder b/app/views/homework_commons/code_review_results.json.jbuilder new file mode 100644 index 000000000..3759ea1c2 --- /dev/null +++ b/app/views/homework_commons/code_review_results.json.jbuilder @@ -0,0 +1,35 @@ +json.partial! "homework_public_navigation", locals: {homework: @homework, course: @course, user: @current_user} +json.last_review_time @last_review_time +json.publish_immediately @user_course_identity < Course::STUDENT && @homework.publish_immediately(@current_user) +json.end_immediately @user_course_identity < Course::STUDENT && @homework.end_immediately(@current_user) + +# 分班情况 +json.group_info do + json.array! @course_groups do |group| + json.id group.id + json.name group.name + json.members_count group.course_members.count + end +end +# 如果存在未分班的查重则显示未分班 +if @non_course_group + json.on_course_group do + json.id 0 + json.name "未分班" + json.members_count @non_course_group + end +end + +# 抄袭作品数 +json.copy_reviews_count @copy_reviews_count +# 所有作品数 +json.all_reviews_count @all_reviews_count + +json.users_reviews do + json.array! @users_reviews do |review| + json.user_id review.user.id + json.username review.user.full_name + json.student_id review.user.student_id + json.code_rate format("%.1f", review.code_rate) + end +end \ No newline at end of file diff --git a/app/views/homework_commons/create.json.jbuilder b/app/views/homework_commons/create.json.jbuilder new file mode 100644 index 000000000..a706fc586 --- /dev/null +++ b/app/views/homework_commons/create.json.jbuilder @@ -0,0 +1,2 @@ +json.status 0 +json.homework_id @homework.id \ No newline at end of file diff --git a/app/views/homework_commons/create_shixun_homework.json.jbuilder b/app/views/homework_commons/create_shixun_homework.json.jbuilder new file mode 100644 index 000000000..55bec35f0 --- /dev/null +++ b/app/views/homework_commons/create_shixun_homework.json.jbuilder @@ -0,0 +1,2 @@ +json.category_id @category.try(:id).to_i +json.homework_ids @homework_ids \ No newline at end of file diff --git a/app/views/homework_commons/create_subject_homework.json.jbuilder b/app/views/homework_commons/create_subject_homework.json.jbuilder new file mode 100644 index 000000000..208432ec9 --- /dev/null +++ b/app/views/homework_commons/create_subject_homework.json.jbuilder @@ -0,0 +1 @@ +json.homework_ids @homework_ids \ No newline at end of file diff --git a/app/views/homework_commons/edit.json.jbuilder b/app/views/homework_commons/edit.json.jbuilder new file mode 100644 index 000000000..49dc11dd8 --- /dev/null +++ b/app/views/homework_commons/edit.json.jbuilder @@ -0,0 +1,21 @@ +json.course_id @course.id +json.course_name @course.name +json.category @homework.category_info + +json.(@homework, :id, :name, :description, :reference_answer) + +if @homework.homework_type == "group" + json.base_on_project @homework.homework_detail_group.try(:base_on_project) + json.min_num @homework.homework_detail_group.try(:min_num) + json.max_num @homework.homework_detail_group.try(:max_num) + json.has_project @homework.has_relate_project + json.has_commit @homework.has_commit_work +end + +json.attachments @homework.des_attachments do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta} +end + +json.ref_attachments @homework.ref_attachments do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta} +end diff --git a/app/views/homework_commons/end_groups.json.jbuilder b/app/views/homework_commons/end_groups.json.jbuilder new file mode 100644 index 000000000..67722bb04 --- /dev/null +++ b/app/views/homework_commons/end_groups.json.jbuilder @@ -0,0 +1,4 @@ +json.course_groups @course_groups do |group| + json.id group.id + json.name group.name +end \ No newline at end of file diff --git a/app/views/homework_commons/group_list.json.jbuilder b/app/views/homework_commons/group_list.json.jbuilder new file mode 100644 index 000000000..1be1cdab6 --- /dev/null +++ b/app/views/homework_commons/group_list.json.jbuilder @@ -0,0 +1,17 @@ +json.group_list do + json.array! @course_groups do |course_group| + json.id course_group.id + json.name course_group.name + json.works_count homework_works_count @homework, course_group + json.last_review_time last_review_time @homework, course_group + end +end +# 未分班展示情况放在最后 +if @course_groups.count > 0 && @course_groups.count < @limit.to_i + json.ungroup_list do + json.id 0 + json.name "未分班" + json.work_count homework_ungroup_works_count @homework, @ungroup_user_ids + json.last_review_time ungroup_last_review_time @homework + end +end \ No newline at end of file diff --git a/app/views/homework_commons/index.json.jbuilder b/app/views/homework_commons/index.json.jbuilder new file mode 100644 index 000000000..18e601871 --- /dev/null +++ b/app/views/homework_commons/index.json.jbuilder @@ -0,0 +1,47 @@ +json.course_identity @user_course_identity +json.homework_type @homework_type +json.course_public @course.is_public == 1 +json.is_end @course.is_end +json.all_count @all_count +json.published_count @published_count +json.unpublished_count @all_count - @published_count +json.task_count @task_count +json.main_category_id @main_category.try(:id) +json.main_category_name @main_category.try(:module_name) +json.category_id @category.try(:id) +json.category_name @category.try(:name) + +json.homeworks @homework_commons.each do |homework| + homework_private = (@user_course_identity > Course::STUDENT) && !homework.is_public + json.homework_id homework.id + json.name homework.name + json.private_icon homework_private + json.status homework_curr_status(homework, @user_course_identity, @course, @member, @member&.teacher_course_groups)[:status] + json.status_time homework_curr_status(homework, @user_course_identity, @course, @member, @member&.teacher_course_groups)[:time] + json.time_status homework_curr_status(homework, @user_course_identity, @course, @member, @member&.teacher_course_groups)[:time_status] + json.allow_late homework.allow_late + + unless homework_curr_status(homework, @user_course_identity, @course, @member, @member&.teacher_course_groups)[:status].include?("未发布") + json.commit_count studentwork_count homework, 1, @user.id + json.uncommit_count studentwork_count homework, 0, @user.id + end + + if @user_course_identity < Course::STUDENT + if homework.homework_type == "practice" + json.shixun_identifier homework.shixuns.first.try(:identifier) + end + elsif @user_course_identity == Course::STUDENT + if homework.homework_type == "practice" + # json.challenge_count homework.shixuns.first.try(:challenges_count).to_i + current_myshixun = homework.user_work(@user.id).try(:myshixun) + # json.game_count current_myshixun ? current_myshixun.exec_count : 0 + json.task_operation task_operation_url(current_myshixun, homework.shixuns.first) + else + work = homework.user_work(@user.id) + json.work_id work.try(:id) + json.work_status student_work_status(homework, @user.id, @course, work) + json.un_commit_work !work.present? || work.work_status == 0 + end + end +end + diff --git a/app/views/homework_commons/new.json.jbuilder b/app/views/homework_commons/new.json.jbuilder new file mode 100644 index 000000000..82a5d78fa --- /dev/null +++ b/app/views/homework_commons/new.json.jbuilder @@ -0,0 +1,3 @@ +json.course_id @course.id +json.course_name @course.name +json.category @course.category_info(@homework_type == 1 ? "common_homework" : "group_homework") \ No newline at end of file diff --git a/app/views/homework_commons/publish_groups.json.jbuilder b/app/views/homework_commons/publish_groups.json.jbuilder new file mode 100644 index 000000000..67722bb04 --- /dev/null +++ b/app/views/homework_commons/publish_groups.json.jbuilder @@ -0,0 +1,4 @@ +json.course_groups @course_groups do |group| + json.id group.id + json.name group.name +end \ No newline at end of file diff --git a/app/views/homework_commons/reference_answer.json.jbuilder b/app/views/homework_commons/reference_answer.json.jbuilder new file mode 100644 index 000000000..829b659a9 --- /dev/null +++ b/app/views/homework_commons/reference_answer.json.jbuilder @@ -0,0 +1,12 @@ +json.partial! "homework_public_navigation", locals: {homework: @homework, course: @course, user: @current_user} + +json.partial! "homework_btn_check", locals: {identity: @user_course_identity, homework: @homework, user: @current_user} + +json.partial! "student_btn_check", locals: {identity: @user_course_identity, homework: @homework, work: @work} + +json.reference_answer @homework.reference_answer + +# 附件 +json.attachments @attachments do |attachment| + json.partial! "attachments/attachment_simple", locals: {attachment: attachment} +end \ No newline at end of file diff --git a/app/views/homework_commons/settings.json.jbuilder b/app/views/homework_commons/settings.json.jbuilder new file mode 100644 index 000000000..75604de0c --- /dev/null +++ b/app/views/homework_commons/settings.json.jbuilder @@ -0,0 +1,40 @@ +json.partial! "homework_public_navigation", locals: {homework: @homework, course: @course, user: @user} + +json.partial! "homework_btn_check", locals: {identity: @user_course_identity, homework: @homework, user: @user} + +json.partial! "student_btn_check", locals: {identity: @user_course_identity, homework: @homework, work: @work} + +json.(@homework, :unified_setting, :publish_time, :end_time, :late_penalty, :allow_late, :late_time, :work_public, + :score_open, :answer_public) + +json.group_settings @course.course_groups do |group| + json.group_id group.id + json.group_name group.name + json.publish_time group_homework_setting(@homework, group.id).try(:publish_time) + json.end_time group_homework_setting(@homework, group.id).try(:end_time) +end + +if @homework.homework_type == "practice" + json.shixun_identifier @homework.shixuns.first.try(:identifier) + json.(@homework, :work_efficiency, :eff_score) + json.(@homework.homework_detail_manual, :answer_open_evaluation, :shixun_evaluation) + + total_exp = 0 + json.challenge_settings @homework.shixuns.first.try(:challenges).each do |challenge| + json.challenge_id challenge.id + json.challenge_name challenge.subject + json.checked challenge_setting(@homework, challenge.id).present? + json.challenge_score challenge_setting(@homework, challenge.id).try(:score).to_f + json.challenge_exp challenge.score + total_exp += challenge.score + end + + json.shixun_exp total_exp + +elsif @homework.homework_type == "normal" || @homework.homework_type == "group" + json.(@homework, :anonymous_comment, :anonymous_appeal) + json.(@homework.homework_detail_manual, :evaluation_start, :evaluation_end, :evaluation_num, :absence_penalty, + :appeal_time, :appeal_penalty, :ta_mode, :final_mode, :te_proportion, :ta_proportion) + + json.st_proportion homework_st_proportion(@homework) +end diff --git a/app/views/homework_commons/shixuns.json.jbuilder b/app/views/homework_commons/shixuns.json.jbuilder new file mode 100644 index 000000000..129a0b6d3 --- /dev/null +++ b/app/views/homework_commons/shixuns.json.jbuilder @@ -0,0 +1,12 @@ +json.tags @tags do |tag| + json.tag_id tag.id + json.tag_name tag.name +end + +json.shixun_list do + json.partial! 'shixuns/choose_shixun', locals: {shixuns: @shixuns} +end + +json.shixuns_count @shixuns_count + +json.partial! 'homework_commons/second_category', locals: {main_catrgory: @main_catrgory, homework_category: @homework_category} \ No newline at end of file diff --git a/app/views/homework_commons/show.json.jbuilder b/app/views/homework_commons/show.json.jbuilder new file mode 100644 index 000000000..e78166fe0 --- /dev/null +++ b/app/views/homework_commons/show.json.jbuilder @@ -0,0 +1,26 @@ +json.partial! "homework_public_navigation", locals: {homework: @homework, course: @course, user: @user} + +json.partial! "homework_btn_check", locals: {identity: @user_course_identity, homework: @homework, user: @user} + +json.partial! "student_btn_check", locals: {identity: @user_course_identity, homework: @homework, work: @work} + +json.description @homework.description + +# 实训作业才有说明 +if @homework.homework_type == "practice" + json.explanation @homework.explanation +end + +# 附件 +json.attachments @attachments do |attachment| + json.partial! "attachments/attachment_simple", locals: {attachment: attachment} +end + +# 分组要求 +if @homework.homework_type == "group" + json.group_info do + json.max_num @homework.homework_detail_group.try(:max_num) + json.min_num @homework.homework_detail_group.try(:min_num) + json.base_on_project @homework.homework_detail_group.try(:base_on_project) + end +end \ No newline at end of file diff --git a/app/views/homework_commons/show_comment.json.jbuilder b/app/views/homework_commons/show_comment.json.jbuilder new file mode 100644 index 000000000..51fed604f --- /dev/null +++ b/app/views/homework_commons/show_comment.json.jbuilder @@ -0,0 +1,14 @@ +# 帖子信息 +json.homework_user_id @homework.user_id +json.messages_count @messages_count +json.parent_messages_count @parent_messages_count +json.comments @messages do |message| + json.partial! "graduation_topics/graduation_comments", locals: {message: message, current_user: @current_user, + identity: @user_course_identity} + if @parent.nil? + json.children message.children(1, 5) do |c_message| + json.partial! 'graduation_topics/graduation_comments', locals: { message: c_message, current_user: @current_user, + identity: @user_course_identity} + end + end +end \ No newline at end of file diff --git a/app/views/homework_commons/subjects.json.jbuilder b/app/views/homework_commons/subjects.json.jbuilder new file mode 100644 index 000000000..ea63f2125 --- /dev/null +++ b/app/views/homework_commons/subjects.json.jbuilder @@ -0,0 +1,13 @@ +json.tags @tags do |tag| + json.tag_id tag.id + json.tag_name tag.name +end + +json.subject_list @subjects do |subject| + json.subject_id subject.id + json.subject_name subject.name + json.shixun_count subject.shixuns.unhidden.size + json.myshixun_count subject.shixuns.pluck(:myshixuns_count).sum +end + +json.subjects_count @subjects_count \ No newline at end of file diff --git a/app/views/homework_commons/works_list.json.jbuilder b/app/views/homework_commons/works_list.json.jbuilder new file mode 100644 index 000000000..1d3110604 --- /dev/null +++ b/app/views/homework_commons/works_list.json.jbuilder @@ -0,0 +1,145 @@ +json.partial! "homework_public_navigation", locals: {homework: @homework, course: @course, user: @current_user} + +json.partial! "homework_btn_check", locals: {identity: @user_course_identity, homework: @homework, user: @current_user} + +json.partial! "student_btn_check", locals: {identity: @user_course_identity, homework: @homework, work: @work} + +json.work_count @work_count +json.all_member_count @all_member_count +json.course_group_count @course.course_groups_count + +json.ta_mode @homework_detail_manual.ta_mode + +json.is_evaluation @is_evaluation ? @is_evaluation : false + +json.work_public @homework.work_public + +if @user_course_identity < Course::STUDENT + + # 教师身份的评阅、提交状态、分班过滤 + if @homework.homework_type != "practice" + json.teacher_comment teacher_comment @homework, @current_user.id + end + json.task_status homework_status @homework, @current_user.id + json.course_group_info course_group_info @course, @current_user.id + +elsif @user_course_identity == Course::STUDENT + json.commit_count studentwork_count @homework, 1, @current_user.id + json.uncommit_count studentwork_count @homework, 0, @current_user.id + json.left_time left_time @homework, @current_user.id + + if @homework.homework_type == "practice" + json.(@work, :id, :work_status, :update_time, :late_penalty, :ultimate_score) + + json.cost_time @work.myshixun.try(:total_cost_time) + json.work_score work_score_format(@work.work_score, true, @homework.score_open) + json.final_score work_score_format(@work.final_score, true, @homework.score_open) + json.efficiency work_score_format(@work.efficiency, true, @homework.score_open) + json.eff_score work_score_format(@work.eff_score, true, @homework.score_open) + json.complete_count @work.myshixun.try(:passed_count) + else + json.(@work, :id, :work_status, :update_time, :late_penalty, :absence_penalty, :appeal_penalty, :ultimate_score) + + json.work_score work_score_format(@work.work_score, true, @homework.score_open) + json.final_score work_score_format(@work.final_score, true, @homework.score_open) + json.teacher_score work_score_format(@work.teacher_score, true, @homework.score_open) + json.student_score work_score_format(@work.student_score, true, @homework.score_open) + json.teaching_asistant_score work_score_format(@work.teaching_asistant_score, true, @homework.score_open) + + json.ta_comment_count @work.ta_comment_count + + if @homework.anonymous_comment + json.student_comment_count @work.student_comment_num + end + + if @homework.anonymous_appeal + json.appeal_all_count @work.appeal_all_count + json.appeal_deal_count @work.appeal_deal_count + end + + if @homework.homework_type == "group" + if @homework.homework_detail_group.base_on_project + json.project_info project_info @work, @current_user, @user_course_identity + end + json.work_group @work.work_group_name + end + + end + json.user_login @work.user.login + json.student_id @work.user.student_id + json.user_name @work.user.real_name + json.group_name @member.course_group_name +end + +if @homework.homework_type == "practice" + json.challenges_count @shixun.challenges_count + json.work_efficiency @homework.work_efficiency + + json.student_works @student_works.each do |work| + json.(work, :id, :work_status, :update_time, :late_penalty, :ultimate_score) + + json.work_score work_score_format(work.work_score, @current_user == work.user, @homework.score_open) + json.final_score work_score_format(work.final_score, @current_user == work.user, @homework.score_open) + json.efficiency work_score_format(work.efficiency, @current_user == work.user, @homework.score_open) + json.eff_score work_score_format(work.eff_score, @current_user == work.user, @homework.score_open) + + json.cost_time work.myshixun.try(:total_cost_time) + json.complete_count work.myshixun.try(:passed_count) + json.user_login work.user.try(:login) + json.user_name work.user.try(:real_name) + json.student_id work.user.try(:student_id) + json.group_name @course.course_student(work.user_id).try(:course_group_name) + end +elsif @homework.homework_type == "group" || @homework.homework_type == "normal" + json.anonymous_comment @homework.anonymous_comment + json.anonymous_appeal @homework.anonymous_appeal + + json.student_works @student_works.each do |work| + + if @is_evaluation + json.(work, :id, :work_status, :update_time) + + json.student_score work_score_format(anon_comments(@current_user, work.id).last.try(:score), false, true) + # json.student_comment_count anon_comments(@current_user, work.id).count + else + json.(work, :id, :work_status, :update_time, :work_score, :final_score, :teacher_score, :student_score, + :teaching_asistant_score, :late_penalty, :absence_penalty, :appeal_penalty, :ultimate_score) + + json.work_score work_score_format(work.work_score, @current_user == work.user, @homework.score_open) + json.final_score work_score_format(work.final_score, @current_user == work.user, @homework.score_open) + json.teacher_score work_score_format(work.teacher_score, @current_user == work.user, @homework.score_open) + json.student_score work_score_format(work.student_score, @current_user == work.user, @homework.score_open) + json.teaching_asistant_score work_score_format(work.teaching_asistant_score, @current_user == work.user, @homework.score_open) + + # 助教评分次数 + json.ta_comment_count work.ta_comment_count + + # 作品匿评条数 + if @homework.anonymous_comment + json.student_comment_count @homework_detail_manual.comment_status > 2 ? work.student_comment_num : 0 + end + + json.student_id work.user.try(:student_id) + json.group_name @course.course_student(work.user_id).try(:course_group_name) + if @homework.homework_type == "group" + if @homework.homework_detail_group.base_on_project + json.project_info project_info work, @current_user, @user_course_identity + end + json.work_group work.work_group_name + end + end + + # 申诉条数 + if @homework.anonymous_appeal + json.appeal_all_count work.appeal_all_count + json.appeal_deal_count work.appeal_deal_count + end + + json.user_login @is_evaluation ? "--" : work.user.try(:login) + json.user_name @is_evaluation ? "匿名" : work.user.try(:real_name) + + end +end + + + diff --git a/app/views/homework_commons/works_list.xlsx.axlsx b/app/views/homework_commons/works_list.xlsx.axlsx new file mode 100644 index 000000000..3809c6264 --- /dev/null +++ b/app/views/homework_commons/works_list.xlsx.axlsx @@ -0,0 +1,17 @@ + +wb = xlsx_package.workbook +wb.styles do |s| + sz_all = s.add_style :border => { :style => :thin, :color =>"000000" },:alignment => {:horizontal => :center} + blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 20,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {:horizontal => :center} + wb.add_worksheet(:name => "学生成绩") do |sheet| + sheet.sheet_view.show_grid_lines = false + sheet.add_row table_columns, :style => blue_cell + if task_users.count > 0 + task_users.each do |user| + sheet.add_row user, :style => sz_all + end #each_widh_index + end + sheet.column_widths *([20]*sheet.column_info.count) + sheet.column_info.first.width = 12 + end #add_worksheet +end \ No newline at end of file diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 000000000..9be96a548 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 000000000..aab62e324 --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/app/views/memos/_memo.json.jbuilder b/app/views/memos/_memo.json.jbuilder new file mode 100644 index 000000000..22adba5fc --- /dev/null +++ b/app/views/memos/_memo.json.jbuilder @@ -0,0 +1,8 @@ +json.(memo, :id, :subject, :is_md, :content, :sticky, :reward, :viewed_count) + +json.tag memo.tag_repertoires.map(&:name) +json.time memo.created_at +json.replies_count memo.all_replies_count +json.attachments_list [] +json.user_praise memo.praise_tread.user_liker(@user.try(:id)) ? true : false +json.memo_praise_count = memo.praise_tread.liker.count diff --git a/app/views/memos/_memo_list.json.jbuilder b/app/views/memos/_memo_list.json.jbuilder new file mode 100644 index 000000000..8da056e92 --- /dev/null +++ b/app/views/memos/_memo_list.json.jbuilder @@ -0,0 +1,9 @@ +json.(memo, :id, :subject, :author_id, :sticky, + :updated_at, :language, :reward, :all_replies_count, + :viewed_count, :forum_id) +json.praise_count memo.praise_tread.praise_count +json.replies_count memo.all_replies_count +json.tag memo.tag_repertoires.map(&:name) +json.user_name memo.author.full_name +json.login memo.author.login +json.image_url url_to_avatar(memo.author) \ No newline at end of file diff --git a/app/views/memos/_memo_recommend.json.jbuilder b/app/views/memos/_memo_recommend.json.jbuilder new file mode 100644 index 000000000..883c82863 --- /dev/null +++ b/app/views/memos/_memo_recommend.json.jbuilder @@ -0,0 +1 @@ +json(memo, :id, :subject, :language, :forum_id, :all_replies_count) \ No newline at end of file diff --git a/app/views/memos/_replies_list.json.jbuilder b/app/views/memos/_replies_list.json.jbuilder new file mode 100644 index 000000000..3dae61813 --- /dev/null +++ b/app/views/memos/_replies_list.json.jbuilder @@ -0,0 +1,27 @@ +json.id memo.id +json.content memo.content +json.time time_from_now(memo.created_at) +json.user_id memo.author_id +json.image_url url_to_avatar(memo.author) +json.username memo.author.full_name +json.reward memo.reward +json.hidden memo.hidden +json.permission @user.manager_of_memo?(memo) +json.praise_count memo.praise_tread.liker.count +json.user_praise memo.praise_tread.select{|pt| pt.user_id == @user.id}.length > 0 +json.user_login memo.author.login +json.admin @user.admin + +json.children do + json.array! memo.children_of_reply do |child| + json.id child.id + json.content child.content + json.time time_from_now(child.created_at) + json.image_url url_to_avatar(child.author) + json.username child.author.full_name + json.hidden child.hidden + json.permission @user.manager_of_memo?(memo) + json.user_login child.author.try(:login) + json.user_id child.author.try(:id) + end +end diff --git a/app/views/memos/create.json.jbuilder b/app/views/memos/create.json.jbuilder new file mode 100644 index 000000000..fb3d5083e --- /dev/null +++ b/app/views/memos/create.json.jbuilder @@ -0,0 +1,3 @@ +json.status @status +json.message @message +json.memo_id @memo.try(:id) \ No newline at end of file diff --git a/app/views/memos/index.json.jbuilder b/app/views/memos/index.json.jbuilder new file mode 100644 index 000000000..8a90e374a --- /dev/null +++ b/app/views/memos/index.json.jbuilder @@ -0,0 +1,29 @@ +## +# memo_list: 帖子列表 +# memo_count: 帖子总数 +# hot_memos: 热门帖子 +# hot_tags: 热门标签 +# recommend_shixuns: 推荐实训 +# current_user: 当前用户信息 +# tidding_count: 消息数 +# # + +json.memo_list do + json.array! @memos do |memo| + json.partial! "memos/memo_list", locals: {memo: memo} + end +end + +json.memo_count @memos_count + +json.hot_memos do + json.array! @hot_memos do |hm| + json.(hm, :id, :subject, :language, :forum_id, :all_replies_count) + json.replies_count hm.all_replies_count + json.praise_count hm.praise_tread.praise_count + json.tag hm.tag_repertoires.map(&:name) + end +end + +json.hot_tags @tags_info.map{|o| o.attributes.dup.except("cnt", "id")} + diff --git a/app/views/memos/new.json.jbuilder b/app/views/memos/new.json.jbuilder new file mode 100644 index 000000000..14313b2ac --- /dev/null +++ b/app/views/memos/new.json.jbuilder @@ -0,0 +1,3 @@ +json.tag_list @tag_list +json.csrf_token @csrf_token + diff --git a/app/views/memos/show.json.jbuilder b/app/views/memos/show.json.jbuilder new file mode 100644 index 000000000..7acd6ba4a --- /dev/null +++ b/app/views/memos/show.json.jbuilder @@ -0,0 +1,18 @@ +json.partial! "memos/memo", memo: @memo + +json.memo_replies do + json.array! @memos do |memo| + json.partial! "memos/replies_list", memo: memo + end +end + +json.author_info do + json.username @memo.author.full_name + # TODO watched_by 插件没法用,等把lib文件载入后在打开代码 + #json.watched @memo.author.watched_by?(@user) + json.image_url url_to_avatar(@memo.author) + json.identity @memo.author.identity + json.login @memo.author.login + json.user_id @memo.author.id +end + diff --git a/app/views/messages/_action_ids.json.jbuilder b/app/views/messages/_action_ids.json.jbuilder new file mode 100644 index 000000000..d41750a61 --- /dev/null +++ b/app/views/messages/_action_ids.json.jbuilder @@ -0,0 +1,3 @@ +json.course_id message.board.course.id +json.board_id message.board.id +json.board_name message.board.fix_name \ No newline at end of file diff --git a/app/views/messages/_content.json.jbuilder b/app/views/messages/_content.json.jbuilder new file mode 100644 index 000000000..5e1d9088b --- /dev/null +++ b/app/views/messages/_content.json.jbuilder @@ -0,0 +1 @@ +json.content content \ No newline at end of file diff --git a/app/views/messages/_list.json.jbuilder b/app/views/messages/_list.json.jbuilder new file mode 100644 index 000000000..6e3cbf72f --- /dev/null +++ b/app/views/messages/_list.json.jbuilder @@ -0,0 +1,8 @@ +json.replies do + json.array! messages do |message| + arr = message.children.preload_messages.by_user(@current_user) + json.total_count arr.size + json.partial! "messages/message_detail", message: message + json.partial! 'messages/list', messages: arr.ordered(sort: 1).limit(5) + end +end diff --git a/app/views/messages/_message.json.jbuilder b/app/views/messages/_message.json.jbuilder new file mode 100644 index 000000000..bff2413cd --- /dev/null +++ b/app/views/messages/_message.json.jbuilder @@ -0,0 +1 @@ +json.extract! message, :id, :parent_id, :subject, :created_on, :total_replies_count, :total_praises_count, :praises_count, :visits, :sticky, :is_hidden, :is_public diff --git a/app/views/messages/_message_detail.json.jbuilder b/app/views/messages/_message_detail.json.jbuilder new file mode 100644 index 000000000..38532429f --- /dev/null +++ b/app/views/messages/_message_detail.json.jbuilder @@ -0,0 +1,6 @@ +json.partial! "messages/message_simple", message: message +json.partial! "commons/like", message: message +json.content message.message_detail.try(:content) +json.author do + json.partial! "users/user_simple", user: message.author +end \ No newline at end of file diff --git a/app/views/messages/_message_simple.jbuilder b/app/views/messages/_message_simple.jbuilder new file mode 100644 index 000000000..9409e15da --- /dev/null +++ b/app/views/messages/_message_simple.jbuilder @@ -0,0 +1 @@ +json.extract! message, :id, :board_id, :created_on, :praises_count, :has_replies, :is_hidden \ No newline at end of file diff --git a/app/views/messages/bulk_delete.json.jbuilder b/app/views/messages/bulk_delete.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/messages/bulk_delete.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/messages/bulk_move.json.jbuilder b/app/views/messages/bulk_move.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/messages/bulk_move.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/messages/bulk_public.json.jbuilder b/app/views/messages/bulk_public.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/messages/bulk_public.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/messages/bulk_send.jbuilder b/app/views/messages/bulk_send.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/messages/bulk_send.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/messages/create.json.jbuilder b/app/views/messages/create.json.jbuilder new file mode 100644 index 000000000..fa8d4660a --- /dev/null +++ b/app/views/messages/create.json.jbuilder @@ -0,0 +1,5 @@ +json.partial! "commons/success" +json.data do + json.partial! "messages/action_ids", message: @message + json.id @message.id +end \ No newline at end of file diff --git a/app/views/messages/destroy.json.jbuilder b/app/views/messages/destroy.json.jbuilder new file mode 100644 index 000000000..408793831 --- /dev/null +++ b/app/views/messages/destroy.json.jbuilder @@ -0,0 +1,4 @@ +json.partial! "commons/success" +json.data do + json.id @message.id +end \ No newline at end of file diff --git a/app/views/messages/index.json.jbuilder b/app/views/messages/index.json.jbuilder new file mode 100644 index 000000000..026e193a6 --- /dev/null +++ b/app/views/messages/index.json.jbuilder @@ -0,0 +1,15 @@ +json.partial! "commons/success" +json.data do + json.id @board.id + json.name @board.fix_name + json.parent_id @board.parent_id + json.total_count @messages.total_count + json.messages do + json.array! @messages do |message| + json.partial! "messages/message", message: message + json.author do + json.partial! "users/user_simple", user: message.author + end + end + end +end diff --git a/app/views/messages/reply.json.jbuilder b/app/views/messages/reply.json.jbuilder new file mode 100644 index 000000000..38ad9d735 --- /dev/null +++ b/app/views/messages/reply.json.jbuilder @@ -0,0 +1,7 @@ +json.partial! "commons/success" +json.data do + json.id @reply.id + json.author do + json.partial! "users/user_simple", user: @reply.author + end +end diff --git a/app/views/messages/reply_list.json.jbuilder b/app/views/messages/reply_list.json.jbuilder new file mode 100644 index 000000000..2b7ef7178 --- /dev/null +++ b/app/views/messages/reply_list.json.jbuilder @@ -0,0 +1,9 @@ +json.partial! "commons/success" +json.data do + json.user_course_identity @current_user.course_identity(@message.board.course) + json.id @message.id + json.total_count @messages.total_count + json.total_replies_count @message.total_replies_count + json.partial! "commons/like", message: @message + json.partial! 'messages/list', messages: @messages +end diff --git a/app/views/messages/show.json.jbuilder b/app/views/messages/show.json.jbuilder new file mode 100644 index 000000000..83d68f115 --- /dev/null +++ b/app/views/messages/show.json.jbuilder @@ -0,0 +1,14 @@ +json.partial! "commons/success" +json.cache! ['v1', @message, @attachment_size, @current_user.course_identity(@message.board.course)] do + json.data do + json.partial! "messages/action_ids", message: @message + json.partial! "messages/message", message: @message + json.partial! "messages/content", content: @message.message_detail.try(:content) + json.author do + json.partial! "users/user_simple", user: @message.author + end + json.attachments do + json.array! @message.attachments, partial: 'attachments/attachment_simple', as: :attachment + end + end +end diff --git a/app/views/messages/sticky_top.json.jbuilder b/app/views/messages/sticky_top.json.jbuilder new file mode 100644 index 000000000..cc73869d9 --- /dev/null +++ b/app/views/messages/sticky_top.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" diff --git a/app/views/messages/update.json.jbuilder b/app/views/messages/update.json.jbuilder new file mode 100644 index 000000000..fa8d4660a --- /dev/null +++ b/app/views/messages/update.json.jbuilder @@ -0,0 +1,5 @@ +json.partial! "commons/success" +json.data do + json.partial! "messages/action_ids", message: @message + json.id @message.id +end \ No newline at end of file diff --git a/app/views/myshixuns/challenges.json.jbuilder b/app/views/myshixuns/challenges.json.jbuilder new file mode 100644 index 000000000..802c2b561 --- /dev/null +++ b/app/views/myshixuns/challenges.json.jbuilder @@ -0,0 +1,9 @@ +json.array! @games do |game| + challenge = game.challenge + json.partial! 'challenges/challenge', locals: { challenge: challenge } + json.status game.status + json.star game.star + json.identifier game.identifier + json.get_gold game.user_get_gold_and_experience(@shixun_status, challenge)[0] + json.get_experience game.user_get_gold_and_experience(@shixun_status, challenge)[1] +end \ No newline at end of file diff --git a/app/views/myshixuns/file_content.json.jbuilder b/app/views/myshixuns/file_content.json.jbuilder new file mode 100644 index 000000000..d4cccf0a7 --- /dev/null +++ b/app/views/myshixuns/file_content.json.jbuilder @@ -0,0 +1 @@ +json.content @content \ No newline at end of file diff --git a/app/views/myshixuns/html_content.html.erb b/app/views/myshixuns/html_content.html.erb new file mode 100644 index 000000000..0fb51d1b8 --- /dev/null +++ b/app/views/myshixuns/html_content.html.erb @@ -0,0 +1 @@ +<%= @contents.html_safe %> \ No newline at end of file diff --git a/app/views/myshixuns/html_content.json.jbuilder b/app/views/myshixuns/html_content.json.jbuilder new file mode 100644 index 000000000..be38d6526 --- /dev/null +++ b/app/views/myshixuns/html_content.json.jbuilder @@ -0,0 +1 @@ +json.content @contents \ No newline at end of file diff --git a/app/views/myshixuns/repository.json.jbuilder b/app/views/myshixuns/repository.json.jbuilder new file mode 100644 index 000000000..7b9f0cd5a --- /dev/null +++ b/app/views/myshixuns/repository.json.jbuilder @@ -0,0 +1 @@ +json.trees @trees diff --git a/app/views/myshixuns/reset_my_game.json.jbuilder b/app/views/myshixuns/reset_my_game.json.jbuilder new file mode 100644 index 000000000..f232122ae --- /dev/null +++ b/app/views/myshixuns/reset_my_game.json.jbuilder @@ -0,0 +1 @@ +json.shixun_identifier @shixun.identifier \ No newline at end of file diff --git a/app/views/myshixuns/update_file.json.jbuilder b/app/views/myshixuns/update_file.json.jbuilder new file mode 100644 index 000000000..c647927c4 --- /dev/null +++ b/app/views/myshixuns/update_file.json.jbuilder @@ -0,0 +1,3 @@ +json.content @content +json.resubmit "#{@resubmit}" +json.content_modified @hide_code ? false : @content_modified diff --git a/app/views/poll_questions/_poll_questions.json.jbuilder b/app/views/poll_questions/_poll_questions.json.jbuilder new file mode 100644 index 000000000..9540d3cbb --- /dev/null +++ b/app/views/poll_questions/_poll_questions.json.jbuilder @@ -0,0 +1,18 @@ +json.question do + json.id question.id + json.question_number question.question_number + json.question_title question.question_title + json.question_type question.question_type + json.is_necessary question.is_necessary + if question.question_type == 2 + json.max_choices question.max_choices + json.min_choices question.min_choices + end + json.answers do + json.array! answers do | a| + json.answer_id a.id + json.answer_position a.answer_position + json.answer_text a.answer_text.nil? ? "other_choices" : a.answer_text ## + end + end +end \ No newline at end of file diff --git a/app/views/poll_questions/create.json.jbuilder b/app/views/poll_questions/create.json.jbuilder new file mode 100644 index 000000000..f25bee59c --- /dev/null +++ b/app/views/poll_questions/create.json.jbuilder @@ -0,0 +1,4 @@ +json.partial! "commons/success" +json.data do + json.id @poll_question.id +end \ No newline at end of file diff --git a/app/views/poll_questions/edit.json.jbuilder b/app/views/poll_questions/edit.json.jbuilder new file mode 100644 index 000000000..f80665501 --- /dev/null +++ b/app/views/poll_questions/edit.json.jbuilder @@ -0,0 +1,3 @@ +json.partial! "commons/success" + +json.partial! "poll_questions/poll_questions", question: @poll_question,answers:@poll_answers diff --git a/app/views/poll_questions/new.json.jbuilder b/app/views/poll_questions/new.json.jbuilder new file mode 100644 index 000000000..64cdb852d --- /dev/null +++ b/app/views/poll_questions/new.json.jbuilder @@ -0,0 +1 @@ +json.extract! @poll_question,:question_title,:question_type,:is_necessary,:question_number,:max_choices,:min_choices \ No newline at end of file diff --git a/app/views/poll_questions/show.json.jbuilder b/app/views/poll_questions/show.json.jbuilder new file mode 100644 index 000000000..9e034e49f --- /dev/null +++ b/app/views/poll_questions/show.json.jbuilder @@ -0,0 +1,4 @@ +json.partial! "commons/success" +json.partial! "poll_questions/poll_questions", question: @poll_question,answers:@poll_answers + + diff --git a/app/views/poll_questions/update.json.jbuilder b/app/views/poll_questions/update.json.jbuilder new file mode 100644 index 000000000..f25bee59c --- /dev/null +++ b/app/views/poll_questions/update.json.jbuilder @@ -0,0 +1,4 @@ +json.partial! "commons/success" +json.data do + json.id @poll_question.id +end \ No newline at end of file diff --git a/app/views/poll_votes/_poll_votes.json.jbuilder b/app/views/poll_votes/_poll_votes.json.jbuilder new file mode 100644 index 000000000..da9b0f390 --- /dev/null +++ b/app/views/poll_votes/_poll_votes.json.jbuilder @@ -0,0 +1,29 @@ +json.question do + json.id question.id + json.question_number question.question_number + json.question_title question.question_title + json.question_type question.question_type + json.is_necessary question.is_necessary + if question.question_type == 2 + json.max_choices question.max_choices + json.min_choices question.min_choices + end + if question.question_type == 2 || question.question_type == 1 # 选择题 + # vote_text_id = votes.find_vote_text.pluck(:poll_answer_id) # 其他选项的输入 + # vote_choose_answer = votes.pluck(:poll_answer_id).reject(&:blank?) - vote_text_id + vote_choose_answer = votes.pluck(:poll_answer_id).reject(&:blank?) + json.answers do + json.array! answers do | a| + vote_choose_boolean = vote_choose_answer.include?(a.id) ? true : false + json.answer_id a.id + json.answer_position a.answer_position + json.answer_text a.answer_text.nil? ? "other_choices" : a.answer_text + json.answer_boolean vote_choose_boolean #判断用户的回答是否为该答案 + end + end + json.poll_answer_ids vote_choose_answer + end + if votes.find_vote_text.present? + json.poll_vote_texts votes.pluck(:vote_text).reject(&:blank?).first + end +end \ No newline at end of file diff --git a/app/views/poll_votes/create.json.jbuilder b/app/views/poll_votes/create.json.jbuilder new file mode 100644 index 000000000..7608f7ab4 --- /dev/null +++ b/app/views/poll_votes/create.json.jbuilder @@ -0,0 +1,6 @@ +json.partial! "commons/success" +json.poll_vote do + json.question_number @current_question_number # 当前问题的位置 + json.question_necessary @current_question_necessary #当前问题是否回答 + json.question_status @current_question_status #当前问题是否回答 +end \ No newline at end of file diff --git a/app/views/polls/_commit_answers_result.json.jbuilder b/app/views/polls/_commit_answers_result.json.jbuilder new file mode 100644 index 000000000..51e84000b --- /dev/null +++ b/app/views/polls/_commit_answers_result.json.jbuilder @@ -0,0 +1,27 @@ +question_vote_user = poll_votes_count(question_votes,@poll_commit_ids) #提交者中该问题的回答者人数 + +json.question do + json.id question.id + json.question_number question.question_number + json.question_title question.question_title + json.question_type question.question_type + json.is_necessary question.is_necessary + if question.question_type == 2 + json.max_choices question.max_choices + json.min_choices question.min_choices + end + json.commit_users_count question_vote_user + + json.answers do + json.array! answers do |a| + answer_users_count = poll_votes_count(a.poll_votes,@poll_commit_ids) + json.answer_text a.answer_text.nil? ? "other_choices" : a.answer_text ## + json.answer_position a.answer_position + json.answer_users_count answer_users_count #该答案的填写人数(已提交) + json.answer_percent question_vote_user.present? ? (answer_users_count.to_f / question_vote_user.to_f).round(3) : 0.0 + end + end + if question_votes.find_vote_text.present? + json.vote_text question_votes.pluck(:vote_text).reject(&:blank?) #问题的回答是否有用户手动输入的内容 + end +end \ No newline at end of file diff --git a/app/views/polls/_course_name.json.jbuilder b/app/views/polls/_course_name.json.jbuilder new file mode 100644 index 000000000..d05bec3e3 --- /dev/null +++ b/app/views/polls/_course_name.json.jbuilder @@ -0,0 +1 @@ +json.extract! course,:id,:name \ No newline at end of file diff --git a/app/views/polls/_poll_detail.json.jbuilder b/app/views/polls/_poll_detail.json.jbuilder new file mode 100644 index 000000000..b4b0f319a --- /dev/null +++ b/app/views/polls/_poll_detail.json.jbuilder @@ -0,0 +1,9 @@ +json.extract! poll, :id, :polls_name,:is_public,:created_at + +json.polls_status poll_status +json.lock_status lock_icon +json.publish_time poll_publish_time # 问卷的发布时间 +json.end_time poll_end_time # 问卷的截止时间 +json.poll_answer poll_answer # 已提交问卷的用户 +json.poll_unanswer poll_unanswer # 已查看问卷/开始答题,但是未提交问卷的用户 +json.current_status current_status #答题的状态 diff --git a/app/views/polls/cancel_publish_modal.json.jbuilder b/app/views/polls/cancel_publish_modal.json.jbuilder new file mode 100644 index 000000000..121a730f8 --- /dev/null +++ b/app/views/polls/cancel_publish_modal.json.jbuilder @@ -0,0 +1,13 @@ +json.partial! "commons/success" + +if @course_groups.size >0 + json.on_commiting @course_groups.size #未发布的分班 + json.course_info do + json.array! @course_groups do |group| + json.course_group_id group.id + json.course_group_name group.name + end + end +else + json.on_commiting 0 +end \ No newline at end of file diff --git a/app/views/polls/commit_result.json.jbuilder b/app/views/polls/commit_result.json.jbuilder new file mode 100644 index 000000000..51f70afa2 --- /dev/null +++ b/app/views/polls/commit_result.json.jbuilder @@ -0,0 +1,22 @@ +json.course do + json.partial! "polls/course_name",locals:{course:@course} +end + +json.question_types do + json.q_counts @poll_questions_count + json.q_singles @poll_question_singles + json.q_doubles @poll_question_doubles + json.q_mains @poll_question_mains +end + +if @poll_questions_count > 0 + json.questions do + json.array! @poll_questions do |question| + json.partial! "polls/commit_answers_result", question: question, + answers:question.poll_answers, + question_votes:question.poll_votes #问题的全部答案 + end + end +else + json.questions [] +end diff --git a/app/views/polls/commit_result.xlsx.axlsx b/app/views/polls/commit_result.xlsx.axlsx new file mode 100644 index 000000000..ce1817f76 --- /dev/null +++ b/app/views/polls/commit_result.xlsx.axlsx @@ -0,0 +1,96 @@ + +wb = xlsx_package.workbook +wb.use_autowidth = false +wb.styles do |s| + sz_all = s.add_style :sz => 10,:border => { :style => :thin, :color =>"000000"},:alignment => {:horizontal => :left} + blue_cell = s.add_style :bg_color => "FAEBDC", :sz => 10,:height => 20,:b => true, :border => { :style => :thin, :color =>"000000" },:alignment => {:horizontal => :left} + + wb.add_worksheet(:name => "统计结果") do |sheet| + sheet.sheet_view.show_grid_lines = false + poll_users_info = %w(序号) + poll_ques_titles = poll_questions.pluck(:question_title).map {|k| strip_export_title(k) if k.present?} + + poll_ques_ids = poll_questions.pluck(:id).sort #问题的全部id + poll_un_anony = @poll.un_anonymous + if poll_un_anony #是否匿名,默认为false + user_info = %w(登陆名 真实姓名 邮箱 学号) + else + user_info = [] + end + poll_users_info = poll_users_info + user_info + poll_ques_titles + poll_questions.each do |q| + if q.question_type != 3 #问题不为主观题 + question_vote_user = q.poll_votes.find_current_vote("user_id",@poll_commit_ids).count #该问题的有效填写量 + sheet_row = ["第#{q.question_number}题"] #选择题答案选项的数组 + sheet_answer_row = ["小计"] #选择题回答的答案人数,数组 + sheet_answer_percent = ["比例"] + sheet_answer_useful = ["有效填写人次",question_vote_user] + q.poll_answers.each do |a| #问卷的答案选项 + answer_users_count = a.poll_votes.find_current_vote("user_id",@poll_commit_ids).count + answer_percent = number_to_percentage((answer_users_count.to_f / question_vote_user.to_f)*100,precision:1) + sheet_row.push(a.answer_text) + sheet_answer_row.push(answer_users_count) + sheet_answer_percent.push(answer_percent.to_s) + end + sheet.add_row sheet_row, :style => blue_cell + sheet.add_row sheet_answer_row, :style => sz_all + sheet.add_row sheet_answer_percent, :style => sz_all + sheet.add_row sheet_answer_useful, :style => sz_all + #合并单元格,但无法填充style + # sheet.merge_cells (Axlsx::cell_r(1,sheet.rows.last.row_index) + ':' + Axlsx::cell_r(sheet_row.count-1,sheet.rows.last.row_index)) + # sheet.rows[sheet.rows.last.row_index].style = sz_all + sheet.add_row [] + else #主观题答案 + main_show_row = ["第#{q.question_number}题",q.question_title] + sheet.add_row main_show_row, :style => blue_cell + q.poll_votes.each do |v| #主观题的答案 + sheet.add_row ["",v.vote_text.present? ? v.vote_text : "--"], :style => sz_all + end + sheet.add_row [], :style => sz_all + end + end #each_with_index + + sheet.add_row poll_users_info, :style => blue_cell + @poll.poll_users.each_with_index do |u,index| + u_user = u.user + user_answer_array = [] + poll_questions.each do |q| + user_poll_votes = u_user.poll_votes.find_current_vote("poll_question_id",q.id) + if user_poll_votes.present? + user_poll_answer_ids = user_poll_votes.pluck(:poll_answer_id).reject(&:blank?) + user_poll_vote_texts = user_poll_votes.pluck(:vote_text).reject(&:blank?) + if user_poll_answer_ids.count > 0 + answer_content = q.poll_answers.find_answer_by_custom("id",user_poll_answer_ids) + if user_poll_answer_ids.count >1 + u_answer = answer_content.pluck(:answer_text).join(";") + else + u_answer = answer_content.first.answer_text + end + elsif user_poll_vote_texts.count > 0 + if user_poll_vote_texts.count > 1 + u_answer = user_poll_vote_texts.join(";") + else + u_answer = user_poll_vote_texts.first + end + else + u_answer = "--" + end + else + u_answer = "--" + end + user_answer_array.push(u_answer) + end + user_cell = [index+1] + if poll_un_anony + user_login = u_user.login + user_name = u_user.real_name.present? ? u_user.real_name : "--" + user_student_id = u_user.student_id.present? ? u_user.student_id : "--" + user_cell += [user_login,user_name, u_user.mail, user_student_id] + end + all_user_cell = user_cell + user_answer_array + sheet.add_row all_user_cell, :style => sz_all + end + sheet.column_widths *([25]*sheet.column_info.count) + sheet.column_info.first.width = 10 + end #add_worksheet +end \ No newline at end of file diff --git a/app/views/polls/common_header.json.jbuilder b/app/views/polls/common_header.json.jbuilder new file mode 100644 index 000000000..39c4ef811 --- /dev/null +++ b/app/views/polls/common_header.json.jbuilder @@ -0,0 +1,19 @@ +json.course_is_end @course.is_end # true表示已结束,false表示未结束 +json.extract! @poll, :id,:polls_name,:polls_description,:polls_status,:show_result + +json.user_permission do + json.is_teacher_or @is_teacher_or + json.current_status @user_poll_answer + json.poll_publish_count @poll_publish_count #是否存在已发布的分班 + json.poll_unpublish_count @poll_unpublish_count #是否存在未发布的分班 + json.left_banner_id @left_banner_id + json.left_banner_name @left_banner_name +end + +poll_url_status = poll_common_header(@is_teacher_or,@poll) +json.common_tabs do + json.array! poll_url_status do |p| + json.common_tab p[:common_tab].to_i + json.active_status p[:active_status] + end +end diff --git a/app/views/polls/create.json.jbuilder b/app/views/polls/create.json.jbuilder new file mode 100644 index 000000000..5c8442605 --- /dev/null +++ b/app/views/polls/create.json.jbuilder @@ -0,0 +1,4 @@ +json.partial! "commons/success" +json.data do + json.id @poll.id +end \ No newline at end of file diff --git a/app/views/polls/edit.json.jbuilder b/app/views/polls/edit.json.jbuilder new file mode 100644 index 000000000..78606d291 --- /dev/null +++ b/app/views/polls/edit.json.jbuilder @@ -0,0 +1,26 @@ +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.course do + json.partial! "polls/course_name",locals:{course:@course} +end + +json.poll do + json.extract! @poll, :id, :polls_name,:polls_description,:polls_status +end + +json.question_types do + json.q_counts @poll_questions_count + json.q_singles @poll_question_singles + json.q_doubles @poll_question_doubles + json.q_mains @poll_question_mains +end + +json.poll_questions do + json.array! @poll_questions do |q| + json.partial! "poll_questions/poll_questions", question: q,answers:q.poll_answers + end +end + + + + diff --git a/app/views/polls/end_poll_modal.json.jbuilder b/app/views/polls/end_poll_modal.json.jbuilder new file mode 100644 index 000000000..58a7339da --- /dev/null +++ b/app/views/polls/end_poll_modal.json.jbuilder @@ -0,0 +1,14 @@ +json.partial! "commons/success" + + +if @course_groups.size >0 + json.on_commiting @course_groups.size #未发布的分班 + json.course_info do + json.array! @course_groups do |group| + json.course_group_id group.id + json.course_group_name group.name + end + end +else + json.on_commiting 0 +end \ No newline at end of file diff --git a/app/views/polls/index.json.jbuilder b/app/views/polls/index.json.jbuilder new file mode 100644 index 000000000..b657da7a0 --- /dev/null +++ b/app/views/polls/index.json.jbuilder @@ -0,0 +1,34 @@ + json.polls_counts do + json.polls_total_counts @polls_count #全部问卷数 + json.polls_all_counts @polls_select_count #选择后的问卷数 + json.polls_unpublish_counts @polls_unpublish_counts #未发布问卷数 + json.polls_published_counts @polls_published_counts #已发布问卷数 + # json.polls_ended_counts @polls_ended_counts #已截止问卷数 + json.left_banner_id @left_banner_id + json.left_banner_name @left_banner_name +end + +json.course_types do + json.course_status @course_status # 课堂的当前是否结束,如结束,则为1,否则为0 + json.course_is_public @course_is_public #判断课堂是否为公开,只有公开课才有设为公开的按钮 + json.user_permission @is_teacher_or # 当前用户存在且为课堂教师/管理员/超级管理员时为1 ,课堂成员为2,否则为0 +end + +if @polls_count > 0 + json.polls do + json.array! @polls do |poll| + poll_index_array = poll_index_show(poll,@course,@is_teacher_or,@current_user_) + json.extract! poll, :id, :polls_name,:is_public,:created_at + json.polls_status poll_index_array[:polls_status] + json.lock_status poll_index_array[:lock_icon] + json.publish_time poll_index_array[:publish_time] # 问卷的发布时间 + json.end_time poll_index_array[:end_time] # 问卷的截止时间 + json.poll_answer poll_index_array[:poll_answer] # 已提交问卷的用户 + json.poll_unanswer poll_index_array[:poll_unanswer] # 已查看问卷/开始答题,但是未提交问卷的用户 + json.current_status poll_index_array[:current_status] #答题的状态 + end + end +else + json.polls [] +end + diff --git a/app/views/polls/my_polls.json.jbuilder b/app/views/polls/my_polls.json.jbuilder new file mode 100644 index 000000000..0873475d8 --- /dev/null +++ b/app/views/polls/my_polls.json.jbuilder @@ -0,0 +1,15 @@ +json.partial! "commons/success" + +json.exercises_count @my_exercises_count + +if @current_user_exercises.count > 0 + json.my_exercises do + json.array! @current_user_exercises do |exercise| + json.poll_name exercise.name + json.poll_description exercise.description + json.poll_id exercise.container_id + end + end +else + json.my_exercises [] +end \ No newline at end of file diff --git a/app/views/polls/new.json.jbuilder b/app/views/polls/new.json.jbuilder new file mode 100644 index 000000000..9c2c83b1d --- /dev/null +++ b/app/views/polls/new.json.jbuilder @@ -0,0 +1,5 @@ +json.left_banner_id @left_banner_id +json.left_banner_name @left_banner_name +json.course do + json.partial! "polls/course_name",locals:{course:@course} +end diff --git a/app/views/polls/poll_lists.json.jbuilder b/app/views/polls/poll_lists.json.jbuilder new file mode 100644 index 000000000..fef129599 --- /dev/null +++ b/app/views/polls/poll_lists.json.jbuilder @@ -0,0 +1,52 @@ +json.course do + json.partial! "polls/course_name",locals:{course:@course} +end + +json.poll_types do + if @poll_current_user_status == 0 + json.published_count @poll_publish_count + json.unpublish_count @poll_unpublish_count + json.un_anonymous @poll.un_anonymous + json.unified_setting @poll.unified_setting + end + json.poll_users_count @poll_users_count + json.total_users @poll_users_size + json.answer_users @poll_answers + json.unanswer_users @poll_unanswers + json.user_permission @poll_current_user_status #当前用户存在且为课堂教师/管理员/超级管理员时为0 ,其他否则为1 + json.poll_id @poll.id + json.poll_end_time @poll.end_time +end + +if @poll_current_user_status == 0 + if @poll_course_groups.present? + json.course_groups do + json.array! @poll_course_groups do |group| + json.course_group_id group[:course_id] #班级id + json.group_group_name group[:course_name] #班级名称 + json.count group[:student_count] #班级人数 + end + end + else + json.course_groups [] + end + # json.course_groups course_group_info @course, @current_user.id +end + +if @poll_users_size > 0 + json.poll_users do + json.array! @poll_users_list do |poll_user| + user_details = poll_user_info(poll_user,@course_all_members,@course) + json.user_id user_details[:user_id] + json.login user_details[:login] + json.user_name user_details[:user_name] + json.user_group_id user_details[:group_id] + json.user_group_name user_details[:group_name] + json.student_id user_details[:student_id] + json.commit_status poll_user.commit_status + json.end_at poll_user.end_at + end + end +else + json.poll_users [] +end diff --git a/app/views/polls/poll_setting.json.jbuilder b/app/views/polls/poll_setting.json.jbuilder new file mode 100644 index 000000000..9e48555f5 --- /dev/null +++ b/app/views/polls/poll_setting.json.jbuilder @@ -0,0 +1,43 @@ +json.course do + json.partial! "polls/course_name",locals:{course:@course} +end + +json.poll do + json.extract! @poll, :id,:polls_name, :polls_status,:publish_time,:end_time,:show_result,:is_public,:unified_setting,:un_anonymous + + json.user_groups_count @user_course_groups.count #当前用户的有权限的分班 + json.published_count @poll_publish_count + json.course_id @course.id + json.user_permission @user_permission ##1当前为老师,且无分班,即有全部的权限,#2其他老师/助教,且有分班的 +end + +if @user_published_setting.count > 0 #老师存在已发布的分班 + total_array_groups = get_user_setting_course(@user_published_setting,@user_course_groups) + json.published_course_groups do + json.array! total_array_groups do |s| + json.course_group_id s[:course_group_id] + json.course_group_name s[:course_group_name] + json.course_publish_time s[:course_publish_time] + json.course_end_time s[:course_end_time] + end + end +else + json.published_course_groups [] +end + +if @user_course_groups.count > 0 + json.course_groups do + json.array! @user_course_groups do |group| + course_choosed = 0 + if @being_setting_course_ids.include?(group[:group_id]) + course_choosed = 1 + end + json.course_group_id group[:group_id] + json.course_group_name group[:group_name] + json.course_choosed course_choosed + end + end +else + json.course_groups [] +end + diff --git a/app/views/polls/public_polls.json.jbuilder b/app/views/polls/public_polls.json.jbuilder new file mode 100644 index 000000000..ea38b8c3a --- /dev/null +++ b/app/views/polls/public_polls.json.jbuilder @@ -0,0 +1,17 @@ +json.partial! "commons/success" + +json.user_certification @user_certification #用户的认证,1为认证通过,0为未认证/认证未通过 +json.exercises_count @public_exercises_count +if @public_exercises_count > 0 + json.public_exercises do + json.array! @public_exercises do |exercise| + json.poll_name exercise.name + json.poll_description exercise.description + json.poll_id exercise.container_id + json.poll_user_id exercise.user_id + json.poll_user_name exercise.user.real_name + end + end +else + json.public_exercises [] +end diff --git a/app/views/polls/publish_modal.json.jbuilder b/app/views/polls/publish_modal.json.jbuilder new file mode 100644 index 000000000..fd1c94d17 --- /dev/null +++ b/app/views/polls/publish_modal.json.jbuilder @@ -0,0 +1,15 @@ +json.partial! "commons/success" + +if @course_groups.count > 0 + json.un_publish @course_groups.count #未发布的分班 + json.course_info do + json.array! @course_groups do |group| + json.course_group_id group.id + json.course_group_name group.name + end + end +else + json.un_publish 0 #未发布的分班 +end + + diff --git a/app/views/polls/show.json.jbuilder b/app/views/polls/show.json.jbuilder new file mode 100644 index 000000000..0f864c97e --- /dev/null +++ b/app/views/polls/show.json.jbuilder @@ -0,0 +1,23 @@ +json.course do + json.partial! "polls/course_name",locals:{course:@course} +end + +json.poll do + json.extract! @poll, :id, :polls_status,:polls_name,:polls_description +end + +json.user_permission do + json.is_teacher_or @is_teacher_or +end +json.question_types do + json.q_counts @poll_questions_count + json.q_singles @poll_question_singles + json.q_doubles @poll_question_doubles + json.q_mains @poll_question_mains +end + +json.questions do + json.array! @poll_questions do | question| + json.partial! "poll_questions/poll_questions", question: question,answers:question.poll_answers + end +end \ No newline at end of file diff --git a/app/views/polls/start_answer.json.jbuilder b/app/views/polls/start_answer.json.jbuilder new file mode 100644 index 000000000..4453f1bbf --- /dev/null +++ b/app/views/polls/start_answer.json.jbuilder @@ -0,0 +1,29 @@ + +json.course do + json.partial! "polls/course_name",locals:{course:@course} +end +json.poll do + json.extract! @poll,:id,:polls_name,:polls_description,:end_time + json.user_poll_status @user_poll_status #当前用户的状态 + json.left_banner_id @left_banner_id + json.left_banner_name @left_banner_name + json.poll_status @poll_status +end + +json.question_answered @answer_status + +json.question_types do + json.q_counts @poll_questions_count + json.q_singles @poll_question_singles + json.q_doubles @poll_question_doubles + json.q_mains @poll_question_mains + json.user_name @answer_user.real_name +end + +json.questions do + json.array! @poll_questions do | question| + json.partial! "poll_votes/poll_votes",question: question, #问题 + answers:question.poll_answers, #问题的答案选项 + votes:@answer_user.poll_votes.find_current_vote("poll_question_id",question.id) #问题的答案 + end +end \ No newline at end of file diff --git a/app/views/praise_tread/like.json.jbuilder b/app/views/praise_tread/like.json.jbuilder new file mode 100644 index 000000000..f9b891601 --- /dev/null +++ b/app/views/praise_tread/like.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" \ No newline at end of file diff --git a/app/views/praise_tread/unlike.json.jbuilder b/app/views/praise_tread/unlike.json.jbuilder new file mode 100644 index 000000000..f9b891601 --- /dev/null +++ b/app/views/praise_tread/unlike.json.jbuilder @@ -0,0 +1 @@ +json.partial! "commons/success" \ No newline at end of file diff --git a/app/views/projects/search.json.jbuilder b/app/views/projects/search.json.jbuilder new file mode 100644 index 000000000..b036d41cd --- /dev/null +++ b/app/views/projects/search.json.jbuilder @@ -0,0 +1,6 @@ +json.count @count +json.projects do + json.array! @projects do |project| + json.extract! project, :id, :name + end +end \ No newline at end of file diff --git a/app/views/question_banks/bank_list.json.jbuilder b/app/views/question_banks/bank_list.json.jbuilder new file mode 100644 index 000000000..54b641e5f --- /dev/null +++ b/app/views/question_banks/bank_list.json.jbuilder @@ -0,0 +1,9 @@ +json.is_teacher @certification_teacher +json.object_list do + json.array! @objects do |obj| + json.id obj.id + json.name obj.name + json.course_list_name obj.course_list.name + json.username obj.user.full_name + end +end \ No newline at end of file diff --git a/app/views/repositories/file_tree.json.jbuilder b/app/views/repositories/file_tree.json.jbuilder new file mode 100644 index 000000000..42b1a3b1e --- /dev/null +++ b/app/views/repositories/file_tree.json.jbuilder @@ -0,0 +1 @@ +json.data @data \ No newline at end of file diff --git a/app/views/schools/school_list.json.jbuilder b/app/views/schools/school_list.json.jbuilder new file mode 100644 index 000000000..1e2c89897 --- /dev/null +++ b/app/views/schools/school_list.json.jbuilder @@ -0,0 +1 @@ +json.shools_name @schools \ No newline at end of file diff --git a/app/views/shixuns/_choose_shixun.json.jbuilder b/app/views/shixuns/_choose_shixun.json.jbuilder new file mode 100644 index 000000000..ca22eeddc --- /dev/null +++ b/app/views/shixuns/_choose_shixun.json.jbuilder @@ -0,0 +1,14 @@ +# shixun_id: 1, //实训id +# shixun_name: '实训名称', +# school_users: 使用院校 +# myshixuns_count: 1, //学习人数 +# preference: '', //评价等级 +# +json.array! shixuns do |shixun| + json.shixun_id shixun.id + json.identifier shixun.identifier + json.shixun_name shixun.name + json.myshixuns_count shixun.myshixuns_count + json.school_users school_user_detail(shixun) + json.preference format("%.1f", shixun.shixun_preference) +end \ No newline at end of file diff --git a/app/views/shixuns/_commit.json.jbuilder b/app/views/shixuns/_commit.json.jbuilder new file mode 100644 index 000000000..cd934baea --- /dev/null +++ b/app/views/shixuns/_commit.json.jbuilder @@ -0,0 +1,21 @@ +json.commits commits do |commit| + json.title commit["title"] + json.time time_from_now(commit["created_at"]) + json.id commit["id"] + + user = git_username(commit["author_email"]) + if user.present? + json.author do + if user + json.partial! 'users/user', user: user + end + end + else + json.author do + json.id nil + json.login nil + json.name commit["author_name"] + json.email commit["author_email"] + end + end +end diff --git a/app/views/shixuns/_right.json.jbuilder b/app/views/shixuns/_right.json.jbuilder new file mode 100644 index 000000000..694b672fb --- /dev/null +++ b/app/views/shixuns/_right.json.jbuilder @@ -0,0 +1,23 @@ +# 实训创建者信息 +json.creator do + json.partial! 'users/user', locals: { user: shixun.owner } +end + +# 推荐实训 +json.recommands do + json.partial! 'shap_shixun', locals: { shixuns: recommend_shixun(shixun) } +end + +# 相关路径 +json.paths do + json.partial! 'subjects/subject', locals: {subjects: relation_path(shixun)} +end + +# 技能标签 +user_tags = shixun.user_tags_name(User.current) +json.tags do + json.array! shixun.challenge_tags_name do |tag| + json.tag_name tag + json.status user_tags.include?(tag) + end +end diff --git a/app/views/shixuns/_shap_shixun.json.jbuilder b/app/views/shixuns/_shap_shixun.json.jbuilder new file mode 100644 index 000000000..1ae054398 --- /dev/null +++ b/app/views/shixuns/_shap_shixun.json.jbuilder @@ -0,0 +1,10 @@ +json.array! shixuns do |shixun| + json.id shixun.id + json.identifier shixun.identifier + json.name shixun.name + json.stu_num shixun.myshixuns_count + json.challenges_count shixun.challenges_count + json.level level_to_s(shixun.trainee) + json.pic url_to_avatar(shixun) +end + diff --git a/app/views/shixuns/_shixun.json.jbuilder b/app/views/shixuns/_shixun.json.jbuilder new file mode 100644 index 000000000..6913c4745 --- /dev/null +++ b/app/views/shixuns/_shixun.json.jbuilder @@ -0,0 +1,27 @@ +# id: 1, //实训id +# name: '实训名称', +# tag_name: 'Python基础' +# stu_num: 1, //学习人数 +# score_info: [5.0,1,2,3,4,5], //实训打分,第一个总分,后五个依次为从5星到1星的百分占比 +# challenges_count: 4,//关卡数 +# exp: 100, //经验值 +# level: '初级', //1. 初级 2. 中级 3. 高级 +# pic: '', //头像url +# +json.array! shixuns do |shixun| + json.id shixun.id + json.identifier shixun.identifier + json.name shixun.name + json.status shixun.status + json.power (User.current.shixun_permission(shixun)) # 现在首页只显示已发布的实训 + # REDO: 局部缓存 + json.tag_name shixun.tag_repertoires.first.try(:name) + json.myshixuns_count shixun.myshixuns_count + json.stu_num shixun.myshixuns_count + json.score_info shixun.averge_star + json.challenges_count shixun.challenges_count + #json.exp shixun.all_score + json.level level_to_s(shixun.trainee) + json.pic url_to_avatar(shixun) +end + diff --git a/app/views/shixuns/_top.json.jbuilder b/app/views/shixuns/_top.json.jbuilder new file mode 100644 index 000000000..7c006cccf --- /dev/null +++ b/app/views/shixuns/_top.json.jbuilder @@ -0,0 +1,19 @@ +json.status shixun.status +# REDO:前端需要通过status来判断发布 +json.task_operation task_operation_url(current_myshixun, shixun) + +json.can_fork @can_fork +json.can_copy shixun.can_copy +if shixun.can_copy + json.fork_num shixun.fork_count +end + +json.identifier shixun.identifier +json.name shixun.name +json.stu_num shixun.myshixuns_count +json.experience shixun.all_score +json.diffcult diff_to_s(shixun.trainee) +json.score_info shixun.averge_star +# 用于是否显示导航栏中的'背景知识' +json.propaedeutics shixun.propaedeutics.present? ? true : false + diff --git a/app/views/shixuns/_users_list.json.jbuilder b/app/views/shixuns/_users_list.json.jbuilder new file mode 100644 index 000000000..010281c31 --- /dev/null +++ b/app/views/shixuns/_users_list.json.jbuilder @@ -0,0 +1,4 @@ +json.user_id user.id +json.identify user.identity +json.nickname user.nickname +json.school_name user.school_name \ No newline at end of file diff --git a/app/views/shixuns/add_collaborators.json.jbuilder b/app/views/shixuns/add_collaborators.json.jbuilder new file mode 100644 index 000000000..ab4716681 --- /dev/null +++ b/app/views/shixuns/add_collaborators.json.jbuilder @@ -0,0 +1,7 @@ +#json.partial! "users/users_list", users: @users +json.array! @users do |user| + json.user_id user.id + json.identify user.identity + json.nickname user.nickname + json.school_name user.school_name +end \ No newline at end of file diff --git a/app/views/shixuns/cancel_publish.json.jbuilder b/app/views/shixuns/cancel_publish.json.jbuilder new file mode 100644 index 000000000..2552b899b --- /dev/null +++ b/app/views/shixuns/cancel_publish.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "撤销发布成功!" \ No newline at end of file diff --git a/app/views/shixuns/change_manager.json.jbuilder b/app/views/shixuns/change_manager.json.jbuilder new file mode 100644 index 000000000..37ad85309 --- /dev/null +++ b/app/views/shixuns/change_manager.json.jbuilder @@ -0,0 +1,9 @@ +if @collaborators + json.array! @collaborators do |col| + json.user_id col.user.try(:id) + json.name col.user.full_name + end +else + json.status 1 + json.message "更换管理员成功" +end \ No newline at end of file diff --git a/app/views/shixuns/collaborators.json.jbuilder b/app/views/shixuns/collaborators.json.jbuilder new file mode 100644 index 000000000..bd880c93e --- /dev/null +++ b/app/views/shixuns/collaborators.json.jbuilder @@ -0,0 +1,21 @@ +# [ +# { +# user: User, +# follow: true, //是否已经关注 +# } +# ] + + +json.array! @members do |member| + json.user do + json.partial! 'users/user', locals: { user: member.user } + json.user_shixuns_count member.user.shixuns.published.count + #json.fans_count member.user.followers.count + json.brief_introduction member.user.user_extension.brief_introduction + json.identity member.user.identity + json.school_name member.user.school_name + json.shixun_manager member.role == 1 + json.user_id member.user_id + end + json.follow follow?(member.user.id, @user.id) +end \ No newline at end of file diff --git a/app/views/shixuns/collaborators_delete.json.jbuilder b/app/views/shixuns/collaborators_delete.json.jbuilder new file mode 100644 index 000000000..edd1290f0 --- /dev/null +++ b/app/views/shixuns/collaborators_delete.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "删除成功!" \ No newline at end of file diff --git a/app/views/shixuns/commits.json.jbuilder b/app/views/shixuns/commits.json.jbuilder new file mode 100644 index 000000000..5689d8632 --- /dev/null +++ b/app/views/shixuns/commits.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'shixuns/commit', locals: { commits: @commits } \ No newline at end of file diff --git a/app/views/shixuns/copy.json.jbuilder b/app/views/shixuns/copy.json.jbuilder new file mode 100644 index 000000000..ffbdfa12c --- /dev/null +++ b/app/views/shixuns/copy.json.jbuilder @@ -0,0 +1 @@ +json.shixun @new_shixun.identifier \ No newline at end of file diff --git a/app/views/shixuns/create.json.jbuilder b/app/views/shixuns/create.json.jbuilder new file mode 100644 index 000000000..f232122ae --- /dev/null +++ b/app/views/shixuns/create.json.jbuilder @@ -0,0 +1 @@ +json.shixun_identifier @shixun.identifier \ No newline at end of file diff --git a/app/views/shixuns/departments.json.jbuilder b/app/views/shixuns/departments.json.jbuilder new file mode 100644 index 000000000..c89af6b32 --- /dev/null +++ b/app/views/shixuns/departments.json.jbuilder @@ -0,0 +1 @@ +json.shools_name @scope \ No newline at end of file diff --git a/app/views/shixuns/destroy.json.jbuilder b/app/views/shixuns/destroy.json.jbuilder new file mode 100644 index 000000000..63a9e2a1c --- /dev/null +++ b/app/views/shixuns/destroy.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "删除成功" \ No newline at end of file diff --git a/app/views/shixuns/discusses.json.jbuilder b/app/views/shixuns/discusses.json.jbuilder new file mode 100644 index 000000000..0f64f290d --- /dev/null +++ b/app/views/shixuns/discusses.json.jbuilder @@ -0,0 +1,40 @@ +# [ +# { +# user: User, +# follow: true, //是否已经关注 +# time: '', //TODO 这里与前端协商是否要返回human格式 +# round: 1, //关卡 +# content: '', //留言内容 +# replies:[ //跟帖 +# { +# user: User, +# time: '', +# content: '' //留言内容 +# } +# ] +# } +# ] + + +json.array! @children_list do |dis| + json.user do + json.partial! 'users/user', locals: { user: dis[:user] } + end + + json.time dis[:time] + json.follow follow?(dis[:user], User.current) + json.round dis[:position] || 1 + json.content dis[:content].html_safe + json.game_url dis[:game_url] + json.hidden dis[:hidden] + + json.replies do + json.array! dis[:children] do |child| + json.user do + json.partial! 'users/user', locals: { user: child[:user] } + end + json.time child[:time] + json.content child[:content].html_safe + end + end +end \ No newline at end of file diff --git a/app/views/shixuns/file_content.json.jbuilder b/app/views/shixuns/file_content.json.jbuilder new file mode 100644 index 000000000..d4cccf0a7 --- /dev/null +++ b/app/views/shixuns/file_content.json.jbuilder @@ -0,0 +1 @@ +json.content @content \ No newline at end of file diff --git a/app/views/shixuns/fork_list.json.jbuilder b/app/views/shixuns/fork_list.json.jbuilder new file mode 100644 index 000000000..5f631eec1 --- /dev/null +++ b/app/views/shixuns/fork_list.json.jbuilder @@ -0,0 +1,17 @@ +# ''' +# [ +# { +# name: '实训名称', +# score: 1.2, //实训打分 +# challenges_count: 4,//关卡数 +# exp: 100, //经验值 +# level: '初级', //等级 +# pic: '', //头像url +# } +# ] +# ''' + +json.total_count @shixuns_count +json.shixuns do + json.partial! 'shixun', locals: {shixuns: @shixuns} +end diff --git a/app/views/shixuns/get_custom_script.json.jbuilder b/app/views/shixuns/get_custom_script.json.jbuilder new file mode 100644 index 000000000..4ae41e66b --- /dev/null +++ b/app/views/shixuns/get_custom_script.json.jbuilder @@ -0,0 +1 @@ +json.shixun_script @shixun_script \ No newline at end of file diff --git a/app/views/shixuns/get_mirror_script.json.jbuilder b/app/views/shixuns/get_mirror_script.json.jbuilder new file mode 100644 index 000000000..fe0f37aa6 --- /dev/null +++ b/app/views/shixuns/get_mirror_script.json.jbuilder @@ -0,0 +1,5 @@ +json.array! @script do |scpt| + json.id scpt.id + json.scptname scpt.script_type + json.description scpt.description +end \ No newline at end of file diff --git a/app/views/shixuns/get_recommend_shixuns.json.jbuilder b/app/views/shixuns/get_recommend_shixuns.json.jbuilder new file mode 100644 index 000000000..327fd3838 --- /dev/null +++ b/app/views/shixuns/get_recommend_shixuns.json.jbuilder @@ -0,0 +1,9 @@ +json.recommend_shixuns do + json.array! @recommend_shixuns do |hs| + json.id hs.id + json.name hs.name + json.identifier hs.identifier + json.myshixuns_count hs.myshixuns.count + json.image_url url_to_avatar(hs) + end +end \ No newline at end of file diff --git a/app/views/shixuns/get_script_contents.json.jbuilder b/app/views/shixuns/get_script_contents.json.jbuilder new file mode 100644 index 000000000..c3c58cfb3 --- /dev/null +++ b/app/views/shixuns/get_script_contents.json.jbuilder @@ -0,0 +1,2 @@ +json.content @script +json.description @description \ No newline at end of file diff --git a/app/views/shixuns/index.json.jbuilder b/app/views/shixuns/index.json.jbuilder new file mode 100644 index 000000000..41da7120f --- /dev/null +++ b/app/views/shixuns/index.json.jbuilder @@ -0,0 +1,9 @@ +if @fuzzy_searchs + json.keyword @fuzzy_searchs + json.total_count @fuzzy_searchs.blank? ? nil : @total_count +end +json.pagination @total_count > 16 ? true : false +json.search_tags @search_tags +json.shixuns do + json.partial! 'shixun', locals: {shixuns: @shixuns} +end diff --git a/app/views/shixuns/menus.json.jbuilder b/app/views/shixuns/menus.json.jbuilder new file mode 100644 index 000000000..379f13e52 --- /dev/null +++ b/app/views/shixuns/menus.json.jbuilder @@ -0,0 +1,32 @@ +# repertoires: [{. //主标签 +# id: 1, +# name: '前端开发', +# sub_repertoires: [ +# { +# id: 1, +# name: '前端基础', +# tags: [ +# id: 1, +# name: 'HTML' +# ] +# } +# ] +# }] + +json.array! @repertoires do |rep| + json.id rep.id + json.name rep.name + json.sub_repertoires do + json.array! rep.sub_repertoires do |sub| + json.id sub.id + json.name sub.name + json.tags do + json.array! sub.tag_repertoires do |tag| + json.id tag.id + json.name tag.name + end + end + end + end +end + diff --git a/app/views/shixuns/new.json.jbuilder b/app/views/shixuns/new.json.jbuilder new file mode 100644 index 000000000..c047d83e7 --- /dev/null +++ b/app/views/shixuns/new.json.jbuilder @@ -0,0 +1,3 @@ +json.sample @introduction_sample +json.main_type @main_type +json.small_type @small_type \ No newline at end of file diff --git a/app/views/shixuns/propaedeutics.json.jbuilder b/app/views/shixuns/propaedeutics.json.jbuilder new file mode 100644 index 000000000..d4cccf0a7 --- /dev/null +++ b/app/views/shixuns/propaedeutics.json.jbuilder @@ -0,0 +1 @@ +json.content @content \ No newline at end of file diff --git a/app/views/shixuns/publish.json.jbuilder b/app/views/shixuns/publish.json.jbuilder new file mode 100644 index 000000000..b5cf770ee --- /dev/null +++ b/app/views/shixuns/publish.json.jbuilder @@ -0,0 +1,3 @@ +json.status @status +json.tag_position @position +json.evaluation_set_position @pos \ No newline at end of file diff --git a/app/views/shixuns/ranking_list.json.jbuilder b/app/views/shixuns/ranking_list.json.jbuilder new file mode 100644 index 000000000..6990bbf6f --- /dev/null +++ b/app/views/shixuns/ranking_list.json.jbuilder @@ -0,0 +1,29 @@ +# [ +# { +# user: User, +# ord: 1, //名次 +# time: '2018-01-19 22:40', //通关时间 +# accuracy: 100, //准确率 +# use_time: 100, //耗时,单位秒 +# gold: 10000, //加金币 +# } +# ] +# +# +# + + + +i = 0 +json.array! @myshixuns do |myshixun| + json.users do + json.image_url url_to_avatar(myshixun.user) + json.user_url "/users/#{myshixun['login']}" + json.name myshixun['lastname'] + end + + json.ord i+=1 + json.time myshixun["updated_at"] + json.use_time myshixun["time"] + json.gold myshixun["score"].to_i < 0 ? 0 : myshixun["score"].to_i +end \ No newline at end of file diff --git a/app/views/shixuns/repository.json.jbuilder b/app/views/shixuns/repository.json.jbuilder new file mode 100644 index 000000000..fa769169d --- /dev/null +++ b/app/views/shixuns/repository.json.jbuilder @@ -0,0 +1,7 @@ +json.trees @trees + +if @trees.present? + json.partial! 'shixuns/commit', locals: { commits: @latest_commit } +end + +json.git_url @repo_url \ No newline at end of file diff --git a/app/views/shixuns/search_user_courses.json.jbuilder b/app/views/shixuns/search_user_courses.json.jbuilder new file mode 100644 index 000000000..4f4dcfb0b --- /dev/null +++ b/app/views/shixuns/search_user_courses.json.jbuilder @@ -0,0 +1,7 @@ +json.courses_count @course_count +json.course_list do + json.array! @courses do |course| + json.course_id course.id + json.name course.name + end +end \ No newline at end of file diff --git a/app/views/shixuns/send_to_course.json.jbuilder b/app/views/shixuns/send_to_course.json.jbuilder new file mode 100644 index 000000000..dd087d3e2 --- /dev/null +++ b/app/views/shixuns/send_to_course.json.jbuilder @@ -0,0 +1,4 @@ +json.status 1 +json.message "发送成功" +json.url course_homework_commons_path(@course.id, type: 4) +# json.url "#{Rails::configuration.educoder['old_edu_host']}/homework_common?course=#{@course.id}&homework_type=4" \ No newline at end of file diff --git a/app/views/shixuns/settings.json.jbuilder b/app/views/shixuns/settings.json.jbuilder new file mode 100644 index 000000000..e97331388 --- /dev/null +++ b/app/views/shixuns/settings.json.jbuilder @@ -0,0 +1,35 @@ +json.shixun do + json.status @shixun.status + json.name @shixun.name + json.description @shixun.description + + # 镜像大小类别 + json.main_type @main_type + json.choice_main_type @choice_main_type + json.small_type @small_type + json.choice_small_type @choice_small_type + + # 脚本 + json.evaluate_script @shixun.evaluate_script + json.standard_scripts @shixun.standrad_script + json.choice_standard_scripts @shixun.mirror_script_id + + # 基础配置 + json.trainee @shixun.trainee + json.can_copy @shixun.can_copy + json.task_pass @shixun.task_pass + json.test_set_permission @shixun.test_set_permission + json.hide_code @shixun.hide_code # 隐藏代码窗口 + json.code_hidden @shixun.code_hidden # 代码目录隐藏 + json.vnc @shixun.vnc + json.exec_time @shixun.exec_time + json.webssh @shixun.webssh + json.multi_webssh @shixun.multi_webssh + json.use_scope @shixun.use_scope + json.scope_partment @shixun.schools.map(&:name) # 公开范围 + json.opening_time @shixun.opening_time + json.forbid_copy @shixun.forbid_copy +end + + + diff --git a/app/views/shixuns/shixun_exec.json.jbuilder b/app/views/shixuns/shixun_exec.json.jbuilder new file mode 100644 index 000000000..e159c5b29 --- /dev/null +++ b/app/views/shixuns/shixun_exec.json.jbuilder @@ -0,0 +1 @@ +json.game_identifier @current_task.identifier \ No newline at end of file diff --git a/app/views/shixuns/shixun_members_added.json.jbuilder b/app/views/shixuns/shixun_members_added.json.jbuilder new file mode 100644 index 000000000..1180cccc7 --- /dev/null +++ b/app/views/shixuns/shixun_members_added.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "添加成员成功!" \ No newline at end of file diff --git a/app/views/shixuns/show.json.jbuilder b/app/views/shixuns/show.json.jbuilder new file mode 100644 index 000000000..8e49a99f4 --- /dev/null +++ b/app/views/shixuns/show.json.jbuilder @@ -0,0 +1,4 @@ +json.fork_from @fork_from +json.identity User.current.shixun_identity(@shixun) +json.power @power +json.partial! 'shixuns/top', locals: { shixun: @shixun, current_myshixun: @current_myshixun } diff --git a/app/views/shixuns/show_right.json.jbuilder b/app/views/shixuns/show_right.json.jbuilder new file mode 100644 index 000000000..8f4679a37 --- /dev/null +++ b/app/views/shixuns/show_right.json.jbuilder @@ -0,0 +1,6 @@ +json.partial! 'shixuns/right', locals: { shixun: @shixun } + +#json.follow follow?(@shixun.owner, User.current) +#json.fans_count @fans_count +#json.followed_count @followed_count +json.user_shixuns_count @user_own_shixuns diff --git a/app/views/shixuns/update.json.jbuilder b/app/views/shixuns/update.json.jbuilder new file mode 100644 index 000000000..f232122ae --- /dev/null +++ b/app/views/shixuns/update.json.jbuilder @@ -0,0 +1 @@ +json.shixun_identifier @shixun.identifier \ No newline at end of file diff --git a/app/views/shixuns/update_file.json.jbuilder b/app/views/shixuns/update_file.json.jbuilder new file mode 100644 index 000000000..d4cccf0a7 --- /dev/null +++ b/app/views/shixuns/update_file.json.jbuilder @@ -0,0 +1 @@ +json.content @content \ No newline at end of file diff --git a/app/views/shixuns/update_propaedeutics.json.jbuilder b/app/views/shixuns/update_propaedeutics.json.jbuilder new file mode 100644 index 000000000..af4a6a777 --- /dev/null +++ b/app/views/shixuns/update_propaedeutics.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "更新成功" \ No newline at end of file diff --git a/app/views/stages/_stage.json.jbuilder b/app/views/stages/_stage.json.jbuilder new file mode 100644 index 000000000..db00ad844 --- /dev/null +++ b/app/views/stages/_stage.json.jbuilder @@ -0,0 +1,21 @@ +# complete_status: 章节实训的通关状态 +# shixun_status: 实训路径详情列表,右侧实训的状态显示栏 +# shixun_path: 实训详情按钮的链接 +# tpi_path: 开始实战按钮的链接 + +json.stage_id stage.id +json.stage_name stage.name +json.stage_description stage.description +json.stage_position stage.position +json.up_path "/stages/#{stage.id}/up_position" +json.down_path "/stages/#{stage.id}/down_position" + +json.shixuns_list do + json.array! stage.shixuns do |shixun| + json.shixun_name shixun.name + json.shixun_hidden shixun.hidden + json.identifier shixun.identifier + json.complete_status stage_myshixun_status(shixun, user) + json.shixun_status stage_shixun_status(subject.status, shixun.status, shixun.hidden) + end +end \ No newline at end of file diff --git a/app/views/stages/create.json.jbuilder b/app/views/stages/create.json.jbuilder new file mode 100644 index 000000000..c9c536b27 --- /dev/null +++ b/app/views/stages/create.json.jbuilder @@ -0,0 +1 @@ +json.subject_id @subject.id \ No newline at end of file diff --git a/app/views/stages/destroy.json.jbuilder b/app/views/stages/destroy.json.jbuilder new file mode 100644 index 000000000..d7f6cfa48 --- /dev/null +++ b/app/views/stages/destroy.json.jbuilder @@ -0,0 +1,2 @@ +json.status @status +json.subject_id @subject.id \ No newline at end of file diff --git a/app/views/stages/down_position.json.jbuilder b/app/views/stages/down_position.json.jbuilder new file mode 100644 index 000000000..5e81bc417 --- /dev/null +++ b/app/views/stages/down_position.json.jbuilder @@ -0,0 +1 @@ +json.status 1 \ No newline at end of file diff --git a/app/views/stages/edit.json.jbuilder b/app/views/stages/edit.json.jbuilder new file mode 100644 index 000000000..bf31c56e1 --- /dev/null +++ b/app/views/stages/edit.json.jbuilder @@ -0,0 +1,11 @@ +json.stage_id @stage.id +json.stage_name @stage.name +json.stage_description @stage.description +json.delete_path "/stages/#{@stage.id}" +json.shixuns_list do + json.array! @stage.shixuns.each do |shixun| + json.shixun_identifier shixun.identifier + json.shixun_name shixun.name + json.shixun_id shixun.id + end +end \ No newline at end of file diff --git a/app/views/stages/index.json.jbuilder b/app/views/stages/index.json.jbuilder new file mode 100644 index 000000000..d186088c4 --- /dev/null +++ b/app/views/stages/index.json.jbuilder @@ -0,0 +1,3 @@ +json.stages @stages do |stage| + json.partial! 'stage', locals: {stage: stage, user:@user, subject:@subject} +end \ No newline at end of file diff --git a/app/views/stages/up_position.json.jbuilder b/app/views/stages/up_position.json.jbuilder new file mode 100644 index 000000000..5e81bc417 --- /dev/null +++ b/app/views/stages/up_position.json.jbuilder @@ -0,0 +1 @@ +json.status 1 \ No newline at end of file diff --git a/app/views/stages/update.json.jbuilder b/app/views/stages/update.json.jbuilder new file mode 100644 index 000000000..c9c536b27 --- /dev/null +++ b/app/views/stages/update.json.jbuilder @@ -0,0 +1 @@ +json.subject_id @subject.id \ No newline at end of file diff --git a/app/views/student_works/adjust_review_score.json.jbuilder b/app/views/student_works/adjust_review_score.json.jbuilder new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/student_works/check_project.json.jbuilder b/app/views/student_works/check_project.json.jbuilder new file mode 100644 index 000000000..cb1b1848d --- /dev/null +++ b/app/views/student_works/check_project.json.jbuilder @@ -0,0 +1,2 @@ +json.is_relate @is_relate +json.relate_user @relate_user \ No newline at end of file diff --git a/app/views/student_works/comment_list.json.jbuilder b/app/views/student_works/comment_list.json.jbuilder new file mode 100644 index 000000000..b14de2f31 --- /dev/null +++ b/app/views/student_works/comment_list.json.jbuilder @@ -0,0 +1,46 @@ +json.allow_score allow_score(@homework, @user_course_identity, @current_user.id, @work) +json.ultimate @work.ultimate_score + +json.last_comment do + json.last_content @last_comment.try(:comment) + json.last_score @last_comment.try(:score) +end + +json.is_author @current_user == @work.user + +json.comment_count @comment_scores.size + +json.comment_scores @comment_scores do |score| + json.user_id score.user_id + json.user_login score.show_name(@user_course_identity, @current_user) ? score.user.login : "--" + json.user_image_url score.show_name(@user_course_identity, @current_user) ? url_to_avatar(score.user) : "--" + json.user_name score.show_name(@user_course_identity, @current_user) ? score.user.real_name : "匿名" + json.comment_id score.id + json.comment_role score.reviewer_role == 1 ? "教师" : score.reviewer_role == 2 ? "助教" : "学生" + json.comment_time score.created_at + json.score score.score + json.score_id score.id + json.content score.comment + json.appeal_status score.appeal_status + json.is_invalid score.is_invalid + json.delete score.allow_delete(@current_user, @user_course_identity) + json.attachments score.attachments do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false} + end + + json.can_appeal @homework.appeal_duration && score.reviewer_role == 3 && score.appeal_status == 0 && @work.user == @current_user + + if @homework.anonymous_appeal && score.reviewer_role == 3 && score.student_works_scores_appeal.present? + json.appeal_info appeal_info(score.student_works_scores_appeal, @user_course_identity, @current_user) + end + + json.can_reply !score.is_invalid && @user_course_identity <= Course::STUDENT + + json.journals score.journals_for_messages.each do |message| + json.user_info message_user_name(message.user, score, @work.user, @current_user, @user_course_identity) + json.id message.id + json.content message.notes + json.time message.created_at + json.can_delete @user_course_identity == Course::ADMIN + end +end \ No newline at end of file diff --git a/app/views/student_works/commit_des.json.jbuilder b/app/views/student_works/commit_des.json.jbuilder new file mode 100644 index 000000000..45c2b0e1a --- /dev/null +++ b/app/views/student_works/commit_des.json.jbuilder @@ -0,0 +1,7 @@ +json.course_id @course.id +json.course_name @course.name +json.category @homework.category_info +json.homework_id @homework.id +json.user_name @current_user.real_name +json.work_id @work.id +json.description @work.description \ No newline at end of file diff --git a/app/views/student_works/create.json.jbuilder b/app/views/student_works/create.json.jbuilder new file mode 100644 index 000000000..c1c966ee9 --- /dev/null +++ b/app/views/student_works/create.json.jbuilder @@ -0,0 +1,3 @@ +json.status 0 +json.message "提交成功" +json.work_id @work_id \ No newline at end of file diff --git a/app/views/student_works/edit.json.jbuilder b/app/views/student_works/edit.json.jbuilder new file mode 100644 index 000000000..ce9d9ff72 --- /dev/null +++ b/app/views/student_works/edit.json.jbuilder @@ -0,0 +1,19 @@ +json.partial! "homework_commons/homework_public_navigation", locals: {homework: @homework, course: @course, user: @current_user} +json.work_id @work.id +json.description @work.description + +json.attachments @work.attachments do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: @work.delete_atta(atta)} +end + +if @homework.homework_type == "group" + json.min_num @homework.homework_detail_group.try(:min_num) + json.max_num @homework.homework_detail_group.try(:max_num) + + json.members @work_members do |member| + json.user_id member.user_id + json.user_name member.user.real_name + json.group_name member.course_group_name + json.student_id member.user.student_id + end +end \ No newline at end of file diff --git a/app/views/student_works/new.json.jbuilder b/app/views/student_works/new.json.jbuilder new file mode 100644 index 000000000..bdd7c4143 --- /dev/null +++ b/app/views/student_works/new.json.jbuilder @@ -0,0 +1,10 @@ +json.partial! "homework_commons/homework_public_navigation", locals: {homework: @homework, course: @course, user: @current_user} + +if @homework.homework_type == "group" + json.min_num @homework.homework_detail_group.try(:min_num) + json.max_num @homework.homework_detail_group.try(:max_num) + json.user_id @current_user.id + json.user_name @current_user.real_name + json.user_student_id @current_user.student_id + json.group_name @course.course_member(@current_user.id).try(:course_group_name) +end \ No newline at end of file diff --git a/app/views/student_works/search_member_list.json.jbuilder b/app/views/student_works/search_member_list.json.jbuilder new file mode 100644 index 000000000..b3882893b --- /dev/null +++ b/app/views/student_works/search_member_list.json.jbuilder @@ -0,0 +1,7 @@ +json.members @members do |member| + json.user_id member.user_id + json.user_name member.user.real_name + json.group_name member.course_group_name + json.student_id member.user.student_id + json.commit_status @homework.user_has_commit_work(member.user_id) +end \ No newline at end of file diff --git a/app/views/student_works/shixun_work.json.jbuilder b/app/views/student_works/shixun_work.json.jbuilder new file mode 100644 index 000000000..3b6b598cb --- /dev/null +++ b/app/views/student_works/shixun_work.json.jbuilder @@ -0,0 +1,32 @@ +json.work_id @work.id +json.shixun_name @shixun.name +json.shixun_score @shixun.all_score +json.view_report @user_course_identity < Course::STUDENT || @current_user == @work_user + +# 作者信息 +json.user_id @work_user.id +json.username @work_user.real_name +json.login @work_user.login +json.image_url url_to_avatar(@work_user) + +json.complete_count @myshixun.passed_count +json.challenges_count @shixun.challenges_count +json.efficiency number_with_precision @work.efficiency, precision: 2 +json.max_efficiency number_with_precision @homework.max_efficiency, precision: 2 +json.passed_time @myshixun.passed_time +json.total_spend_time @myshixun.total_spend_time + +# 关卡完成情况 +index = 1 +json.game_list @myshixun.games do |game| + json.position index + json.end_time game.end_time ? game.end_time : '--' + json.cost_time game.cost_time + json.score game.final_score + json.complete_status game_status(game, @homework) + index += 1 +end + + + + diff --git a/app/views/student_works/shixun_work_report.json.jbuilder b/app/views/student_works/shixun_work_report.json.jbuilder new file mode 100644 index 000000000..1c6ed5899 --- /dev/null +++ b/app/views/student_works/shixun_work_report.json.jbuilder @@ -0,0 +1,59 @@ +json.homework_common_id @homework.id +json.category @homework.category_info +json.course_name @course.name +if @shixun + json.shixun_name @shixun.name +# 总体评价 + json.overall_appraisal @work.overall_appraisal + json.myself_experience @work.myshixun.try(:total_score) + json.total_experience @shixun.all_score + json.work_score number_with_precision @work.work_score, precision: 1 + json.all_work_score 100 + json.time_consuming @work.myshixun_consume + json.evaluate_count @user_evaluate_count.to_i + +# 阶段成绩 + json.stage_list do + json.array! @games do |game| + json.name game.challenge.subject + json.is_delay student_work_is_delay?(@homework, game) + json.open_time myshixun_open_time game + json.evaluate_count game.evaluate_count + json.finished_time finished_time game.end_time + json.time_consuming time_consuming game + json.myself_experience game.final_score + json.experience game.challenge.all_score + json.complete_status game_status(game, @homework) + end + end + +# 个人总结 + json.work_description @work.description + +# 用户信息 + json.user_id @user.id + json.username @user.real_name + json.student_id @user.student_id + +# 图形统计 +# 1: 效率 + json.echart_data @echart_data + +# 实训详情 + json.shixun_detail do + json.array! @games do |game| + json.game_identifier game.identifier + json.st game.challenge.st + json.position game.challenge.position + json.path game.challenge.path + json.subject game.challenge.subject + json.outputs game.distinct_query_index do |output| + json.position output.query_index + json.output_detail output_detail game, output + end + json.passed_code game.try(:lastest_code) + end + end +end + + diff --git a/app/views/student_works/show.json.jbuilder b/app/views/student_works/show.json.jbuilder new file mode 100644 index 000000000..653ed6450 --- /dev/null +++ b/app/views/student_works/show.json.jbuilder @@ -0,0 +1,24 @@ +json.partial! "homework_commons/homework_public_navigation", locals: {homework: @homework, course: @course, user: @current_user} +json.(@work, :description, :commit_time, :update_time) + +json.is_evaluation @is_evaluation +json.author_name @is_evaluation ? "匿名" : @work.user.real_name +json.is_author @is_author +json.update_user_name @is_evaluation ? "匿名" : @work.commit_user.try(:real_name) + +json.update_atta @homework.late_duration && @is_author + +json.attachments @attachments do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: @work.delete_atta(atta)} +end + +unless @is_evaluation + if @homework.homework_type == "group" && @homework.homework_detail_group.base_on_project + json.project_info project_info @work, @current_user, @user_course_identity + end + + json.work_members @work_members.each do |member| + json.user_name member.user.real_name + json.user_login member.user.login + end +end diff --git a/app/views/student_works/supply_attachments.json.jbuilder b/app/views/student_works/supply_attachments.json.jbuilder new file mode 100644 index 000000000..ef72c0828 --- /dev/null +++ b/app/views/student_works/supply_attachments.json.jbuilder @@ -0,0 +1,8 @@ +json.revise_reason @last_atta.try(:description) +json.atta_update_time @last_atta.try(:created_on) +json.atta_update_user @is_evaluation ? "匿名" : @last_atta.try(:author).try(:real_name) +json.atta_update_user_login @is_evaluation ? "--" : @last_atta.try(:author).try(:login) + +json.revise_attachments @revise_attachments.each do |atta| + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: @work.delete_atta(atta)} +end \ No newline at end of file diff --git a/app/views/subjects/_subject.json.jbuilder b/app/views/subjects/_subject.json.jbuilder new file mode 100644 index 000000000..b9a322530 --- /dev/null +++ b/app/views/subjects/_subject.json.jbuilder @@ -0,0 +1,10 @@ +json.array! subjects do |subject| + json.id subject.id + json.image_url url_to_avatar(subject) + json.name subject.name + json.tag_name subject.repertoire.try(:name) + json.stages_count subject.stages_count + json.shixuns_count subject.shixuns_count + json.members_count subject.member_count + json.allow_visit subject.status > 1 || User.current.manager_of_subject?(subject) || User.current.admin? +end \ No newline at end of file diff --git a/app/views/subjects/_subject_member.json.jbuilder b/app/views/subjects/_subject_member.json.jbuilder new file mode 100644 index 000000000..5372e1013 --- /dev/null +++ b/app/views/subjects/_subject_member.json.jbuilder @@ -0,0 +1,6 @@ +json.name user.full_name +json.image_url url_to_avatar(user) +json.user_url "/users/#{user.login}" +json.school user.school_name +json.identity user.identity +json.id user.id \ No newline at end of file diff --git a/app/views/subjects/add_subject_members.json.jbuilder b/app/views/subjects/add_subject_members.json.jbuilder new file mode 100644 index 000000000..410b5641b --- /dev/null +++ b/app/views/subjects/add_subject_members.json.jbuilder @@ -0,0 +1,3 @@ +json.members @subject.subject_members do |member| + json.partial! 'subject_member', locals: { user: member.user } +end \ No newline at end of file diff --git a/app/views/subjects/append_to_stage.json.jbuilder b/app/views/subjects/append_to_stage.json.jbuilder new file mode 100644 index 000000000..4f3a15e2e --- /dev/null +++ b/app/views/subjects/append_to_stage.json.jbuilder @@ -0,0 +1,5 @@ +json.shixun_lists @shixuns do |shixun| + json.shixun_identifier shixun.identifier + json.shixun_name shixun.name + json.shixun_id shixun.id +end \ No newline at end of file diff --git a/app/views/subjects/cancel_has_publish.json.jbuilder b/app/views/subjects/cancel_has_publish.json.jbuilder new file mode 100644 index 000000000..60f06b5df --- /dev/null +++ b/app/views/subjects/cancel_has_publish.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.subject_id @subject.id \ No newline at end of file diff --git a/app/views/subjects/cancel_publish.json.jbuilder b/app/views/subjects/cancel_publish.json.jbuilder new file mode 100644 index 000000000..60f06b5df --- /dev/null +++ b/app/views/subjects/cancel_publish.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.subject_id @subject.id \ No newline at end of file diff --git a/app/views/subjects/choose_course.json.jbuilder b/app/views/subjects/choose_course.json.jbuilder new file mode 100644 index 000000000..f5e33d4ee --- /dev/null +++ b/app/views/subjects/choose_course.json.jbuilder @@ -0,0 +1,16 @@ +json.courses @courses do |course| + json.course_id course.id + json.course_name course.name + json.created_at course.created_at +end + +json.stages @subject.stages do |stage| + index = 1 + json.shixuns stage.shixuns do |shixun| + if shixun.status == 2 && !@none_shixun_ids.include?(shixun.id) + json.shixun_id shixun.id + json.shixun_name "#{stage.position}-#{index} #{shixun.name}" + end + index += 1 + end +end \ No newline at end of file diff --git a/app/views/subjects/choose_subject_shixun.json.jbuilder b/app/views/subjects/choose_subject_shixun.json.jbuilder new file mode 100644 index 000000000..6243336b7 --- /dev/null +++ b/app/views/subjects/choose_subject_shixun.json.jbuilder @@ -0,0 +1,10 @@ +json.tags @tags do |tag| + json.tag_id tag.id + json.tag_name tag.name +end + +json.shixun_list do + json.partial! 'shixuns/choose_shixun', locals: {shixuns: @shixuns} +end + +json.shixuns_count @shixuns_count \ No newline at end of file diff --git a/app/views/subjects/create.json.jbuilder b/app/views/subjects/create.json.jbuilder new file mode 100644 index 000000000..c9c536b27 --- /dev/null +++ b/app/views/subjects/create.json.jbuilder @@ -0,0 +1 @@ +json.subject_id @subject.id \ No newline at end of file diff --git a/app/views/subjects/delete_member.json.jbuilder b/app/views/subjects/delete_member.json.jbuilder new file mode 100644 index 000000000..63a9e2a1c --- /dev/null +++ b/app/views/subjects/delete_member.json.jbuilder @@ -0,0 +1,2 @@ +json.status 1 +json.message "删除成功" \ No newline at end of file diff --git a/app/views/subjects/destroy.json.jbuilder b/app/views/subjects/destroy.json.jbuilder new file mode 100644 index 000000000..5e81bc417 --- /dev/null +++ b/app/views/subjects/destroy.json.jbuilder @@ -0,0 +1 @@ +json.status 1 \ No newline at end of file diff --git a/app/views/subjects/down_member_position.json.jbuilder b/app/views/subjects/down_member_position.json.jbuilder new file mode 100644 index 000000000..410b5641b --- /dev/null +++ b/app/views/subjects/down_member_position.json.jbuilder @@ -0,0 +1,3 @@ +json.members @subject.subject_members do |member| + json.partial! 'subject_member', locals: { user: member.user } +end \ No newline at end of file diff --git a/app/views/subjects/edit.json.jbuilder b/app/views/subjects/edit.json.jbuilder new file mode 100644 index 000000000..a48316c26 --- /dev/null +++ b/app/views/subjects/edit.json.jbuilder @@ -0,0 +1 @@ +json.(@subject, :id, :name, :description, :learning_notes) \ No newline at end of file diff --git a/app/views/subjects/index.json.jbuilder b/app/views/subjects/index.json.jbuilder new file mode 100644 index 000000000..8cf7898c7 --- /dev/null +++ b/app/views/subjects/index.json.jbuilder @@ -0,0 +1,10 @@ +json.tags @tech_system do |tag| + json.tag_id tag.id + json.tag_name tag.name +end + +json.subjects do + json.partial! 'subject', locals: {subjects: @subjects} +end + +json.total_count @total_count diff --git a/app/views/subjects/publish.json.jbuilder b/app/views/subjects/publish.json.jbuilder new file mode 100644 index 000000000..8484543db --- /dev/null +++ b/app/views/subjects/publish.json.jbuilder @@ -0,0 +1,2 @@ +json.status @status +json.message @status == 0 ? "已发布过申请,请等待管理员审核" : "发布申请已提交,请等待管理员的审核" \ No newline at end of file diff --git a/app/views/subjects/school_report.json.jbuilder b/app/views/subjects/school_report.json.jbuilder new file mode 100644 index 000000000..dd5821b22 --- /dev/null +++ b/app/views/subjects/school_report.json.jbuilder @@ -0,0 +1,9 @@ +json.schools @schools.each do |school| + pass_count = Myshixun.find_by_sql("select count(ms.id) ms_count from myshixuns ms, user_extensions ue where ue.school_id = + #{school.id} and ms.user_id = ue.user_id and ms.status = 1 and shixun_id in + (select shixun_id from stage_shixuns where subject_id = '#{@subject.id}')").first.try(:ms_count).to_i + json.name school.school_name + json.student_count school.ue_count + json.pass_count pass_count + json.unpass_count school.ue_count - pass_count +end \ No newline at end of file diff --git a/app/views/subjects/search_members.json.jbuilder b/app/views/subjects/search_members.json.jbuilder new file mode 100644 index 000000000..e4493424c --- /dev/null +++ b/app/views/subjects/search_members.json.jbuilder @@ -0,0 +1,7 @@ +json.users @users do |user| + json.user_id user.id + json.user_name user.full_name + json.nickname user.nickname + json.identity user.identity + json.school_name user.school_name +end \ No newline at end of file diff --git a/app/views/subjects/send_to_course.json.jbuilder b/app/views/subjects/send_to_course.json.jbuilder new file mode 100644 index 000000000..23da82281 --- /dev/null +++ b/app/views/subjects/send_to_course.json.jbuilder @@ -0,0 +1,3 @@ +json.status 1 +json.message "发送成功" +json.url "/homework_commons?course=#{@course.id}&homework_type=4" \ No newline at end of file diff --git a/app/views/subjects/shixun_report.json.jbuilder b/app/views/subjects/shixun_report.json.jbuilder new file mode 100644 index 000000000..6965f7a75 --- /dev/null +++ b/app/views/subjects/shixun_report.json.jbuilder @@ -0,0 +1,9 @@ +json.shixun_lists @subject.stages.each do |stage| + json.array! stage.stage_shixuns do |stage_shixun| + shixun = stage_shixun.shixun + json.number "#{stage.position}-#{stage_shixun.position}" + json.shixun_name shixun.name + json.member_count shixun.myshixuns_count + json.school_count UserExtension.where(user_id: shixun.myshixuns.pluck(:user_id)).pluck(:school_id).uniq.length + end +end \ No newline at end of file diff --git a/app/views/subjects/show.json.jbuilder b/app/views/subjects/show.json.jbuilder new file mode 100644 index 000000000..14eb1942f --- /dev/null +++ b/app/views/subjects/show.json.jbuilder @@ -0,0 +1,33 @@ +json.(@subject, :id, :name, :description, :learning_notes, :stages_count, :stage_shixuns_count) + +json.challenge_choose_count @subject.subject_challenge_choose_count +json.challenges_count @subject.subject_challenge_count +json.subject_score @subject.all_score +json.member_count @subject.member_count + +json.allow_delete @is_creator && (@subject.status != 2 || @user.admin?) +json.publish_status publish_status(@subject, @is_creator, @user) +json.allow_statistics @user.manager_of_subject?(@subject) +json.allow_send @user.logged? +json.allow_visit @user.manager_of_subject?(@subject) || @user.admin? || @subject.status > 1 +json.allow_add_member @user.admin? + +json.members @members do |member| + json.partial! 'subject_member', locals: { user: member.user } +end + +# 技能标签 +json.tags @tags do |tag| + unless tag.blank? + json.tag_name tag + json.status @user_tags.include?(tag) + end +end + +# 我的进展 +json.progress do + json.my_score @subject.my_subject_score + json.all_score @subject.all_score + json.learned @subject.my_subject_progress + json.time @subject.my_consume_time +end \ No newline at end of file diff --git a/app/views/subjects/statistics.json.jbuilder b/app/views/subjects/statistics.json.jbuilder new file mode 100644 index 000000000..53e84ca61 --- /dev/null +++ b/app/views/subjects/statistics.json.jbuilder @@ -0,0 +1,20 @@ +json.subject_id @subject.id +json.subject_name @subject.name +json.learn_count @learn_count +json.course_count @course_count +json.schools_count @schools_count +json.school_total_count @school_total_count + +json.schools @schools.try(:each) do |school| + json.name school[:name] + json.course_count school[:course_count] + json.student_count school[:student_count] + json.homework_count school[:homework_count] +end + +index = 0 +json.stage_info @stage_user_info.each do |stage| + json.stage_no "第#{index + 1}章" + json.value @sum == 0 ? 0 : (stage * 100 / @sum.to_f).round + index += 1 +end \ No newline at end of file diff --git a/app/views/subjects/up_member_position.json.jbuilder b/app/views/subjects/up_member_position.json.jbuilder new file mode 100644 index 000000000..410b5641b --- /dev/null +++ b/app/views/subjects/up_member_position.json.jbuilder @@ -0,0 +1,3 @@ +json.members @subject.subject_members do |member| + json.partial! 'subject_member', locals: { user: member.user } +end \ No newline at end of file diff --git a/app/views/subjects/update.json.jbuilder b/app/views/subjects/update.json.jbuilder new file mode 100644 index 000000000..c9c536b27 --- /dev/null +++ b/app/views/subjects/update.json.jbuilder @@ -0,0 +1 @@ +json.subject_id @subject.id \ No newline at end of file diff --git a/app/views/tem_tests/_form.html.erb b/app/views/tem_tests/_form.html.erb new file mode 100644 index 000000000..2d32de6ec --- /dev/null +++ b/app/views/tem_tests/_form.html.erb @@ -0,0 +1,27 @@ +<%= form_with(model: tem_test, local: true) do |form| %> + <% if tem_test.errors.any? %> +
    +

    <%= pluralize(tem_test.errors.count, "error") %> prohibited this tem_test from being saved:

    + +
      + <% tem_test.errors.full_messages.each do |message| %> +
    • <%= message %>
    • + <% end %> +
    +
    + <% end %> + +
    + <%= form.label :name %> + <%= form.text_field :name %> +
    + +
    + <%= form.label :email %> + <%= form.text_field :email %> +
    + +
    + <%= form.submit %> +
    +<% end %> diff --git a/app/views/tem_tests/_tem_test.json.jbuilder b/app/views/tem_tests/_tem_test.json.jbuilder new file mode 100644 index 000000000..4493d42c1 --- /dev/null +++ b/app/views/tem_tests/_tem_test.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! tem_test, :id, :name, :email, :created_at, :updated_at +json.url tem_test_url(tem_test, format: :json) diff --git a/app/views/tem_tests/edit.html.erb b/app/views/tem_tests/edit.html.erb new file mode 100644 index 000000000..6ddd6f0ea --- /dev/null +++ b/app/views/tem_tests/edit.html.erb @@ -0,0 +1,6 @@ +

    Editing Tem Test

    + +<%= render 'form', tem_test: @tem_test %> + +<%= link_to 'Show', @tem_test %> | +<%= link_to 'Back', tem_tests_path %> diff --git a/app/views/tem_tests/index.html.erb b/app/views/tem_tests/index.html.erb new file mode 100644 index 000000000..96a3d843f --- /dev/null +++ b/app/views/tem_tests/index.html.erb @@ -0,0 +1,29 @@ +

    <%= notice %>

    + +

    Tem Tests

    + + + + + + + + + + + + <% @tem_tests.each do |tem_test| %> + + + + + + + + <% end %> + +
    NameEmail
    <%= tem_test.name %><%= tem_test.email %><%= link_to 'Show', tem_test %><%= link_to 'Edit', edit_tem_test_path(tem_test) %><%= link_to 'Destroy', tem_test, method: :delete, data: { confirm: 'Are you sure?' } %>
    + +
    + +<%= link_to 'New Tem Test', new_tem_test_path %> diff --git a/app/views/tem_tests/index.json.jbuilder b/app/views/tem_tests/index.json.jbuilder new file mode 100644 index 000000000..d77e48320 --- /dev/null +++ b/app/views/tem_tests/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @tem_tests, partial: 'tem_tests/tem_test', as: :tem_test diff --git a/app/views/tem_tests/new.html.erb b/app/views/tem_tests/new.html.erb new file mode 100644 index 000000000..38b7a49c6 --- /dev/null +++ b/app/views/tem_tests/new.html.erb @@ -0,0 +1,5 @@ +

    New Tem Test

    + +<%= render 'form', tem_test: @tem_test %> + +<%= link_to 'Back', tem_tests_path %> diff --git a/app/views/tem_tests/show.html.erb b/app/views/tem_tests/show.html.erb new file mode 100644 index 000000000..9d6eeaf3e --- /dev/null +++ b/app/views/tem_tests/show.html.erb @@ -0,0 +1,14 @@ +

    <%= notice %>

    + +

    + Name: + <%= @tem_test.name %> +

    + +

    + Email: + <%= @tem_test.email %> +

    + +<%= link_to 'Edit', edit_tem_test_path(@tem_test) %> | +<%= link_to 'Back', tem_tests_path %> diff --git a/app/views/tem_tests/show.json.jbuilder b/app/views/tem_tests/show.json.jbuilder new file mode 100644 index 000000000..0f9ed64ac --- /dev/null +++ b/app/views/tem_tests/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "tem_tests/tem_test", tem_test: @tem_test diff --git a/app/views/tidings/_tiding.json.jbuilder b/app/views/tidings/_tiding.json.jbuilder new file mode 100644 index 000000000..7a7168d38 --- /dev/null +++ b/app/views/tidings/_tiding.json.jbuilder @@ -0,0 +1,9 @@ +json.extract! tiding, :id, :status, :viewed, :user_id, :tiding_type, :container_type, :parent_container_type +json.content tiding.content +json.time tiding.how_long_time + +json.trigger_user do + json.partial! 'users/user_simple', user: tiding.trigger_user +end + +json.attachments tiding.attachments, partial: 'attachments/attachment_small', as: :attachment diff --git a/app/views/tidings/index.json.jbuilder b/app/views/tidings/index.json.jbuilder new file mode 100644 index 000000000..69f932f8f --- /dev/null +++ b/app/views/tidings/index.json.jbuilder @@ -0,0 +1,2 @@ +json.count @count +json.tidings @tidings, partial: 'tidings/tiding', as: :tiding diff --git a/app/views/user_mailer/register_email.html.erb b/app/views/user_mailer/register_email.html.erb new file mode 100644 index 000000000..24ae606b7 --- /dev/null +++ b/app/views/user_mailer/register_email.html.erb @@ -0,0 +1,62 @@ + + + + 验证码发送 + + + + + +
    +
    +
    + + + +
    +
    +
    +

    + 您好! +

    +

    + 您正在注册Educoder,请在10分钟内在注册页输入此验证码,并进行下一步操作。 + 如非你本人操作,请忽略此邮件。 +

    +
    +
    +

    <%= @code %>

    +
    + + 此邮件为系统所发,请勿直接回复。
    + 要解决问题或了解您的帐户详情,您可以访问 帮助中心。 +
    +
    +

    + 如果您并未发过此请求,则可能是因为其他用户在注册时误输了您的邮件地址,而使您收到了这封邮件,那么您可以放心的忽略此邮件,无需进一步采取任何操作。 +

    +
    + +
    +
    + + diff --git a/app/views/user_mailer/register_email.text.erb b/app/views/user_mailer/register_email.text.erb new file mode 100644 index 000000000..b6fc4c620 --- /dev/null +++ b/app/views/user_mailer/register_email.text.erb @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/app/views/user_mailer/welcome_email.html.erb b/app/views/user_mailer/welcome_email.html.erb new file mode 100644 index 000000000..6f88177c5 --- /dev/null +++ b/app/views/user_mailer/welcome_email.html.erb @@ -0,0 +1,62 @@ + + + + 验证码发送 + + + + + +
    +
    +
    + + + +
    +
    +
    +

    + 您好! +

    +

    + 您正在注册Educoder,请在10分钟内在注册页输入此验证码,并进行下一步操作。 + 如非你本人操作,请忽略此邮件。 +

    +
    +
    +

    <%= @code %>

    +
    + + 此邮件为系统所发,请勿直接回复。
    + 要解决问题或了解您的帐户详情,您可以访问 帮助中心。 +
    +
    +

    + 如果您并未发过此请求,则可能是因为其他用户在注册时误输了您的邮件地址,而使您收到了这封邮件,那么您可以放心的忽略此邮件,无需进一步采取任何操作。 +

    +
    + +
    +
    + + diff --git a/app/views/users/_memo_user_info.json.jbuilder b/app/views/users/_memo_user_info.json.jbuilder new file mode 100644 index 000000000..a8d57e358 --- /dev/null +++ b/app/views/users/_memo_user_info.json.jbuilder @@ -0,0 +1,6 @@ +json.username @user.full_name +json.login @user.login +json.user_id @user.id +json.image_url url_to_avatar(@user) +json.admin @user.admin +json.is_teacher @user.user_extension.teacher? \ No newline at end of file diff --git a/app/views/users/_user.json.jbuilder b/app/views/users/_user.json.jbuilder new file mode 100644 index 000000000..1d26506f3 --- /dev/null +++ b/app/views/users/_user.json.jbuilder @@ -0,0 +1,8 @@ +json.user_id user.id +json.login user.login +json.name user.full_name +json.grade user.grade +# json.email user.mail # 邮箱原则上不暴露的,如果实在需要的话只能对某些具体的接口公开 +json.image_url url_to_avatar(user) +json.user_url user_path(user) +json.school user.school_name \ No newline at end of file diff --git a/app/views/users/_user_simple.json.jbuilder b/app/views/users/_user_simple.json.jbuilder new file mode 100644 index 000000000..0d8f9d50c --- /dev/null +++ b/app/views/users/_user_simple.json.jbuilder @@ -0,0 +1,4 @@ +json.id user.id +json.name user.full_name +json.login user.login +json.image_url url_to_avatar(user) \ No newline at end of file diff --git a/app/views/users/_user_small.json.jbuilder b/app/views/users/_user_small.json.jbuilder new file mode 100644 index 000000000..54107b0e3 --- /dev/null +++ b/app/views/users/_user_small.json.jbuilder @@ -0,0 +1,8 @@ +# 单表存储的信息可以放里面 +json.array! users do |user| + json.username user.full_name + json.login user.login + json.user_id user.id + json.image_url url_to_avatar(user) +end + diff --git a/app/views/users/accounts/show.json.jbuilder b/app/views/users/accounts/show.json.jbuilder new file mode 100644 index 000000000..fca883ea0 --- /dev/null +++ b/app/views/users/accounts/show.json.jbuilder @@ -0,0 +1,25 @@ +json.extract! observed_user, :id, :nickname, :phone, :mail, :show_realname + +json.avatar_url url_to_avatar(observed_user) +user = ActiveDecorator::Decorator.instance.decorate(observed_user) +json.name user.name +json.authentication user.authentication_status +json.professional_certification user.professional_certification_status + +extension = observed_user.user_extension +json.gender extension&.gender +json.location extension&.location +json.location_city extension&.location_city + +json.identity extension&.identity +json.technical_title extension&.technical_title +json.student_id extension&.student_id + +json.school_id extension&.school_id +json.school_name extension&.school&.name + +json.department_id extension&.department_id +json.department_name extension&.department&.name + +json.base_info_completed user.base_info_completed? +json.all_certified user.all_certified? diff --git a/app/views/users/courses/index.json.jbuilder b/app/views/users/courses/index.json.jbuilder new file mode 100644 index 000000000..614e06391 --- /dev/null +++ b/app/views/users/courses/index.json.jbuilder @@ -0,0 +1,3 @@ + +json.count @count +json.courses @courses, partial: 'users/courses/shared/course', as: :course diff --git a/app/views/users/courses/shared/_course.json.jbuilder b/app/views/users/courses/shared/_course.json.jbuilder new file mode 100644 index 000000000..e5823212e --- /dev/null +++ b/app/views/users/courses/shared/_course.json.jbuilder @@ -0,0 +1,14 @@ +json.id course.id +json.name course.name +json.members_count course.members_count +json.homework_commons_count course.homework_commons_count +json.attachments_count course.attachments.count + +json.first_category_url module_url(course.course_modules.where.not(module_type: "activity").where(hidden: 0).order(position: :desc).first, course) + +json.is_public course.is_public +json.can_visited observed_logged_user? || course.can_visited? + +json.teacher do + json.partial! 'users/shared/real_user', user: course.teacher +end \ No newline at end of file diff --git a/app/views/users/experience_records/shared/_experience.json.jbuilder b/app/views/users/experience_records/shared/_experience.json.jbuilder new file mode 100644 index 000000000..a8277e323 --- /dev/null +++ b/app/views/users/experience_records/shared/_experience.json.jbuilder @@ -0,0 +1,4 @@ +json.container_type_text experience.container_type_text +json.score experience.score +json.created_at experience.created_at&.strftime('%Y-%m-%d %H:%M') +json.content experience.content \ No newline at end of file diff --git a/app/views/users/experience_records/show.json.jbuilder b/app/views/users/experience_records/show.json.jbuilder new file mode 100644 index 000000000..52d42300b --- /dev/null +++ b/app/views/users/experience_records/show.json.jbuilder @@ -0,0 +1,3 @@ +json.experience_total observed_user.experience +json.count @count +json.experiences @experience_records, partial: 'users/experience_records/shared/experience', as: :experience \ No newline at end of file diff --git a/app/views/users/get_navigation_info.json.jbuilder b/app/views/users/get_navigation_info.json.jbuilder new file mode 100644 index 000000000..57a303cb6 --- /dev/null +++ b/app/views/users/get_navigation_info.json.jbuilder @@ -0,0 +1,48 @@ +json.top do + json.shixun_url "/shixuns" + json.shixun_paths_url "#{@old_domain}/paths" + json.course_url "#{@old_domain}/courses" + json.competitions_url "#{@old_domain}/competitions" + json.topic_url "#{@old_domain}/forums" + json.new_course_url "#{@old_domain}/courses/new" + json.new_shixun_url "#{@old_domain}/shixuns/new" + json.new_shixun_path_url "#{@old_domain}/paths/new" + json.new_project_url "#{@old_domain}/projects/new" + json.join_course_url "#{@old_domain}/courses/join_course_multi_role" + json.join_project_url "#{@old_domain}/applied_project/applied_project_info" + json.message_url "#{@user_url}/user_tidings" + json.new_message @new_message + + json.career_url do + json.array! @career.to_a do |c| + if c[1].present? + json.name c[1] + json.url "#{@old_domain}/careers/#{c[0]}/introduction" + end + end + end + json.auth @auth + + json.avatar_url "#{@user_url}" + json.my_course_url "#{@user_url}" + json.my_shixun_url "#{@user_url}?type=a_shixun" + json.my_shixun_paths_url "#{@user_url}?type=a_path" + json.my_project_url "#{@user_url}?type=a_project" + json.account_manager_url "#{@old_domain}/my/account" + json.logout_url logout_accounts_path + # 旧版的域名 + json.old_url @old_domain +end + +json.down do + json.web_root "#{@old_domain}" + json.about_us "#{@old_domain}/help?index=1" + json.connect_us "#{@old_domain}/help?index=2" + json.cooperation_partner "#{@old_domain}/help?index=3" + json.service_agreement "#{@old_domain}/help?index=4" + json.help_center "#{@old_domain}/help?index=5" + json.feedback "#{@old_domain}/help?index=6" +end + +json.online_consult "https://shang.qq.com/wpa/qunwpa?idkey=2f2043d88c1bd61d182b98bf1e061c6185e23055bec832c07d8148fe11c5a6cd" + diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder new file mode 100644 index 000000000..779d58e95 --- /dev/null +++ b/app/views/users/get_user_info.json.jbuilder @@ -0,0 +1,20 @@ +json.username @user.full_name +json.login @user.login +json.user_id @user.id +json.image_url url_to_avatar(@user) +json.admin @user.admin? +json.is_teacher @user.user_extension&.teacher? +json.tidding_count 0 +json.user_phone_binded @user.phone.present? +if @course + json.course_identity @course_identity + json.course_name @course.name + json.course_public @course.is_public + if params[:group_info] + json.group_info @course.teacher_group(@user.id) if @course_identity < Course::STUDENT + end +end + +if params[:school] + json.user_school @user.school_name +end diff --git a/app/views/users/grade_records/shared/_grade.json.jbuilder b/app/views/users/grade_records/shared/_grade.json.jbuilder new file mode 100644 index 000000000..71a28b3a0 --- /dev/null +++ b/app/views/users/grade_records/shared/_grade.json.jbuilder @@ -0,0 +1,4 @@ +json.container_type_text grade.container_type_text +json.score grade.score +json.created_at grade.created_at&.strftime('%Y-%m-%d %H:%M') +json.content grade.content \ No newline at end of file diff --git a/app/views/users/grade_records/show.json.jbuilder b/app/views/users/grade_records/show.json.jbuilder new file mode 100644 index 000000000..ead81df17 --- /dev/null +++ b/app/views/users/grade_records/show.json.jbuilder @@ -0,0 +1,3 @@ +json.grade_total observed_user.grade +json.count @count +json.grade_records @grade_records, partial: 'users/grade_records/shared/grade', as: :grade \ No newline at end of file diff --git a/app/views/users/homepage_info.json.jbuilder b/app/views/users/homepage_info.json.jbuilder new file mode 100644 index 000000000..3f985eab9 --- /dev/null +++ b/app/views/users/homepage_info.json.jbuilder @@ -0,0 +1,22 @@ +json.id @user.id +json.name @user.homepage_name +json.avatar_url url_to_avatar(@user) +json.is_logged_user @user.logged_user? +json.experience @user.experience +json.grade @user.grade +json.follow_count @user.follow_count +json.fan_count @user.fan_count +json.identity @user.identity +json.brief_introduction @user.user_extension&.brief_introduction +json.authentication @user.authentication +json.professional_certification @user.professional_certification +json.phone_binded @user.phone_binded? +json.email_binded @user.email_binded? +json.college_identifier @user.college_identifier +json.followed User.current.watched?(@user) + +if @user.logged_user? + json.can_apply_trial @user.can_apply_trial? + json.attendance_signed @user.attendance_signed? + json.tomorrow_attendance_gold @user.tomorrow_attendance_gold +end diff --git a/app/views/users/projects/index.json.jbuilder b/app/views/users/projects/index.json.jbuilder new file mode 100644 index 000000000..c0ef2a548 --- /dev/null +++ b/app/views/users/projects/index.json.jbuilder @@ -0,0 +1,3 @@ + +json.count @count +json.projects @projects, partial: 'users/projects/shared/project', as: :project diff --git a/app/views/users/projects/shared/_project.json.jbuilder b/app/views/users/projects/shared/_project.json.jbuilder new file mode 100644 index 000000000..5cc985909 --- /dev/null +++ b/app/views/users/projects/shared/_project.json.jbuilder @@ -0,0 +1,13 @@ +json.id project.id +json.name project.name + +json.members_count project.members.count +json.issues_count project.issues.count +json.changesets_count project.project_score&.changeset_num.to_i + +json.is_public project.is_public? +json.can_visited project.can_visited? + +json.owner do + json.partial! 'users/shared/real_user', user: project.owner +end \ No newline at end of file diff --git a/app/views/users/question_banks/index.json.jbuilder b/app/views/users/question_banks/index.json.jbuilder new file mode 100644 index 000000000..bee5d1b5d --- /dev/null +++ b/app/views/users/question_banks/index.json.jbuilder @@ -0,0 +1,9 @@ + +json.count @count +json.course_list @course_lists, partial: 'users/question_banks/shared/course_list', as: :course_list +json.question_banks do + json.array! @question_banks do |question_bank| + json.partial! 'users/question_banks/shared/question_bank', locals: { question_bank: question_bank } + json.solve_count @solve_count_map.fetch(question_bank.id, 0) + end +end diff --git a/app/views/users/question_banks/shared/_course_list.json.jbuilder b/app/views/users/question_banks/shared/_course_list.json.jbuilder new file mode 100644 index 000000000..7e9dae781 --- /dev/null +++ b/app/views/users/question_banks/shared/_course_list.json.jbuilder @@ -0,0 +1,3 @@ + +json.id course_list.id +json.name course_list.name diff --git a/app/views/users/question_banks/shared/_question_bank.json.jbuilder b/app/views/users/question_banks/shared/_question_bank.json.jbuilder new file mode 100644 index 000000000..0c3370310 --- /dev/null +++ b/app/views/users/question_banks/shared/_question_bank.json.jbuilder @@ -0,0 +1,8 @@ + +json.id question_bank.id +json.name question_bank.name +json.is_public question_bank.is_public +json.quotes_count question_bank.quotes +json.creator_name question_bank.user.name +json.course_list_name question_bank.course_list.name +json.updated_at question_bank.updated_at diff --git a/app/views/users/reply_message.json.jbuilder b/app/views/users/reply_message.json.jbuilder new file mode 100644 index 000000000..26052baa8 --- /dev/null +++ b/app/views/users/reply_message.json.jbuilder @@ -0,0 +1 @@ +json.id @message.id \ No newline at end of file diff --git a/app/views/users/search_user_projects.json.jbuilder b/app/views/users/search_user_projects.json.jbuilder new file mode 100644 index 000000000..9a8bf1cc3 --- /dev/null +++ b/app/views/users/search_user_projects.json.jbuilder @@ -0,0 +1,4 @@ +json.projects @projects do |project| + json.project_id project.id + json.project_name project.name +end \ No newline at end of file diff --git a/app/views/users/shared/_real_user.json.jbuilder b/app/views/users/shared/_real_user.json.jbuilder new file mode 100644 index 000000000..60065a339 --- /dev/null +++ b/app/views/users/shared/_real_user.json.jbuilder @@ -0,0 +1,4 @@ +json.id user.id +json.real_name user.real_name +json.avatar_url url_to_avatar(user) +json.school_name user.school_name \ No newline at end of file diff --git a/app/views/users/shixuns/index.json.jbuilder b/app/views/users/shixuns/index.json.jbuilder new file mode 100644 index 000000000..a5321f1cd --- /dev/null +++ b/app/views/users/shixuns/index.json.jbuilder @@ -0,0 +1,3 @@ + +json.count @count +json.shixuns @shixuns, partial: 'users/shixuns/shared/shixun', as: :shixun, locals: { user: observed_user } diff --git a/app/views/users/shixuns/shared/_shixun.json.jbuilder b/app/views/users/shixuns/shared/_shixun.json.jbuilder new file mode 100644 index 000000000..13cc3a9ee --- /dev/null +++ b/app/views/users/shixuns/shared/_shixun.json.jbuilder @@ -0,0 +1,9 @@ +json.id shixun.id +json.identifier shixun.identifier +json.tag shixun.first_tag_repertoire&.name +json.image_url url_to_avatar(shixun) +json.name shixun.name +json.status shixun.status +json.human_status shixun.human_status +json.challenges_count shixun.challenges_count +json.finished_challenges_count shixun.finished_challenges_count(user) \ No newline at end of file diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder new file mode 100644 index 000000000..09fef7e2f --- /dev/null +++ b/app/views/users/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'users/user', locals: { user: @user } \ No newline at end of file diff --git a/app/views/users/subjects/index.json.jbuilder b/app/views/users/subjects/index.json.jbuilder new file mode 100644 index 000000000..0a617bd78 --- /dev/null +++ b/app/views/users/subjects/index.json.jbuilder @@ -0,0 +1,3 @@ + +json.count @count +json.subjects @subjects, partial: 'users/subjects/shared/subject', as: :subject diff --git a/app/views/users/subjects/shared/_subject.json.jbuilder b/app/views/users/subjects/shared/_subject.json.jbuilder new file mode 100644 index 000000000..2059bc461 --- /dev/null +++ b/app/views/users/subjects/shared/_subject.json.jbuilder @@ -0,0 +1,8 @@ +json.id subject.id +json.name subject.name +json.tag subject.repertoire&.name +json.image_url url_to_avatar(subject) +json.owner_id subject.user.id +json.owner_name subject.user.full_name +json.visits_count subject.visits +json.can_visited subject.can_visited? diff --git a/bin/bundle b/bin/bundle new file mode 100644 index 000000000..b48d3a0d5 --- /dev/null +++ b/bin/bundle @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) +load Gem.bin_path('bundler', 'bundle') diff --git a/bin/rails b/bin/rails new file mode 100644 index 000000000..a017658c5 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake new file mode 100644 index 000000000..8704afdf3 --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100644 index 000000000..ef26bb399 --- /dev/null +++ b/bin/setup @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') + + # puts "\n== Copying sample files ==" + # unless File.exist?('config/database.yml') + # cp 'config/database.yml.sample', 'config/database.yml' + # end + + puts "\n== Preparing database ==" + system! 'bin/rails db:setup' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/bin/update b/bin/update new file mode 100644 index 000000000..c5e43745e --- /dev/null +++ b/bin/update @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a way to update your development environment automatically. + # Add necessary update steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') + + puts "\n== Updating database ==" + system! 'bin/rails db:migrate' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/bin/yarn b/bin/yarn new file mode 100644 index 000000000..b3095ee0e --- /dev/null +++ b/bin/yarn @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + begin + exec "yarnpkg", *ARGV + rescue Errno::ENOENT + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 + end +end diff --git a/config.ru b/config.ru new file mode 100644 index 000000000..897c3f927 --- /dev/null +++ b/config.ru @@ -0,0 +1,5 @@ +# This file is used by Rack-based servers to start the application. + +require_relative 'config/environment' + +run Rails.application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 000000000..8f1d3aebf --- /dev/null +++ b/config/application.rb @@ -0,0 +1,40 @@ +require_relative 'boot' + +require 'rails/all' + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module Educoderplus + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 5.2 + + # Settings in config/environments/* take precedence over those specified here. + # Application configuration can go into files in config/initializers + # -- all .rb files in that directory are automatically loaded after loading + # the framework and any gems in your application. + # + # + config.educoder = config_for(:configuration) + + config.active_record.default_timezone = :local + config.time_zone = 'Beijing' + + # I18n + config.i18n.default_locale = 'zh-CN' + config.i18n.load_path += Dir[Rails.root.join('config/locales', '**', '*.yml').to_s] + + # job + config.active_job.queue_adapter = :sidekiq + + config.middleware.insert_before 0, Rack::Cors do + allow do + origins '*' + # location of your api + resource '/*', :headers => :any, :methods => [:get, :post, :delete, :options, :put] + end + end + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 000000000..5343f6cb9 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) + +require 'bundler/setup' # Set up gems listed in the Gemfile. +require 'bootsnap/setup' # Speed up boot time by caching expensive operations. diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 000000000..3516b3fde --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: educoderplus_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 000000000..0e77b175f --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +HQzrAxnd5iZF+w0HBwIETJ66R0NXf7lW02rnNpD0nfzWVpRxtFwBtVKYzbwih+8RA2BIVF6uHFjDVdBnLL0/VcQt6iOAgYqWUUnjThaGu62M4OxbxCKpp/qiWTkxPalAGjIFN3xc/OR76G1aKwW8kfBJhvzyT74YC3NfhJditXQlZWPBn4XJQFlqabGJH2BR9FoKyuOBLuSwDLK5LCE4BIz5gPeJBD1G7et1UimSixG7Fc8DeJfwMFfikFG51YqcX7wNyeQQQifv4f/bdduX31dhWG6ElE9sXcQCD4iowsHLyepA++3nCpSqCSuht0SsSb6r16QJBh0zfr/IscjFnWM1WoW5Iccp3WllqAENzKHi6iS9M6lk87SL4r/Kbf5n7WTEPkyL76OrC1tugnfE2ARMmzmZ2uVyXWea--DhX+q3d9jB/R6/Iv--ibe53X5kyDC3RPvu2x2OqQ== \ No newline at end of file diff --git a/config/database.yml.example b/config/database.yml.example new file mode 100644 index 000000000..4e65c2f0b --- /dev/null +++ b/config/database.yml.example @@ -0,0 +1,54 @@ +# MySQL. Versions 5.1.10 and up are supported. +# +# Install the MySQL driver +# gem install mysql2 +# +# Ensure the MySQL gem is defined in your Gemfile +# gem 'mysql2' +# +# And be sure to use new-style password hashing: +# https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html +# +default: &default + adapter: mysql2 + encoding: utf8 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + username: root + password: 123456 +# socket: /var/run/mysqld/mysqld.sock + +development: + <<: *default + database: eduplus + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: eduplus + +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%= ENV['DATABASE_URL'] %> +# +production: + <<: *default + database: eduplus + username: educoderplus + password: <%= ENV['EDUCODERPLUS_DATABASE_PASSWORD'] %> diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 000000000..d59d63f1f --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative 'application' + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 000000000..0b31f5828 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,76 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + + config.cache_store = :file_store, "#{Rails.root }/files/cache_store/" + + # if Rails.root.join('tmp', 'caching-dev.txt').exist? + # config.action_controller.perform_caching = true + # + # config.cache_store = :memory_store + # config.public_file_server.headers = { + # 'Cache-Control' => "public, max-age=#{2.days.to_i}" + # } + # else + # config.action_controller.perform_caching = false + # + # config.cache_store = :null_store + # end + + # Store uploaded files on the local file system (see config/storage.yml for options) + config.active_storage.service = :local + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true + + # Use an evented file watcher to asynchronously detect changes in source code, + # routes, locales, etc. This feature depends on the listen gem. + config.file_watcher = ActiveSupport::EventedFileUpdateChecker + + config.action_controller.perform_caching = true + + config.action_mailer.delivery_method = :smtp + config.action_mailer.smtp_settings = { + address: 'smtp.exmail.qq.com', + port: 25, + domain: 'smtp.qq.com', + user_name: 'educoder@trustie.org', + password: 'mAZc9EWbe2Kawaqo2', + authentication: 'login', + enable_starttls_auto: true } +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 000000000..38938b7e3 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,110 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + ## config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? + config.public_file_server.enabled = true + + # Compress JavaScripts and CSS. + config.assets.js_compressor = :uglifier + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.action_controller.asset_host = 'http://assets.example.com' + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options) + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain + # config.action_cable.mount_path = nil + # config.action_cable.url = 'wss://example.com/cable' + # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment) + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "educoderplus_#{Rails.env}" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners. + config.active_support.deprecation = :notify + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require 'syslog/logger' + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + config.active_record.belongs_to_required_by_default = false + + # config.cache_store = :file_store, "#{Rails.root }/files/cache_store/" + config.cache_store = :redis_store, 'redis://10.9.72.102:6379/0/cache', { expires_in: 90.minutes } + + config.action_mailer.delivery_method = :smtp + config.action_mailer.smtp_settings = { + address: 'smtp.exmail.qq.com', + port: 25, + domain: 'smtp.qq.com', + user_name: 'educoder@trustie.org', + password: 'mAZc9EWbe2Kawaqo2', + authentication: 'login', + enable_starttls_auto: true } +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 000000000..5342fa99a --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,51 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true + # + # + + # Dont clean the database before test + config.active_record.maintain_test_schema = false +end diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb new file mode 100644 index 000000000..a9d54e6ed --- /dev/null +++ b/config/initializers/application_controller_renderer.rb @@ -0,0 +1,9 @@ +# Be sure to restart your server when you modify this file. + +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end + diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb new file mode 100644 index 000000000..c664f7cdd --- /dev/null +++ b/config/initializers/assets.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 000000000..803738d70 --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb new file mode 100644 index 000000000..397d77fce --- /dev/null +++ b/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy +# For further information see the following documentation +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + +# Rails.application.config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https + +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end + +# If you are using UJS then enable automatic nonce generation +# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } + +# Report CSP violations to a specified URI +# For further information see the following documentation: +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only +# Rails.application.config.content_security_policy_report_only = true diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb new file mode 100644 index 000000000..7e009bed7 --- /dev/null +++ b/config/initializers/cookies_serializer.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Specify a serializer for the signed and encrypted cookie jars. +# Valid options are :json, :marshal, and :hybrid. +Rails.application.config.action_dispatch.cookies_serializer = :marshal diff --git a/config/initializers/eudcoder_config.rb b/config/initializers/eudcoder_config.rb new file mode 100644 index 000000000..6c94a1f7a --- /dev/null +++ b/config/initializers/eudcoder_config.rb @@ -0,0 +1 @@ +require 'educoder' \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 000000000..180af8a4d --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Configure sensitive parameters which will be filtered from the log file. +Rails.application.config.filter_parameters += [:password] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 000000000..d173fb9fa --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym 'RESTful' +# end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 000000000..31415ae8a --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf +Mime::Type.register "application/xls", :xls diff --git a/config/initializers/pdfkit.rb b/config/initializers/pdfkit.rb new file mode 100644 index 000000000..168fc0c1e --- /dev/null +++ b/config/initializers/pdfkit.rb @@ -0,0 +1,24 @@ +PDFKit.configure do |config| + config.wkhtmltopdf = ENV["WKHTMLTOPDF_EXEC"] || 'wkhtmltopdf' + config.default_options = { + page_size: 'A4', + print_media_type: true, + dpi: 300, + debug_javascript: true, + javascript_delay: 500, + stop_slow_scripts:false, + no_stop_slow_scripts: true + } +end + +# 原有方法会给所有含 head 标签的地方插入css,导致html类实训代码块渲染异常 +module FixStylesheetAppend + def append_stylesheets + raise ImproperSourceError.new('Stylesheets may only be added to an HTML source') if stylesheets.any? && !@source.html? + + stylesheets.each do |stylesheet| + @source.to_s.insert(0, style_tag_for(stylesheet)) + end + end +end +PDFKit.prepend(FixStylesheetAppend) diff --git a/config/initializers/session_extenstions.rb b/config/initializers/session_extenstions.rb new file mode 100644 index 000000000..36a8ae8c7 --- /dev/null +++ b/config/initializers/session_extenstions.rb @@ -0,0 +1,35 @@ +#coding=utf-8 + +module SessionExtenstions + + module EntryExtension + def compressed? + @compressed + end + + def value + if @value + begin + Marshal.load(compressed? ? Zlib::Inflate.inflate(@value) : @value) + rescue TypeError + compressed? ? Zlib::Inflate.inflate(@value) : @value + end + end + end + + def size + if @value.nil? + 0 + else + @value.bytesize + end + end + end + + +end + +ActiveSupport::Cache::Entry.const_set("DEFAULT_COMPRESS_LIMIT", 1) +ActiveSupport::Cache::Entry.send(:prepend, SessionExtenstions::EntryExtension) + + diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 000000000..b8d29a52c --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1,8 @@ +# Use the database for sessions instead of the cookie-based default, +# which shouldn't be used to store highly confidential information +# (create the session table with "rails g active_record:session_migration") +# Rails.application.config.session_store :active_record_store + +# Be sure to restart your server when you modify this file. +Rails.application.config.session_store :cache_store, :expire_after => 10.hours, key: '_educoder_session', domain: :all + diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb new file mode 100644 index 000000000..b3f2d0576 --- /dev/null +++ b/config/initializers/sidekiq.rb @@ -0,0 +1,10 @@ +redis_config = Rails.application.config_for(:redis) +sidekiq_url = redis_config["url"] + +Sidekiq.configure_server do |config| + config.redis = { url: sidekiq_url } +end + +Sidekiq.configure_client do |config| + config.redis = { url: sidekiq_url } +end diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb new file mode 100644 index 000000000..be2540b2a --- /dev/null +++ b/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# To enable root element in JSON for ActiveRecord objects. +# ActiveSupport.on_load(:active_record) do +# self.include_root_in_json = true +# end diff --git a/config/locales/ec_course_targets/zh-CN.yml b/config/locales/ec_course_targets/zh-CN.yml new file mode 100644 index 000000000..f447da201 --- /dev/null +++ b/config/locales/ec_course_targets/zh-CN.yml @@ -0,0 +1,9 @@ +'zh-CN': + activerecord: + models: + ec_course_target: '课程目标' + attributes: + ec_course_target: + content: '内容' + standard_grade: '达成标准(分)' + weight: '权重' diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 000000000..bb1bb3934 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,4 @@ +en: + error: + record_not_found: Record not found + forbidden: Forbidden \ No newline at end of file diff --git a/config/locales/experiences/zh-CN.yml b/config/locales/experiences/zh-CN.yml new file mode 100644 index 000000000..923ea7d8b --- /dev/null +++ b/config/locales/experiences/zh-CN.yml @@ -0,0 +1,5 @@ +'zh-CN': + experience: + container_type: + game: 闯关 + shixun_publish: 发布实训 \ No newline at end of file diff --git a/config/locales/forms/apply_shixun_mirror_form.zh-CN.yml b/config/locales/forms/apply_shixun_mirror_form.zh-CN.yml new file mode 100644 index 000000000..801608282 --- /dev/null +++ b/config/locales/forms/apply_shixun_mirror_form.zh-CN.yml @@ -0,0 +1,15 @@ +'zh-CN': + activemodel: + attributes: + apply_shixun_mirror_form: + language: 语言 + runtime: 系统环境 + run_method: 测试代码运行方式 + attachment_id: 测试代码附件 + errors: + models: + apply_shixun_mirror_form: + attributes: + attachment_id: + attachment_not_exist: 不存在 + diff --git a/config/locales/forms/apply_trail_form.zh-CN.yml b/config/locales/forms/apply_trail_form.zh-CN.yml new file mode 100644 index 000000000..8cff35832 --- /dev/null +++ b/config/locales/forms/apply_trail_form.zh-CN.yml @@ -0,0 +1,15 @@ +'zh-CN': + activemodel: + attributes: + users/apply_trail_form: + user: '' + phone: 手机号 + code: 验证码 + reason: 申请原因 + errors: + models: + users/apply_trail_form: + attributes: + user: + already_trial: 已经处于试用状态了 + diff --git a/config/locales/forms/bind_email_form.zh-CN.yml b/config/locales/forms/bind_email_form.zh-CN.yml new file mode 100644 index 000000000..abd7474bc --- /dev/null +++ b/config/locales/forms/bind_email_form.zh-CN.yml @@ -0,0 +1,6 @@ +'zh-CN': + activemodel: + attributes: + users/bind_email_form: + email: 邮箱 + code: 验证码 diff --git a/config/locales/forms/bind_phone_form.zh-CN.yml b/config/locales/forms/bind_phone_form.zh-CN.yml new file mode 100644 index 000000000..5cd22a535 --- /dev/null +++ b/config/locales/forms/bind_phone_form.zh-CN.yml @@ -0,0 +1,6 @@ +'zh-CN': + activemodel: + attributes: + users/bind_phone_form: + phone: 手机号 + code: 验证码 diff --git a/config/locales/forms/create_course_achievement_methods_form.zh-CN.yml b/config/locales/forms/create_course_achievement_methods_form.zh-CN.yml new file mode 100644 index 000000000..5551281b9 --- /dev/null +++ b/config/locales/forms/create_course_achievement_methods_form.zh-CN.yml @@ -0,0 +1,25 @@ +'zh-CN': + activemodel: + models: + ecs/create_course_achievement_methods_form: 评价方法 + attributes: + ecs/create_course_achievement_methods_form: + course_achievement_methods: 评价方法 + ecs/create_course_achievement_methods_form/sub_form: + course_evaluation_id: 考核方式 + course_evaluation_subitem_ids: 考核方式分项 + score: 支撑总分值 + percentage: 评价占比 + errors: + models: + ecs/create_course_achievement_methods_form: + attributes: + course_achievement_methods: + percentage_error: 评价占比总和必须在0~100范围内 + ecs/create_course_achievement_methods_form/sub_form: + attributes: + course_evaluation_id: + record_not_exist: 不存在 + course_evaluation_subitem_ids: + record_not_exist: 不存在 + diff --git a/config/locales/forms/save_course_evaluation_form.zh-CN.yml b/config/locales/forms/save_course_evaluation_form.zh-CN.yml new file mode 100644 index 000000000..e619e3aff --- /dev/null +++ b/config/locales/forms/save_course_evaluation_form.zh-CN.yml @@ -0,0 +1,17 @@ +'zh-CN': + activemodel: + models: + ecs/save_course_evaluation_form: 考核方式 + attributes: + ecs/save_course_evaluation_form: + name: 名称 + evaluation_count: 考核次数 + status: 支撑方式 + course_evaluation_subitems: 考核分项 + errors: + models: + ecs/save_course_evaluation_form: + attributes: + course_evaluation_subitems: + name_blank: 名称不能为空 + diff --git a/config/locales/forms/save_graduation_course_support_form.zh-CN.yml b/config/locales/forms/save_graduation_course_support_form.zh-CN.yml new file mode 100644 index 000000000..1bcb93c69 --- /dev/null +++ b/config/locales/forms/save_graduation_course_support_form.zh-CN.yml @@ -0,0 +1,15 @@ +'zh-CN': + activemodel: + models: + ecs/save_graduation_course_support_form: '' + attributes: + ecs/save_graduation_course_support_form: + course_supports: '' + errors: + models: + ecs/save_graduation_course_support_form: + attributes: + course_supports: + weights_too_big: 权重之和不能大于1 + not_unique: 支撑课程不能重复 + diff --git a/config/locales/forms/update_account_form.zh-CN.yml b/config/locales/forms/update_account_form.zh-CN.yml new file mode 100644 index 000000000..b6511d7f3 --- /dev/null +++ b/config/locales/forms/update_account_form.zh-CN.yml @@ -0,0 +1,25 @@ +'zh-CN': + activemodel: + attributes: + users/update_account_form: + user: '' + nickname: 昵称 + name: 姓名 + gender: 性别 + location: 所在省份 + location_city: 所在城市 + identity: 职业 + technical_title: 职称 + school_id: '学校/单位' + department_id: '院系/部门' + errors: + models: + users/update_account_form: + attributes: + school_id: + blank: 不能为空 + not_exist: 不存在 + department_id: + blank: 不能为空 + not_exist: 不存在 + diff --git a/config/locales/forms/update_password_form.zh-CN.yml b/config/locales/forms/update_password_form.zh-CN.yml new file mode 100644 index 000000000..bc6982d3d --- /dev/null +++ b/config/locales/forms/update_password_form.zh-CN.yml @@ -0,0 +1,6 @@ +'zh-CN': + activemodel: + attributes: + users/update_password_form: + password: 新密码 + old_password: 旧密码 diff --git a/config/locales/grades/zh-CN.yml b/config/locales/grades/zh-CN.yml new file mode 100644 index 000000000..6c85b44e5 --- /dev/null +++ b/config/locales/grades/zh-CN.yml @@ -0,0 +1,20 @@ +'zh-CN': + grade: + container_type: + avatar: 首次上传头像 + phone: 绑定手机 + attendance: 签到 + mail: 绑定邮箱 + account: 完善基本资料 + answer: 查看参考答案 + game: 闯关 + memo: 额外奖励 + discusses: 额外奖励 + test_set: 查看隐藏测试集 + shixun_publish: 发布实训 + star: 实训评分 + check_ta_answer: 查看TA人解答 + feedback: 额外奖励 + authentication: 完成实名认证 + professional: 完成职业认证 + diff --git a/config/locales/question_banks/zh-CN.yml b/config/locales/question_banks/zh-CN.yml new file mode 100644 index 000000000..c1a18781d --- /dev/null +++ b/config/locales/question_banks/zh-CN.yml @@ -0,0 +1,10 @@ +'zh-CN': + question_bank: + container_type: + Common: 普通作业 + Shixun: 实训作业 + Group: 分组作业 + Exercise: 试卷 + Poll: 问卷 + GraduationTask: 毕设任务 + GradutionTopic: 毕设选题 diff --git a/config/locales/shixuns/en.yml b/config/locales/shixuns/en.yml new file mode 100644 index 000000000..0f1a9f695 --- /dev/null +++ b/config/locales/shixuns/en.yml @@ -0,0 +1,7 @@ +'en': + shixun: + status: + 0: editing + 1: applying + 2: published + 3: closed diff --git a/config/locales/shixuns/zh-CN.yml b/config/locales/shixuns/zh-CN.yml new file mode 100644 index 000000000..c5ba574d8 --- /dev/null +++ b/config/locales/shixuns/zh-CN.yml @@ -0,0 +1,7 @@ +'zh-CN': + shixun: + status: + 0: 编辑中 + 1: 审核中 + 2: 已发布 + 3: 已关闭 diff --git a/config/locales/tidings/zh-CN.yml b/config/locales/tidings/zh-CN.yml new file mode 100644 index 000000000..66262588c --- /dev/null +++ b/config/locales/tidings/zh-CN.yml @@ -0,0 +1,201 @@ +'zh-CN': + tiding: + ApplyUserAuthentication: + Apply: + "1_end": "申请实名认证:%s %s" + "2_end": "申请职业认证:%s %s" + System: + "1_1_end": "你提交的实名认证申请,审核已通过" + "1_2_end": "你提交的实名认证申请,审核未通过    原因:%{reason}" + "2_1_end": "你提交的职业认证申请,审核已通过" + "2_2_end": "你提交的职业认证申请,审核未通过    原因:%{reason}" + CancelUserAuthentication_end: "取消了你的实名认证:%s %s" + CancelUserProCertification_end: "取消了你的实名认证:%s %s" + JoinCourse: + "9_end": "申请加入课堂:%s(教师)" + "7_end": "申请加入课堂:%s(助教)" + DealCourse: + "9_1_end": "你提交的加入课堂申请:%s(教师), 审核已通过" + "9_2_end": "你提交的加入课堂申请:%s(教师), 审核未通过" + "7_1_end": "你提交的加入课堂申请:%s(助教), 审核已通过" + "7_2_end": "你提交的加入课堂申请:%s(助教), 审核未通过" + StudentJoinCourse_end: "加入了课堂:%s(学生)" + TeacherJoinCourse: + "9_end": "%s将你加入课堂:%s(教师)" + "7_end": "%s将你加入课堂:%s(助教)" + "10_end": "%s将你加入课堂:%s(学生)" + ApplyAddDepartment: + Apply_end: "申请添加二级单位:%s(%s)" + System: + "1_end": "你提交的添加二级单位申请:%s(%s),审核已通过" + "2_false_end": "你提交的添加二级单位申请:%s(%s),审核未通过    原因:%{reason}" + "2_true_end": "你提交的添加二级单位申请:%s(%s),审核未通过" + "3_end": "你提交的添加二级单位申请:%s(%s),已被更改为%{reason}" + ApplyAddSchools: + Apply_end: "申请添加单位:%s" + System: + "1_end": "你提交的添加单位申请:%{name},审核已通过" + "2_reason_end": "你提交的添加单位申请:%{name},审核未通过    原因:%{reason}" + "2_no_reason_end": "你提交的添加单位申请:%{name},审核未通过" + "3_end": "你提交的添加单位申请:%{name},已被更改为:%{reason}" + ApplyAction: + ApplyShixun: + System: + "1_end": "你提交的实训发布申请:%{name},审核已通过" + "2_end": "你提交的实训发布申请:%{name},审核未通过    原因:%{reason}" + Apply_end: "申请发布实训:%{name}" + ApplySubject: + System: + "1_end": "你提交的实训课程发布申请:%{name},审核已通过" + "2_end": "你提交的实训课程发布申请:%{name},审核未通过    原因:%{reason}" + Apply_end: "申请发布实训课程:%{name}" + TrialAuthorization: + System: + "1_end": "你提交的试用授权申请,审核已通过" + "2_end": "你提交的试用授权申请,审核未通过    原因:%{reason}" + Apply_end: "提交了试用授权申请" + Course_end: "成功创建了课堂:%s" + Shixun_end: "成功创建了实训:%s" + Subject_end: "成功创建了实训课程:%s" + ArchiveCourse_end: "你的课堂已经归档:%s" + JournalsForMessage: + Mentioned_end: "@了你:%s" + Principal: + true_true_end: "评论了你的回复:%s" + true_false_end: "评论了你的留言:%s" + false_true_end: "给你留言:%s" + false_false_end: "给你私信:%s" + HomeworkCommon: + true_end: "评论了你的回复:%s" + false_end: "评论了你发布的作业:%s" + GraduationTopic: + true_end: "评论了你的回复:%s" + false_end: "评论了你发布的毕设选题:%s" + StudentWorksScore: + true_end: "评论了你的回复:%s" + false_end: "评论了你发布的作品评语:%s" + Message: + Mentioned_end: "@了你:%s" + true_true_end: "评论了你的帖子:%s" + true_false_end: "评论了你的回复:%s" + false_end: "发布了帖子:%s" + Memo: + true_true_end: "评论了你的帖子:%s" + true_false_end: "评论了你的回复:%s" + false_end: "发布了帖子:%s" + Watcher_end: "关注了你" + PraiseTread: + Challenge: + "1_end": "赞了你发布的实训任务:%s,第%s关" + "2_end": "踩了你发布的实训任务:%s,第%s关" + Memo: + true_end: "赞了你的评论:%s" + false_end: "赞了发布的帖子:%s" + Message: + true_end: "赞了你的评论:%s" + false_end: "赞了发布的帖子:%s" + HomeworkCommon_end: "赞了你发布的作业:%s" + JournalsForMessage: + true_end: "赞了你的留言:%s" + false_end: "赞了你的评论:%s" + Discuss_end: "赞了你的评论:%s" + Issue_end: "赞了你发布的项目Issue:%s" + Journal_end: "赞了你的回复%s" + Discuss: + true_end: "评论了你的回复:%s" + false_end: "评论了你发布的实训:%s" + Grade: + Avatar_end: "首次上传头像获得金币奖励:%s金币" + Phone_end: "首次绑定手机号码获得金币奖励:%s金币" + Attendance_end: "签到成功获得金币奖励:%s金币" + Mail_end: "首次绑定邮箱获得金币奖励:%s金币" + Account_end: "首次填写基本资料获得金币奖励:%s金币" + Answer: + true_end: "查看实训%s第%s关的参考答案消耗金币:%s金币" + false_end: "查看实训的参考答案消耗金币:%s金币" + Game_end: "通过实训%s的第%s关获得金币奖励:%s金币" + Memo_end: "发布的评论或者帖子获得平台奖励:%s金币" + Discusses_end: "发布的评论获得金币奖励:%s金币" + testSet_end: "查看实训的第%s关的隐藏测试集消耗的金币:%s金币" + shixunPublish_end: "发布实训%s获得的奖励:%s金币" + Star_end: "给实训评分获得的随机奖励:%s金币" + Feedback_end: "反馈的问题获得平台奖励:%s金币" + Authentication_end: "用户首次完成实名认证获得的奖励:%s金币" + Professional_end: "用户首次完成职业认证获得的奖励:%s金币" + JoinProject: + 3_end: "申请加入项目:%s(管理人员)" + 4_end: "申请加入项目:%s(开发人员)" + DealProject: + 3_1_end: "你提交的加入项目申请:%s(管理人员), 审核已通过" + 3_2_end: "你提交的加入项目申请:%s(管理人员), 审核未通过" + 4_1_end: "你提交的加入项目申请:%s(开发人员), 审核已通过" + 4_2_end: "你提交的加入项目申请:%s(开发人员), 审核未通过" + ReporterJoinProject_end: "加入了项目:%s(报告人员)" + ManagerJoinProject: + 3_end: "%s将你加入项目:%s(管理人员)" + 4_end: "%s将你加入项目:%s(开发人员)" + 5_end: "%s将你加入项目:%s(报告人员)" + Journal_end: "更新了Issue:%s" + Journal: + Mentioned_end: "@了你:%s" + Comment: + true_end: "评论了你的回复:%s" + false_end: "评论了你发布的项目issue:%s" + Issue_end: "指派了Issue给你:%s" + PullRequest: + Apply_end: "提交了PullRequest:%s" + 2_end: "接受了PullRequest:%s" + 3_end: "重新打开了PullRequest:%s" + 4_end: "关闭了PullRequest:%s" + SendMessage: + old_end: "申请了新镜像:%s" + new_end: "申请了新镜像:【语言】%s;【系统环境】%s;【测试代码运行方式】%s" + Poll: + PollPublish_end: "发布了问卷:%s" + NearlyEnd_end: "问卷的截止时间快到啦:%s" + CommitPoll_end: "提交了问卷答题:%s" + Exercise: + ExercisePublish_end: "发布了试卷:%s" + NearlyEnd_end: "试卷的截止时间快到啦:%s" + CommitExercise_end: "提交了试卷答题:%s" + ExerciseScore_end: "评阅了你的试卷:%s" + StudentGraduationTopic_end: "选择了毕设选题:%s" + DealStudentTopicSelect: + 1_end: "你提交的选题申请:%s,审核已通过" + 2_end: "你提交的选题申请:%s,审核未通过" + GraduationTask: + TaskPublish_end: "发布了毕设任务:%s" + NearlyEnd_end: "毕设任务的提交截止时间快到啦:%s" + NearlyLateEnd_end: "毕设任务的补交截止时间快到啦:%s" + CrossComment_end: "开启了交叉评阅:%s" + GraduationWork: + true_end: "提交了作品:%s" + false_end: "重新提交了作品,建议您重新评阅:%s" + GraduationWorkScore_end: "评阅了你的作品:%s" + HomeworkCommon: + AnonymousComment_end: "开启了作业匿评:%{name}" + AnonymousCommentFail_end: "开启作业匿评失败:%{name},
    原因:%{reason}" + AnonymousAppeal_end: "开启了匿评申诉:%{name}" + HomeworkPublish_end: "发布了作业:%{name}" + NearlyEnd_end: "作业的提交截止时间快到啦:%{name}" + AppealNearlyEnd_end: "作品的匿评申诉时间快到啦:%{name}" + EvaluationNearlyEnd_end: "作业的匿评截止时间快到啦:%{name}" + StudentWork: + true_end: "提交了作品:%s" + false_end: "重新提交了作品,建议您重新评阅:%s" + StudentWorksScore: + 1_end: "评阅了你的作品:%s" + 2_end: "评阅了你的作品:%s" + 3_end: "有人匿评了你的作品:%s" + ChallengeWorkScore_end: "调整了你的作品分数:%s" + StudentWorksScoresAppeal: + UserAppealResult: + 1_end: "同意了你提交的匿评申诉申请:%s" + 2_end: "拒绝了你提交的匿评申诉:%s" + AppealResult: + 1_end: "同意了他人对你的匿评申诉申请:%s" + 2_end: "拒绝了他人对你的匿评申诉:%s" + StudentWork: + Apply_end: "发起了匿评申诉申请:%s" + HomeworkCommon_end: "有人对你的匿评发起了申诉:%s" + Department_end: "你选填的二级单位:%s(%s)因不符合规范,已被系统删除.请重新选择" diff --git a/config/locales/users/zh-CN.yml b/config/locales/users/zh-CN.yml new file mode 100644 index 000000000..5c4ad76a7 --- /dev/null +++ b/config/locales/users/zh-CN.yml @@ -0,0 +1,12 @@ +'zh-CN': + user: + identity: + teacher: 教师 + student: 学生 + professional: 专业人士 + developer: 从业者 + enterprise: 组织 + "0": 教师 + "1": 学生 + "2": 专业人士 + "3": 专业人士 \ No newline at end of file diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml new file mode 100644 index 000000000..99d5ac843 --- /dev/null +++ b/config/locales/zh-CN.yml @@ -0,0 +1,4 @@ +'zh-CN': + error: + record_not_found: 您访问的页面不存在或已被删除 + forbidden: 您没有权限进行该操作 \ No newline at end of file diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 000000000..e31c00feb --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,34 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked webserver processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. +# +# preload_app! + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/config/redis.yml b/config/redis.yml new file mode 100644 index 000000000..71e61cfd9 --- /dev/null +++ b/config/redis.yml @@ -0,0 +1,12 @@ +defaults: &defaults + url: <%= ENV["REDIS_URL"] || "redis://localhost:6379/0" %> + +development: + <<: *defaults + +test: + <<: *defaults + +production: + <<: *defaults + url: redis://10.9.72.102:6379/0/job \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 000000000..e7fac7331 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,656 @@ +Rails.application.routes.draw do + + resources :edu_settings + scope '/api' do + get 'home/index' + get 'home/search' + + post 'praise_tread/like', to: 'praise_tread#like' + delete 'praise_tread/unlike', to: 'praise_tread#unlike' + + put 'commons/hidden', to: 'commons#hidden' + put 'commons/unhidden', to: 'commons#unhidden' + delete 'commons/delete', to: 'commons#delete' + + resources :memos + resources :tem_tests + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html + # + # + resources :accounts do + + collection do + post :login + post :register + post :reset_password + get :logout + get :get_verification_code + get :valid_email_and_phone + end + + end + + resources :users do + member do + get :homepage_info + end + + scope module: :users do + resources :courses, only: [:index] + resources :shixuns, only: [:index] + resources :projects, only: [:index] + resources :subjects, only: [:index] + resources :question_banks, only: [:index] + resource :experience_records, only: [:show] + resource :grade_records, only: [:show] + resource :watch, only: [:create, :destroy] + end + + + collection do + post :following + post :unfollow + get :get_user_info + get :attachment_show + get :get_navigation_info + post :reply_message + get :search_user_projects + post :brief_introduction + post :attendance + + resource :trial_apply, only: [:create] + resources :projects, only: [] do + get :search, on: :collection + end + + resources :tidings, only: [:index] + + scope module: :users do + resources :accounts, only: [:show, :update] do + resource :phone_bind, only: [:create] + resource :email_bind, only: [:create] + resource :password, only: [:update] + resource :avatar, only: [:update] + end + end + end + end + + resources :myshixuns, param: :identifier, shallow: true do + member do + post :repository + post :commits + post :file_content + post :update_file + get :reset_my_game + post :html_content + get :open_webssh + get :challenges + end + collection do + get :sigle_mul_test + match :training_task_status, :via => [:get, :post] + match :code_runinng_message, :via => [:get, :post] + end + resources :games + end + + resources :games, path: :tasks, param: :identifier do + member do + get :star + get :git_entries + get :answer + get :answer_grade + get :rep_content + get :reset_original_code + get :reset_passed_code + post :file_update + post :choose_build + get :game_build + get :game_status + post :plus_or_cancel_praise + get :cost_time + get :system_update + get :sync_modify_time + get :picture_display + get :sync_codes + get :close_webssh + get :get_answer_info + get :unlock_answer + + end + collection do + get :challenges + end + end + + resources :shixuns, param: :identifier do + collection do + get :menus + get :get_recommend_shixuns + get :departments + get :get_mirror_script + post :apply_shixun_mirror + get :download_file + end + + member do + post :copy + get :propaedeutics + get :show_right + get :operation + get :ranking_list + get :discusses + get :tasks + get :collaborators + get :settings + get :get_script_contents + get :get_custom_script + post :repository + post :commits + post :file_content + post :update_file + post :close + get :fork_list + post :update_propaedeutics + get :add_collaborators + post :shixun_members_added + match :change_manager, :via => [:get, :post] + get :search_user_courses + post :send_to_course + delete :collaborators_delete + get :cancel_publish + get :publish + get :shixun_exec + end + + resources :challenges do + member do + get 'index_up' + get 'index_down' + post 'create_choose_question' + get 'show_choose_question' + match 'choose_type_show', :via => [:get, :post] + match 'edit_choose_question', :via => [:get, :post] + match 'update_choose_question', :via => [:get, :post] + delete 'destroy_challenge_choose' + post :crud_answer + get :answer + + end + end + + resources :repositories do + collection do + post :add_project + post :fork_project + + post :file_tree # 目录树 + post :update_file # 文件更新 + post :file_content # 文件内容 + + post :commits # 提交记录 + end + end + end + + resources :discusses do + collection do + get :new_message + end + + member do + post :reply + post :hidden + post :reward_code + post :plus + end + end + + resources :subjects, path: :paths do + member do + get 'choose_subject_shixun' + get 'publish' + get 'cancel_publish' + get 'cancel_has_publish' + get 'statistics' + get 'shixun_report' + get 'school_report' + post 'update_attr' + post :search_members + post 'add_subject_members' + delete 'delete_member' + get :choose_course + post 'send_to_course' + delete :delete_member + post :up_member_position + post :down_member_position + end + + collection do + get 'create_subject' + get 'new_subject' + post 'append_to_stage' + get 'search' + end + end + + resources :stages do + member do + get 'down_position' + get 'up_position' + end + end + + resources :files, only: [:index, :show, :update] do + collection do + delete :bulk_delete + put :bulk_move + post :bulk_send + put :bulk_public + get :public_with_course_and_project + get :mine_with_course_and_project + post :import + post :upload + end + member do + get :histories + end + end + + resources :courses do + member do + get 'settings', :action => 'settings', :as => 'settings' + post 'set_invite_code_halt' + post 'set_public_or_private' + post 'search_teacher_candidate' + post 'add_teacher' + post 'create_graduation_group' + post 'join_graduation_group' + post 'set_course_group' + post 'change_course_admin' + post 'change_course_teacher' + post 'delete_course_teacher' + post 'teacher_application_review' + post 'transfer_to_course_group' + post 'delete_from_course' + post 'add_students_by_search' + post 'create_group_by_importing_file' + post 'duplicate_course' + post 'visits_plus_one' + get 'get_historical_courses' + get 'get_historical_course_students' + get 'course_group_list' + get 'add_teacher_popup' + get 'teachers' + get 'graduation_group_list' + get 'top_banner' + get 'left_banner' + get 'students' + get 'all_course_groups' + get 'search_users' + get 'base_info' + get 'attahcment_category_list' + get 'export_member_scores_excel' #导出课堂信息 + post 'switch_to_teacher' + post 'switch_to_assistant' + post 'switch_to_student' + post 'exit_course' + end + + collection do + post 'apply_to_join_course' + post 'search_course_list' + get 'board_list' + get 'mine' + end + + resources :polls, only:[:index,:new,:create] do + collection do + post :publish # 立即发布 + post :end_poll # 立即截止 + post :destroys # 多个删除 + post :set_public # 设置公开 + post :join_poll_banks # 加入习题集 + get :my_polls #我的问卷题库 + get :public_polls # 公共问卷题库 + get :publish_modal # 立即发布弹窗内容 + get :end_poll_modal # 立即截止弹窗内容 + end + end + + resources :homework_commons, shallow: true do + + member do + get :group_list + post :homework_code_repeat + get :code_review_results + get :code_review_detail + post :update_explanation + get :show_comment + get :settings + post :update_settings + match 'works_list', :via => [:get, :post] + # post :works_list + get :reference_answer + get :publish_groups + get :end_groups + post :alter_name + end + + collection do + post 'create_shixun_homework' + match 'shixuns', via: [:get, :post] + match 'subjects', via: [:get, :post] + post 'create_subject_homework' + post 'publish_homework' + post 'end_homework' + post 'set_public' + post 'move_to_category' + get 'choose_category' + post 'multi_destroy' + post 'add_to_homework_bank' + end + + resources :student_works do + member do + get :shixun_work + get :shixun_work_report + post :adjust_review_score + get :commit_des + post :update_des + post :adjust_score + post :add_score + post :add_score_reply + delete :destroy_score + delete :destroy_score_reply + get :comment_list + get :supply_attachments + post :revise_attachment + delete :destroy_score + post :appeal_anonymous_score + post :deal_appeal_score + post :cancel_appeal + get :export_shixun_work_report + end + + collection do + get :search_member_list + get :check_project + get :cancel_relate_project + post :relate_project + end + end + end + + + resources :boards, shallow: true do + resources :messages do + collection do + delete :bulk_delete + put :bulk_move + post :bulk_send + put :bulk_public + end + + member do + get :reply_list + put :sticky_top + post :reply + end + end + member do + post 'move_category' + end + end + + resources :exercises ,only:[:index,:new,:create] do + collection do + get :my_exercises #我的试卷题库 + get :public_exercises # 公共试卷题库 + get :publish_modal # 立即发布弹窗内容 + get :end_modal # 立即截止弹窗内容 + post :destroys + post :set_public # 设置公开 + post :join_exercise_banks # 加入习题集 + post :publish # 立即发布 + post :end_exercise # 立即截止 + + end + end + + resources :course_groups, shallow: true do + member do + post 'rename_group' + post 'move_category' + end + + collection do + end + end + + resources :graduation_topics do + member do + post :refuse_student_topic + post :accept_student_topic + post :student_select_topic + post :student_cancel_topic + get :show_detail + get :show_comment + end + collection do + delete :destroys + post :set_public + get :export + post :add_to_bank + end + end + + resources :graduation_tasks, shallow: true do + resources :graduation_works do + collection do + post 'search_member_list' + get 'check_project' + post 'relate_project' + get 'cancel_relate_project' + post 'revise_attachment' + end + + member do + get 'comment_list' + post 'add_score' + post 'adjust_score' + delete 'delete_score' + get 'supply_attachments' + post 'revise_attachment' + post :assign_teacher + end + end + member do + get 'settings' + post 'update_settings' + get 'tasks_list' + get :show_comment + end + + collection do + post 'set_public' + delete 'multi_destroy' + post 'publish_task' + post 'end_task' + post 'add_to_bank' + end + end + end + + resources :polls,except:[:index,:new,:create] do + member do + get :poll_setting + post :commit_setting + get :start_answer + post :commit_poll + get :commit_result + get :poll_lists # 问卷的答题列表 + post :cancel_publish #撤销发布 + get :cancel_publish_modal #撤销发布的弹窗 + get :common_header + end + resources :poll_questions,only:[:new,:create] + end + + resources :poll_questions,except:[:new,:create,:index] do + member do + post :delete_answer + post :up_down + post :commit_answer + end + resource :poll_votes,only:[:create,:destroy] + end + + resources :question_banks do + collection do + get :bank_list + post :save_banks + end + end + + + resources :exercises do + member do + get :choose_shixun + get :commit_shixun + get :exercise_setting + post :commit_setting + get :start_answer + post :commit_exercise + get :redo_modal #打回重做弹窗内容 + post :redo_exercise + get :review_exercise + get :exercise_lists + # get :blank_exercise #摒弃,仅作为测试html页面才会使用 + get :export_exercise + get :common_header + get :exercise_result + post :cancel_exercise + get :begin_commit #提交前的弹窗 + end + resources :exercise_questions,only:[:new,:create,:index] + end + + resources :exercise_questions,except:[:new,:create,:index] do + member do + post :up_down + post :delete_answer + post :adjust_score + end + resource :exercise_answers,only:[:create,:destroy] + end + + + resources :course_modules, shallow: true do + member do + get 'sticky_module' + get 'hidden_module' + post 'rename_module' + post 'add_second_category' + end + collection do + post 'unhidden_modules' + end + end + + resources :course_second_categories, shallow: true do + member do + post 'rename_category' + post 'move_category' + end + collection do + + end + end + resources :attachments + + resources :schools do + member do + end + collection do + get "school_list" + end + + scope module: :ecs do + get :detail, to: 'homes#index' + + resources :ec_majors, only: [:index] + resources :ec_major_schools, only: [:index, :create, :destroy] + end + end + + # 为避免url过长以及层级过深,路由定义和controller继承都做了处理 + scope module: :ecs do + resources :ec_major_schools, only: [] do + resources :major_managers, only: [:create, :destroy] + resources :ec_years, only: [:index, :create, :destroy] + end + + resources :ec_years, only: [] do + resource :ec_training_objectives, only: [:show, :create] + resources :ec_graduation_requirements, only: [:index, :create] + resource :requirement_support_objectives, only: [:show, :create, :destroy] + resource :subitem_support_standards, only: [:show, :create, :destroy] + resource :students, only: [:show, :destroy] do + post :import, on: :collection + end + + resources :ec_courses, only: [:index, :create, :destroy] do + post :link_course, on: :member + + collection do + post :import + get :search + end + end + + resource :graduation_course_supports, only: [:show, :create] + resource :reach_evaluation, only: [:show, :create] + resource :reach_criteria, only: [:create] + end + + resources :ec_courses, only: [] do + resource :evaluation, only: [:show, :create] + resources :course_managers, only: [:create, :destroy] + resources :course_targets, only: [:index, :create] do + get :with_achievement_methods, on: :collection + + resource :course_achievement_methods, only: [:create] + end + resources :course_evaluations, only: [:index, :create, :update, :destroy] do + member do + get :average_score_import_template + get :detail_score_import_template + get :import_student_achievement + end + get :slimmer, on: :collection + end + resource :score_levels, only: [:show, :create] + end + end + + resource :zip, only: [] do + collection do + get :shixun_report + get :export_exercises + end + end + end + + #git 认证回调 + match 'gitauth/*url', to: 'gits#auth', via: :all + + get 'oauth/get_code', to: 'oauth#get_code' + get 'oauth/get_token_callback', to: 'oauth#get_token_callback' + + root 'main#index' + + ## react用 + get '*path', to: 'main#index', constraints: ReactConstraint.new +end diff --git a/config/sidekiq.yml b/config/sidekiq.yml new file mode 100644 index 000000000..a2b3fc0be --- /dev/null +++ b/config/sidekiq.yml @@ -0,0 +1,6 @@ +:concurrency: <%= ENV["sidekiq_threads"] || 20 %> +:pidfile: tmp/pids/sidekiq.pid +:logfile: log/sidekiq.log +:queues: + - [default, 3] + - [notify, 100] \ No newline at end of file diff --git a/config/spring.rb b/config/spring.rb new file mode 100644 index 000000000..3d9795158 --- /dev/null +++ b/config/spring.rb @@ -0,0 +1,6 @@ +%w[ + .ruby-version + .rbenv-vars + tmp/restart.txt + tmp/caching-dev.txt +].each { |path| Spring.watch(path) } diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 000000000..a6cba4441 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20180920063955_create_graduation_topics.rb b/db/migrate/20180920063955_create_graduation_topics.rb new file mode 100644 index 000000000..5e7a4640e --- /dev/null +++ b/db/migrate/20180920063955_create_graduation_topics.rb @@ -0,0 +1,26 @@ +class CreateGraduationTopics < ActiveRecord::Migration[5.2] + def change + create_table :graduation_topics do |t| + t.references :user + t.references :course + t.integer :tea_id + t.string :name + t.text :description + t.integer :status, :default => 0 + t.integer :topic_type + t.integer :source + t.integer :property + t.integer :property_two + t.string :source_unit + t.integer :repeat + t.string :province + t.string :city + t.boolean :is_public, :default => 0 + + t.timestamps + end + add_index :graduation_topics, :user_id + add_index :graduation_topics, :course_id + add_index :graduation_topics, :tea_id + end +end diff --git a/db/migrate/20181024015607_add_column_to_poll.rb b/db/migrate/20181024015607_add_column_to_poll.rb new file mode 100644 index 000000000..65ebe98d3 --- /dev/null +++ b/db/migrate/20181024015607_add_column_to_poll.rb @@ -0,0 +1,6 @@ +class AddColumnToPoll < ActiveRecord::Migration[5.2] + # 问卷是否实名 + def change + add_column :polls, :un_anonymous, :boolean, :default => 0 + end +end diff --git a/db/migrate/20181105031300_add_repo_name_to_shixuns.rb b/db/migrate/20181105031300_add_repo_name_to_shixuns.rb new file mode 100644 index 000000000..3210184ad --- /dev/null +++ b/db/migrate/20181105031300_add_repo_name_to_shixuns.rb @@ -0,0 +1,5 @@ +class AddRepoNameToShixuns < ActiveRecord::Migration[5.2] + def change + add_column :shixuns, :repo_name, :string + end +end diff --git a/db/migrate/20181105061745_add_repo_name_to_myshixuns.rb b/db/migrate/20181105061745_add_repo_name_to_myshixuns.rb new file mode 100644 index 000000000..70ca92abb --- /dev/null +++ b/db/migrate/20181105061745_add_repo_name_to_myshixuns.rb @@ -0,0 +1,5 @@ +class AddRepoNameToMyshixuns < ActiveRecord::Migration[5.2] + def change + add_column :myshixuns, :repo_name, :string + end +end diff --git a/db/migrate/20181115071148_create_relationships.rb b/db/migrate/20181115071148_create_relationships.rb new file mode 100644 index 000000000..4437e9ea5 --- /dev/null +++ b/db/migrate/20181115071148_create_relationships.rb @@ -0,0 +1,13 @@ +class CreateRelationships < ActiveRecord::Migration[5.2] + def change + create_table :relationships do |t| + t.integer :follower_id + t.integer :followed_id + + t.timestamps + end + add_index :relationships, :followed_id + add_index :relationships, :follower_id + add_index :relationships, [:follower_id, :followed_id], unique: true + end +end diff --git a/db/migrate/20181118075620_sync_gitlab_admin.rb b/db/migrate/20181118075620_sync_gitlab_admin.rb new file mode 100644 index 000000000..17cb3bd18 --- /dev/null +++ b/db/migrate/20181118075620_sync_gitlab_admin.rb @@ -0,0 +1,6 @@ +class SyncGitlabAdmin < ActiveRecord::Migration[5.2] + def change + user = User.find_by_login("forge01") + user.update_column(:mail, 'admin@example.com') + end +end diff --git a/db/migrate/20181207064509_add_cloud_url_to_attachments.rb b/db/migrate/20181207064509_add_cloud_url_to_attachments.rb new file mode 100644 index 000000000..6dd3ffb6d --- /dev/null +++ b/db/migrate/20181207064509_add_cloud_url_to_attachments.rb @@ -0,0 +1,5 @@ +class AddCloudUrlToAttachments < ActiveRecord::Migration[5.2] + def change + add_column :attachments, :cloud_url, :string, default: '' + end +end diff --git a/db/migrate/20181213024859_add_averge_star_to_shixuns.rb b/db/migrate/20181213024859_add_averge_star_to_shixuns.rb new file mode 100644 index 000000000..c801c8675 --- /dev/null +++ b/db/migrate/20181213024859_add_averge_star_to_shixuns.rb @@ -0,0 +1,5 @@ +class AddAvergeStarToShixuns < ActiveRecord::Migration[5.2] + def change + add_column :shixuns, :averge_star, :float, :default => 0 + end +end diff --git a/db/migrate/20181213025239_sync_averger_star_to_shixun.rb b/db/migrate/20181213025239_sync_averger_star_to_shixun.rb new file mode 100644 index 000000000..e117475a4 --- /dev/null +++ b/db/migrate/20181213025239_sync_averger_star_to_shixun.rb @@ -0,0 +1,12 @@ +class SyncAvergerStarToShixun < ActiveRecord::Migration[5.2] + def change + Shixun.find_each do |shixun| + averge_star = Game.find_by_sql("select ifnull(sum(g.star),0)/ifnull(count(*),1) as averge_star from (games g left join + (myshixuns m join shixuns s on s.id = m.shixun_id) on m.id = g.myshixun_id) + where star != 0 and s.id = #{shixun.id}").first.try(:averge_star) + averge_star = averge_star || 5 + puts(averge_star) + shixun.update_column(:averge_star, averge_star.round(1)) + end + end +end diff --git a/db/migrate/20181228095820_create_shixun_infos.rb b/db/migrate/20181228095820_create_shixun_infos.rb new file mode 100644 index 000000000..f5c72d5a3 --- /dev/null +++ b/db/migrate/20181228095820_create_shixun_infos.rb @@ -0,0 +1,12 @@ +class CreateShixunInfos < ActiveRecord::Migration[5.2] + def change + create_table :shixun_infos do |t| + t.longtext :propaedeutics + t.longtext :description + t.longtext :evaluate_script + t.integer :shixun_id + + t.timestamps + end + end +end diff --git a/db/migrate/20181228115324_add_index_to_users.rb b/db/migrate/20181228115324_add_index_to_users.rb new file mode 100644 index 000000000..ccd8f771f --- /dev/null +++ b/db/migrate/20181228115324_add_index_to_users.rb @@ -0,0 +1,5 @@ +class AddIndexToUsers < ActiveRecord::Migration[5.2] + def change + add_index :users, :experience + end +end diff --git a/db/migrate/20190108074759_modify_status_and_visits_for_subjects.rb b/db/migrate/20190108074759_modify_status_and_visits_for_subjects.rb new file mode 100644 index 000000000..08a5d0e3a --- /dev/null +++ b/db/migrate/20190108074759_modify_status_and_visits_for_subjects.rb @@ -0,0 +1,6 @@ +class ModifyStatusAndVisitsForSubjects < ActiveRecord::Migration[5.2] + def change + change_column :subjects, :status, :integer, :default => 0 + change_column :subjects, :visits, :integer, :default => 1 + end +end diff --git a/db/migrate/20190109005614_add_opening_time_for_shixuns.rb b/db/migrate/20190109005614_add_opening_time_for_shixuns.rb new file mode 100644 index 000000000..d02cd6113 --- /dev/null +++ b/db/migrate/20190109005614_add_opening_time_for_shixuns.rb @@ -0,0 +1,5 @@ +class AddOpeningTimeForShixuns < ActiveRecord::Migration[5.2] + def change + add_column :shixuns, :opening_time, :string + end +end diff --git a/db/migrate/20190109013210_modify_opening_time_for_shixuns.rb b/db/migrate/20190109013210_modify_opening_time_for_shixuns.rb new file mode 100644 index 000000000..b3360c424 --- /dev/null +++ b/db/migrate/20190109013210_modify_opening_time_for_shixuns.rb @@ -0,0 +1,5 @@ +class ModifyOpeningTimeForShixuns < ActiveRecord::Migration[5.2] + def change + change_column :shixuns, :opening_time, :datetime + end +end diff --git a/db/migrate/20190111063956_add_averge_star_default_for_shixuns.rb b/db/migrate/20190111063956_add_averge_star_default_for_shixuns.rb new file mode 100644 index 000000000..fb0b4d3aa --- /dev/null +++ b/db/migrate/20190111063956_add_averge_star_default_for_shixuns.rb @@ -0,0 +1,5 @@ +class AddAvergeStarDefaultForShixuns < ActiveRecord::Migration[5.2] + def change + change_column :shixuns, :averge_star, :float, :default => 5 + end +end diff --git a/db/migrate/20190120063702_sync_reponame.rb b/db/migrate/20190120063702_sync_reponame.rb new file mode 100644 index 000000000..c40eba131 --- /dev/null +++ b/db/migrate/20190120063702_sync_reponame.rb @@ -0,0 +1,16 @@ +class SyncReponame < ActiveRecord::Migration[5.2] + def change + g = Gitlab.client + myshixuns = Myshixun.where("repo_name is null") + myshixuns.find_each do |myshixun| + begin + puts myshixun.id + repo_name = g.project(myshixun.gpid).path_with_namespace + puts repo_name + myshixun.update_column(:repo_name, repo_name) + rescue Exception => e + Rails.logger.error("e.message") + end + end + end +end diff --git a/db/migrate/20190220014052_add_shixuns_count_to_stage.rb b/db/migrate/20190220014052_add_shixuns_count_to_stage.rb new file mode 100644 index 000000000..caf459a8e --- /dev/null +++ b/db/migrate/20190220014052_add_shixuns_count_to_stage.rb @@ -0,0 +1,5 @@ +class AddShixunsCountToStage < ActiveRecord::Migration[5.2] + def change + add_column :stages, :shixuns_count, :integer, default: 0 + end +end diff --git a/db/migrate/20190220061013_add_shixuns_count_to_subject.rb b/db/migrate/20190220061013_add_shixuns_count_to_subject.rb new file mode 100644 index 000000000..3f803d2f1 --- /dev/null +++ b/db/migrate/20190220061013_add_shixuns_count_to_subject.rb @@ -0,0 +1,5 @@ +class AddShixunsCountToSubject < ActiveRecord::Migration[5.2] + def change + add_column :subjects, :shixuns_count, :integer, default: 0 + end +end diff --git a/db/migrate/20190220074947_sync_cache_count_for_subjects.rb b/db/migrate/20190220074947_sync_cache_count_for_subjects.rb new file mode 100644 index 000000000..ce2b22d62 --- /dev/null +++ b/db/migrate/20190220074947_sync_cache_count_for_subjects.rb @@ -0,0 +1,8 @@ +class SyncCacheCountForSubjects < ActiveRecord::Migration[5.2] + def change + Subject.find_each do |s| + Subject.reset_counters s.id, :shixuns + Subject.reset_counters s.id, :stages + end + end +end diff --git a/db/migrate/20190221003048_add_users_count_to_shixun.rb b/db/migrate/20190221003048_add_users_count_to_shixun.rb new file mode 100644 index 000000000..dffca5be9 --- /dev/null +++ b/db/migrate/20190221003048_add_users_count_to_shixun.rb @@ -0,0 +1,5 @@ +class AddUsersCountToShixun < ActiveRecord::Migration[5.2] + def change + add_column :shixuns, :users_count, :integer, default: 0 + end +end diff --git a/db/migrate/20190221003137_sync_users_count_for_shixun.rb b/db/migrate/20190221003137_sync_users_count_for_shixun.rb new file mode 100644 index 000000000..155ddda58 --- /dev/null +++ b/db/migrate/20190221003137_sync_users_count_for_shixun.rb @@ -0,0 +1,7 @@ +class SyncUsersCountForShixun < ActiveRecord::Migration[5.2] + def change + Shixun.find_each do |s| + Shixun.reset_counters s.id, :users_count + end + end +end diff --git a/db/migrate/20190228030508_delete_none_myshixun_games.rb b/db/migrate/20190228030508_delete_none_myshixun_games.rb new file mode 100644 index 000000000..89130d3fa --- /dev/null +++ b/db/migrate/20190228030508_delete_none_myshixun_games.rb @@ -0,0 +1,6 @@ +class DeleteNoneMyshixunGames < ActiveRecord::Migration[5.2] + def change + games = Game.where.not(myshixun_id: Myshixun.where(nil).pluck(:id)) + games.destroy_all + end +end diff --git a/db/migrate/20190304082236_create_challenge_answers.rb b/db/migrate/20190304082236_create_challenge_answers.rb new file mode 100644 index 000000000..630c92661 --- /dev/null +++ b/db/migrate/20190304082236_create_challenge_answers.rb @@ -0,0 +1,13 @@ +class CreateChallengeAnswers < ActiveRecord::Migration[5.2] + def change + create_table :challenge_answers do |t| + t.string :name + t.longtext :contents + t.integer :score + t.integer :level + t.references :challenge, index: true + t.timestamps + end + + end +end diff --git a/db/migrate/20190304082811_create_course_members.rb b/db/migrate/20190304082811_create_course_members.rb new file mode 100644 index 000000000..fd54891fd --- /dev/null +++ b/db/migrate/20190304082811_create_course_members.rb @@ -0,0 +1,19 @@ +class CreateCourseMembers < ActiveRecord::Migration[5.2] + def change + create_table :course_members do |t| + t.integer :course_id + t.integer :user_id + t.integer :course_group_id, default: 0 + t.integer :graduation_group_id, default: 0 + t.integer :role, default: 0 + t.boolean :is_active, default: 1 + + t.timestamps + end + + add_index :course_members, :course_id + add_index :course_members, :user_id + add_index :course_members, :course_group_id + add_index :course_members, :graduation_group_id + end +end diff --git a/db/migrate/20190305015556_modify_answer_open_for_games.rb b/db/migrate/20190305015556_modify_answer_open_for_games.rb new file mode 100644 index 000000000..7ae83ac9e --- /dev/null +++ b/db/migrate/20190305015556_modify_answer_open_for_games.rb @@ -0,0 +1,5 @@ +class ModifyAnswerOpenForGames < ActiveRecord::Migration[5.2] + def change + change_column :games, :answer_open, :integer, :default => 0 + end +end diff --git a/db/migrate/20190305074102_add_checkout_answer_score_for_games.rb b/db/migrate/20190305074102_add_checkout_answer_score_for_games.rb new file mode 100644 index 000000000..9c026fc3f --- /dev/null +++ b/db/migrate/20190305074102_add_checkout_answer_score_for_games.rb @@ -0,0 +1,5 @@ +class AddCheckoutAnswerScoreForGames < ActiveRecord::Migration[5.2] + def change + add_column :games, :answer_deduction, :integer, :default => 0 + end +end diff --git a/db/migrate/20190305080703_add_course_members_count_to_course.rb b/db/migrate/20190305080703_add_course_members_count_to_course.rb new file mode 100644 index 000000000..d38aaca5b --- /dev/null +++ b/db/migrate/20190305080703_add_course_members_count_to_course.rb @@ -0,0 +1,9 @@ +class AddCourseMembersCountToCourse < ActiveRecord::Migration[5.2] + def change + add_column :courses, :course_members_count, :integer, default: 0 + + Course.find_each do |c| + Course.reset_counters c.id, :course_members + end + end +end diff --git a/db/migrate/20190306023331_add_score_for_test_sets.rb b/db/migrate/20190306023331_add_score_for_test_sets.rb new file mode 100644 index 000000000..08b67ad85 --- /dev/null +++ b/db/migrate/20190306023331_add_score_for_test_sets.rb @@ -0,0 +1,6 @@ +class AddScoreForTestSets < ActiveRecord::Migration[5.2] + def change + add_column :test_sets, :score, :integer + add_column :challenges, :test_set_score, :boolean, :default => false + end +end diff --git a/db/migrate/20190306064421_add_answer_for_challenge_answer.rb b/db/migrate/20190306064421_add_answer_for_challenge_answer.rb new file mode 100644 index 000000000..32a6a6aa2 --- /dev/null +++ b/db/migrate/20190306064421_add_answer_for_challenge_answer.rb @@ -0,0 +1,10 @@ +class AddAnswerForChallengeAnswer < ActiveRecord::Migration[5.2] + def change + challenges = Challenge.where("answer is not null") + challenges.find_each do |c| + puts "####################{c.id}" + ChallengeAnswer.create(name: "解题代码", contents: "#{c.answer}", level: 1, score: 100, challenge_id: c.id) + end + + end +end diff --git a/db/migrate/20190307063217_add_pod_life_to_shixuns.rb b/db/migrate/20190307063217_add_pod_life_to_shixuns.rb new file mode 100644 index 000000000..e596367f2 --- /dev/null +++ b/db/migrate/20190307063217_add_pod_life_to_shixuns.rb @@ -0,0 +1,5 @@ +class AddPodLifeToShixuns < ActiveRecord::Migration[5.2] + def change + add_column :shixuns, :pod_life, :integer, :default => 0 + end +end diff --git a/db/migrate/20190309085449_migrate_course_members.rb b/db/migrate/20190309085449_migrate_course_members.rb new file mode 100644 index 000000000..ef8741bfb --- /dev/null +++ b/db/migrate/20190309085449_migrate_course_members.rb @@ -0,0 +1,40 @@ +class MigrateCourseMembers < ActiveRecord::Migration[5.2] + def change + add_column :course_groups, :position, :integer, default: 0 + + Course.find_each do |course| + position = 1 + course.course_groups.reorder("CONVERT(course_groups.name USING gbk) COLLATE gbk_chinese_ci ASC").find_each do |group| + group.update_attribute(:position, position) + position += 1 + end + end + + + add_column :course_groups, :course_members_count, :integer, default: 0 + + CourseGroup.find_each do |g| + CourseGroup.reset_counters g.id, :course_members + end + + ActiveRecord::Base.transaction do + begin + Member.where("course_id != -1").find_each do |member| + if member.course && member.user + puts(member.course_id) + member.member_roles.each do |role| + course_member_role = role.role_id == 3 ? 1 : (role.role_id == 9 ? 2 : (role.role_id == 7 ? 3 : 4)) + member_group_id = role.role_id == 10 ? member.course_group_id : 0 + CourseMember.create!(course_id: member.course_id, user_id: member.user_id, course_group_id: member_group_id.to_i, + graduation_group_id: member.graduation_group_id.to_i, role: course_member_role, is_active: role.is_current) + end + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("migrate_course_members 迁移失败!") + raise ActiveRecord::Rollback + end + end + end +end diff --git a/db/migrate/20190309091056_add_course_member_id.rb b/db/migrate/20190309091056_add_course_member_id.rb new file mode 100644 index 000000000..86993d725 --- /dev/null +++ b/db/migrate/20190309091056_add_course_member_id.rb @@ -0,0 +1,21 @@ +class AddCourseMemberId < ActiveRecord::Migration[5.2] + def change + add_column :student_graduation_topics, :course_member_id, :integer + add_index :student_graduation_topics, :course_member_id + + StudentGraduationTopic.find_each do |student| + course_member = CourseMember.where(course_id: student.course_id, user_id: student.user_id, + role: 4).first + student.update_column("course_member_id", course_member.try(:id)) if course_member.present? + end + + add_column :teacher_course_groups, :course_member_id, :integer + add_index :teacher_course_groups, :course_member_id + + TeacherCourseGroup.find_each do |teacher| + course_member = CourseMember.where(course_id: teacher.course_id, user_id: teacher.user_id, + role: [1, 2, 3]).first + teacher.update_column("course_member_id", course_member.try(:id)) if course_member.present? + end + end +end diff --git a/db/migrate/20190311064138_add_course_groups_count_to_course.rb b/db/migrate/20190311064138_add_course_groups_count_to_course.rb new file mode 100644 index 000000000..ecd11e7cb --- /dev/null +++ b/db/migrate/20190311064138_add_course_groups_count_to_course.rb @@ -0,0 +1,9 @@ +class AddCourseGroupsCountToCourse < ActiveRecord::Migration[5.2] + def change + add_column :courses, :course_groups_count, :integer, default: 0 + + Course.find_each do |c| + Course.reset_counters c.id, :course_groups + end + end +end diff --git a/db/migrate/20190311080729_add_position_to_course_groups.rb b/db/migrate/20190311080729_add_position_to_course_groups.rb new file mode 100644 index 000000000..4a59a7d97 --- /dev/null +++ b/db/migrate/20190311080729_add_position_to_course_groups.rb @@ -0,0 +1,5 @@ +class AddPositionToCourseGroups < ActiveRecord::Migration[5.2] + def change + + end +end diff --git a/db/migrate/20190311090818_create_course_second_categories.rb b/db/migrate/20190311090818_create_course_second_categories.rb new file mode 100644 index 000000000..51850c2fd --- /dev/null +++ b/db/migrate/20190311090818_create_course_second_categories.rb @@ -0,0 +1,12 @@ +class CreateCourseSecondCategories < ActiveRecord::Migration[5.2] + def change + create_table :course_second_categories do |t| + t.references :course + t.string :category_type + t.string :name + t.integer :position + + t.timestamps + end + end +end diff --git a/db/migrate/20190312024018_migrate_course_second_category.rb b/db/migrate/20190312024018_migrate_course_second_category.rb new file mode 100644 index 000000000..382c6fd6f --- /dev/null +++ b/db/migrate/20190312024018_migrate_course_second_category.rb @@ -0,0 +1,19 @@ +class MigrateCourseSecondCategory < ActiveRecord::Migration[5.2] + def change + add_column :homework_commons, :course_second_category_id, :integer, default: 0 + add_index :homework_commons, :course_second_category_id + add_column :course_second_categories, :course_module_id, :integer + add_index :course_second_categories, :course_module_id + + Course.find_each do |course| + homework_position = 1 + course_module = course.course_modules.where(module_type: "shixun_homework").first + course.course_homework_categories.reorder("CONVERT(name USING gbk) COLLATE gbk_chinese_ci ASC").find_each do |category| + new_category = CourseSecondCategory.create!(course_id: course.id, name: category.name, category_type: "shixun_homework", + position: homework_position, course_module_id: course_module.id) + course.homework_commons.where(course_homework_category_id: category.id).update_all(course_second_category_id: new_category.id) + homework_position += 1 + end + end + end +end diff --git a/db/migrate/20190312032623_add_course_second_category_to_attachment.rb b/db/migrate/20190312032623_add_course_second_category_to_attachment.rb new file mode 100644 index 000000000..972422e43 --- /dev/null +++ b/db/migrate/20190312032623_add_course_second_category_to_attachment.rb @@ -0,0 +1,6 @@ +class AddCourseSecondCategoryToAttachment < ActiveRecord::Migration[5.2] + def change + add_column :attachments, :course_second_category_id, :integer, default: 0 + add_index :attachments, :course_second_category_id + end +end diff --git a/db/migrate/20190321081720_add_praises_count_to_messages.rb b/db/migrate/20190321081720_add_praises_count_to_messages.rb new file mode 100644 index 000000000..14f9260cb --- /dev/null +++ b/db/migrate/20190321081720_add_praises_count_to_messages.rb @@ -0,0 +1,11 @@ +class AddPraisesCountToMessages < ActiveRecord::Migration[5.2] + def change + add_column :messages, :praises_count, :integer, :default => 0 + + Message.find_each do |msg| + total_count = msg.praise_treads.liker.count + puts "====> set message's praises_count to #{total_count}" + msg.update_column(:praises_count, total_count) + end + end +end diff --git a/db/migrate/20190321091429_change_praise_or_tread_default_in_praise_treads.rb b/db/migrate/20190321091429_change_praise_or_tread_default_in_praise_treads.rb new file mode 100644 index 000000000..15dd3f6e9 --- /dev/null +++ b/db/migrate/20190321091429_change_praise_or_tread_default_in_praise_treads.rb @@ -0,0 +1,5 @@ +class ChangePraiseOrTreadDefaultInPraiseTreads < ActiveRecord::Migration[5.2] + def change + change_column_default :praise_treads, :praise_or_tread, from: nil, to: 1 + end +end diff --git a/db/migrate/20190322065716_create_message_details.rb b/db/migrate/20190322065716_create_message_details.rb new file mode 100644 index 000000000..5fd1ba7d8 --- /dev/null +++ b/db/migrate/20190322065716_create_message_details.rb @@ -0,0 +1,11 @@ +class CreateMessageDetails < ActiveRecord::Migration[5.2] + def change + create_table :message_details do |t| + t.longtext :content + t.integer :message_id + + t.timestamps + end + add_index :message_details, :message_id + end +end diff --git a/db/migrate/20190322070515_move_content_of_messages_to_message_details.rb b/db/migrate/20190322070515_move_content_of_messages_to_message_details.rb new file mode 100644 index 000000000..be747c898 --- /dev/null +++ b/db/migrate/20190322070515_move_content_of_messages_to_message_details.rb @@ -0,0 +1,10 @@ +class MoveContentOfMessagesToMessageDetails < ActiveRecord::Migration[5.2] + def change + Message.find_each do |msg| + unless msg.message_detail.present? + message_detail = MessageDetail.create(message: msg, content: msg.content) + puts "-------> create MessageDetail success: id is #{message_detail.id}" + end + end + end +end diff --git a/db/migrate/20190322091313_remove_content_from_messages.rb b/db/migrate/20190322091313_remove_content_from_messages.rb new file mode 100644 index 000000000..ee6830e53 --- /dev/null +++ b/db/migrate/20190322091313_remove_content_from_messages.rb @@ -0,0 +1,5 @@ +class RemoveContentFromMessages < ActiveRecord::Migration[5.2] + def change + remove_column :messages, :content, :longtext + end +end diff --git a/db/migrate/20190323005303_modify_graduation_topics.rb b/db/migrate/20190323005303_modify_graduation_topics.rb new file mode 100644 index 000000000..18998fdcd --- /dev/null +++ b/db/migrate/20190323005303_modify_graduation_topics.rb @@ -0,0 +1,8 @@ +class ModifyGraduationTopics < ActiveRecord::Migration[5.2] + def change + rename_column :graduation_topics, :source, :topic_source + rename_column :graduation_topics, :property, :topic_property_first + rename_column :graduation_topics, :property_two, :topic_property_second + rename_column :graduation_topics, :repeat, :topic_repeat + end +end diff --git a/db/migrate/20190325022227_add_is_public_to_graduation_task.rb b/db/migrate/20190325022227_add_is_public_to_graduation_task.rb new file mode 100644 index 000000000..159aa90e9 --- /dev/null +++ b/db/migrate/20190325022227_add_is_public_to_graduation_task.rb @@ -0,0 +1,8 @@ +class AddIsPublicToGraduationTask < ActiveRecord::Migration[5.2] + def change + add_column :graduation_tasks, :is_public, :boolean, default: false + add_column :graduation_tasks, :late_time, :datetime + + GraduationTask.where(status: 3).update_all(status: 4) + end +end diff --git a/db/migrate/20190325023830_change_digest_to_string_in_attachments.rb b/db/migrate/20190325023830_change_digest_to_string_in_attachments.rb new file mode 100644 index 000000000..3b59e56e8 --- /dev/null +++ b/db/migrate/20190325023830_change_digest_to_string_in_attachments.rb @@ -0,0 +1,5 @@ +class ChangeDigestToStringInAttachments < ActiveRecord::Migration[5.2] + def change + change_column :attachments, :digest, :string, :limit => 60 + end +end diff --git a/db/migrate/20190326015900_add_hidden_for_journal_for_messages.rb b/db/migrate/20190326015900_add_hidden_for_journal_for_messages.rb new file mode 100644 index 000000000..2ff25360d --- /dev/null +++ b/db/migrate/20190326015900_add_hidden_for_journal_for_messages.rb @@ -0,0 +1,5 @@ +class AddHiddenForJournalForMessages < ActiveRecord::Migration[5.2] + def change + add_column :journals_for_messages, :hidden, :boolean, :default => false + end +end diff --git a/db/migrate/20190326095920_add_is_hidden_to_messages.rb b/db/migrate/20190326095920_add_is_hidden_to_messages.rb new file mode 100644 index 000000000..ee97a3f6c --- /dev/null +++ b/db/migrate/20190326095920_add_is_hidden_to_messages.rb @@ -0,0 +1,6 @@ +class AddIsHiddenToMessages < ActiveRecord::Migration[5.2] + def change + add_column :messages, :is_hidden, :boolean, :default => false + add_index :messages, :is_hidden + end +end diff --git a/db/migrate/20190327063241_course_group_count_cache.rb b/db/migrate/20190327063241_course_group_count_cache.rb new file mode 100644 index 000000000..cf0b868ff --- /dev/null +++ b/db/migrate/20190327063241_course_group_count_cache.rb @@ -0,0 +1,5 @@ +class CourseGroupCountCache < ActiveRecord::Migration[5.2] + def change + + end +end diff --git a/db/migrate/20190328134047_sync_shixuninfo.rb b/db/migrate/20190328134047_sync_shixuninfo.rb new file mode 100644 index 000000000..bb374dc29 --- /dev/null +++ b/db/migrate/20190328134047_sync_shixuninfo.rb @@ -0,0 +1,8 @@ +class SyncShixuninfo < ActiveRecord::Migration[5.2] + def change + Shixun.find_each do |shixun| + ShixunInfo.create!(propaedeutics: shixun.propaedeutics, description: shixun.description, + evaluate_script: shixun.evaluate_script, shixun_id: shixun.id) + end + end +end diff --git a/db/migrate/20190328152957_remove_column_for_shixun.rb b/db/migrate/20190328152957_remove_column_for_shixun.rb new file mode 100644 index 000000000..70131a4b2 --- /dev/null +++ b/db/migrate/20190328152957_remove_column_for_shixun.rb @@ -0,0 +1,5 @@ +class RemoveColumnForShixun < ActiveRecord::Migration[5.2] + def change + remove_columns :shixuns, :description, :propaedeutics, :evaluate_script + end +end diff --git a/db/migrate/20190329091942_add_index_to_shixun_infos.rb b/db/migrate/20190329091942_add_index_to_shixun_infos.rb new file mode 100644 index 000000000..c7a14dfaa --- /dev/null +++ b/db/migrate/20190329091942_add_index_to_shixun_infos.rb @@ -0,0 +1,5 @@ +class AddIndexToShixunInfos < ActiveRecord::Migration[5.2] + def change + add_index :shixun_infos, :shixun_id, unique: true + end +end diff --git a/db/migrate/20190401083919_change_quotes_to_integer_in_attachments.rb b/db/migrate/20190401083919_change_quotes_to_integer_in_attachments.rb new file mode 100644 index 000000000..4e25ab522 --- /dev/null +++ b/db/migrate/20190401083919_change_quotes_to_integer_in_attachments.rb @@ -0,0 +1,6 @@ +class ChangeQuotesToIntegerInAttachments < ActiveRecord::Migration[5.2] + def change + change_column :attachments, :quotes, :integer, :default => 0 + add_index :attachments, :quotes + end +end diff --git a/db/migrate/20190401094623_add_index_to_attachments_is_public.rb b/db/migrate/20190401094623_add_index_to_attachments_is_public.rb new file mode 100644 index 000000000..d098253d0 --- /dev/null +++ b/db/migrate/20190401094623_add_index_to_attachments_is_public.rb @@ -0,0 +1,5 @@ +class AddIndexToAttachmentsIsPublic < ActiveRecord::Migration[5.2] + def change + add_index :attachments, :is_public + end +end diff --git a/db/migrate/20190402015918_add_invalid_to_graduation_work_score.rb b/db/migrate/20190402015918_add_invalid_to_graduation_work_score.rb new file mode 100644 index 000000000..5a7ea9c16 --- /dev/null +++ b/db/migrate/20190402015918_add_invalid_to_graduation_work_score.rb @@ -0,0 +1,5 @@ +class AddInvalidToGraduationWorkScore < ActiveRecord::Migration[5.2] + def change + add_column :graduation_work_scores, :is_invalid, :boolean, default: false + end +end diff --git a/db/migrate/20190402083252_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb b/db/migrate/20190402083252_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb new file mode 100644 index 000000000..b4bc9a2f6 --- /dev/null +++ b/db/migrate/20190402083252_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb @@ -0,0 +1,40 @@ +# This migration comes from acts_as_taggable_on_engine (originally 1) +if ActiveRecord.gem_version >= Gem::Version.new('5.0') + class ActsAsTaggableOnMigration < ActiveRecord::Migration[4.2]; end +else + class ActsAsTaggableOnMigration < ActiveRecord::Migration; end +end +ActsAsTaggableOnMigration.class_eval do + def self.up + unless ActiveRecord::Base.connection.table_exists? 'tags' + create_table :tags do |t| + t.string :name + end + end + + unless ActiveRecord::Base.connection.table_exists? 'taggings' + create_table :taggings do |t| + t.references :tag + + # You should make sure that the column created is + # long enough to store the required class names. + t.references :taggable, polymorphic: true + t.references :tagger, polymorphic: true + + # Limit is created to prevent MySQL error on index + # length for MyISAM table type: http://bit.ly/vgW2Ql + t.string :context, limit: 128 + + t.datetime :created_at + end + end + + # add_index :taggings, :tag_id + # add_index :taggings, [:taggable_id, :taggable_type, :context] + end + + def self.down + drop_table :taggings + drop_table :tags + end +end diff --git a/db/migrate/20190402083253_add_missing_unique_indices.acts_as_taggable_on_engine.rb b/db/migrate/20190402083253_add_missing_unique_indices.acts_as_taggable_on_engine.rb new file mode 100644 index 000000000..7206c90e6 --- /dev/null +++ b/db/migrate/20190402083253_add_missing_unique_indices.acts_as_taggable_on_engine.rb @@ -0,0 +1,26 @@ +# This migration comes from acts_as_taggable_on_engine (originally 2) +if ActiveRecord.gem_version >= Gem::Version.new('5.0') + class AddMissingUniqueIndices < ActiveRecord::Migration[4.2]; end +else + class AddMissingUniqueIndices < ActiveRecord::Migration; end +end +AddMissingUniqueIndices.class_eval do + def self.up + # add_index :tags, :name, unique: true + + remove_index :taggings, :tag_id if index_exists?(:taggings, :tag_id) + remove_index :taggings, [:taggable_id, :taggable_type, :context] + add_index :taggings, + [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type], + unique: true, name: 'taggings_idx' + end + + def self.down + remove_index :tags, :name + + remove_index :taggings, name: 'taggings_idx' + + add_index :taggings, :tag_id unless index_exists?(:taggings, :tag_id) + add_index :taggings, [:taggable_id, :taggable_type, :context] + end +end diff --git a/db/migrate/20190402083254_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb b/db/migrate/20190402083254_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb new file mode 100644 index 000000000..5409eef63 --- /dev/null +++ b/db/migrate/20190402083254_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb @@ -0,0 +1,20 @@ +# This migration comes from acts_as_taggable_on_engine (originally 3) +if ActiveRecord.gem_version >= Gem::Version.new('5.0') + class AddTaggingsCounterCacheToTags < ActiveRecord::Migration[4.2]; end +else + class AddTaggingsCounterCacheToTags < ActiveRecord::Migration; end +end +AddTaggingsCounterCacheToTags.class_eval do + def self.up + add_column :tags, :taggings_count, :integer, default: 0 + + ActsAsTaggableOn::Tag.reset_column_information + ActsAsTaggableOn::Tag.find_each do |tag| + ActsAsTaggableOn::Tag.reset_counters(tag.id, :taggings) + end + end + + def self.down + remove_column :tags, :taggings_count + end +end diff --git a/db/migrate/20190402083255_add_missing_taggable_index.acts_as_taggable_on_engine.rb b/db/migrate/20190402083255_add_missing_taggable_index.acts_as_taggable_on_engine.rb new file mode 100644 index 000000000..097600b59 --- /dev/null +++ b/db/migrate/20190402083255_add_missing_taggable_index.acts_as_taggable_on_engine.rb @@ -0,0 +1,15 @@ +# This migration comes from acts_as_taggable_on_engine (originally 4) +if ActiveRecord.gem_version >= Gem::Version.new('5.0') + class AddMissingTaggableIndex < ActiveRecord::Migration[4.2]; end +else + class AddMissingTaggableIndex < ActiveRecord::Migration; end +end +AddMissingTaggableIndex.class_eval do + def self.up + add_index :taggings, [:taggable_id, :taggable_type, :context] + end + + def self.down + remove_index :taggings, [:taggable_id, :taggable_type, :context] + end +end diff --git a/db/migrate/20190402083256_change_collation_for_tag_names.acts_as_taggable_on_engine.rb b/db/migrate/20190402083256_change_collation_for_tag_names.acts_as_taggable_on_engine.rb new file mode 100644 index 000000000..731f66c5a --- /dev/null +++ b/db/migrate/20190402083256_change_collation_for_tag_names.acts_as_taggable_on_engine.rb @@ -0,0 +1,15 @@ +# This migration comes from acts_as_taggable_on_engine (originally 5) +# This migration is added to circumvent issue #623 and have special characters +# work properly +if ActiveRecord.gem_version >= Gem::Version.new('5.0') + class ChangeCollationForTagNames < ActiveRecord::Migration[4.2]; end +else + class ChangeCollationForTagNames < ActiveRecord::Migration; end +end +ChangeCollationForTagNames.class_eval do + def up + if ActsAsTaggableOn::Utils.using_mysql? + execute("ALTER TABLE tags MODIFY name varchar(255) CHARACTER SET utf8 COLLATE utf8_bin;") + end + end +end diff --git a/db/migrate/20190402083257_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb b/db/migrate/20190402083257_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb new file mode 100644 index 000000000..7073df2a2 --- /dev/null +++ b/db/migrate/20190402083257_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb @@ -0,0 +1,23 @@ +# This migration comes from acts_as_taggable_on_engine (originally 6) +if ActiveRecord.gem_version >= Gem::Version.new('5.0') + class AddMissingIndexesOnTaggings < ActiveRecord::Migration[4.2]; end +else + class AddMissingIndexesOnTaggings < ActiveRecord::Migration; end +end +AddMissingIndexesOnTaggings.class_eval do + def change + add_index :taggings, :tag_id unless index_exists? :taggings, :tag_id + add_index :taggings, :taggable_id unless index_exists? :taggings, :taggable_id + add_index :taggings, :taggable_type unless index_exists? :taggings, :taggable_type + add_index :taggings, :tagger_id unless index_exists? :taggings, :tagger_id + add_index :taggings, :context unless index_exists? :taggings, :context + + unless index_exists? :taggings, [:tagger_id, :tagger_type] + add_index :taggings, [:tagger_id, :tagger_type] + end + + unless index_exists? :taggings, [:taggable_id, :taggable_type, :tagger_id, :context], name: 'taggings_idy' + add_index :taggings, [:taggable_id, :taggable_type, :tagger_id, :context], name: 'taggings_idy' + end + end +end diff --git a/db/migrate/20190403022053_create_gtask_banks.rb b/db/migrate/20190403022053_create_gtask_banks.rb new file mode 100644 index 000000000..f7c7b4ffb --- /dev/null +++ b/db/migrate/20190403022053_create_gtask_banks.rb @@ -0,0 +1,19 @@ +class CreateGtaskBanks < ActiveRecord::Migration[5.2] + def change + create_table :gtask_banks do |t| + t.references :user + t.string :name + t.text :description + t.integer :task_type + t.integer :min_num, default: 0 + t.integer :max_num, default: 0 + t.integer :base_on_project, default: false + t.boolean :is_public, default: false + t.integer :quotes, default: 0 + t.references :graduation_task + t.references :course_list + + t.timestamps + end + end +end diff --git a/db/migrate/20190403025525_add_praises_count_for_jouranls_for_messages.rb b/db/migrate/20190403025525_add_praises_count_for_jouranls_for_messages.rb new file mode 100644 index 000000000..a175d64e5 --- /dev/null +++ b/db/migrate/20190403025525_add_praises_count_for_jouranls_for_messages.rb @@ -0,0 +1,13 @@ +class AddPraisesCountForJouranlsForMessages < ActiveRecord::Migration[5.2] + def change + add_column :journals_for_messages, :praises_count, :integer, :default => 0 + + messages = JournalsForMessage.includes(:praise_treads).all + messages.find_each do |m| + puts("####{m.id}") + praises_count = m.praise_treads.liker.count + m.update_column(:praises_count, praises_count) + end + + end +end diff --git a/db/migrate/20190403065609_create_gtopic_banks.rb b/db/migrate/20190403065609_create_gtopic_banks.rb new file mode 100644 index 000000000..a4e280252 --- /dev/null +++ b/db/migrate/20190403065609_create_gtopic_banks.rb @@ -0,0 +1,23 @@ +class CreateGtopicBanks < ActiveRecord::Migration[5.2] + def change + create_table :gtopic_banks do |t| + t.references :user + t.string :name + t.text :description + t.integer :quotes + t.boolean :is_public + t.integer :topic_type + t.integer :topic_source + t.integer :topic_property_first + t.integer :topic_property_second + t.string :source_unit + t.integer :topic_repeat + t.string :province + t.string :city + t.references :graduation_topic + t.references :course_list + + t.timestamps + end + end +end diff --git a/db/migrate/20190408060723_add_is_ordered_to_exercise_standard_answers.rb b/db/migrate/20190408060723_add_is_ordered_to_exercise_standard_answers.rb new file mode 100644 index 000000000..8ed2a6f8c --- /dev/null +++ b/db/migrate/20190408060723_add_is_ordered_to_exercise_standard_answers.rb @@ -0,0 +1,6 @@ +class AddIsOrderedToExerciseStandardAnswers < ActiveRecord::Migration[5.2] + def change + #试题的多空标准答案是否为一一对应,默认为一一对应,即true + add_column :exercise_standard_answers,:is_ordered,:boolean,:default => true + end +end diff --git a/db/migrate/20190410033511_change_column_in_homeworks.rb b/db/migrate/20190410033511_change_column_in_homeworks.rb new file mode 100644 index 000000000..df8da9b43 --- /dev/null +++ b/db/migrate/20190410033511_change_column_in_homeworks.rb @@ -0,0 +1,12 @@ +class ChangeColumnInHomeworks < ActiveRecord::Migration[5.2] + def change + change_column_default :homework_commons, :late_penalty, from: nil, to: 5 + change_column_default :homework_commons, :anonymous_comment, from: 0, to: 1 + change_column_default :homework_commons, :work_efficiency, from: 1, to: 0 + change_column_default :homework_commons, :eff_score, from: 20, to: 0 + change_column_default :homework_detail_manuals, :ta_proportion, from: nil, to: 0 + change_column_default :homework_detail_manuals, :comment_status, from: nil, to: 0 + change_column_default :homework_detail_manuals, :evaluation_num, from: nil, to: 0 + change_column_default :homework_detail_manuals, :absence_penalty, from: 1, to: 0 + end +end diff --git a/db/migrate/20190410081421_change_is_ordered_from_answer_to_question.rb b/db/migrate/20190410081421_change_is_ordered_from_answer_to_question.rb new file mode 100644 index 000000000..ae7144c4e --- /dev/null +++ b/db/migrate/20190410081421_change_is_ordered_from_answer_to_question.rb @@ -0,0 +1,6 @@ +class ChangeIsOrderedFromAnswerToQuestion < ActiveRecord::Migration[5.2] + def change + remove_column :exercise_standard_answers,:is_ordered + add_column :exercise_questions,:is_ordered,:boolean,:default => true + end +end diff --git a/db/migrate/20190410081736_migrate_homework_attachments.rb b/db/migrate/20190410081736_migrate_homework_attachments.rb new file mode 100644 index 000000000..fbdc26f6a --- /dev/null +++ b/db/migrate/20190410081736_migrate_homework_attachments.rb @@ -0,0 +1,5 @@ +class MigrateHomeworkAttachments < ActiveRecord::Migration[5.2] + def change + Attachment.where(container_type: "HomeworkCommon").update_all(attachtype: 1) + end +end diff --git a/db/migrate/20190413011125_add_cloud_url_to_attachment_histories.rb b/db/migrate/20190413011125_add_cloud_url_to_attachment_histories.rb new file mode 100644 index 000000000..a2f9db27d --- /dev/null +++ b/db/migrate/20190413011125_add_cloud_url_to_attachment_histories.rb @@ -0,0 +1,5 @@ +class AddCloudUrlToAttachmentHistories < ActiveRecord::Migration[5.2] + def change + add_column :attachment_histories, :cloud_url, :string, default: '' + end +end diff --git a/db/migrate/20190415090426_change_homework_common_columns.rb b/db/migrate/20190415090426_change_homework_common_columns.rb new file mode 100644 index 000000000..11360d47f --- /dev/null +++ b/db/migrate/20190415090426_change_homework_common_columns.rb @@ -0,0 +1,13 @@ +class ChangeHomeworkCommonColumns < ActiveRecord::Migration[5.2] + def up + change_column :homework_commons, :score_open, :boolean, default: 1 + change_column :homework_commons, :anonymous_comment, :boolean, default: 1 + change_column :homework_commons, :anonymous_appeal, :boolean, default: 0 + end + + def down + change_column :homework_commons, :score_open, :int, default: 1 + change_column :homework_commons, :anonymous_comment, :int, default: 1 + change_column :homework_commons, :anonymous_appeal, :int, default: 0 + end +end diff --git a/db/migrate/20190422032141_migrate_homework_late_time.rb b/db/migrate/20190422032141_migrate_homework_late_time.rb new file mode 100644 index 000000000..342986b9c --- /dev/null +++ b/db/migrate/20190422032141_migrate_homework_late_time.rb @@ -0,0 +1,21 @@ +class MigrateHomeworkLateTime < ActiveRecord::Migration[5.2] + def change + homeworks = HomeworkCommon.where.not(end_time: nil).where(homework_type: [1, 3 ,4], allow_late: 1, late_time: nil) + homeworks.each do |homework| + if homework.course.try(:end_date).present? + homework.update_column("late_time", homework.course.end_date) + elsif homework.end_time.present? + homework.update_column("late_time", Time.at(homework.end_time.to_i + 30*24*3600)) + end + end + + tasks = GraduationTask.where.not(end_time: nil).where(allow_late: 1, late_time: nil) + tasks.each do |task| + if task.course.try(:end_date).present? + task.update_column("late_time", task.course.end_date) + elsif task.end_time.present? + task.update_column("late_time", Time.at(task.end_time.to_i + 30*24*3600)) + end + end + end +end diff --git a/db/migrate/20190422083020_add_journals_for_messages_count_for_hm_and_gt_and_gw.rb b/db/migrate/20190422083020_add_journals_for_messages_count_for_hm_and_gt_and_gw.rb new file mode 100644 index 000000000..37162c850 --- /dev/null +++ b/db/migrate/20190422083020_add_journals_for_messages_count_for_hm_and_gt_and_gw.rb @@ -0,0 +1,18 @@ +class AddJournalsForMessagesCountForHmAndGtAndGw < ActiveRecord::Migration[5.2] + def change + #add_column :homework_commons, :journals_for_messages_count, :integer, :default => 0 + #add_column :graduation_tasks, :journals_for_messages_count, :integer, :default => 0 + #add_column :graduation_topics, :journals_for_messages_count, :integer, :default => 0 + + type = ["GraduationTopic", "GraduationTask", "HomeworkCommon"] + messages = JournalsForMessage.where(jour_type: type).where("m_parent_id is not null") + # 迁移所有2级以上的回复 + messages.each do |message| + while message.parent.try(:m_parent_id).present? do + puts "parent: #{message.parent.try(:m_parent_id)}" + message.update_attribute(:m_parent_id, message.parent.m_parent_id) + end + end + + end +end diff --git a/db/migrate/20190424014128_migrate_homework_anonymous_comment.rb b/db/migrate/20190424014128_migrate_homework_anonymous_comment.rb new file mode 100644 index 000000000..21c20fcce --- /dev/null +++ b/db/migrate/20190424014128_migrate_homework_anonymous_comment.rb @@ -0,0 +1,7 @@ +class MigrateHomeworkAnonymousComment < ActiveRecord::Migration[5.2] + def change + change_column_default :homework_commons, :anonymous_comment, from: 1, to: 0 + + HomeworkCommon.update_all("anonymous_comment = !anonymous_comment") + end +end diff --git a/db/migrate/20190426010412_add_is_invalid_to_student_works_scores.rb b/db/migrate/20190426010412_add_is_invalid_to_student_works_scores.rb new file mode 100644 index 000000000..2d782f924 --- /dev/null +++ b/db/migrate/20190426010412_add_is_invalid_to_student_works_scores.rb @@ -0,0 +1,25 @@ +class AddIsInvalidToStudentWorksScores < ActiveRecord::Migration[5.2] + def change + add_column :student_works_scores, :is_invalid, :boolean, default: false + + StudentWorksScore.where("score is not null").order("id desc").find_each do |score| + unless score.is_invalid + if score.student_work.present? + puts score.id + work = score.student_work + + # 如果分数是调整分 则之前的所有分都无效 + if score.is_ultimate + work.student_works_scores.where("score is not null and id < #{score.id}").update_all(is_invalid: 1) + + # 如果是同一个用户角色的重复评分,则之前的评分都无效 + elsif work.student_works_scores.where("user_id = #{score.user_id} and reviewer_role = #{score.reviewer_role} + and score is not null and id < #{score.id}").count > 0 + work.student_works_scores.where("user_id = #{score.user_id} and reviewer_role = #{score.reviewer_role} + and score is not null and id < #{score.id}").update_all(is_invalid: 1) + end + end + end + end + end +end diff --git a/db/migrate/20190427010940_change_exercise_score_to_float.rb b/db/migrate/20190427010940_change_exercise_score_to_float.rb new file mode 100644 index 000000000..e8c57bc1e --- /dev/null +++ b/db/migrate/20190427010940_change_exercise_score_to_float.rb @@ -0,0 +1,29 @@ +class ChangeExerciseScoreToFloat < ActiveRecord::Migration[5.2] + def up + change_column :exercise_users,:score,:decimal,precision: 10, scale: 1 + change_column :exercise_users, :objective_score, :decimal,precision: 10, scale: 1,default: 0.0 + # change_column :exercise_users, :subjective_score, :decimal,precision: 10, scale: 1,default: 0.0 + change_column :exercise_users, :subjective_score, :decimal,precision: 10, scale: 1,default: -1.0 + # change_column :exercise_answers,:score,:decimal,precision: 10, scale: 1,default: 0.0 + change_column :exercise_answers,:score,:decimal,precision: 10, scale: 1,default: -1.0 #6.10修改,方便判断主观题是否批阅 + change_column :exercise_bank_questions,:question_score,:decimal,precision: 10, scale: 1 + change_column :exercise_bank_shixun_challenges,:question_score,:decimal,precision: 10, scale: 1 + change_column :exercise_questions,:question_score,:decimal,precision: 10, scale: 1 + change_column :exercise_shixun_answers,:score,:decimal,precision: 10, scale: 1 + change_column :exercise_shixun_challenges,:question_score,:decimal,precision: 10, scale: 1 + change_column :exercise_answer_comments, :score,:decimal,precision: 10, scale: 1 + end + + def down + change_column :exercise_users,:score,:integer + change_column :exercise_users, :objective_score, :integer,default: -1 + change_column :exercise_users, :subjective_score, :integer,default: -1 + change_column :exercise_answers,:score,:integer,default: -1 + change_column :exercise_bank_questions,:question_score,:integer + change_column :exercise_shixun_answers,:score,:integer + change_column :exercise_bank_shixun_challenges,:question_score,:integer + change_column :exercise_questions,:question_score,:integer + change_column :exercise_shixun_challenges,:question_score,:integer + change_column :exercise_answer_comments, :score,:integer + end +end diff --git a/db/migrate/20190427045904_update_exercise_default_value.rb b/db/migrate/20190427045904_update_exercise_default_value.rb new file mode 100644 index 000000000..05d76ee44 --- /dev/null +++ b/db/migrate/20190427045904_update_exercise_default_value.rb @@ -0,0 +1,7 @@ +class UpdateExerciseDefaultValue < ActiveRecord::Migration[5.2] + def change + ExerciseUser.where(objective_score: -1.0).update_all(objective_score: 0.0) + # ExerciseUser.where(subjective_score: -1.0).update_all(subjective_score: 0.0) #主观题默认分数为-1,不需修改 + # ExerciseAnswer.where(score: -1.0).update_all(score: 0.0) #6.10 修改,方便判断主观题是否 + end +end diff --git a/db/migrate/20190429012219_change_digest_to_string_in_attachment_histories.rb b/db/migrate/20190429012219_change_digest_to_string_in_attachment_histories.rb new file mode 100644 index 000000000..d7c7e5b14 --- /dev/null +++ b/db/migrate/20190429012219_change_digest_to_string_in_attachment_histories.rb @@ -0,0 +1,5 @@ +class ChangeDigestToStringInAttachmentHistories < ActiveRecord::Migration[5.2] + def change + change_column :attachment_histories, :digest, :string, :limit => 60 + end +end diff --git a/db/migrate/20190429015510_add_default_for_exercises.rb b/db/migrate/20190429015510_add_default_for_exercises.rb new file mode 100644 index 000000000..3ebbf6e2f --- /dev/null +++ b/db/migrate/20190429015510_add_default_for_exercises.rb @@ -0,0 +1,7 @@ +class AddDefaultForExercises < ActiveRecord::Migration[5.2] + def change + change_column :exercises, :exercise_status, :integer, :default => 1 + change_column :exercises, :show_result, :integer, :default => 1 + change_column :exercises, :time, :integer, :default => -1 + end +end diff --git a/db/migrate/20190429080104_add_quotes_for_graduation_topics.rb b/db/migrate/20190429080104_add_quotes_for_graduation_topics.rb new file mode 100644 index 000000000..57694008e --- /dev/null +++ b/db/migrate/20190429080104_add_quotes_for_graduation_topics.rb @@ -0,0 +1,5 @@ +class AddQuotesForGraduationTopics < ActiveRecord::Migration[5.2] + def change + add_column :graduation_topics, :quotes, :integer, :default => 0 + end +end diff --git a/db/migrate/20190430090659_add_default_for_polls.rb b/db/migrate/20190430090659_add_default_for_polls.rb new file mode 100644 index 000000000..2fcb260ab --- /dev/null +++ b/db/migrate/20190430090659_add_default_for_polls.rb @@ -0,0 +1,5 @@ +class AddDefaultForPolls < ActiveRecord::Migration[5.2] + def change + change_column :polls, :polls_status, :integer, :default => 1 + end +end diff --git a/db/migrate/20190505031946_sync_users_index.rb b/db/migrate/20190505031946_sync_users_index.rb new file mode 100644 index 000000000..a1f9b40fb --- /dev/null +++ b/db/migrate/20190505031946_sync_users_index.rb @@ -0,0 +1,8 @@ +class SyncUsersIndex < ActiveRecord::Migration[5.2] + def change + remove_index :users, name: :index_users_on_phone_and_mail + remove_index :users, name: :index_users_on_id_and_type + remove_index :users, name: :index_users_on_auth_source_id + remove_index :users, name: :index_users_on_type + end +end diff --git a/db/migrate/20190505072404_remove_index_from_users.rb b/db/migrate/20190505072404_remove_index_from_users.rb new file mode 100644 index 000000000..b19219346 --- /dev/null +++ b/db/migrate/20190505072404_remove_index_from_users.rb @@ -0,0 +1,5 @@ +class RemoveIndexFromUsers < ActiveRecord::Migration[5.2] + def change + remove_index :users, name: :index_users_on_experience + end +end diff --git a/db/migrate/20190505092009_delete_ivalid_data.rb b/db/migrate/20190505092009_delete_ivalid_data.rb new file mode 100644 index 000000000..98f13d9e4 --- /dev/null +++ b/db/migrate/20190505092009_delete_ivalid_data.rb @@ -0,0 +1,34 @@ +class DeleteIvalidData < ActiveRecord::Migration[5.2] + def change + users = User.find_by_sql("select count(*) as user_count, login from users group by login having user_count>1") + users.each do |user| + valid_users = User.where(login: user.login) + valid_users.each do |valid_user| + unless valid_user.lastname.present? + valid_user.delete + end + end + end + + mail_users = User.find_by_sql("select count(*) as user_count, mail from users where mail is not null group by mail having user_count>1") + mail_users.each do |mail_user| + valid_mail_users = User.where(mail: mail_user.mail) + valid_mail_users.each do |valid_mail_user| + unless valid_mail_user.lastname.present? + valid_mail_user.delete + end + end + end + + + phone_users = User.find_by_sql("select count(*) as user_count, phone from users where phone is not null group by phone having user_count>1") + phone_users.each do |phone_user| + valid_phone_users = User.where(phone: phone_user.phone) + valid_phone_users.each do |valid_phone_user| + unless valid_phone_user.lastname.present? + valid_phone_user.delete + end + end + end + end +end diff --git a/db/migrate/20190505093440_init_use_index.rb b/db/migrate/20190505093440_init_use_index.rb new file mode 100644 index 000000000..d885c3a9d --- /dev/null +++ b/db/migrate/20190505093440_init_use_index.rb @@ -0,0 +1,9 @@ +class InitUseIndex < ActiveRecord::Migration[5.2] + def change + remove_index :users, name: :index_users_on_login if index_exists?(:users, :login, name: :index_users_on_login) + remove_index :users, name: :index_users_on_mail if index_exists?(:users, :mail, name: :index_users_on_mail) + add_index :users, :login, unique: true + add_index :users, :mail, unique: true + add_index :users, :phone, unique: true + end +end diff --git a/db/migrate/20190505095131_add_authentication_and_professional_certification_to_courses.rb b/db/migrate/20190505095131_add_authentication_and_professional_certification_to_courses.rb new file mode 100644 index 000000000..2cc1ba940 --- /dev/null +++ b/db/migrate/20190505095131_add_authentication_and_professional_certification_to_courses.rb @@ -0,0 +1,6 @@ +class AddAuthenticationAndProfessionalCertificationToCourses < ActiveRecord::Migration[5.2] + def change + add_column :courses, :authentication, :boolean, default: false + add_column :courses, :professional_certification, :boolean, default: false + end +end diff --git a/db/migrate/20190508090916_migrate_new_student_work_status.rb b/db/migrate/20190508090916_migrate_new_student_work_status.rb new file mode 100644 index 000000000..d2e9bb379 --- /dev/null +++ b/db/migrate/20190508090916_migrate_new_student_work_status.rb @@ -0,0 +1,6 @@ +class MigrateNewStudentWorkStatus < ActiveRecord::Migration[5.2] + def change + homeworks = HomeworkCommon.where(allow_late: 0) + StudentWork.where(homework_common_id: homeworks, work_status: 2).update_all(work_status: 1) + end +end diff --git a/db/migrate/20190511020736_add_is_public_to_messages.rb b/db/migrate/20190511020736_add_is_public_to_messages.rb new file mode 100644 index 000000000..bbbba8f50 --- /dev/null +++ b/db/migrate/20190511020736_add_is_public_to_messages.rb @@ -0,0 +1,5 @@ +class AddIsPublicToMessages < ActiveRecord::Migration[5.2] + def change + add_column :messages, :is_public, :boolean, :default => false + end +end diff --git a/db/migrate/20190514023907_add_column_to_zip_packs.rb b/db/migrate/20190514023907_add_column_to_zip_packs.rb new file mode 100644 index 000000000..8ba250f37 --- /dev/null +++ b/db/migrate/20190514023907_add_column_to_zip_packs.rb @@ -0,0 +1,10 @@ +class AddColumnToZipPacks < ActiveRecord::Migration[5.2] + def change + add_column :zip_packs, :container_id, :integer, default: 0 + add_column :zip_packs, :container_type, :string + + add_index :zip_packs, [:container_id, :container_type] + + ZipPack.all.update_all("container_type='HomeworkCommon', container_id = homework_id") + end +end diff --git a/db/migrate/20190514083047_change_question_random_exercises.rb b/db/migrate/20190514083047_change_question_random_exercises.rb new file mode 100644 index 000000000..313d648bb --- /dev/null +++ b/db/migrate/20190514083047_change_question_random_exercises.rb @@ -0,0 +1,11 @@ +class ChangeQuestionRandomExercises < ActiveRecord::Migration[5.2] + def up + change_column :exercises,:question_random,:boolean,default: false + change_column :exercises,:choice_random,:boolean,default: false + + end + def down + change_column :exercises,:question_random,:integer,default: 0 + change_column :exercises,:choice_random,:integer,default: 0 + end +end diff --git a/db/migrate/20190515014734_change_poll_show_result_boolean.rb b/db/migrate/20190515014734_change_poll_show_result_boolean.rb new file mode 100644 index 000000000..f74dd02c4 --- /dev/null +++ b/db/migrate/20190515014734_change_poll_show_result_boolean.rb @@ -0,0 +1,10 @@ +class ChangePollShowResultBoolean < ActiveRecord::Migration[5.2] + def change + def up + change_column :polls,:show_result,:boolean,default: true + end + def down + change_column :polls,:show_result,:integer,default: 1 + end + end +end diff --git a/db/migrate/20190517080313_add_test_set_average_for_challenges.rb b/db/migrate/20190517080313_add_test_set_average_for_challenges.rb new file mode 100644 index 000000000..59fabec9d --- /dev/null +++ b/db/migrate/20190517080313_add_test_set_average_for_challenges.rb @@ -0,0 +1,5 @@ +class AddTestSetAverageForChallenges < ActiveRecord::Migration[5.2] + def change + add_column :challenges, :test_set_average, :boolean, :default => false + end +end diff --git a/db/migrate/20190517083326_change_test_set_averger_for_challenges.rb b/db/migrate/20190517083326_change_test_set_averger_for_challenges.rb new file mode 100644 index 000000000..bf474245f --- /dev/null +++ b/db/migrate/20190517083326_change_test_set_averger_for_challenges.rb @@ -0,0 +1,5 @@ +class ChangeTestSetAvergerForChallenges < ActiveRecord::Migration[5.2] + def change + change_column :challenges, :test_set_average, :boolean, :default => true + end +end diff --git a/db/migrate/20190517085407_create_edu_settings.rb b/db/migrate/20190517085407_create_edu_settings.rb new file mode 100644 index 000000000..e6c081233 --- /dev/null +++ b/db/migrate/20190517085407_create_edu_settings.rb @@ -0,0 +1,10 @@ +class CreateEduSettings < ActiveRecord::Migration[5.2] + def change + create_table :edu_settings do |t| + t.string :name + t.string :value + + t.timestamps + end + end +end diff --git a/db/migrate/20190517092730_add_description_to_edu_settings.rb b/db/migrate/20190517092730_add_description_to_edu_settings.rb new file mode 100644 index 000000000..ad273b805 --- /dev/null +++ b/db/migrate/20190517092730_add_description_to_edu_settings.rb @@ -0,0 +1,14 @@ +class AddDescriptionToEduSettings < ActiveRecord::Migration[5.2] + def change + add_column :edu_settings, :description, :string + add_index :edu_settings, :name, unique: :true + + ['tomcat_webssh', 'webssh_username', 'webssh_password', 'git_address_ip', 'git_address_domain', 'git_username', + 'git_password', 'public_key', 'private_key', 'public_bucket', 'public_bucket_host', 'public_cdn_host', 'cloud_bridge', + 'cloud_tomcat_php', 'host_name', 'old_edu_host'].each do |name| + if EduSetting.find_by_name(name).nil? + EduSetting.create(name: name) + end + end + end +end diff --git a/db/migrate/20190518085626_add_index_to_verificatiojn_codes.rb b/db/migrate/20190518085626_add_index_to_verificatiojn_codes.rb new file mode 100644 index 000000000..e4bdaac19 --- /dev/null +++ b/db/migrate/20190518085626_add_index_to_verificatiojn_codes.rb @@ -0,0 +1,6 @@ +class AddIndexToVerificatiojnCodes < ActiveRecord::Migration[5.2] + def change + add_index :verification_codes, [:phone], name: 'by_phone' if !index_exists?(:verification_codes, :phone) + add_index :verification_codes, [:email], name: 'by_email' if !index_exists?(:verification_codes, :email) + end +end diff --git a/db/migrate/20190522091226_alter_educoder_indexs.rb b/db/migrate/20190522091226_alter_educoder_indexs.rb new file mode 100644 index 000000000..6e1ed9bb5 --- /dev/null +++ b/db/migrate/20190522091226_alter_educoder_indexs.rb @@ -0,0 +1,70 @@ +class AlterEducoderIndexs < ActiveRecord::Migration[5.2] + def change + + add_index :onclick_times, :user_id if !index_exists?(:onclick_times, :user_id) + remove_index :courses, :syllabus_id + add_index :courses, :tea_id + add_index :course_modules, [:course_id, :module_type] + remove_index :homework_commons, :course_homework_category_id + add_index :exercises, :course_id + remove_index :teacher_course_groups, :member_id + remove_index :student_works, :created_at + remove_index :student_works, :user_id + remove_index :student_works, :myshixun_id + remove_index :homework_challenge_settings, :shixun_id + remove_index :exercise_users, :exercise_id + add_index :exercise_users, [:exercise_id, :user_id] + add_index :homework_banks, :user_id + remove_index :exercise_answers, :exercise_choice_id + remove_index :exercise_answers, :exercise_question_id + add_index :exercise_answers, [:exercise_question_id, :user_id] + remove_index :exercise_shixun_challenges, :shixun_id + remove_index :exercise_shixun_answers, :exercise_shixun_challenge_id + remove_index :exercise_shixun_answers, :exercise_question_id + add_index :exercise_shixun_answers, [:exercise_question_id, :user_id], name: "exercise_question_id_user_id" + remove_index :student_works_evaluation_distributions, :student_work_id + add_index :student_works_evaluation_distributions, :user_id + remove_index :challenge_work_scores, :user_id + add_index :poll_questions, :poll_id + add_index :poll_users, [:poll_id, :user_id] + add_index :poll_answers, :poll_question_id + add_index :poll_votes, [:poll_question_id, :user_id], name: "poll_question_id_user_id" + remove_index :graduation_tasks, :user_id + remove_index :graduation_work_comment_assignations, :graduation_group_id + remove_index :graduation_works, :course_id + remove_index :graduation_works, :project_id + remove_index :graduation_works, :graduation_task_id + remove_index :graduation_works, :user_id + add_index :graduation_works, [:graduation_task_id, :user_id], name: "graduation_task_id_user_id" + + remove_index :graduation_work_scores, :graduation_task_id + remove_index :graduation_topics, :user_id + remove_index :graduation_topics, :tea_id + remove_index :student_graduation_topics, :member_id + remove_index :student_graduation_topics, :course_member_id + add_index :boards, :course_id + remove_index :messages, :author_id + remove_index :messages, :is_hidden + remove_index :messages, :root_id + remove_index :messages, :created_on + remove_index :attachments, :quotes + remove_index :attachments, :is_public + remove_index :attachments, :course_second_category_id + remove_index :course_members, :graduation_group_id + add_index :student_works_scores_appeals, :student_works_score_id + add_index :challenges, :shixun_id + add_index :challenge_chooses, :challenge_id + add_index :challenge_questions, :challenge_choose_id + add_index :challenge_tags, :challenge_id + remove_index :games, :user_id + add_index :shixun_members, :shixun_id + add_index :shixun_tag_repertoires, [:shixun_id, :tag_repertoire_id], name: "shixun_id_tag_repertoire_id" + add_index :shixun_schools, :shixun_id + add_index :shixun_mirror_repositories, :shixun_id + add_index :shixun_modifies, [:shixun_id, :myshixun_id], name: "shixun_id_myshixun_id" + remove_index :myshixuns, :user_id + remove_index :outputs, :created_at + remove_index :outputs, :test_set_position + remove_index :stages, :user_id + end +end diff --git a/db/migrate/20190524020819_change_exercise_question_type.rb b/db/migrate/20190524020819_change_exercise_question_type.rb new file mode 100644 index 000000000..625a57d06 --- /dev/null +++ b/db/migrate/20190524020819_change_exercise_question_type.rb @@ -0,0 +1,10 @@ +class ChangeExerciseQuestionType < ActiveRecord::Migration[5.2] + def change + ExerciseQuestion.where(question_type: 1).update_all(question_type: 0) #新版0为单选题,1为多选题,2为判断题 + ExerciseQuestion.where(question_type: 2).update_all(question_type: 1) + + ExerciseBankQuestion.where(question_type: 1).update_all(question_type: 0) + ExerciseBankQuestion.where(question_type: 2).update_all(question_type: 1) + + end +end diff --git a/db/migrate/20190528024055_migrate_base_on_project.rb b/db/migrate/20190528024055_migrate_base_on_project.rb new file mode 100644 index 000000000..d0ee197cb --- /dev/null +++ b/db/migrate/20190528024055_migrate_base_on_project.rb @@ -0,0 +1,5 @@ +class MigrateBaseOnProject < ActiveRecord::Migration[5.2] + def change + change_column :homework_detail_groups, :base_on_project, :boolean, default: true + end +end diff --git a/db/migrate/20190603024856_migrate_course_late_settings.rb b/db/migrate/20190603024856_migrate_course_late_settings.rb new file mode 100644 index 000000000..3097d3d34 --- /dev/null +++ b/db/migrate/20190603024856_migrate_course_late_settings.rb @@ -0,0 +1,9 @@ +class MigrateCourseLateSettings < ActiveRecord::Migration[5.2] + def change + change_column_default :homework_commons, :allow_late, from: 1, to: 0 + change_column_default :homework_commons, :late_penalty, from: 5, to: 0 + + change_column_default :graduation_tasks, :allow_late, from: 1, to: 0 + change_column_default :graduation_tasks, :late_penalty, from: 5, to: 0 + end +end diff --git a/db/migrate/20190605060799_modify_script_and_description_for_shixuninfo.rb b/db/migrate/20190605060799_modify_script_and_description_for_shixuninfo.rb new file mode 100644 index 000000000..4b3318d56 --- /dev/null +++ b/db/migrate/20190605060799_modify_script_and_description_for_shixuninfo.rb @@ -0,0 +1,15 @@ +class ModifyScriptAndDescriptionForShixuninfo < ActiveRecord::Migration[5.2] + def change + Shixun.find_each do |shixun| + if shixun.shixun_info + shixun.shixun_info.update_attributes(propaedeutics: shixun[:propaedeutics], + description: shixun[:description], + evaluate_script: shixun[:evaluate_script], + shixun_id: shixun[:id]) + else + ShixunInfo.create!(propaedeutics: shixun[:propaedeutics], description: shixun[:description], + evaluate_script: shixun[:evaluate_script], shixun_id: shixun.id) + end + end + end +end diff --git a/db/migrate/20190606061948_migrate_student_works_scores_score.rb b/db/migrate/20190606061948_migrate_student_works_scores_score.rb new file mode 100644 index 000000000..c531357a8 --- /dev/null +++ b/db/migrate/20190606061948_migrate_student_works_scores_score.rb @@ -0,0 +1,5 @@ +class MigrateStudentWorksScoresScore < ActiveRecord::Migration[5.2] + def change + change_column :student_works_scores, :score, :float + end +end diff --git a/db/migrate/20190610013620_change_question_random_default_true.rb b/db/migrate/20190610013620_change_question_random_default_true.rb new file mode 100644 index 000000000..d0c785d46 --- /dev/null +++ b/db/migrate/20190610013620_change_question_random_default_true.rb @@ -0,0 +1,12 @@ +class ChangeQuestionRandomDefaultTrue < ActiveRecord::Migration[5.2] + #试卷的题目和选项的随机显示,需默认勾选 + def up + change_column_default :exercises,:question_random,true + change_column_default :exercises,:choice_random,true + end + + def down + change_column_default :exercises,:question_random,false + change_column_default :exercises,:choice_random,false + end +end diff --git a/db/migrate/20190613022158_add_exec_time_to_challenge.rb b/db/migrate/20190613022158_add_exec_time_to_challenge.rb new file mode 100644 index 000000000..c1743674c --- /dev/null +++ b/db/migrate/20190613022158_add_exec_time_to_challenge.rb @@ -0,0 +1,9 @@ +class AddExecTimeToChallenge < ActiveRecord::Migration[5.2] + def change + add_column :challenges, :exec_time, :integer + + Shixun.find_each do |shixun| + shixun.challenges.update_all(exec_time: shixun.exec_time) + end + end +end diff --git a/db/migrate/20190617081105_change_default_data_for_name_in_borads.rb b/db/migrate/20190617081105_change_default_data_for_name_in_borads.rb new file mode 100644 index 000000000..2dbbb7146 --- /dev/null +++ b/db/migrate/20190617081105_change_default_data_for_name_in_borads.rb @@ -0,0 +1,10 @@ +class ChangeDefaultDataForNameInBorads < ActiveRecord::Migration[5.2] + def change + puts "--------- START ------------" + Board.roots.joins(:course).where('courses.id = boards.course_id').find_each do |board| + board.update_columns(name: '讨论区') unless board.name.strip === '讨论区' + puts "Board ID IS #{board.id}" + end + puts "--------- END ----------" + end +end diff --git a/db/migrate/20190619055012_add_uniq_index_to_course_modules.rb b/db/migrate/20190619055012_add_uniq_index_to_course_modules.rb new file mode 100644 index 000000000..92ae6449f --- /dev/null +++ b/db/migrate/20190619055012_add_uniq_index_to_course_modules.rb @@ -0,0 +1,43 @@ +class AddUniqIndexToCourseModules < ActiveRecord::Migration[5.2] + def change + # sql = %Q(delete from exercise_users where (user_id, exercise_id) in + # (select * from (select user_id, exercise_id from exercise_users group by user_id, exercise_id having count(*) > 1) a) + # and id not in (select * from (select min(id) from exercise_users group by user_id, exercise_id having count(*) > 1 order by id) b)) + # ActiveRecord::Base.connection.execute sql + # + # add_index :exercise_users, [:user_id, :exercise_id], unique: true, name: "index_user_id_and_exercise_id" + + + sql = %Q(delete from exercise_shixun_answers where (user_id, exercise_shixun_challenge_id) in + (select * from (select user_id, exercise_shixun_challenge_id from exercise_shixun_answers group by user_id, exercise_shixun_challenge_id having count(*) > 1) a) + and id not in (select * from (select min(id) from exercise_shixun_answers group by user_id, exercise_shixun_challenge_id having count(*) > 1 order by id) b)) + ActiveRecord::Base.connection.execute sql + + add_index :exercise_shixun_answers, [:user_id, :exercise_shixun_challenge_id], unique: true, + name: "index_user_id_and_exercise_shixun_challenge_id" + + + # sql = %Q(delete from student_works where (user_id, homework_common_id) in + # (select * from (select user_id, homework_common_id from student_works group by user_id, homework_common_id having count(*) > 1) a) + # and id not in (select * from (select min(id) from student_works group by user_id, homework_common_id having count(*) > 1 order by id) b)) + # ActiveRecord::Base.connection.execute sql + # + # add_index :student_works, [:user_id, :homework_common_id], unique: true, name: "index_user_id_and_homework_common_id" + # + # + # sql = %Q(delete from poll_users where (user_id, poll_id) in + # (select * from (select user_id, poll_id from poll_users group by user_id, poll_id having count(*) > 1) a) and + # id not in (select * from (select min(id) from poll_users group by user_id, poll_id having count(*) > 1 order by id) b)) + # ActiveRecord::Base.connection.execute sql + # + # add_index :poll_users, [:user_id, :poll_id], unique: true, name: "index_user_id_and_poll_id" + # + # + # sql = %Q(delete from graduation_works where (user_id, graduation_task_id) in + # (select * from (select user_id, graduation_task_id from graduation_works group by user_id, graduation_task_id having count(*) > 1) a) and + # id not in (select * from (select min(id) from graduation_works group by user_id, graduation_task_id having count(*) > 1 order by id) b)) + # ActiveRecord::Base.connection.execute sql + # + # add_index :graduation_works, [:user_id, :graduation_task_id], unique: true, name: "index_user_id_and_graduation_task_id" + end +end diff --git a/db/migrate/20190619093200_add_profile_completed_to_users.rb b/db/migrate/20190619093200_add_profile_completed_to_users.rb new file mode 100644 index 000000000..5248abd58 --- /dev/null +++ b/db/migrate/20190619093200_add_profile_completed_to_users.rb @@ -0,0 +1,5 @@ +class AddProfileCompletedToUsers < ActiveRecord::Migration[5.2] + def change + add_column :users, :profile_completed, :boolean, default: false + end +end diff --git a/db/migrate/20190619120609_add_graduation_topics_count_to_course.rb b/db/migrate/20190619120609_add_graduation_topics_count_to_course.rb new file mode 100644 index 000000000..01444b7ce --- /dev/null +++ b/db/migrate/20190619120609_add_graduation_topics_count_to_course.rb @@ -0,0 +1,9 @@ +class AddGraduationTopicsCountToCourse < ActiveRecord::Migration[5.2] + def change + add_column :courses, :graduation_topics_count, :integer, :default => 0 + add_column :courses, :graduation_tasks_count, :integer, :default => 0 + # add_column :courses, :attachments_count, :integer, :default => 0 + add_column :courses, :polls_count, :integer, :default => 0 + add_column :courses, :exercises_count, :integer, :default => 0 + end +end diff --git a/db/migrate/20190619123328_sync_countcha_for_course.rb b/db/migrate/20190619123328_sync_countcha_for_course.rb new file mode 100644 index 000000000..acd9e9716 --- /dev/null +++ b/db/migrate/20190619123328_sync_countcha_for_course.rb @@ -0,0 +1,11 @@ +class SyncCountchaForCourse < ActiveRecord::Migration[5.2] + def change + Course.find_each do |course| + Course.reset_counters course.id, :graduation_topics + Course.reset_counters course.id, :graduation_tasks + Course.reset_counters course.id, :polls + Course.reset_counters course.id, :exercises + # Course.reset_counters course.id, :attachments + end + end +end diff --git a/db/migrate/20190620010439_add_uniq_index_to_course_member.rb b/db/migrate/20190620010439_add_uniq_index_to_course_member.rb new file mode 100644 index 000000000..f17cd4274 --- /dev/null +++ b/db/migrate/20190620010439_add_uniq_index_to_course_member.rb @@ -0,0 +1,10 @@ +class AddUniqIndexToCourseMember < ActiveRecord::Migration[5.2] + def change + # sql = %Q(delete from course_members where (user_id, course_id, role) in + # (select * from (select user_id, course_id, role from course_members group by user_id, course_id, role having count(*) > 1) a) + # and id not in (select * from (select min(id) from course_members group by user_id, course_id, role having count(*) > 1 order by id) b)) + # ActiveRecord::Base.connection.execute sql + # + # add_index :course_members, [:user_id, :course_id, :role], unique: true, name: "index_user_id_course_id_role" + end +end diff --git a/db/migrate/20190620015912_modify_colla_index.rb b/db/migrate/20190620015912_modify_colla_index.rb new file mode 100644 index 000000000..0e9e23301 --- /dev/null +++ b/db/migrate/20190620015912_modify_colla_index.rb @@ -0,0 +1,51 @@ +class ModifyCollaIndex < ActiveRecord::Migration[5.2] + def change + remove_index :exercise_users, [:user_id, :exercise_id] if index_exists?(:exercise_users, [:user_id, :exercise_id]) + remove_index :exercise_users, [:exercise_id, :user_id] if index_exists?(:exercise_users, [:exercise_id, :user_id]) + sql = %Q(delete from exercise_users where (user_id, exercise_id) in + (select * from (select user_id, exercise_id from exercise_users group by user_id, exercise_id having count(*) > 1) a) + and id not in (select * from (select min(id) from exercise_users group by user_id, exercise_id having count(*) > 1 order by id) b)) + ActiveRecord::Base.connection.execute sql + add_index :exercise_users, [:exercise_id, :user_id], unique: true, name: "index_on_exercise_id_user_id" + + + remove_index :exercise_shixun_answers, :user_id + + + remove_index :student_works, [:user_id, :homework_common_id] if index_exists?(:student_works, [:user_id, :homework_common_id]) + remove_index :student_works, [:homework_common_id, :user_id] if index_exists?(:student_works, [:homework_common_id, :user_id]) + sql = %Q(delete from student_works where (user_id, homework_common_id) in + (select * from (select user_id, homework_common_id from student_works group by user_id, homework_common_id having count(*) > 1) a) + and id not in (select * from (select min(id) from student_works group by user_id, homework_common_id having count(*) > 1 order by id) b)) + ActiveRecord::Base.connection.execute sql + add_index :student_works, [:homework_common_id, :user_id], unique: true, name: "index_on_homework_common_id_user_id" + + + remove_index :poll_users, [:user_id, :poll_id] if index_exists?(:poll_users, [:user_id, :poll_id]) + remove_index :poll_users, [:poll_id, :user_id] if index_exists?(:poll_users, [:poll_id, :user_id]) + sql = %Q(delete from poll_users where (user_id, poll_id) in + (select * from (select user_id, poll_id from poll_users group by user_id, poll_id having count(*) > 1) a) and + id not in (select * from (select min(id) from poll_users group by user_id, poll_id having count(*) > 1 order by id) b)) + ActiveRecord::Base.connection.execute sql + add_index :poll_users, [:poll_id, :user_id], unique: true, name: "index_poll_id_and_user_id" + + + remove_index :graduation_works, [:user_id, :graduation_task_id] if index_exists?(:graduation_works, [:user_id, :graduation_task_id]) + remove_index :graduation_works, [:graduation_task_id, :user_id] if index_exists?(:graduation_works, [:graduation_task_id, :user_id]) + sql = %Q(delete from graduation_works where (user_id, graduation_task_id) in + (select * from (select user_id, graduation_task_id from graduation_works group by user_id, graduation_task_id having count(*) > 1) a) and + id not in (select * from (select min(id) from graduation_works group by user_id, graduation_task_id having count(*) > 1 order by id) b)) + ActiveRecord::Base.connection.execute sql + add_index :graduation_works, [:graduation_task_id, :user_id], unique: true, name: "index_graduation_task_id_and_user_id" + + + remove_index :course_members, [:user_id, :course_id, :role] if index_exists?(:course_members, [:user_id, :course_id, :role]) + remove_index :course_members, :course_id if index_exists?(:course_members, :course_id) + remove_index :course_members, :user_id if index_exists?(:course_members, :user_id) + sql = %Q(delete from course_members where (course_id, user_id, role) in + (select * from (select course_id, user_id, role from course_members group by course_id, user_id, role having count(*) > 1) a) + and id not in (select * from (select min(id) from course_members group by course_id, user_id, role having count(*) > 1 order by id) b)) + ActiveRecord::Base.connection.execute sql + add_index :course_members, [:course_id, :user_id, :role], unique: true, name: "index_course_id_user_id_role" + end +end diff --git a/db/migrate/20190620021243_add_homework_bank_id_index_to_homework_commons.rb b/db/migrate/20190620021243_add_homework_bank_id_index_to_homework_commons.rb new file mode 100644 index 000000000..9a97b82bf --- /dev/null +++ b/db/migrate/20190620021243_add_homework_bank_id_index_to_homework_commons.rb @@ -0,0 +1,5 @@ +class AddHomeworkBankIdIndexToHomeworkCommons < ActiveRecord::Migration[5.2] + def change + add_index :homework_commons, :homework_bank_id + end +end diff --git a/db/migrate/20190620075503_add_bank_id_for_graduation_task_and_topic.rb b/db/migrate/20190620075503_add_bank_id_for_graduation_task_and_topic.rb new file mode 100644 index 000000000..8149731e7 --- /dev/null +++ b/db/migrate/20190620075503_add_bank_id_for_graduation_task_and_topic.rb @@ -0,0 +1,6 @@ +class AddBankIdForGraduationTaskAndTopic < ActiveRecord::Migration[5.2] + def change + add_column :graduation_tasks, :gtask_bank_id, :integer + add_column :graduation_topics, :gtopic_bank_id, :integer + end +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 000000000..bc60c4ac6 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup). +# +# Examples: +# +# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) +# Character.create(name: 'Luke', movie: movies.first) + +# create_table :outputs do |t| +# t.integer :code +# t.integer :game_id +# t.text :msg +# t.longtext :out_put +# t.integer :test_set_position +# t.text :actual_output +# +# t.timestamps +# end \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql new file mode 100644 index 000000000..dd64cbec2 --- /dev/null +++ b/db/structure.sql @@ -0,0 +1,6778 @@ + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `activities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `activities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `act_id` int(11) NOT NULL, + `act_type` varchar(255) NOT NULL, + `user_id` int(11) NOT NULL, + `activity_container_id` int(11) DEFAULT NULL, + `activity_container_type` varchar(255) DEFAULT '', + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_activities_on_user_id` (`user_id`), + KEY `index_activities_on_act_id_and_act_type` (`act_id`,`act_type`), + KEY `index_activities_on_user_id_and_act_type` (`user_id`,`act_type`) +) ENGINE=InnoDB AUTO_INCREMENT=124468 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `activity_notifies`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `activity_notifies` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `activity_container_id` int(11) DEFAULT NULL, + `activity_container_type` varchar(255) DEFAULT NULL, + `activity_id` int(11) DEFAULT NULL, + `activity_type` varchar(255) DEFAULT NULL, + `notify_to` int(11) DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `is_read` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_an_notify_to` (`notify_to`), + KEY `index_an_created_on` (`created_on`), + KEY `index_an_activity_container_id` (`activity_container_id`,`activity_container_type`) +) ENGINE=InnoDB AUTO_INCREMENT=1294 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `api_keys`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `api_keys` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `access_token` varchar(255) DEFAULT NULL, + `expires_at` datetime DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `active` tinyint(1) DEFAULT '1', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_api_keys_on_user_id` (`user_id`), + KEY `index_api_keys_on_access_token` (`access_token`) +) ENGINE=InnoDB AUTO_INCREMENT=2906 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `applied_contests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `applied_contests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `contest_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `role` varchar(255) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_applied_contests_on_contest_id` (`contest_id`), + KEY `index_applied_contests_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=112 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `applied_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `applied_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `applied_id` int(11) DEFAULT NULL, + `applied_type` varchar(255) DEFAULT NULL, + `viewed` int(11) DEFAULT '0', + `status` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `name` varchar(255) DEFAULT NULL, + `applied_user_id` int(11) DEFAULT NULL, + `role` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6189 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `applied_projects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `applied_projects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `role` int(11) DEFAULT '0', + `status` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=859 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `apply_actions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `apply_actions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `reason` varchar(255) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `dealer_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `status` tinyint(4) DEFAULT '0', + `apply_reason` text, + `noticed` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=11512 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `apply_add_departments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `apply_add_departments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `department_id` int(11) DEFAULT NULL, + `school_id` int(11) DEFAULT NULL, + `remarks` text, + `user_id` int(11) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_apply_add_departments_on_department_id` (`department_id`), + KEY `index_apply_add_departments_on_school_id` (`school_id`), + KEY `index_apply_add_departments_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=734 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `apply_add_schools`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `apply_add_schools` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `province` varchar(255) DEFAULT NULL, + `city` varchar(255) DEFAULT NULL, + `address` varchar(255) DEFAULT NULL, + `remarks` varchar(255) DEFAULT NULL, + `school_id` int(11) DEFAULT NULL, + `status` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1024 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `apply_homeworks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `apply_homeworks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `status` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `homework_common_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_apply_homeworks_on_user_id` (`user_id`), + KEY `index_apply_homeworks_on_homework_common_id` (`homework_common_id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `apply_project_masters`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `apply_project_masters` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `apply_type` varchar(255) DEFAULT NULL, + `apply_id` int(11) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `apply_resources`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `apply_resources` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `status` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `attachment_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `content` text, + `apply_user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `apply_user_authentications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `apply_user_authentications` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `auth_type` int(11) DEFAULT NULL, + `remarks` varchar(255) DEFAULT NULL, + `dealer` int(11) DEFAULT NULL, + `deal_time` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `is_delete` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_apply_user_authentications_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1257 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `article_homepages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `article_homepages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(255) DEFAULT NULL, + `content` text, + `user_id` int(11) DEFAULT NULL, + `homepage_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_article_homepages_on_user_id` (`user_id`), + KEY `index_article_homepages_on_homepage_id` (`homepage_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1632 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `at_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `at_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `at_message_id` int(11) DEFAULT NULL, + `at_message_type` varchar(255) DEFAULT NULL, + `viewed` tinyint(1) DEFAULT '0', + `container_type` varchar(255) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `sender_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_at_messages_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=4562 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `attachment_group_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `attachment_group_settings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `attachment_id` int(11) DEFAULT NULL, + `course_group_id` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `publish_time` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_attachment_group_settings_on_attachment_id` (`attachment_id`), + KEY `index_attachment_group_settings_on_course_group_id` (`course_group_id`), + KEY `index_attachment_group_settings_on_course_id` (`course_id`) +) ENGINE=InnoDB AUTO_INCREMENT=56 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `attachment_histories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `attachment_histories` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `filename` varchar(255) DEFAULT '', + `disk_filename` varchar(255) DEFAULT '', + `filesize` int(11) DEFAULT '0', + `content_type` varchar(255) DEFAULT '', + `digest` varchar(40) DEFAULT '', + `downloads` int(11) DEFAULT '0', + `author_id` int(11) DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `description` text, + `disk_directory` varchar(255) DEFAULT NULL, + `attachtype` int(11) DEFAULT NULL, + `is_public` int(11) DEFAULT NULL, + `copy_from` int(11) DEFAULT NULL, + `quotes` int(11) DEFAULT NULL, + `version` int(11) DEFAULT NULL, + `attachment_id` int(11) DEFAULT NULL, + `is_publish` int(11) DEFAULT '1', + `publish_time` date DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=358 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `attachments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `attachments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(30) DEFAULT NULL, + `filename` varchar(255) NOT NULL DEFAULT '', + `disk_filename` varchar(255) NOT NULL DEFAULT '', + `filesize` int(11) NOT NULL DEFAULT '0', + `content_type` varchar(255) DEFAULT '', + `digest` varchar(40) NOT NULL DEFAULT '', + `downloads` int(11) NOT NULL DEFAULT '0', + `author_id` int(11) NOT NULL DEFAULT '0', + `created_on` datetime DEFAULT NULL, + `description` text, + `disk_directory` varchar(255) DEFAULT NULL, + `attachtype` int(11) DEFAULT '1', + `is_public` int(11) DEFAULT '1', + `copy_from` int(11) DEFAULT NULL, + `quotes` int(11) DEFAULT NULL, + `is_publish` int(11) DEFAULT '1', + `publish_time` datetime DEFAULT NULL, + `resource_bank_id` int(11) DEFAULT NULL, + `unified_setting` tinyint(1) DEFAULT '1', + PRIMARY KEY (`id`), + KEY `index_attachments_on_author_id` (`author_id`), + KEY `index_attachments_on_created_on` (`created_on`), + KEY `index_attachments_on_container_id_and_container_type` (`container_id`,`container_type`) +) ENGINE=InnoDB AUTO_INCREMENT=206533 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `attachmentstypes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `attachmentstypes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `typeId` int(11) NOT NULL, + `typeName` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `attendances`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `attendances` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `score` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `user` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=24510 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `auth_sources`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `auth_sources` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `type` varchar(30) NOT NULL DEFAULT '', + `name` varchar(60) NOT NULL DEFAULT '', + `host` varchar(60) DEFAULT NULL, + `port` int(11) DEFAULT NULL, + `account` varchar(255) DEFAULT NULL, + `account_password` varchar(255) DEFAULT '', + `base_dn` varchar(255) DEFAULT NULL, + `attr_login` varchar(30) DEFAULT NULL, + `attr_firstname` varchar(30) DEFAULT NULL, + `attr_lastname` varchar(30) DEFAULT NULL, + `attr_mail` varchar(30) DEFAULT NULL, + `onthefly_register` tinyint(1) NOT NULL DEFAULT '0', + `tls` tinyint(1) NOT NULL DEFAULT '0', + `filter` varchar(255) DEFAULT NULL, + `timeout` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_auth_sources_on_id_and_type` (`id`,`type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `authentications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `authentications` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `level` tinyint(4) DEFAULT NULL, + `permissions` text, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `authentications_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `authentications_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `authentication_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1949 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `biding_projects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `biding_projects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `bid_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `reward` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=86 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `bids`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `bids` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `budget` varchar(255) NOT NULL, + `author_id` int(11) DEFAULT NULL, + `deadline` date DEFAULT NULL, + `description` text, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + `commit` int(11) DEFAULT NULL, + `reward_type` int(11) DEFAULT NULL, + `homework_type` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + `password` varchar(255) DEFAULT NULL, + `is_evaluation` int(11) DEFAULT NULL, + `proportion` int(11) DEFAULT '60', + `comment_status` int(11) DEFAULT '0', + `evaluation_num` int(11) DEFAULT '3', + `open_anonymous_evaluation` int(11) DEFAULT '1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=761 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `blog_comments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `blog_comments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `blog_id` int(11) NOT NULL, + `parent_id` int(11) DEFAULT NULL, + `title` varchar(255) NOT NULL DEFAULT '', + `content` text, + `author_id` int(11) DEFAULT NULL, + `comments_count` int(11) NOT NULL DEFAULT '0', + `last_comment_id` int(11) DEFAULT NULL, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + `locked` tinyint(1) DEFAULT '0', + `sticky` int(11) DEFAULT '0', + `reply_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `root_id` int(11) DEFAULT NULL, + `visits` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_blog_comments_on_root_id` (`root_id`) +) ENGINE=InnoDB AUTO_INCREMENT=620 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `blog_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `blog_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `blog_message_id` int(11) DEFAULT NULL, + `blog_id` int(11) DEFAULT NULL, + `blog_message_type` varchar(255) DEFAULT NULL, + `viewed` tinyint(1) DEFAULT '0', + `content` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `user_operator_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `blogs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `blogs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL DEFAULT '', + `description` text, + `position` int(11) DEFAULT '1', + `article_count` int(11) NOT NULL DEFAULT '0', + `comments_count` int(11) NOT NULL DEFAULT '0', + `last_comments_id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + `author_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `homepage_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=24115 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `boards`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `boards` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) NOT NULL, + `name` varchar(255) NOT NULL DEFAULT '', + `description` varchar(255) DEFAULT NULL, + `position` int(11) DEFAULT '1', + `topics_count` int(11) NOT NULL DEFAULT '0', + `messages_count` int(11) NOT NULL DEFAULT '0', + `last_message_id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT '0', + `course_id` int(11) DEFAULT NULL, + `org_subfield_id` int(11) DEFAULT NULL, + `contest_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `boards_project_id` (`project_id`), + KEY `index_boards_on_last_message_id` (`last_message_id`), + KEY `parent` (`parent_id`) +) ENGINE=InnoDB AUTO_INCREMENT=5852 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `bug_to_osps`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `bug_to_osps` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `osp_id` int(11) DEFAULT NULL, + `relative_memo_id` int(11) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `challenge_chooses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `challenge_chooses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `subject` text, + `challenge_id` int(11) DEFAULT NULL, + `standard_answer` varchar(255) DEFAULT NULL, + `answer` text, + `score` int(11) DEFAULT NULL, + `difficult` int(11) DEFAULT '1', + `category` int(11) DEFAULT NULL, + `position` int(11) DEFAULT '1', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=277 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `challenge_questions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `challenge_questions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `option_name` text, + `challenge_choose_id` int(11) DEFAULT NULL, + `right_key` tinyint(1) DEFAULT NULL, + `position` tinyint(4) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2146 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `challenge_samples`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `challenge_samples` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `input` varchar(255) DEFAULT NULL, + `output` varchar(255) DEFAULT NULL, + `challenge_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `game_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `challenge_tags`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `challenge_tags` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `challenge_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `challenge_choose_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=13972 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `challenges`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `challenges` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `subject` varchar(255) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `status` tinyint(4) DEFAULT '0', + `position` tinyint(4) DEFAULT '1', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `task_pass` longtext, + `answer` longtext, + `score` int(11) DEFAULT '100', + `visits` int(11) DEFAULT '0', + `path` varchar(255) DEFAULT NULL, + `evaluation_way` int(11) DEFAULT '0', + `difficulty` int(11) DEFAULT '1', + `exec_path` varchar(255) DEFAULT NULL, + `code_line` int(11) DEFAULT NULL, + `st` tinyint(4) DEFAULT '0', + `web_route` text, + `picture_path` text, + `expect_picture_path` text, + `modify_time` datetime DEFAULT NULL, + `challenge_tags_count` int(11) DEFAULT '0', + `original_picture_path` varchar(255) DEFAULT NULL, + `show_type` int(11) DEFAULT '-1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3286 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `changes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `changeset_id` int(11) NOT NULL, + `action` varchar(1) NOT NULL DEFAULT '', + `path` text NOT NULL, + `from_path` text, + `from_revision` varchar(255) DEFAULT NULL, + `revision` varchar(255) DEFAULT NULL, + `branch` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `changesets_changeset_id` (`changeset_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1128132 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `changeset_parents`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changeset_parents` ( + `changeset_id` int(11) NOT NULL, + `parent_id` int(11) NOT NULL, + KEY `changeset_parents_changeset_ids` (`changeset_id`), + KEY `changeset_parents_parent_ids` (`parent_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `changesets`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changesets` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `repository_id` int(11) NOT NULL, + `revision` varchar(255) NOT NULL, + `committer` varchar(255) DEFAULT NULL, + `committed_on` datetime NOT NULL, + `comments` text, + `commit_date` date DEFAULT NULL, + `scmid` varchar(255) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `type` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `changesets_repos_rev` (`repository_id`,`revision`), + KEY `index_changesets_on_user_id` (`user_id`), + KEY `index_changesets_on_repository_id` (`repository_id`), + KEY `index_changesets_on_committed_on` (`committed_on`), + KEY `changesets_repos_scmid` (`repository_id`,`scmid`) +) ENGINE=InnoDB AUTO_INCREMENT=121390 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `changesets_issues`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `changesets_issues` ( + `changeset_id` int(11) NOT NULL, + `issue_id` int(11) NOT NULL, + UNIQUE KEY `changesets_issues_ids` (`changeset_id`,`issue_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `chart_rules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `chart_rules` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `rule_type` varchar(255) DEFAULT NULL, + `content` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `choose_outputs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `choose_outputs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `challenge_choose_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `answer` varchar(255) DEFAULT NULL, + `correct` tinyint(1) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=71 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `code_tests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `code_tests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `homework_id` int(11) DEFAULT NULL, + `wait_time` int(11) DEFAULT '0', + `language` int(11) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `time_used` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `student_work_id` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=759267 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `comments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `comments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `commented_type` varchar(30) NOT NULL DEFAULT '', + `commented_id` int(11) NOT NULL DEFAULT '0', + `author_id` int(11) NOT NULL DEFAULT '0', + `comments` text, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + `parent_id` int(11) DEFAULT NULL, + `comments_count` int(11) DEFAULT '0', + `reply_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_comments_on_commented_id_and_commented_type` (`commented_id`,`commented_type`), + KEY `index_comments_on_author_id` (`author_id`) +) ENGINE=InnoDB AUTO_INCREMENT=4799 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `commit_issues`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `commit_issues` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `commit_id` varchar(255) DEFAULT NULL, + `issue_id` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `commits`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `commits` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `repository_id` int(11) DEFAULT NULL, + `version` varchar(255) DEFAULT NULL, + `committer` varchar(255) DEFAULT NULL, + `comments` text, + `committed_on` datetime DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `competition_entries`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `competition_entries` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `competition_stage_section_id` int(11) DEFAULT NULL, + `competition_stage_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `url` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_competition_entries_on_competition_stage_section_id` (`competition_stage_section_id`), + KEY `index_competition_entries_on_competition_stage_id` (`competition_stage_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `competition_lists`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `competition_lists` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `competition_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_competition_lists_on_competition_id` (`competition_id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `competition_modules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `competition_modules` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `competition_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `hidden` tinyint(1) DEFAULT '0', + `url` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_competition_modules_on_competition_id` (`competition_id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `competition_scores`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `competition_scores` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `score` float DEFAULT NULL, + `score_type` varchar(255) DEFAULT NULL, + `region` varchar(255) DEFAULT NULL, + `cost_time` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_competition_scores_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=337 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `competition_stage_sections`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `competition_stage_sections` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `competition_id` int(11) DEFAULT NULL, + `competition_stage_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `start_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `entry` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_competition_stage_sections_on_competition_id` (`competition_id`), + KEY `index_competition_stage_sections_on_competition_stage_id` (`competition_stage_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `competition_stages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `competition_stages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `competition_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_competition_stages_on_competition_id` (`competition_id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `competitions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `competitions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `start_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `identifier` varchar(255) DEFAULT NULL, + `status` tinyint(1) DEFAULT '0', + `online_time` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `visits` int(11) DEFAULT '0', + `competition_lists_count` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contest_activities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contest_activities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `contest_id` int(11) DEFAULT NULL, + `contest_act_id` int(11) DEFAULT NULL, + `contest_act_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_contest_activities_on_user_id` (`user_id`), + KEY `index_contest_activities_on_contest_id` (`contest_id`) +) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contest_member_roles`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contest_member_roles` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `contest_member_id` int(11) DEFAULT NULL, + `role_id` int(11) DEFAULT NULL, + `is_current` tinyint(1) DEFAULT '1', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_contest_member_roles_on_contest_member_id` (`contest_member_id`), + KEY `index_contest_member_roles_on_role_id` (`role_id`) +) ENGINE=InnoDB AUTO_INCREMENT=185 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contest_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contest_members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `contest_id` int(11) DEFAULT NULL, + `is_collect` tinyint(1) DEFAULT '1', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_contest_members_on_user_id` (`user_id`), + KEY `index_contest_members_on_contest_id` (`contest_id`) +) ENGINE=InnoDB AUTO_INCREMENT=175 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contest_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contest_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `contest_id` int(11) DEFAULT NULL, + `contest_message_id` int(11) DEFAULT NULL, + `contest_message_type` varchar(255) DEFAULT NULL, + `viewed` tinyint(1) DEFAULT '0', + `content` text, + `status` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_contest_messages_on_user_id` (`user_id`), + KEY `index_contest_messages_on_contest_id` (`contest_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1983 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contestant_for_contests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contestant_for_contests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `student_id` int(11) DEFAULT NULL, + `contest_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_contestant_for_contests_on_contest_id` (`contest_id`), + KEY `index_contestant_for_contests_on_student_id` (`student_id`) +) ENGINE=InnoDB AUTO_INCREMENT=129 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contestant_work_evaluation_distributions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contestant_work_evaluation_distributions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `contestant_work_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_contestant_work_evaluation_distributions_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contestant_work_projects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contestant_work_projects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `contest_id` int(11) DEFAULT NULL, + `work_id` int(11) DEFAULT NULL, + `contestant_work_id` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `is_leader` tinyint(1) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_contestant_work_projects_on_contest_id` (`contest_id`), + KEY `index_contestant_work_projects_on_work_id` (`work_id`), + KEY `index_contestant_work_projects_on_contestant_work_id` (`contestant_work_id`), + KEY `index_contestant_work_projects_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=83 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contestant_work_scores`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contestant_work_scores` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `contestant_work_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `score` int(11) DEFAULT NULL, + `comment` text, + `reviewer_role` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_contestant_work_scores_on_contestant_work_id` (`contestant_work_id`), + KEY `index_contestant_work_scores_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contestant_works`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contestant_works` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` text, + `work_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `work_score` float DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `work_status` int(11) DEFAULT NULL, + `commit_time` datetime DEFAULT NULL, + `is_delete` tinyint(1) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `judge_score` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_contestant_works_on_work_id` (`work_id`), + KEY `index_contestant_works_on_user_id` (`user_id`), + KEY `index_contestant_works_on_project_id` (`project_id`) +) ENGINE=InnoDB AUTO_INCREMENT=114 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `contests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `contests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `description` text, + `is_public` tinyint(1) DEFAULT NULL, + `is_delete` tinyint(1) DEFAULT '0', + `visits` int(11) DEFAULT '0', + `invite_code` varchar(255) DEFAULT NULL, + `invite_code_halt` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=810 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `coo_imgs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `coo_imgs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `src_states` varchar(255) DEFAULT NULL, + `url_states` varchar(255) DEFAULT NULL, + `img_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `position` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `coop_imgs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `coop_imgs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `src_states` varchar(255) DEFAULT NULL, + `url_states` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `img_type` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `cooperations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `cooperations` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `mail` varchar(255) DEFAULT NULL, + `qq` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `user_type` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_activities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_activities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `course_act_id` int(11) DEFAULT NULL, + `course_act_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `course_act_index` (`course_id`,`course_act_id`,`course_act_type`,`created_at`) +) ENGINE=InnoDB AUTO_INCREMENT=38842 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_attachments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_attachments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `filename` varchar(255) DEFAULT NULL, + `disk_filename` varchar(255) DEFAULT NULL, + `filesize` int(11) DEFAULT NULL, + `content_type` varchar(255) DEFAULT NULL, + `digest` varchar(255) DEFAULT NULL, + `downloads` int(11) DEFAULT NULL, + `author_id` varchar(255) DEFAULT NULL, + `integer` varchar(255) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `disk_directory` varchar(255) DEFAULT NULL, + `attachtype` int(11) DEFAULT NULL, + `is_public` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `container_id` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=413 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_contributor_scores`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_contributor_scores` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `course_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `message_num` int(11) DEFAULT '0', + `message_reply_num` int(11) DEFAULT '0', + `news_reply_num` int(11) DEFAULT '0', + `resource_num` int(11) DEFAULT '0', + `journal_num` int(11) DEFAULT '0', + `journal_reply_num` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `total_score` int(11) DEFAULT '0', + `homework_journal_num` int(11) DEFAULT '0', + `news_num` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_course_contributor_scores_on_course_id_and_user_id` (`course_id`,`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=34579 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_groups` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `members_count` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_course_groups_on_course_id` (`course_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1009 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_homework_statistics`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_homework_statistics` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `committed_work_num` int(11) DEFAULT '0', + `un_commit_work_num` int(11) DEFAULT '0', + `late_commit_work_num` int(11) DEFAULT '0', + `absence_evaluation_work_num` int(11) DEFAULT '0', + `un_evaluation_work_num` int(11) DEFAULT '0', + `appeal_num` int(11) DEFAULT '0', + `average_score` float DEFAULT '0', + `total_score` float DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=31032 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_infos`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_infos` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `course_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1417 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_lists`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_lists` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `is_admin` tinyint(1) DEFAULT '1', + `support_shixuns_search` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1178 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `course_message_id` int(11) DEFAULT NULL, + `course_message_type` varchar(255) DEFAULT NULL, + `viewed` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `content` text, + `status` int(11) DEFAULT NULL, + `apply_user_id` int(11) DEFAULT NULL, + `apply_result` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_course_messages_on_user_id_and_course_id_and_created_at` (`user_id`,`course_id`,`created_at`), + KEY `index_course_messages_on_course_message_type` (`course_message_type`) +) ENGINE=InnoDB AUTO_INCREMENT=1032687 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_modules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_modules` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `course_id` int(11) DEFAULT NULL, + `module_type` varchar(255) DEFAULT NULL, + `position` int(11) DEFAULT NULL, + `hidden` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `module_name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=12718 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `course_statuses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `course_statuses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `changesets_count` int(11) DEFAULT NULL, + `watchers_count` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `grade` float DEFAULT '0', + `course_ac_para` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=666 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `courses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `courses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `tea_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `state` int(11) DEFAULT NULL, + `code` varchar(255) DEFAULT NULL, + `time` int(11) DEFAULT NULL, + `extra` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `location` varchar(255) DEFAULT NULL, + `term` varchar(255) DEFAULT NULL, + `string` varchar(255) DEFAULT NULL, + `password` varchar(255) DEFAULT NULL, + `setup_time` varchar(255) DEFAULT NULL, + `endup_time` varchar(255) DEFAULT NULL, + `class_period` varchar(255) DEFAULT NULL, + `school_id` int(11) DEFAULT NULL, + `description` text, + `status` int(11) DEFAULT '1', + `attachmenttype` int(11) DEFAULT '2', + `lft` int(11) DEFAULT NULL, + `rgt` int(11) DEFAULT NULL, + `is_public` tinyint(4) DEFAULT '1', + `inherit_members` tinyint(4) DEFAULT '1', + `open_student` int(11) DEFAULT '0', + `outline` int(11) DEFAULT '0', + `publish_resource` int(11) DEFAULT '0', + `is_delete` int(11) DEFAULT '0', + `end_time` int(11) DEFAULT NULL, + `end_term` varchar(255) DEFAULT NULL, + `is_excellent` int(11) DEFAULT '0', + `excellent_option` int(11) DEFAULT '0', + `is_copy` int(11) DEFAULT '0', + `visits` int(11) DEFAULT '0', + `syllabus_id` int(11) DEFAULT NULL, + `invite_code` varchar(255) DEFAULT NULL, + `qrcode` varchar(255) DEFAULT NULL, + `qrcode_expiretime` int(11) DEFAULT '0', + `invite_code_halt` tinyint(4) DEFAULT '0', + `os_allow` int(11) DEFAULT '0', + `credit` float DEFAULT NULL, + `is_end` tinyint(1) DEFAULT '0', + `end_date` date DEFAULT NULL, + `choose_group_allow` tinyint(1) DEFAULT '0', + `homepage_show` tinyint(1) DEFAULT '0', + `course_list_id` int(11) DEFAULT NULL, + `members_count` int(11) DEFAULT '0', + `homework_commons_count` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `index_courses_on_invite_code` (`invite_code`), + KEY `index_courses_on_syllabus_id` (`syllabus_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1439 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `custom_fields`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `custom_fields` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `type` varchar(30) NOT NULL DEFAULT '', + `name` varchar(30) NOT NULL DEFAULT '', + `field_format` varchar(30) NOT NULL DEFAULT '', + `possible_values` text, + `regexp` varchar(255) DEFAULT '', + `min_length` int(11) NOT NULL DEFAULT '0', + `max_length` int(11) NOT NULL DEFAULT '0', + `is_required` tinyint(1) NOT NULL DEFAULT '0', + `is_for_all` tinyint(1) NOT NULL DEFAULT '0', + `is_filter` tinyint(1) NOT NULL DEFAULT '0', + `position` int(11) DEFAULT '1', + `searchable` tinyint(1) DEFAULT '0', + `default_value` text, + `editable` tinyint(1) DEFAULT '1', + `visible` tinyint(1) NOT NULL DEFAULT '1', + `multiple` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_custom_fields_on_id_and_type` (`id`,`type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `custom_fields_projects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `custom_fields_projects` ( + `custom_field_id` int(11) NOT NULL DEFAULT '0', + `project_id` int(11) NOT NULL DEFAULT '0', + UNIQUE KEY `index_custom_fields_projects_on_custom_field_id_and_project_id` (`custom_field_id`,`project_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `custom_fields_trackers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `custom_fields_trackers` ( + `custom_field_id` int(11) NOT NULL DEFAULT '0', + `tracker_id` int(11) NOT NULL DEFAULT '0', + UNIQUE KEY `index_custom_fields_trackers_on_custom_field_id_and_tracker_id` (`custom_field_id`,`tracker_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `custom_values`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `custom_values` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `customized_type` varchar(30) NOT NULL DEFAULT '', + `customized_id` int(11) NOT NULL DEFAULT '0', + `custom_field_id` int(11) NOT NULL DEFAULT '0', + `value` text, + PRIMARY KEY (`id`), + KEY `custom_values_customized` (`customized_type`,`customized_id`), + KEY `index_custom_values_on_custom_field_id` (`custom_field_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `data_exceptions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `data_exceptions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `message` varchar(255) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `delayed_jobs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `delayed_jobs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `priority` int(11) NOT NULL DEFAULT '0', + `attempts` int(11) NOT NULL DEFAULT '0', + `handler` text NOT NULL, + `last_error` text, + `run_at` datetime DEFAULT NULL, + `locked_at` datetime DEFAULT NULL, + `failed_at` datetime DEFAULT NULL, + `locked_by` varchar(255) DEFAULT NULL, + `queue` varchar(255) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `delayed_jobs_priority` (`priority`,`run_at`) +) ENGINE=InnoDB AUTO_INCREMENT=13817 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `delayed_jobs_20161218`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `delayed_jobs_20161218` ( + `id` int(11) NOT NULL DEFAULT '0', + `priority` int(11) NOT NULL DEFAULT '0', + `attempts` int(11) NOT NULL DEFAULT '0', + `handler` text NOT NULL, + `last_error` text, + `run_at` datetime DEFAULT NULL, + `locked_at` datetime DEFAULT NULL, + `failed_at` datetime DEFAULT NULL, + `locked_by` varchar(255) DEFAULT NULL, + `queue` varchar(255) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `department_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `department_members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `department_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_department_members_on_department_id` (`department_id`), + KEY `index_department_members_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `departments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `departments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `school_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `is_auth` tinyint(1) DEFAULT '0', + `identifier` varchar(255) DEFAULT NULL, + `host_count` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_departments_on_school_id` (`school_id`) +) ENGINE=InnoDB AUTO_INCREMENT=776 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `discipline_categories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `discipline_categories` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `major_level` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `discuss_demos`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `discuss_demos` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(255) DEFAULT NULL, + `body` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `discusses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `discusses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `dis_type` varchar(255) DEFAULT NULL, + `dis_id` int(11) DEFAULT NULL, + `content` text, + `parent_id` int(11) DEFAULT NULL, + `root_id` int(11) DEFAULT NULL, + `praise_count` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `challenge_id` int(11) DEFAULT NULL, + `reward` int(11) DEFAULT NULL, + `hidden` tinyint(1) DEFAULT '0', + `last_reply_id` int(11) DEFAULT NULL, + `position` tinyint(4) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_discusses_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1820 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `documents`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `documents` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) NOT NULL DEFAULT '0', + `category_id` int(11) NOT NULL DEFAULT '0', + `title` varchar(60) NOT NULL DEFAULT '', + `description` text, + `created_on` datetime DEFAULT NULL, + `user_id` int(11) DEFAULT '0', + `is_public` int(11) DEFAULT '1', + PRIMARY KEY (`id`), + KEY `documents_project_id` (`project_id`), + KEY `index_documents_on_category_id` (`category_id`), + KEY `index_documents_on_created_on` (`created_on`) +) ENGINE=InnoDB AUTO_INCREMENT=222 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `dts`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `dts` ( + `Num` int(11) NOT NULL DEFAULT '0', + `Defect` varchar(50) DEFAULT NULL, + `Category` varchar(50) DEFAULT NULL, + `File` varchar(255) DEFAULT NULL, + `Method` varchar(255) DEFAULT NULL, + `Module` varchar(20) DEFAULT NULL, + `Variable` varchar(50) DEFAULT NULL, + `StartLine` int(11) DEFAULT NULL, + `IPLine` int(11) DEFAULT NULL, + `IPLineCode` varchar(200) DEFAULT NULL, + `Judge` varchar(15) DEFAULT NULL, + `Review` tinyint(4) DEFAULT NULL, + `Description` varchar(255) DEFAULT NULL, + `PreConditions` longtext, + `TraceInfo` longtext, + `Code` longtext, + `project_id` int(11) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL, + `id` int(11) NOT NULL, + PRIMARY KEY (`Num`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `editor_of_documents`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `editor_of_documents` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `editor_id` int(11) DEFAULT NULL, + `org_document_comment_id` int(11) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1663 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `enabled_modules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `enabled_modules` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `name` varchar(255) NOT NULL, + `course_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `enabled_modules_project_id` (`project_id`) +) ENGINE=InnoDB AUTO_INCREMENT=38150 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `enumerations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `enumerations` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(30) NOT NULL DEFAULT '', + `position` int(11) DEFAULT '1', + `is_default` tinyint(1) NOT NULL DEFAULT '0', + `type` varchar(255) DEFAULT NULL, + `active` tinyint(1) NOT NULL DEFAULT '1', + `project_id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + `position_name` varchar(30) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_enumerations_on_project_id` (`project_id`), + KEY `index_enumerations_on_id_and_type` (`id`,`type`) +) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `error_checks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `error_checks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `game_indentifier` varchar(255) DEFAULT NULL, + `login` varchar(255) DEFAULT NULL, + `path` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=864 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `evaluate_records`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `evaluate_records` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `shixun_id` int(11) DEFAULT NULL, + `game_id` int(11) DEFAULT NULL, + `consume_time` float DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `file_update` float DEFAULT NULL, + `git_pull` float DEFAULT NULL, + `create_pod` float DEFAULT NULL, + `pod_execute` float DEFAULT NULL, + `student_work` float DEFAULT NULL, + `test_cases` float DEFAULT NULL, + `retry` float DEFAULT NULL, + `game_build` float DEFAULT NULL, + `return_back` float DEFAULT NULL, + `brige` float DEFAULT NULL, + `create_status` datetime DEFAULT NULL, + `front_js` float DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `game` (`game_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1078311 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_answers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_answers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `exercise_question_id` int(11) DEFAULT NULL, + `exercise_choice_id` int(11) DEFAULT NULL, + `answer_text` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `score` int(11) DEFAULT '-1', + PRIMARY KEY (`id`), + KEY `eq` (`exercise_question_id`), + KEY `index_exercise_answers_on_exercise_choice_id` (`exercise_choice_id`) +) ENGINE=InnoDB AUTO_INCREMENT=393183 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_bank_choices`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_bank_choices` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `exercise_bank_question_id` int(11) DEFAULT NULL, + `choice_text` text, + `choice_position` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_exercise_bank_choices_on_exercise_bank_question_id` (`exercise_bank_question_id`) +) ENGINE=InnoDB AUTO_INCREMENT=9343 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_bank_questions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_bank_questions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `question_title` text, + `question_type` int(11) DEFAULT NULL, + `question_number` int(11) DEFAULT NULL, + `question_score` int(11) DEFAULT NULL, + `exercise_bank_id` int(11) DEFAULT NULL, + `max_choices` int(11) DEFAULT NULL, + `min_choices` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `shixun_id` int(11) DEFAULT NULL, + `is_necessary` int(11) DEFAULT '1', + PRIMARY KEY (`id`), + KEY `index_exercise_bank_questions_on_exercise_bank_id` (`exercise_bank_id`) +) ENGINE=InnoDB AUTO_INCREMENT=3007 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_bank_shixun_challenges`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_bank_shixun_challenges` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `challenge_id` int(11) DEFAULT NULL, + `shixun_id` int(11) DEFAULT NULL, + `exercise_bank_question_id` int(11) DEFAULT NULL, + `question_score` int(11) DEFAULT NULL, + `position` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_exercise_bank_shixun_challenges_on_challenge_id` (`challenge_id`), + KEY `index_exercise_bank_shixun_challenges_on_shixun_id` (`shixun_id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_bank_standard_answers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_bank_standard_answers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `exercise_bank_question_id` int(11) DEFAULT NULL, + `exercise_bank_choice_id` int(11) DEFAULT NULL, + `answer_text` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2330 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_banks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_banks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` text, + `user_id` int(11) DEFAULT NULL, + `is_public` tinyint(1) DEFAULT NULL, + `quotes` int(11) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `course_list_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_exercise_banks_on_user_id` (`user_id`), + KEY `index_exercise_banks_on_course_list_id` (`course_list_id`) +) ENGINE=InnoDB AUTO_INCREMENT=403 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_choices`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_choices` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `exercise_question_id` int(11) DEFAULT NULL, + `choice_text` text, + `choice_position` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_exercise_choices_on_exercise_question_id` (`exercise_question_id`) +) ENGINE=InnoDB AUTO_INCREMENT=23255 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_group_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_group_settings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `exercise_id` int(11) DEFAULT NULL, + `course_group_id` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `publish_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_exercise_group_settings_on_exercise_id` (`exercise_id`), + KEY `index_exercise_group_settings_on_course_group_id` (`course_group_id`), + KEY `index_exercise_group_settings_on_course_id` (`course_id`) +) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_questions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_questions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `question_title` text, + `question_type` int(11) DEFAULT NULL, + `question_number` int(11) DEFAULT NULL, + `exercise_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `question_score` int(11) DEFAULT NULL, + `shixun_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_exercise_questions_on_exercise_id` (`exercise_id`) +) ENGINE=InnoDB AUTO_INCREMENT=7396 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_shixun_answers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_shixun_answers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `exercise_question_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `exercise_shixun_challenge_id` int(11) DEFAULT NULL, + `answer_text` text, + `score` int(11) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_exercise_shixun_answers_on_exercise_question_id` (`exercise_question_id`), + KEY `index_exercise_shixun_answers_on_user_id` (`user_id`), + KEY `index_exercise_shixun_answers_on_exercise_shixun_challenge_id` (`exercise_shixun_challenge_id`) +) ENGINE=InnoDB AUTO_INCREMENT=663 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_shixun_challenges`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_shixun_challenges` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `challenge_id` int(11) DEFAULT NULL, + `shixun_id` int(11) DEFAULT NULL, + `exercise_question_id` int(11) DEFAULT NULL, + `question_score` int(11) DEFAULT NULL, + `position` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_exercise_shixun_challenges_on_challenge_id` (`challenge_id`), + KEY `index_exercise_shixun_challenges_on_shixun_id` (`shixun_id`), + KEY `index_exercise_shixun_challenges_on_exercise_question_id` (`exercise_question_id`) +) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_standard_answers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_standard_answers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `exercise_question_id` int(11) DEFAULT NULL, + `exercise_choice_id` int(11) DEFAULT NULL, + `answer_text` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_exercise_standard_answers_on_exercise_question_id` (`exercise_question_id`) +) ENGINE=InnoDB AUTO_INCREMENT=8350 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercise_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercise_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `exercise_id` int(11) DEFAULT NULL, + `score` int(11) DEFAULT NULL, + `start_at` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `end_at` datetime DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `commit_status` int(11) DEFAULT '0', + `objective_score` int(11) DEFAULT '-1', + `subjective_score` int(11) DEFAULT '-1', + PRIMARY KEY (`id`), + KEY `index_exercise_users_on_exercise_id` (`exercise_id`) +) ENGINE=InnoDB AUTO_INCREMENT=81502 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `exercises`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `exercises` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `exercise_name` text, + `exercise_description` text, + `course_id` int(11) DEFAULT NULL, + `exercise_status` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `time` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `publish_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `show_result` int(11) DEFAULT NULL, + `question_random` int(11) DEFAULT '0', + `choice_random` int(11) DEFAULT '0', + `is_public` tinyint(1) DEFAULT '0', + `score_open` tinyint(1) DEFAULT '1', + `answer_open` tinyint(1) DEFAULT '1', + `exercise_bank_id` int(11) DEFAULT NULL, + `unified_setting` tinyint(1) DEFAULT '1', + `show_statistic` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=764 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `experiences`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `experiences` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `score` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `exper` (`container_id`,`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=217105 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `first_level_disciplines`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `first_level_disciplines` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `discipline_category_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_first_level_disciplines_on_discipline_category_id` (`discipline_category_id`) +) ENGINE=InnoDB AUTO_INCREMENT=312 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `first_pages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `first_pages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `web_title` varchar(255) DEFAULT NULL, + `title` varchar(255) DEFAULT NULL, + `description` text, + `page_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `sort_type` int(11) DEFAULT NULL, + `image_width` int(11) DEFAULT '107', + `image_height` int(11) DEFAULT '63', + `show_course` int(11) DEFAULT '1', + `show_contest` int(11) DEFAULT '1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `forge_activities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `forge_activities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `forge_act_id` int(11) DEFAULT NULL, + `forge_act_type` varchar(255) DEFAULT NULL, + `org_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_forge_activities_on_forge_act_id` (`forge_act_id`), + KEY `forge_act_index` (`project_id`,`forge_act_id`,`created_at`,`forge_act_type`) +) ENGINE=InnoDB AUTO_INCREMENT=29856 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `forge_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `forge_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `forge_message_id` int(11) DEFAULT NULL, + `forge_message_type` varchar(255) DEFAULT NULL, + `viewed` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `secret_key` varchar(255) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `operate_user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_forge_messages_on_user_id_and_project_id_and_created_at` (`user_id`,`project_id`,`created_at`), + KEY `index_forge_messages_on_forge_message_id_and_forge_message_type` (`forge_message_id`,`forge_message_type`) +) ENGINE=InnoDB AUTO_INCREMENT=27628 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `forums`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `forums` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `description` text, + `topic_count` int(11) DEFAULT '0', + `memo_count` int(11) DEFAULT '0', + `last_memo_id` int(11) DEFAULT '0', + `creator_id` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `sticky` int(11) DEFAULT NULL, + `locked` int(11) DEFAULT NULL, + `visits` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `forwards`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `forwards` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `from_id` int(11) DEFAULT NULL, + `from_type` varchar(255) DEFAULT NULL, + `to_id` int(11) DEFAULT NULL, + `to_type` varchar(255) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=603 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `game_codes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `game_codes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `game_id` int(11) DEFAULT NULL, + `original_code` longtext, + `new_code` longtext, + `path` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `current_code` longtext, + PRIMARY KEY (`id`), + KEY `game_id` (`game_id`) +) ENGINE=InnoDB AUTO_INCREMENT=284340 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `game_outputs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `game_outputs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `code` int(11) DEFAULT NULL, + `game_id` int(11) DEFAULT NULL, + `msg` text, + `out_put` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `games`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `games` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `myshixun_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `status` int(11) DEFAULT '0', + `final_score` int(11) DEFAULT '0', + `challenge_id` int(11) DEFAULT NULL, + `open_time` datetime DEFAULT NULL, + `identifier` varchar(255) DEFAULT NULL, + `answer_open` tinyint(1) DEFAULT '0', + `end_time` datetime DEFAULT NULL, + `retry_status` int(11) DEFAULT '0', + `resubmit_identifier` varchar(255) DEFAULT NULL, + `test_sets_view` tinyint(1) DEFAULT '0', + `picture_path` text, + `accuracy` float DEFAULT NULL, + `modify_time` datetime DEFAULT NULL, + `star` int(11) DEFAULT '0', + `cost_time` int(11) DEFAULT '0', + `evaluate_count` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `user` (`user_id`), + KEY `challenge` (`challenge_id`), + KEY `myshixun` (`myshixun_id`), + KEY `index_games_on_identifier` (`identifier`) +) ENGINE=InnoDB AUTO_INCREMENT=292926 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `gitlab_urls`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `gitlab_urls` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `myshixun_id` int(11) DEFAULT NULL, + `url` varchar(255) DEFAULT NULL, + `myshixun_identifier` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=16162 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `grades`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `grades` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `score` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `container` (`user_id`,`container_id`) +) ENGINE=InnoDB AUTO_INCREMENT=332272 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `groups_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `groups_users` ( + `group_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + UNIQUE KEY `groups_users_ids` (`group_id`,`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `helps`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `helps` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `about_us` text, + `agreement` text, + `status` text, + `help_center` text, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homepages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homepages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `article_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_homepages_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=23796 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_attaches`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_attaches` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `bid_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `reward` varchar(255) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `description` text, + `state` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT '0', + `score` float DEFAULT '0', + `is_teacher_score` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_homework_attaches_on_bid_id` (`bid_id`) +) ENGINE=InnoDB AUTO_INCREMENT=24754 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_bank_samples`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_bank_samples` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `input` text, + `output` text, + `homework_bank_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_homework_bank_samples_on_homework_bank_id` (`homework_bank_id`) +) ENGINE=InnoDB AUTO_INCREMENT=197 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_bank_shixuns`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_bank_shixuns` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `homework_bank_id` int(11) DEFAULT NULL, + `shixun_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_homework_bank_shixuns_on_homework_bank_id` (`homework_bank_id`), + KEY `index_homework_bank_shixuns_on_shixun_id` (`shixun_id`) +) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_bank_tests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_bank_tests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `input` text, + `output` text, + `test_type` tinyint(1) DEFAULT NULL, + `homework_bank_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=40569 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_banks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_banks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `description` text, + `homework_type` int(11) DEFAULT NULL, + `quotes` int(11) DEFAULT '0', + `is_public` tinyint(1) DEFAULT NULL, + `language` varchar(255) DEFAULT NULL, + `standard_code` longtext, + `min_num` int(11) DEFAULT NULL, + `max_num` int(11) DEFAULT NULL, + `base_on_project` tinyint(1) DEFAULT NULL, + `applicable_syllabus` varchar(255) DEFAULT NULL, + `homework_common_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `reference_answer` text, + `syllabus_id` int(11) DEFAULT NULL, + `major_level` text, + `discipline_category_id` text, + `first_level_discipline_id` text, + `course_list_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4233 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_challenge_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_challenge_settings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `homework_common_id` int(11) DEFAULT NULL, + `challenge_id` int(11) DEFAULT NULL, + `shixun_id` int(11) DEFAULT NULL, + `score` float DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_homework_challenge_settings_on_homework_common_id` (`homework_common_id`), + KEY `index_homework_challenge_settings_on_challenge_id` (`challenge_id`), + KEY `index_homework_challenge_settings_on_shixun_id` (`shixun_id`) +) ENGINE=InnoDB AUTO_INCREMENT=5414 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_commons`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_commons` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `description` text, + `publish_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `homework_type` int(11) DEFAULT '1', + `late_penalty` varchar(255) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `teacher_priority` int(11) DEFAULT '1', + `anonymous_comment` int(11) DEFAULT '0', + `quotes` int(11) DEFAULT '0', + `is_open` int(11) DEFAULT '0', + `simi_time` datetime DEFAULT NULL, + `score_open` int(11) DEFAULT '1', + `anonymous_appeal` int(11) DEFAULT '0', + `homework_bank_id` int(11) DEFAULT NULL, + `is_update` tinyint(1) DEFAULT '0', + `is_public` tinyint(1) DEFAULT '0', + `reference_answer` text, + `answer_public` tinyint(1) DEFAULT '1', + `archive_time` datetime DEFAULT NULL, + `allow_late` tinyint(1) DEFAULT '1', + `late_time` datetime DEFAULT NULL, + `work_public` tinyint(1) DEFAULT '1', + `explanation` text, + `unified_setting` tinyint(1) DEFAULT '1', + PRIMARY KEY (`id`), + KEY `index_homework_commons_on_course_id_and_id` (`course_id`,`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7704 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_commons_shixuns`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_commons_shixuns` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `homework_common_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1589 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_detail_groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_detail_groups` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `homework_common_id` int(11) DEFAULT NULL, + `min_num` int(11) DEFAULT NULL, + `max_num` int(11) DEFAULT NULL, + `base_on_project` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_homework_detail_groups_on_homework_common_id` (`homework_common_id`) +) ENGINE=InnoDB AUTO_INCREMENT=321 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_detail_manuals`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_detail_manuals` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ta_proportion` float DEFAULT NULL, + `comment_status` int(11) DEFAULT NULL, + `evaluation_start` datetime DEFAULT NULL, + `evaluation_end` datetime DEFAULT NULL, + `evaluation_num` int(11) DEFAULT NULL, + `absence_penalty` int(11) DEFAULT '1', + `homework_common_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `no_anon_penalty` int(11) DEFAULT '1', + `appeal_penalty` int(11) DEFAULT '0', + `ta_mode` int(11) DEFAULT '1', + `appeal_time` datetime DEFAULT NULL, + `te_proportion` float DEFAULT '1', + `final_mode` tinyint(1) DEFAULT '0', + `answer_open_evaluation` tinyint(1) DEFAULT '0', + `shixun_evaluation` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7700 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_detail_programings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_detail_programings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `language` varchar(255) DEFAULT NULL, + `standard_code` longtext, + `homework_common_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `ta_proportion` float DEFAULT '0.1', + `question_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2766 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_evaluations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_evaluations` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(255) DEFAULT NULL, + `homework_attach_id` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=17792 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_for_courses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_for_courses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `course_id` int(11) DEFAULT NULL, + `bid_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_homework_for_courses_on_course_id` (`course_id`), + KEY `index_homework_for_courses_on_bid_id` (`bid_id`) +) ENGINE=InnoDB AUTO_INCREMENT=737 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_group_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_group_settings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `homework_common_id` int(11) DEFAULT NULL, + `course_group_id` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `publish_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_homework_group_settings_on_homework_common_id` (`homework_common_id`), + KEY `index_homework_group_settings_on_course_group_id` (`course_group_id`), + KEY `index_homework_group_settings_on_course_id` (`course_id`) +) ENGINE=InnoDB AUTO_INCREMENT=252 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_reference_answers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_reference_answers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `answer` text, + `homework_common_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_homework_reference_answers_on_homework_common_id` (`homework_common_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_samples`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_samples` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `input` text, + `output` text, + `homework_common_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_homework_samples_on_homework_common_id` (`homework_common_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1212 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_tests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_tests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `input` text, + `output` text, + `homework_common_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `result` int(11) DEFAULT NULL, + `error_msg` text, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=51640 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `homework_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `homework_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `homework_attach_id` varchar(255) DEFAULT NULL, + `user_id` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `import_course_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `import_course_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_student_id` varchar(255) DEFAULT NULL, + `user_name` varchar(255) DEFAULT NULL, + `user_group_name` varchar(255) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `school_id` int(11) DEFAULT NULL, + `status` tinyint(1) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_import_course_users_on_course_id` (`course_id`), + KEY `index_import_course_users_on_school_id` (`school_id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `import_students`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `import_students` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `student_number` varchar(255) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `school_id` int(11) DEFAULT NULL, + `status` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `informs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `informs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `container_type` varchar(255) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `innodb_monitor`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `innodb_monitor` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `invite_lists`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `invite_lists` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `mail` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=141 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `issue_categories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `issue_categories` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) NOT NULL DEFAULT '0', + `name` varchar(30) NOT NULL DEFAULT '', + `assigned_to_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `issue_categories_project_id` (`project_id`), + KEY `index_issue_categories_on_assigned_to_id` (`assigned_to_id`) +) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `issue_relations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `issue_relations` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `issue_from_id` int(11) NOT NULL, + `issue_to_id` int(11) NOT NULL, + `relation_type` varchar(255) NOT NULL DEFAULT '', + `delay` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `index_issue_relations_on_issue_from_id_and_issue_to_id` (`issue_from_id`,`issue_to_id`), + KEY `index_issue_relations_on_issue_from_id` (`issue_from_id`), + KEY `index_issue_relations_on_issue_to_id` (`issue_to_id`) +) ENGINE=InnoDB AUTO_INCREMENT=48 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `issue_statuses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `issue_statuses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(30) NOT NULL DEFAULT '', + `is_closed` tinyint(1) NOT NULL DEFAULT '0', + `is_default` tinyint(1) NOT NULL DEFAULT '0', + `position` int(11) DEFAULT '1', + `default_done_ratio` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_issue_statuses_on_position` (`position`), + KEY `index_issue_statuses_on_is_closed` (`is_closed`), + KEY `index_issue_statuses_on_is_default` (`is_default`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `issues`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `issues` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `tracker_id` int(11) NOT NULL, + `project_id` int(11) NOT NULL, + `subject` varchar(255) NOT NULL DEFAULT '', + `description` text, + `due_date` date DEFAULT NULL, + `category_id` int(11) DEFAULT NULL, + `status_id` int(11) NOT NULL, + `assigned_to_id` int(11) DEFAULT NULL, + `priority_id` int(11) NOT NULL, + `fixed_version_id` int(11) DEFAULT NULL, + `author_id` int(11) NOT NULL, + `lock_version` int(11) NOT NULL DEFAULT '0', + `created_on` datetime DEFAULT NULL, + `updated_on` datetime DEFAULT NULL, + `start_date` date DEFAULT NULL, + `done_ratio` int(11) NOT NULL DEFAULT '0', + `estimated_hours` float DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + `root_id` int(11) DEFAULT NULL, + `lft` int(11) DEFAULT NULL, + `rgt` int(11) DEFAULT NULL, + `is_private` tinyint(1) NOT NULL DEFAULT '0', + `closed_on` datetime DEFAULT NULL, + `project_issues_index` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `issues_project_id` (`project_id`), + KEY `index_issues_on_status_id` (`status_id`), + KEY `index_issues_on_category_id` (`category_id`), + KEY `index_issues_on_assigned_to_id` (`assigned_to_id`), + KEY `index_issues_on_fixed_version_id` (`fixed_version_id`), + KEY `index_issues_on_tracker_id` (`tracker_id`), + KEY `index_issues_on_priority_id` (`priority_id`), + KEY `index_issues_on_author_id` (`author_id`), + KEY `index_issues_on_created_on` (`created_on`), + KEY `index_issues_on_root_id_and_lft_and_rgt` (`root_id`,`lft`,`rgt`) +) ENGINE=InnoDB AUTO_INCREMENT=11837 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `join_in_competitions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `join_in_competitions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `competition_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `join_in_contests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `join_in_contests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `bid_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `journal_details`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `journal_details` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `journal_id` int(11) NOT NULL DEFAULT '0', + `property` varchar(30) NOT NULL DEFAULT '', + `prop_key` varchar(30) NOT NULL DEFAULT '', + `old_value` text, + `value` text, + PRIMARY KEY (`id`), + KEY `journal_details_journal_id` (`journal_id`) +) ENGINE=InnoDB AUTO_INCREMENT=24527 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `journal_replies`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `journal_replies` ( + `journal_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `reply_id` int(11) DEFAULT NULL, + KEY `index_journal_replies_on_user_id` (`user_id`), + KEY `index_journal_replies_on_journal_id` (`journal_id`), + KEY `index_journal_replies_on_reply_id` (`reply_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `journals`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `journals` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `journalized_id` int(11) NOT NULL DEFAULT '0', + `journalized_type` varchar(30) NOT NULL DEFAULT '', + `user_id` int(11) NOT NULL DEFAULT '0', + `notes` text, + `created_on` datetime NOT NULL, + `private_notes` tinyint(1) NOT NULL DEFAULT '0', + `parent_id` int(11) DEFAULT NULL, + `comments_count` int(11) DEFAULT '0', + `reply_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `journals_journalized_id` (`journalized_id`,`journalized_type`), + KEY `index_journals_on_user_id` (`user_id`), + KEY `index_journals_on_journalized_id` (`journalized_id`), + KEY `index_journals_on_created_on` (`created_on`) +) ENGINE=InnoDB AUTO_INCREMENT=19600 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `journals_for_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `journals_for_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `jour_id` int(11) DEFAULT NULL, + `jour_type` varchar(255) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `notes` text, + `status` int(11) DEFAULT NULL, + `reply_id` int(11) DEFAULT NULL, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + `m_parent_id` varchar(255) DEFAULT NULL, + `is_readed` tinyint(1) DEFAULT NULL, + `m_reply_count` int(11) DEFAULT NULL, + `m_reply_id` int(11) DEFAULT NULL, + `is_comprehensive_evaluation` int(11) DEFAULT NULL, + `private` int(11) DEFAULT '0', + `root_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_journals_for_messages_on_root_id` (`root_id`) +) ENGINE=InnoDB AUTO_INCREMENT=80534 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `kindeditor_assets`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `kindeditor_assets` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `asset` varchar(255) DEFAULT NULL, + `file_size` int(11) DEFAULT NULL, + `file_type` varchar(255) DEFAULT NULL, + `owner_id` int(11) DEFAULT NULL, + `asset_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `owner_type` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=24663 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `major_courses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `major_courses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `course_list_id` int(11) DEFAULT NULL, + `major_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_major_courses_on_course_list_id` (`course_list_id`), + KEY `index_major_courses_on_major_id` (`major_id`) +) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `majors`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `majors` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `major_code` varchar(255) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `first_level_discipline_id` int(11) DEFAULT NULL, + `discipline_category_id` int(11) DEFAULT NULL, + `major_level` int(11) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL, + `support_shixuns` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_majors_on_first_level_discipline_id` (`first_level_discipline_id`), + KEY `index_majors_on_discipline_category_id` (`discipline_category_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1660 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `mark_downs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mark_downs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `description` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `member_roles`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `member_roles` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `member_id` int(11) NOT NULL, + `role_id` int(11) NOT NULL, + `inherited_from` int(11) DEFAULT NULL, + `is_current` int(11) DEFAULT '1', + PRIMARY KEY (`id`), + KEY `index_member_roles_on_member_id` (`member_id`), + KEY `index_member_roles_on_role_id` (`role_id`) +) ENGINE=InnoDB AUTO_INCREMENT=66130 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL DEFAULT '0', + `project_id` int(11) DEFAULT '0', + `created_on` datetime DEFAULT NULL, + `mail_notification` tinyint(1) NOT NULL DEFAULT '0', + `course_id` int(11) DEFAULT '-1', + `course_group_id` int(11) DEFAULT '0', + `is_collect` int(11) DEFAULT '1', + PRIMARY KEY (`id`), + UNIQUE KEY `index_members_on_user_id_and_project_id` (`user_id`,`project_id`,`course_id`), + KEY `index_members_on_user_id` (`user_id`), + KEY `index_members_on_project_id` (`project_id`), + KEY `index_members_on_course_id` (`course_id`) +) ENGINE=InnoDB AUTO_INCREMENT=64562 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `memo_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `memo_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `forum_id` int(11) DEFAULT NULL, + `memo_id` int(11) DEFAULT NULL, + `memo_type` varchar(255) DEFAULT NULL, + `viewed` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_memo_messages_on_user_id_and_forum_id_and_created_at` (`user_id`,`forum_id`,`created_at`), + KEY `index_memo_messages_on_memo_id_and_memo_type` (`memo_id`,`memo_type`) +) ENGINE=InnoDB AUTO_INCREMENT=3891 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `memo_tag_repertoires`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `memo_tag_repertoires` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `memo_id` int(11) DEFAULT NULL, + `tag_repertoire_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_memo_tag_repertoires_on_memo_id` (`memo_id`), + KEY `index_memo_tag_repertoires_on_tag_repertoire_id` (`tag_repertoire_id`) +) ENGINE=InnoDB AUTO_INCREMENT=184 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `memos`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `memos` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `forum_id` int(11) NOT NULL, + `parent_id` int(11) DEFAULT NULL, + `subject` varchar(255) NOT NULL, + `content` longtext NOT NULL, + `author_id` int(11) NOT NULL, + `replies_count` int(11) DEFAULT '0', + `last_reply_id` int(11) DEFAULT NULL, + `lock` tinyint(1) DEFAULT '0', + `sticky` tinyint(1) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `viewed_count` int(11) DEFAULT '0', + `root_id` int(11) DEFAULT NULL, + `reward` int(11) DEFAULT NULL, + `language` varchar(255) DEFAULT NULL, + `hidden` tinyint(4) DEFAULT '0', + `repertoire_name` varchar(255) DEFAULT NULL, + `is_md` tinyint(1) DEFAULT '1', + `all_replies_count` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_memos_on_root_id` (`root_id`) +) ENGINE=InnoDB AUTO_INCREMENT=3377 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `message_alls`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `message_alls` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `message_id` int(11) DEFAULT NULL, + `message_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_message_alls_on_user_id_and_message_id_and_created_at` (`user_id`,`message_id`,`created_at`), + KEY `index_message_alls_on_message_type` (`message_type`) +) ENGINE=InnoDB AUTO_INCREMENT=974095 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `board_id` int(11) NOT NULL, + `parent_id` int(11) DEFAULT NULL, + `subject` varchar(255) NOT NULL DEFAULT '', + `content` longtext, + `author_id` int(11) DEFAULT NULL, + `replies_count` int(11) NOT NULL DEFAULT '0', + `last_reply_id` int(11) DEFAULT NULL, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + `locked` tinyint(1) DEFAULT '0', + `sticky` int(11) DEFAULT '0', + `reply_id` int(11) DEFAULT NULL, + `quotes` int(11) DEFAULT NULL, + `status` int(11) DEFAULT '0', + `root_id` int(11) DEFAULT NULL, + `visits` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `messages_board_id` (`board_id`), + KEY `messages_parent_id` (`parent_id`), + KEY `index_messages_on_last_reply_id` (`last_reply_id`), + KEY `index_messages_on_author_id` (`author_id`), + KEY `index_messages_on_created_on` (`created_on`), + KEY `index_messages_on_root_id` (`root_id`) +) ENGINE=InnoDB AUTO_INCREMENT=34681 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `mirror_migrate_errors`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mirror_migrate_errors` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `game_info` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `mirror_operation_records`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mirror_operation_records` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `mirror_repository_id` int(11) DEFAULT NULL, + `mirror_id` text, + `mirror_name` text, + `status` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `user_id` int(11) DEFAULT NULL, + `old_tag` varchar(255) DEFAULT NULL, + `new_tag` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=561 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `mirror_repositories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mirror_repositories` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `mirrorID` varchar(255) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `main_type` varchar(255) DEFAULT NULL, + `description` text, + `status` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `type_name` text, + `script_template` longtext, + `resource_limit` int(11) DEFAULT '10000', + `memory_limit` int(11) DEFAULT '1024', + `cpu_limit` tinyint(4) DEFAULT '1', + `time_limit` int(11) DEFAULT '120', + `should_compile` tinyint(1) DEFAULT NULL, + `repertoire_id` int(11) DEFAULT NULL, + `sub_repertoire_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `mirror_repository_types`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mirror_repository_types` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `mirror_type_id` int(11) DEFAULT NULL, + `mirror_repository_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_mirror_repository_types_on_mirror_type_id` (`mirror_type_id`), + KEY `index_mirror_repository_types_on_mirror_repository_id` (`mirror_repository_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `mirror_scripts`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mirror_scripts` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `mirror_repository_id` int(11) DEFAULT NULL, + `script` longtext, + `script_type` varchar(255) DEFAULT NULL, + `description` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `mirror_types`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mirror_types` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `mirror_update_records`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mirror_update_records` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `mirror_repository_id` int(11) DEFAULT NULL, + `oldName` varchar(255) DEFAULT NULL, + `newName` varchar(255) DEFAULT NULL, + `oldType` varchar(255) DEFAULT NULL, + `newType` varchar(255) DEFAULT NULL, + `oldTag` text, + `newTag` text, + `oldDescription` text, + `newDescription` text, + `oldStatus` int(11) DEFAULT NULL, + `newStatus` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_mirror_update_records_on_user_id` (`user_id`), + KEY `index_mirror_update_records_on_mirror_repository_id` (`mirror_repository_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `mul_tests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mul_tests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `action` varchar(255) DEFAULT NULL, + `time` int(11) DEFAULT NULL, + `status` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `language` varchar(255) DEFAULT NULL, + `num` int(11) DEFAULT NULL, + `indentifier` varchar(255) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `shixun_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `myshixun_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `myshixun_members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `myshixun_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `role` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1434 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `myshixuns`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `myshixuns` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `is_public` tinyint(1) DEFAULT '1', + `user_id` int(11) DEFAULT NULL, + `gpid` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `status` int(11) DEFAULT '0', + `identifier` varchar(255) DEFAULT NULL, + `commit_id` varchar(255) DEFAULT NULL, + `modify_time` datetime DEFAULT NULL, + `reset_time` datetime DEFAULT NULL, + `system_tip` tinyint(1) DEFAULT '0', + `git_url` varchar(255) DEFAULT NULL, + `onclick_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `index_myshixuns_on_user_id_and_shixun_id` (`user_id`,`shixun_id`), + KEY `index_myshixuns_on_identifier` (`identifier`), + KEY `index_myshixuns_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=86406 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `news`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `news` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `title` varchar(60) NOT NULL DEFAULT '', + `summary` varchar(255) DEFAULT '', + `description` text, + `author_id` int(11) NOT NULL DEFAULT '0', + `created_on` datetime DEFAULT NULL, + `comments_count` int(11) NOT NULL DEFAULT '0', + `course_id` int(11) DEFAULT NULL, + `sticky` int(11) DEFAULT '0', + `org_subfield_id` int(11) DEFAULT NULL, + `contest_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `news_project_id` (`project_id`), + KEY `index_news_on_author_id` (`author_id`), + KEY `index_news_on_created_on` (`created_on`) +) ENGINE=InnoDB AUTO_INCREMENT=2585 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `no_uses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `no_uses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `no_use_type` varchar(255) DEFAULT NULL, + `no_use_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `notificationcomments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `notificationcomments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `notificationcommented_type` varchar(255) DEFAULT NULL, + `notificationcommented_id` int(11) DEFAULT NULL, + `author_id` int(11) DEFAULT NULL, + `notificationcomments` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `onclick_times`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `onclick_times` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `onclick_time` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=28992 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `open_id_authentication_associations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `open_id_authentication_associations` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `issued` int(11) DEFAULT NULL, + `lifetime` int(11) DEFAULT NULL, + `handle` varchar(255) DEFAULT NULL, + `assoc_type` varchar(255) DEFAULT NULL, + `server_url` blob, + `secret` blob, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `open_id_authentication_nonces`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `open_id_authentication_nonces` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `timestamp` int(11) NOT NULL, + `server_url` varchar(255) DEFAULT NULL, + `salt` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `open_source_projects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `open_source_projects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` text, + `commit_count` int(11) DEFAULT '0', + `code_line` int(11) DEFAULT '0', + `users_count` int(11) DEFAULT '0', + `last_commit_time` date DEFAULT NULL, + `url` varchar(255) DEFAULT NULL, + `date_collected` date DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=488570 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `option_numbers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `option_numbers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `memo` int(11) DEFAULT NULL, + `messages_for_issues` int(11) DEFAULT NULL, + `issues_status` int(11) DEFAULT NULL, + `replay_for_message` int(11) DEFAULT NULL, + `replay_for_memo` int(11) DEFAULT NULL, + `follow` int(11) DEFAULT NULL, + `tread` int(11) DEFAULT NULL, + `praise_by_one` int(11) DEFAULT NULL, + `praise_by_two` int(11) DEFAULT NULL, + `praise_by_three` int(11) DEFAULT NULL, + `tread_by_one` int(11) DEFAULT NULL, + `tread_by_two` int(11) DEFAULT NULL, + `tread_by_three` int(11) DEFAULT NULL, + `changeset` int(11) DEFAULT NULL, + `document` int(11) DEFAULT NULL, + `attachment` int(11) DEFAULT NULL, + `issue_done_ratio` int(11) DEFAULT NULL, + `post_issue` int(11) DEFAULT NULL, + `score_type` int(11) DEFAULT NULL, + `total_score` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `project_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=22597 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `org_activities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `org_activities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `org_act_id` int(11) DEFAULT NULL, + `org_act_type` varchar(255) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=58588 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `org_courses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `org_courses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `organization_id` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=98 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `org_document_comments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `org_document_comments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` text, + `content` text, + `organization_id` int(11) DEFAULT NULL, + `creator_id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + `reply_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `locked` tinyint(1) DEFAULT '0', + `sticky` int(11) DEFAULT '0', + `org_subfield_id` int(11) DEFAULT NULL, + `status` int(11) DEFAULT '0', + `root_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_org_document_comments_on_root_id` (`root_id`) +) ENGINE=InnoDB AUTO_INCREMENT=6511 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `org_member_roles`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `org_member_roles` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `org_member_id` int(11) DEFAULT NULL, + `role_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=634 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `org_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `org_members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `organization_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=637 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `org_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `org_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `sender_id` int(11) DEFAULT NULL, + `organization_id` int(11) DEFAULT NULL, + `message_type` varchar(255) DEFAULT NULL, + `message_id` int(11) DEFAULT NULL, + `viewed` int(11) DEFAULT NULL, + `content` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `status` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=233 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `org_projects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `org_projects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `organization_id` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=138 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `org_subfield_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `org_subfield_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `org_subfield_id` int(11) DEFAULT NULL, + `message_id` int(11) DEFAULT NULL, + `message_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `org_subfields`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `org_subfields` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `organization_id` int(11) DEFAULT NULL, + `priority` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `field_type` varchar(255) DEFAULT NULL, + `hide` int(11) DEFAULT '0', + `status` int(11) DEFAULT '1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=717 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `organizations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `organizations` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` text, + `creator_id` int(11) DEFAULT NULL, + `home_id` int(11) DEFAULT NULL, + `is_public` tinyint(1) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `allow_guest_download` tinyint(1) DEFAULT '1', + `visits` int(11) DEFAULT '0', + `show_mode` int(11) DEFAULT '0', + `allow_teacher` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=150 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `phone_app_versions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `phone_app_versions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `version` varchar(255) DEFAULT NULL, + `description` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `platform_samples`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `platform_samples` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `samples_type` varchar(255) DEFAULT NULL, + `contents` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `poll_answers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `poll_answers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `poll_question_id` int(11) DEFAULT NULL, + `answer_text` text, + `answer_position` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3961 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `poll_group_settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `poll_group_settings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `poll_id` int(11) DEFAULT NULL, + `course_group_id` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `publish_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_poll_group_settings_on_poll_id` (`poll_id`), + KEY `index_poll_group_settings_on_course_group_id` (`course_group_id`), + KEY `index_poll_group_settings_on_course_id` (`course_id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `poll_questions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `poll_questions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `question_title` varchar(255) DEFAULT NULL, + `question_type` int(11) DEFAULT NULL, + `is_necessary` int(11) DEFAULT NULL, + `poll_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `question_number` int(11) DEFAULT NULL, + `max_choices` int(11) DEFAULT '0', + `min_choices` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1391 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `poll_users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `poll_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `poll_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `commit_status` int(11) DEFAULT '0', + `start_at` datetime DEFAULT NULL, + `end_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=35650 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `poll_votes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `poll_votes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `poll_question_id` int(11) DEFAULT NULL, + `poll_answer_id` int(11) DEFAULT NULL, + `vote_text` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=41374 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `polls`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `polls` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `polls_name` varchar(255) DEFAULT NULL, + `polls_type` varchar(255) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `polls_status` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `publish_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `polls_description` text, + `show_result` int(11) DEFAULT '1', + `exercise_bank_id` int(11) DEFAULT NULL, + `is_public` tinyint(1) DEFAULT '0', + `unified_setting` tinyint(1) DEFAULT '1', + PRIMARY KEY (`id`), + KEY `index_polls_on_course_id` (`course_id`) +) ENGINE=InnoDB AUTO_INCREMENT=492 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `praise_tread_caches`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `praise_tread_caches` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `object_id` int(11) NOT NULL, + `object_type` varchar(255) DEFAULT NULL, + `praise_num` int(11) DEFAULT NULL, + `tread_num` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=9870 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `praise_treads`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `praise_treads` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `praise_tread_object_id` int(11) DEFAULT NULL, + `praise_tread_object_type` varchar(255) DEFAULT NULL, + `praise_or_tread` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `praise_tread` (`praise_tread_object_id`,`praise_tread_object_type`) +) ENGINE=InnoDB AUTO_INCREMENT=31598 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `principal_activities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `principal_activities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `principal_id` int(11) DEFAULT NULL, + `principal_act_id` int(11) DEFAULT NULL, + `principal_act_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=69540 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `private_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `private_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `target_id` int(11) DEFAULT NULL, + `sender_id` int(11) DEFAULT NULL, + `receiver_id` int(11) DEFAULT NULL, + `content` text, + `send_time` datetime DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_private_messages_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=177 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `professional_levels`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `professional_levels` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `level` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `project_infos`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `project_infos` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4934 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `project_scores`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `project_scores` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` varchar(255) DEFAULT NULL, + `score` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `issue_num` int(11) DEFAULT '0', + `issue_journal_num` int(11) DEFAULT '0', + `news_num` int(11) DEFAULT '0', + `documents_num` int(11) DEFAULT '0', + `changeset_num` int(11) DEFAULT '0', + `board_message_num` int(11) DEFAULT '0', + `board_num` int(11) DEFAULT '0', + `attach_num` int(11) DEFAULT '0', + `commit_time` datetime DEFAULT NULL, + `pull_request_num` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3100 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `project_statuses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `project_statuses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `changesets_count` int(11) DEFAULT NULL, + `watchers_count` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `project_type` int(11) DEFAULT NULL, + `grade` float DEFAULT '0', + `course_ac_para` int(11) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_project_statuses_on_grade` (`grade`) +) ENGINE=InnoDB AUTO_INCREMENT=3141 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `projecting_softapplictions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `projecting_softapplictions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `softapplication_id` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `projects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `projects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL DEFAULT '', + `description` text, + `homepage` varchar(255) DEFAULT '', + `is_public` tinyint(1) NOT NULL DEFAULT '1', + `parent_id` int(11) DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `updated_on` datetime DEFAULT NULL, + `identifier` varchar(255) DEFAULT NULL, + `status` int(11) NOT NULL DEFAULT '1', + `lft` int(11) DEFAULT NULL, + `rgt` int(11) DEFAULT NULL, + `inherit_members` tinyint(1) NOT NULL DEFAULT '0', + `project_type` int(11) DEFAULT NULL, + `hidden_repo` tinyint(1) NOT NULL DEFAULT '0', + `attachmenttype` int(11) DEFAULT '1', + `user_id` int(11) DEFAULT NULL, + `dts_test` int(11) DEFAULT '0', + `enterprise_name` varchar(255) DEFAULT NULL, + `organization_id` int(11) DEFAULT NULL, + `project_new_type` int(11) DEFAULT NULL, + `gpid` int(11) DEFAULT NULL, + `forked_from_project_id` int(11) DEFAULT NULL, + `forked_count` int(11) DEFAULT NULL, + `publish_resource` int(11) DEFAULT '0', + `visits` int(11) DEFAULT '0', + `hot` int(11) DEFAULT '0', + `invite_code` varchar(255) DEFAULT NULL, + `qrcode` varchar(255) DEFAULT NULL, + `qrcode_expiretime` int(11) DEFAULT '0', + `script` text, + `training_status` tinyint(4) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_projects_on_lft` (`lft`), + KEY `index_projects_on_rgt` (`rgt`) +) ENGINE=InnoDB AUTO_INCREMENT=3215 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `projects_trackers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `projects_trackers` ( + `project_id` int(11) NOT NULL DEFAULT '0', + `tracker_id` int(11) NOT NULL DEFAULT '0', + UNIQUE KEY `projects_trackers_unique` (`project_id`,`tracker_id`), + KEY `projects_trackers_project_id` (`project_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `pull_requests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `pull_requests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `pull_request_id` int(11) DEFAULT NULL, + `gpid` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `status` int(11) DEFAULT '0', + `project_id` int(11) DEFAULT NULL, + `title` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=312 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `quality_analyses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `quality_analyses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `author_login` varchar(255) DEFAULT NULL, + `rep_identifier` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `sonar_version` int(11) DEFAULT '0', + `path` varchar(255) DEFAULT NULL, + `branch` varchar(255) DEFAULT NULL, + `language` varchar(255) DEFAULT NULL, + `sonar_name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=237 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `queries`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `queries` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `name` varchar(255) NOT NULL DEFAULT '', + `filters` text, + `user_id` int(11) NOT NULL DEFAULT '0', + `is_public` tinyint(1) NOT NULL DEFAULT '0', + `column_names` text, + `sort_criteria` text, + `group_by` varchar(255) DEFAULT NULL, + `type` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_queries_on_project_id` (`project_id`), + KEY `index_queries_on_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `question_banks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `question_banks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` text, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `quotes` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `is_public` tinyint(1) DEFAULT NULL, + `course_list_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2490 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `reference_materials`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `reference_materials` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `book` varchar(255) DEFAULT NULL, + `editor` varchar(255) DEFAULT NULL, + `press` varchar(255) DEFAULT NULL, + `syllabus_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_reference_materials_on_syllabus_id` (`syllabus_id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `relative_memo_to_open_source_projects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `relative_memo_to_open_source_projects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `osp_id` int(11) DEFAULT NULL, + `relative_memo_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=596992 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `relative_memos`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `relative_memos` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `osp_id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + `subject` varchar(255) NOT NULL, + `content` mediumtext NOT NULL, + `author_id` int(11) DEFAULT NULL, + `replies_count` int(11) DEFAULT '0', + `last_reply_id` int(11) DEFAULT NULL, + `lock` tinyint(1) DEFAULT '0', + `sticky` tinyint(1) DEFAULT '0', + `is_quote` tinyint(1) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `viewed_count_crawl` int(11) DEFAULT '0', + `viewed_count_local` int(11) DEFAULT '0', + `url` varchar(255) DEFAULT NULL, + `username` varchar(255) DEFAULT NULL, + `userhomeurl` varchar(255) DEFAULT NULL, + `date_collected` date DEFAULT NULL, + `topic_resource` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=451234 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `rep_statics`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rep_statics` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `commits_num` int(11) DEFAULT NULL, + `uname` varchar(255) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + `add` int(11) DEFAULT NULL, + `del` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `changeset` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1475 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `repertoires`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repertoires` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `repositories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `repositories` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) NOT NULL DEFAULT '0', + `url` varchar(255) NOT NULL DEFAULT '', + `login` varchar(60) DEFAULT '', + `password` varchar(255) DEFAULT '', + `root_url` varchar(255) DEFAULT '', + `type` varchar(255) DEFAULT NULL, + `path_encoding` varchar(64) DEFAULT NULL, + `log_encoding` varchar(64) DEFAULT NULL, + `extra_info` text, + `identifier` varchar(255) DEFAULT NULL, + `is_default` tinyint(1) DEFAULT '0', + `hidden` tinyint(1) DEFAULT '0', + `shixun_id` int(11) DEFAULT NULL, + `myshixun_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_repositories_on_project_id` (`project_id`) +) ENGINE=InnoDB AUTO_INCREMENT=75046 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `resource_banks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `resource_banks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `course_id` int(11) DEFAULT NULL, + `attachment_id` int(11) DEFAULT NULL, + `filename` varchar(255) DEFAULT NULL, + `disk_filename` varchar(255) DEFAULT NULL, + `filesize` int(11) DEFAULT NULL, + `digest` varchar(255) DEFAULT NULL, + `downloads` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `description` text, + `disk_directory` varchar(255) DEFAULT NULL, + `is_public` tinyint(1) DEFAULT NULL, + `copy_from` int(11) DEFAULT NULL, + `quotes` int(11) DEFAULT NULL, + `applicable_syllabus` varchar(255) DEFAULT NULL, + `major_level` int(11) DEFAULT NULL, + `discipline_category_id` int(11) DEFAULT NULL, + `first_level_discipline_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `content_type` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_resource_banks_on_course_id` (`course_id`), + KEY `index_resource_banks_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=8798 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `rich_rich_files`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rich_rich_files` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `rich_file_file_name` varchar(255) DEFAULT NULL, + `rich_file_content_type` varchar(255) DEFAULT NULL, + `rich_file_file_size` int(11) DEFAULT NULL, + `rich_file_updated_at` datetime DEFAULT NULL, + `owner_type` varchar(255) DEFAULT NULL, + `owner_id` int(11) DEFAULT NULL, + `uri_cache` text, + `simplified_type` varchar(255) DEFAULT 'file', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `roles`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `roles` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(30) NOT NULL DEFAULT '', + `position` int(11) DEFAULT '1', + `assignable` tinyint(1) DEFAULT '1', + `builtin` int(11) NOT NULL DEFAULT '0', + `permissions` text, + `issues_visibility` varchar(30) NOT NULL DEFAULT 'default', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `schema_migrations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `schema_migrations` ( + `version` varchar(255) NOT NULL, + UNIQUE KEY `unique_schema_migrations` (`version`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `schools`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `schools` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `province` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `logo_link` varchar(255) DEFAULT NULL, + `pinyin` varchar(255) DEFAULT NULL, + `school_type` int(11) DEFAULT '0', + `city` varchar(255) DEFAULT NULL, + `address` varchar(255) DEFAULT NULL, + `auto_users_trial` tinyint(1) DEFAULT '0', + `shool_code` varchar(255) DEFAULT NULL, + `authorization_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3159 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `score_indicator_qualities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `score_indicator_qualities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `upper_limit` float DEFAULT NULL, + `lower_limit` float DEFAULT NULL, + `score_set_id` int(11) DEFAULT NULL, + `position` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `score_indicators`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `score_indicators` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `score_set_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `scale` float DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `score_quality_descriptions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `score_quality_descriptions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `score_indicator_id` int(11) DEFAULT NULL, + `position` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `score_sets`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `score_sets` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `secdomains`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `secdomains` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `sub_type` int(11) DEFAULT NULL, + `subname` varchar(255) DEFAULT NULL, + `pid` int(11) DEFAULT '0', + `desc` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=56 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `seems_rateable_cached_ratings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `seems_rateable_cached_ratings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `cacheable_id` bigint(20) DEFAULT NULL, + `cacheable_type` varchar(255) DEFAULT NULL, + `avg` float NOT NULL, + `cnt` int(11) NOT NULL, + `dimension` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3294 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `seems_rateable_rates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `seems_rateable_rates` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `rater_id` bigint(20) DEFAULT NULL, + `rateable_id` int(11) DEFAULT NULL, + `rateable_type` varchar(255) DEFAULT NULL, + `stars` float NOT NULL, + `dimension` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `is_teacher_score` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=21336 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `settings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `settings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL DEFAULT '', + `value` text, + `updated_on` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_settings_on_name` (`name`) +) ENGINE=InnoDB AUTO_INCREMENT=77 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shares`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shares` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `created_on` date DEFAULT NULL, + `url` varchar(255) DEFAULT NULL, + `title` varchar(255) DEFAULT NULL, + `share_type` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `project_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shield_activities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shield_activities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `container_type` varchar(255) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `shield_type` varchar(255) DEFAULT NULL, + `shield_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=153 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shield_wechat_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shield_wechat_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `shield_id` int(11) DEFAULT NULL, + `shield_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shixun_major_courses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shixun_major_courses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `course_list_id` int(11) DEFAULT NULL, + `major_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_shixun_major_courses_on_shixun_id` (`shixun_id`), + KEY `index_shixun_major_courses_on_major_id` (`major_id`) +) ENGINE=InnoDB AUTO_INCREMENT=4082 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shixun_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shixun_members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `shixun_id` int(11) DEFAULT NULL, + `role` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2413 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shixun_mirror_repositories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shixun_mirror_repositories` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `mirror_repository_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3953 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shixun_modifies`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shixun_modifies` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `myshixun_id` int(11) DEFAULT NULL, + `status` tinyint(4) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4547 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shixun_ports`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shixun_ports` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `port` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shixun_schools`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shixun_schools` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `school_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=170 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shixun_tag_repertoires`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shixun_tag_repertoires` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `shixun_id` int(11) DEFAULT NULL, + `tag_repertoire_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1020 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `shixuns`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `shixuns` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` text, + `user_id` int(11) DEFAULT NULL, + `gpid` int(11) DEFAULT NULL, + `visits` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `status` int(11) DEFAULT '0', + `language` varchar(255) DEFAULT NULL, + `authentication` tinyint(1) DEFAULT '0', + `identifier` varchar(255) DEFAULT NULL, + `propaedeutics` longtext, + `trainee` int(11) DEFAULT '1', + `major_id` int(11) DEFAULT NULL, + `webssh` int(11) DEFAULT '0', + `homepage_show` tinyint(1) DEFAULT '0', + `hidden` tinyint(1) DEFAULT '0', + `fork_from` int(11) DEFAULT NULL, + `can_copy` tinyint(1) DEFAULT '0', + `modify_time` datetime DEFAULT NULL, + `reset_time` datetime DEFAULT NULL, + `publish_time` datetime DEFAULT NULL, + `closer_id` int(11) DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `git_url` varchar(255) DEFAULT NULL, + `vnc` tinyint(1) DEFAULT '0', + `myshixuns_count` int(11) DEFAULT '0' COMMENT '学习人数', + `challenges_count` int(11) DEFAULT '0', + `use_scope` tinyint(4) DEFAULT '0', + `evaluate_script` longtext, + `mirror_script_id` int(11) DEFAULT NULL, + `image_text` varchar(60) DEFAULT NULL, + `code_hidden` tinyint(1) DEFAULT '0', + `task_pass` tinyint(1) DEFAULT '0', + `exec_time` int(11) DEFAULT '120', + PRIMARY KEY (`id`), + KEY `index_shixuns_on_identifier` (`identifier`), + KEY `index_shixuns_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1116 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `softapplications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `softapplications` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` text, + `app_type_id` int(11) DEFAULT NULL, + `app_type_name` varchar(255) DEFAULT NULL, + `android_min_version_available` varchar(255) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `contest_id` int(11) DEFAULT NULL, + `softapplication_id` int(11) DEFAULT NULL, + `is_public` int(11) DEFAULT NULL, + `application_developers` varchar(255) DEFAULT NULL, + `deposit_project_url` varchar(255) DEFAULT NULL, + `deposit_project` varchar(255) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=77 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `sonar_errors`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `sonar_errors` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `jenkins_job_name` varchar(255) DEFAULT NULL, + `output` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `ssos`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `ssos` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `openid` varchar(255) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `password` varchar(255) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + `sex` int(11) DEFAULT NULL, + `school` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_ssos_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=89 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `stage_shixuns`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `stage_shixuns` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `subject_id` int(11) DEFAULT NULL, + `stage_id` int(11) DEFAULT NULL, + `shixun_id` int(11) DEFAULT NULL, + `position` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_stage_shixuns_on_subject_id` (`subject_id`), + KEY `index_stage_shixuns_on_stage_id` (`stage_id`), + KEY `index_stage_shixuns_on_shixun_id` (`shixun_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1216 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `stages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `stages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `subject_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `description` text, + `user_id` int(11) DEFAULT NULL, + `position` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_stages_on_subject_id` (`subject_id`), + KEY `index_stages_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=254 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `student_work_projects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `student_work_projects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `homework_common_id` int(11) DEFAULT NULL, + `student_work_id` int(11) DEFAULT NULL, + `project_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `is_leader` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `course_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_student_work_projects_on_homework_common_id` (`homework_common_id`), + KEY `index_student_work_projects_on_user_id` (`user_id`), + KEY `index_student_work_projects_on_project_id` (`project_id`), + KEY `index_student_work_projects_on_student_work_id` (`student_work_id`) +) ENGINE=InnoDB AUTO_INCREMENT=4970 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `student_work_tests`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `student_work_tests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `student_work_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `status` int(11) DEFAULT '9', + `results` text, + `src` text, + PRIMARY KEY (`id`), + KEY `index_student_work_tests_on_student_work_id` (`student_work_id`) +) ENGINE=InnoDB AUTO_INCREMENT=373663 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `student_works`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `student_works` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` longtext, + `homework_common_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `final_score` float DEFAULT NULL, + `teacher_score` float DEFAULT NULL, + `student_score` float DEFAULT NULL, + `teaching_asistant_score` float DEFAULT NULL, + `project_id` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `late_penalty` int(11) DEFAULT '0', + `absence_penalty` int(11) DEFAULT '0', + `system_score` float DEFAULT '0', + `is_test` tinyint(1) DEFAULT '0', + `simi_id` int(11) DEFAULT NULL, + `simi_value` int(11) DEFAULT NULL, + `work_score` float DEFAULT NULL, + `work_status` int(11) DEFAULT '0', + `commit_time` datetime DEFAULT NULL, + `is_delete` int(11) DEFAULT '0', + `appeal_penalty` int(11) DEFAULT '0', + `re_commit` tinyint(1) DEFAULT '0', + `late_reason` text, + `group_id` int(11) DEFAULT '0', + `myshixun_id` int(11) DEFAULT '0', + `update_time` datetime DEFAULT NULL, + `commit_user_id` int(11) DEFAULT NULL, + `ultimate_score` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_student_works_on_homework_common_id_and_user_id` (`homework_common_id`,`user_id`), + KEY `myshixun_id` (`myshixun_id`), + KEY `index_student_works_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=578531 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `student_works_evaluation_distributions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `student_works_evaluation_distributions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `student_work_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=156340 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `student_works_scores`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `student_works_scores` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `student_work_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `score` int(11) DEFAULT NULL, + `comment` text, + `reviewer_role` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `appeal_status` int(11) DEFAULT '0', + `is_hidden` tinyint(1) DEFAULT '0', + `is_ultimate` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `user_id` (`user_id`), + KEY `student_work_id` (`student_work_id`) +) ENGINE=InnoDB AUTO_INCREMENT=142316 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `student_works_scores_appeals`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `student_works_scores_appeals` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `student_works_score_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `comment` text, + `appeal_status` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `students_for_courses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `students_for_courses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `student_id` int(11) DEFAULT NULL, + `course_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_students_for_courses_on_student_id` (`student_id`), + KEY `index_students_for_courses_on_course_id` (`course_id`) +) ENGINE=InnoDB AUTO_INCREMENT=53883 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `sub_document_comments`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `sub_document_comments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `content` text, + `title` text, + `sub_domain_id` int(11) DEFAULT NULL, + `creator_id` int(11) DEFAULT NULL, + `parent_id` int(11) DEFAULT NULL, + `reply_id` int(11) DEFAULT NULL, + `locked` int(11) DEFAULT NULL, + `sticky` int(11) DEFAULT NULL, + `org_subfield_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `sub_domains`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `sub_domains` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `org_subfield_id` int(11) DEFAULT NULL, + `priority` int(11) DEFAULT '0', + `name` varchar(255) DEFAULT NULL, + `field_type` varchar(255) DEFAULT NULL, + `hide` int(11) DEFAULT '0', + `status` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `sub_repertoires`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `sub_repertoires` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `repertoire_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_sub_repertoires_on_repertoire_id` (`repertoire_id`) +) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `subfield_subdomain_dirs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `subfield_subdomain_dirs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `org_subfield_id` int(11) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `subject_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `subject_members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `subject_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `role` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_subject_members_on_subject_id` (`subject_id`), + KEY `index_subject_members_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `subjects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `subjects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` text, + `user_id` int(11) DEFAULT NULL, + `visits` int(11) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `course_list_id` int(11) DEFAULT NULL, + `major_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `hidden` tinyint(1) DEFAULT '0', + `learning_notes` text, + `introduction` varchar(255) DEFAULT NULL, + `stages_count` int(11) DEFAULT '0', + `stage_shixuns_count` int(11) DEFAULT '0', + `homepage_show` tinyint(1) DEFAULT '0', + `repertoire_id` int(11) DEFAULT NULL, + `score_count` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_subjects_on_user_id` (`user_id`), + KEY `index_subjects_on_course_list_id` (`course_list_id`), + KEY `index_subjects_on_major_id` (`major_id`) +) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `syllabus_members`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `syllabus_members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `rank` int(11) DEFAULT NULL, + `syllabus_id` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_syllabus_members_on_syllabus_id` (`syllabus_id`), + KEY `index_syllabus_members_on_user_id` (`user_id`), + KEY `index_syllabus_members_on_rank` (`rank`) +) ENGINE=InnoDB AUTO_INCREMENT=1009 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `syllabus_update_records`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `syllabus_update_records` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `syllabus_id` int(11) DEFAULT NULL, + `property` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_syllabus_update_records_on_user_id` (`user_id`), + KEY `index_syllabus_update_records_on_syllabus_id` (`syllabus_id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `syllabuses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `syllabuses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(255) DEFAULT NULL, + `description` text, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `eng_name` varchar(255) DEFAULT NULL, + `syllabus_type` int(11) DEFAULT NULL, + `credit` int(11) DEFAULT NULL, + `hours` int(11) DEFAULT NULL, + `theory_hours` int(11) DEFAULT NULL, + `practice_hours` int(11) DEFAULT NULL, + `applicable_major` varchar(255) DEFAULT NULL, + `pre_course` varchar(255) DEFAULT NULL, + `visits` int(11) DEFAULT '0', + `des_status` int(11) DEFAULT '0', + `major_level` int(11) DEFAULT NULL, + `discipline_category_id` int(11) DEFAULT NULL, + `first_level_discipline_id` int(11) DEFAULT NULL, + `major_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_syllabuses_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=997 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `system_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `system_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `content` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `description` text, + `subject` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `system_update_notices`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `system_update_notices` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `subject` varchar(255) DEFAULT NULL, + `notes` text, + `start_time` datetime DEFAULT NULL, + `end_time` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `notice_type` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `tag_repertoires`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tag_repertoires` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `sub_repertoire_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=165 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `taggings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `taggings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `tag_id` int(11) DEFAULT NULL, + `taggable_id` int(11) DEFAULT NULL, + `taggable_type` varchar(255) DEFAULT NULL, + `tagger_id` int(11) DEFAULT NULL, + `tagger_type` varchar(255) DEFAULT NULL, + `context` varchar(128) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_taggings_on_tag_id` (`tag_id`), + KEY `index_taggings_on_taggable_id_and_taggable_type_and_context` (`taggable_id`,`taggable_type`,`context`), + KEY `index_taggings_on_taggable_type` (`taggable_type`) +) ENGINE=InnoDB AUTO_INCREMENT=907227 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `tags`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tags` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=135634 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `teachers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `teachers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `tea_name` varchar(255) DEFAULT NULL, + `location` varchar(255) DEFAULT NULL, + `couurse_time` int(11) DEFAULT NULL, + `course_code` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `extra` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `test_sets`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `test_sets` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `input` varchar(255) DEFAULT NULL, + `output` text, + `challenge_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `is_public` tinyint(1) DEFAULT '1', + `result` tinyint(1) DEFAULT '1', + `position` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `testset` (`challenge_id`) +) ENGINE=InnoDB AUTO_INCREMENT=20790 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `tidings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tidings` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `trigger_user_id` int(11) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `parent_container_id` int(11) DEFAULT NULL, + `parent_container_type` varchar(255) DEFAULT NULL, + `belong_container_id` int(11) DEFAULT NULL, + `belong_container_type` varchar(255) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `viewed` tinyint(1) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `tiding_type` varchar(255) DEFAULT NULL, + `extra` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=123332 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `time_entries`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `time_entries` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `issue_id` int(11) DEFAULT NULL, + `hours` float NOT NULL, + `comments` varchar(255) DEFAULT NULL, + `activity_id` int(11) NOT NULL, + `spent_on` date NOT NULL, + `tyear` int(11) NOT NULL, + `tmonth` int(11) NOT NULL, + `tweek` int(11) NOT NULL, + `created_on` datetime NOT NULL, + `updated_on` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `time_entries_project_id` (`project_id`), + KEY `time_entries_issue_id` (`issue_id`), + KEY `index_time_entries_on_activity_id` (`activity_id`), + KEY `index_time_entries_on_user_id` (`user_id`), + KEY `index_time_entries_on_created_on` (`created_on`) +) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `tokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tokens` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL DEFAULT '0', + `action` varchar(30) NOT NULL DEFAULT '', + `value` varchar(40) NOT NULL DEFAULT '', + `created_on` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `tokens_value` (`value`), + KEY `index_tokens_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=116513 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `trackers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `trackers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(30) NOT NULL DEFAULT '', + `is_in_chlog` tinyint(1) NOT NULL DEFAULT '0', + `position` int(11) DEFAULT '1', + `is_in_roadmap` tinyint(1) NOT NULL DEFAULT '1', + `fields_bits` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `training_tasks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `training_tasks` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) DEFAULT NULL, + `tracker_id` int(11) DEFAULT NULL, + `subject` varchar(255) DEFAULT NULL, + `description` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `author_id` int(11) DEFAULT NULL, + `status` tinyint(4) DEFAULT '0', + `position` tinyint(4) DEFAULT '0', + `result` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_actions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_actions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `action_type` varchar(255) DEFAULT NULL, + `action_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1258332 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_activities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_activities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `act_type` varchar(255) DEFAULT NULL, + `act_id` int(11) DEFAULT NULL, + `container_type` varchar(255) DEFAULT NULL, + `container_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `user_act_index` (`act_id`,`act_type`,`container_id`,`created_at`) +) ENGINE=InnoDB AUTO_INCREMENT=137962 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_day_certifications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_day_certifications` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `status` int(11) DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_user_day_certifications_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=304 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_extensions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_extensions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `birthday` date DEFAULT NULL, + `brief_introduction` varchar(255) DEFAULT NULL, + `gender` int(11) DEFAULT NULL, + `location` varchar(255) DEFAULT NULL, + `occupation` varchar(255) DEFAULT NULL, + `work_experience` int(11) DEFAULT NULL, + `zip_code` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `technical_title` varchar(255) DEFAULT NULL, + `identity` int(11) DEFAULT NULL, + `student_id` varchar(255) DEFAULT NULL, + `teacher_realname` varchar(255) DEFAULT NULL, + `student_realname` varchar(255) DEFAULT NULL, + `location_city` varchar(255) DEFAULT NULL, + `school_id` int(11) DEFAULT NULL, + `description` varchar(255) DEFAULT '', + `department_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_user_extensions_on_user_id` (`user_id`), + KEY `index_user_extensions_on_school_id` (`school_id`), + KEY `index_user_extensions_on_department_id` (`department_id`) +) ENGINE=InnoDB AUTO_INCREMENT=35959 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_feedback_messages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_feedback_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `journals_for_message_id` int(11) DEFAULT NULL, + `journals_for_message_type` varchar(255) DEFAULT NULL, + `viewed` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_user_feedback_messages_on_user_id_and_created_at` (`user_id`,`created_at`), + KEY `index_user_feedback_messages_on_journals_for_message_id` (`journals_for_message_id`) +) ENGINE=InnoDB AUTO_INCREMENT=30409 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_grades`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_grades` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `project_id` int(11) NOT NULL, + `grade` float DEFAULT '0', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_user_grades_on_grade` (`grade`), + KEY `index_user_grades_on_project_id` (`project_id`), + KEY `index_user_grades_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=7683 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_hidden_modules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_hidden_modules` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `module_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_user_hidden_modules_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=932 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_levels`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_levels` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `level` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6330 DEFAULT CHARSET=latin1; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_preferences`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_preferences` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL DEFAULT '0', + `others` text, + `hide_mail` tinyint(1) DEFAULT '0', + `time_zone` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_user_preferences_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=34261 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_score_details`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_score_details` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `current_user_id` int(11) DEFAULT NULL, + `target_user_id` int(11) DEFAULT NULL, + `score_type` varchar(255) DEFAULT NULL, + `score_action` varchar(255) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `old_score` int(11) DEFAULT NULL, + `new_score` int(11) DEFAULT NULL, + `current_user_level` int(11) DEFAULT NULL, + `target_user_level` int(11) DEFAULT NULL, + `score_changeable_obj_id` int(11) DEFAULT NULL, + `score_changeable_obj_type` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=55181 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_scores`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_scores` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `collaboration` int(11) DEFAULT NULL, + `influence` int(11) DEFAULT NULL, + `skill` int(11) DEFAULT NULL, + `active` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=10128 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_searches`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_searches` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `search_type` int(11) DEFAULT NULL, + `subject` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_user_searches_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1273 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_statuses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_statuses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `changesets_count` int(11) DEFAULT NULL, + `watchers_count` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `grade` float DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_user_statuses_on_changesets_count` (`changesets_count`), + KEY `index_user_statuses_on_watchers_count` (`watchers_count`), + KEY `index_user_statuses_on_grade` (`grade`) +) ENGINE=InnoDB AUTO_INCREMENT=35170 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_system_notices`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_system_notices` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `notice_type` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_user_system_notices_on_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1214 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `user_wechats`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_wechats` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `subscribe` int(11) DEFAULT NULL, + `openid` varchar(255) DEFAULT NULL, + `nickname` varchar(255) DEFAULT NULL, + `sex` int(11) DEFAULT NULL, + `language` varchar(255) DEFAULT NULL, + `city` varchar(255) DEFAULT NULL, + `province` varchar(255) DEFAULT NULL, + `country` varchar(255) DEFAULT NULL, + `headimgurl` varchar(255) DEFAULT NULL, + `subscribe_time` varchar(255) DEFAULT NULL, + `unionid` varchar(255) DEFAULT NULL, + `remark` varchar(255) DEFAULT NULL, + `groupid` int(11) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `bindtype` int(11) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2424 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `login` varchar(255) NOT NULL DEFAULT '', + `hashed_password` varchar(40) NOT NULL DEFAULT '', + `firstname` varchar(30) NOT NULL DEFAULT '', + `lastname` varchar(255) NOT NULL DEFAULT '', + `mail` varchar(60) NOT NULL DEFAULT '', + `admin` tinyint(1) NOT NULL DEFAULT '0', + `status` int(11) NOT NULL DEFAULT '1', + `last_login_on` datetime DEFAULT NULL, + `language` varchar(5) DEFAULT '', + `auth_source_id` int(11) DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `updated_on` datetime DEFAULT NULL, + `type` varchar(255) DEFAULT NULL, + `identity_url` varchar(255) DEFAULT NULL, + `mail_notification` varchar(255) NOT NULL DEFAULT '', + `salt` varchar(64) DEFAULT NULL, + `gid` int(11) DEFAULT NULL, + `visits` int(11) DEFAULT '0', + `excellent_teacher` int(11) DEFAULT '0', + `excellent_student` int(11) DEFAULT '0', + `phone` varchar(255) DEFAULT NULL, + `authentication` tinyint(1) DEFAULT '0', + `grade` int(11) DEFAULT NULL, + `experience` int(11) DEFAULT '0', + `nickname` varchar(255) DEFAULT NULL, + `show_realname` tinyint(1) DEFAULT '1', + `professional_certification` tinyint(1) DEFAULT '0', + `ID_number` varchar(255) DEFAULT NULL, + `certification` int(11) DEFAULT '0', + `homepage_teacher` tinyint(1) DEFAULT '0', + `homepage_engineer` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `index_users_on_id_and_type` (`id`,`type`), + KEY `index_users_on_auth_source_id` (`auth_source_id`), + KEY `index_users_on_type` (`type`), + KEY `index_users_on_homepage_engineer` (`homepage_engineer`), + KEY `index_users_on_homepage_teacher` (`homepage_teacher`) +) ENGINE=InnoDB AUTO_INCREMENT=36346 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `users_authentications`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users_authentications` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `authentication_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `verification_codes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `verification_codes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `code` varchar(255) DEFAULT NULL, + `code_type` int(11) DEFAULT NULL, + `status` int(11) DEFAULT NULL, + `phone` varchar(255) DEFAULT NULL, + `email` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=27716 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `versions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `versions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) NOT NULL DEFAULT '0', + `name` varchar(255) NOT NULL DEFAULT '', + `description` varchar(255) DEFAULT '', + `effective_date` date DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `updated_on` datetime DEFAULT NULL, + `wiki_page_title` varchar(255) DEFAULT NULL, + `status` varchar(255) DEFAULT 'open', + `sharing` varchar(255) NOT NULL DEFAULT 'none', + `user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `versions_project_id` (`project_id`), + KEY `index_versions_on_sharing` (`sharing`) +) ENGINE=InnoDB AUTO_INCREMENT=456 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `visitors`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `visitors` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `master_id` int(11) DEFAULT NULL, + `updated_on` datetime DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `index_visitors_user_id` (`user_id`), + KEY `index_visitors_master_id` (`master_id`), + KEY `index_visitors_updated_on` (`updated_on`) +) ENGINE=InnoDB AUTO_INCREMENT=61423 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `watchers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `watchers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `watchable_type` varchar(255) NOT NULL DEFAULT '', + `watchable_id` int(11) NOT NULL DEFAULT '0', + `user_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `watchers_user_id_type` (`user_id`,`watchable_type`), + KEY `index_watchers_on_user_id` (`user_id`), + KEY `index_watchers_on_watchable_id_and_watchable_type` (`watchable_id`,`watchable_type`) +) ENGINE=InnoDB AUTO_INCREMENT=36722 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `web_footer_companies`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `web_footer_companies` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `logo_size` varchar(255) DEFAULT NULL, + `url` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `web_footer_oranizers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `web_footer_oranizers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `description` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `websshes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `websshes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `myshixun_id` int(11) DEFAULT NULL, + `host` varchar(255) DEFAULT NULL, + `port` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `wechat_logs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `wechat_logs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `openid` varchar(255) NOT NULL, + `request_raw` text, + `response_raw` text, + `session_raw` text, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_wechat_logs_on_openid` (`openid`) +) ENGINE=InnoDB AUTO_INCREMENT=119051 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `wiki_content_versions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `wiki_content_versions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `wiki_content_id` int(11) NOT NULL, + `page_id` int(11) NOT NULL, + `author_id` int(11) DEFAULT NULL, + `data` longblob, + `compression` varchar(6) DEFAULT '', + `comments` varchar(255) DEFAULT '', + `updated_on` datetime NOT NULL, + `version` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `wiki_content_versions_wcid` (`wiki_content_id`), + KEY `index_wiki_content_versions_on_updated_on` (`updated_on`) +) ENGINE=InnoDB AUTO_INCREMENT=264 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `wiki_contents`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `wiki_contents` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `page_id` int(11) NOT NULL, + `author_id` int(11) DEFAULT NULL, + `text` longtext, + `comments` varchar(255) DEFAULT '', + `updated_on` datetime NOT NULL, + `version` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `wiki_contents_page_id` (`page_id`), + KEY `index_wiki_contents_on_author_id` (`author_id`) +) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `wiki_pages`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `wiki_pages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `wiki_id` int(11) NOT NULL, + `title` varchar(255) NOT NULL, + `created_on` datetime NOT NULL, + `protected` tinyint(1) NOT NULL DEFAULT '0', + `parent_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `wiki_pages_wiki_id_title` (`wiki_id`,`title`), + KEY `index_wiki_pages_on_wiki_id` (`wiki_id`), + KEY `index_wiki_pages_on_parent_id` (`parent_id`) +) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `wiki_redirects`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `wiki_redirects` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `wiki_id` int(11) NOT NULL, + `title` varchar(255) DEFAULT NULL, + `redirects_to` varchar(255) DEFAULT NULL, + `created_on` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `wiki_redirects_wiki_id_title` (`wiki_id`,`title`), + KEY `index_wiki_redirects_on_wiki_id` (`wiki_id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `wikis`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `wikis` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `project_id` int(11) NOT NULL, + `start_page` varchar(255) NOT NULL, + `status` int(11) NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + KEY `wikis_project_id` (`project_id`) +) ENGINE=InnoDB AUTO_INCREMENT=2825 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `work_detail_groups`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `work_detail_groups` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `work_id` int(11) DEFAULT NULL, + `min_num` int(11) DEFAULT NULL, + `max_num` int(11) DEFAULT NULL, + `base_on_project` tinyint(1) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_work_detail_groups_on_work_id` (`work_id`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `work_detail_manuals`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `work_detail_manuals` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `evaluation_start` date DEFAULT NULL, + `evaluation_end` date DEFAULT NULL, + `evaluation_num` int(11) DEFAULT NULL, + `work_id` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `index_work_detail_manuals_on_work_id` (`work_id`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `workflows`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `workflows` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `tracker_id` int(11) NOT NULL DEFAULT '0', + `old_status_id` int(11) NOT NULL DEFAULT '0', + `new_status_id` int(11) NOT NULL DEFAULT '0', + `role_id` int(11) NOT NULL DEFAULT '0', + `assignee` tinyint(1) NOT NULL DEFAULT '0', + `author` tinyint(1) NOT NULL DEFAULT '0', + `type` varchar(30) DEFAULT NULL, + `field_name` varchar(30) DEFAULT NULL, + `rule` varchar(30) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `wkfs_role_tracker_old_status` (`role_id`,`tracker_id`,`old_status_id`), + KEY `index_workflows_on_old_status_id` (`old_status_id`), + KEY `index_workflows_on_role_id` (`role_id`), + KEY `index_workflows_on_new_status_id` (`new_status_id`) +) ENGINE=InnoDB AUTO_INCREMENT=626 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `works`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `works` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `user_id` int(11) DEFAULT NULL, + `description` text, + `publish_time` date DEFAULT NULL, + `end_time` date DEFAULT NULL, + `work_type` int(11) DEFAULT NULL, + `contest_id` int(11) DEFAULT NULL, + `is_delete` tinyint(1) DEFAULT '0', + `score_open` tinyint(1) DEFAULT '0', + `is_open` tinyint(1) DEFAULT '0', + `work_status` int(11) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `online_evaluation` tinyint(1) DEFAULT '0', + `score_valid` tinyint(1) DEFAULT '1', + PRIMARY KEY (`id`), + KEY `index_works_on_user_id` (`user_id`), + KEY `index_works_on_contest_id` (`contest_id`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `works_categories`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `works_categories` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `category` varchar(255) DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `zip_packs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `zip_packs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) DEFAULT NULL, + `homework_id` int(11) DEFAULT NULL, + `file_digest` varchar(255) DEFAULT NULL, + `file_path` varchar(255) DEFAULT NULL, + `pack_times` int(11) DEFAULT '1', + `pack_size` int(11) DEFAULT '0', + `file_digests` text, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=25828 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +INSERT INTO `schema_migrations` (version) VALUES +('1'), +('10'), +('100'), +('101'), +('102'), +('103'), +('104'), +('105'), +('106'), +('107'), +('108'), +('11'), +('12'), +('13'), +('14'), +('15'), +('16'), +('17'), +('18'), +('19'), +('2'), +('20'), +('20090214190337'), +('20090312172426'), +('20090312194159'), +('20090318181151'), +('20090323224724'), +('20090401221305'), +('20090401231134'), +('20090403001910'), +('20090406161854'), +('20090425161243'), +('20090503121501'), +('20090503121505'), +('20090503121510'), +('20090614091200'), +('20090704172350'), +('20090704172355'), +('20090704172358'), +('20091010093521'), +('20091017212227'), +('20091017212457'), +('20091017212644'), +('20091017212938'), +('20091017213027'), +('20091017213113'), +('20091017213151'), +('20091017213228'), +('20091017213257'), +('20091017213332'), +('20091017213444'), +('20091017213536'), +('20091017213642'), +('20091017213716'), +('20091017213757'), +('20091017213835'), +('20091017213910'), +('20091017214015'), +('20091017214107'), +('20091017214136'), +('20091017214236'), +('20091017214308'), +('20091017214336'), +('20091017214406'), +('20091017214440'), +('20091017214519'), +('20091017214611'), +('20091017214644'), +('20091017214720'), +('20091017214750'), +('20091025163651'), +('20091108092559'), +('20091114105931'), +('20091123212029'), +('20091205124427'), +('20091220183509'), +('20091220183727'), +('20091220184736'), +('20091225164732'), +('20091227112908'), +('20100129193402'), +('20100129193813'), +('20100221100219'), +('20100313132032'), +('20100313171051'), +('20100705164950'), +('20100819172912'), +('20101104182107'), +('20101107130441'), +('20101114115114'), +('20101114115359'), +('20110220160626'), +('20110223180944'), +('20110223180953'), +('20110224000000'), +('20110226120112'), +('20110226120132'), +('20110227125750'), +('20110228000000'), +('20110228000100'), +('20110401192910'), +('20110408103312'), +('20110412065600'), +('20110511000000'), +('20110902000000'), +('20111201201315'), +('20120115143024'), +('20120115143100'), +('20120115143126'), +('20120127174243'), +('20120205111326'), +('20120223110929'), +('20120301153455'), +('20120422150750'), +('20120705074331'), +('20120707064544'), +('20120714122000'), +('20120714122100'), +('20120714122200'), +('20120731164049'), +('20120930112914'), +('20121026002032'), +('20121026003537'), +('20121209123234'), +('20121209123358'), +('20121213084931'), +('20130110122628'), +('20130201184705'), +('20130202090625'), +('20130207175206'), +('20130207181455'), +('20130215073721'), +('20130215111127'), +('20130215111141'), +('20130217094251'), +('20130418001207-redmine_ckeditor'), +('20130418001208-redmine_ckeditor'), +('20130418001209-redmine_ckeditor'), +('20130418001210-redmine_ckeditor'), +('20130725021433'), +('20130725122407'), +('20130725132508'), +('20130727021306'), +('20130728021709'), +('20130801081314'), +('20130805131602'), +('20130806072429'), +('20130806083151'), +('20130806083152'), +('20130807021235'), +('20130807021309'), +('20130807031901'), +('20130809122945'), +('20130810014337'), +('20130810085341'), +('20130811001727'), +('20130811122119'), +('20130814084938'), +('20130819020004'), +('20130823133435'), +('20130823143552'), +('20130827003308'), +('20130828004955'), +('20130828080407'), +('20130831080808'), +('20130831080955'), +('20130904075504'), +('20130904135804'), +('20130906124330'), +('20130910075221'), +('20130911005626'), +('20130911135608'), +('20130911140019'), +('20130911140205'), +('20130913005337'), +('20130913125835'), +('20130917123036'), +('20130918004629'), +('20130918085747'), +('20130922123727'), +('20130922123849'), +('20130925031313'), +('20130926005448'), +('20130926140427'), +('20130927011824'), +('20130929011921'), +('20131009074454'), +('20131017080750'), +('20131017120541'), +('20131017131615'), +('20131017135933'), +('20131017140104'), +('20131017140123'), +('20131021024144'), +('20131031071414'), +('20131031071452'), +('20131031093317'), +('20131107073302'), +('20131108133857'), +('20131112005309'), +('20131112015232'), +('20131113124237'), +('20131122020026'), +('20131122132942'), +('20131215065910'), +('20131224021723'), +('20140318011702'), +('20140318021747'), +('20140318072309'), +('20140319092720'), +('20140320015156'), +('20140320022724'), +('20140324015819'), +('20140327071420'), +('20140327073052'), +('20140327082704'), +('20140401004102'), +('20140401121611'), +('20140402023357'), +('20140403075029'), +('20140403113341'), +('20140404030103'), +('20140404031622'), +('20140410015850'), +('20140410020848'), +('20140410021724'), +('20140411003234'), +('20140411004155'), +('20140411005214'), +('20140411011700'), +('20140413022725'), +('20140414012423'), +('20140415090718'), +('20140415090829'), +('20140417085550'), +('20140417090022'), +('20140417091429'), +('20140421044829'), +('20140421044830'), +('20140424022002'), +('20140424072458'), +('20140428005537'), +('20140428013546'), +('20140505082635'), +('20140505083218'), +('20140505083430'), +('20140508030039'), +('20140508030358'), +('20140509020307'), +('20140513073801'), +('20140515013449'), +('20140516031200'), +('20140519020211'), +('20140519030825'), +('20140519054846'), +('20140519070751'), +('20140519074133'), +('20140521072851'), +('20140522025137'), +('20140522025721'), +('20140526031949'), +('20140526104509'), +('20140527060344'), +('20140529084427'), +('20140530010015'), +('20140530102014'), +('20140603033359'), +('20140603042015'), +('20140603081801'), +('20140604011630'), +('20140604071623'), +('20140604071624'), +('20140605003915'), +('20140605025247'), +('20140605025300'), +('20140605025302'), +('20140605025303'), +('20140606027403'), +('20140606028512'), +('20140609061903'), +('20140611161801'), +('20140617013146'), +('20140617092219'), +('20140618020535'), +('20140618105213'), +('20140618155324'), +('20140626012511'), +('20140701031909'), +('20140701075839'), +('20140703011335'), +('20140703085204'), +('20140704034832'), +('20140707095213'), +('20140708023356'), +('20140710024054'), +('20140710030426'), +('20140710071720'), +('20140710095123'), +('20140711010124'), +('20140711012924'), +('20140714021812'), +('20140714081030'), +('20140715015540'), +('20140716021202'), +('20140716021558'), +('20140718091306'), +('20140719030741'), +('20140719030941'), +('20140719080032'), +('20140721074353'), +('20140722024513'), +('20140722080529'), +('20140722080924'), +('20140723082637'), +('20140724080319'), +('20140725013735'), +('20140725062302'), +('20140725073357'), +('20140728014933'), +('20140730021521'), +('20140730024419'), +('20140801034242'), +('20140811022947'), +('20140812032957'), +('20140812065147'), +('20140812065417'), +('20140814062455'), +('20140826072838'), +('20140916005319'), +('20140922032830'), +('20140930072719'), +('20141009010934'), +('20141009055029'), +('20141013014908'), +('20141013023400'), +('20141029065917'), +('20141031065238'), +('20141031111632'), +('20141031122331'), +('20141102054414'), +('20141103015148'), +('20141103032156'), +('20141103065703'), +('20141105012624'), +('20141119011439'), +('20141120091234'), +('20141126091207'), +('20141126091750'), +('20141127015431'), +('20141127072548'), +('20141201085218'), +('20141210070327'), +('20141226074532'), +('20141229025519'), +('20141229025925'), +('20141229081716'), +('20141229141201'), +('20141230011546'), +('20141230034253'), +('20141230062844'), +('20141230081209'), +('20141230081744'), +('20141231020031'), +('20141231085350'), +('20150108034148'), +('20150108034253'), +('20150108034414'), +('20150108035301'), +('20150108035338'), +('20150112024820'), +('20150112080435'), +('20150114022710'), +('20150121030451'), +('20150123020615'), +('20150128032421'), +('20150206023634'), +('20150206060632'), +('20150210062236'), +('20150227061944'), +('20150227065713'), +('20150227083257'), +('20150227085333'), +('20150302061232'), +('20150302091345'), +('20150305011023'), +('20150305011359'), +('20150305081132'), +('20150309090143'), +('20150311013036'), +('20150316032155'), +('20150316083717'), +('20150318025244'), +('20150324021043'), +('20150328115230'), +('20150331031554'), +('20150331032810'), +('20150402015402'), +('20150409092151'), +('20150414115406'), +('20150415032102'), +('20150422034543'), +('20150428021035'), +('20150505023015'), +('20150505023127'), +('20150505023452'), +('20150505025003'), +('20150505025537'), +('20150510100343'), +('20150514133640'), +('20150519012744'), +('20150519014600'), +('20150519014639'), +('20150519020031'), +('20150519022200'), +('20150519023821'), +('20150519030544'), +('20150528024616'), +('20150601032112'), +('20150602021020'), +('20150602055730'), +('20150604153000'), +('20150619060110'), +('20150630031857'), +('20150702073245'), +('20150702073308'), +('20150708025533'), +('20150708085629'), +('20150709071731'), +('20150712063406'), +('20150713161100'), +('20150714161100'), +('20150714162200'), +('20150715070534'), +('20150715162300'), +('20150719092427'), +('20150722015428'), +('20150730093403'), +('20150730130816'), +('20150801034945'), +('20150810064247'), +('20150811010817'), +('20150811065543'), +('20150811080754'), +('20150811083322'), +('20150814011838'), +('20150814024425'), +('20150814031258'), +('20150815030833'), +('20150819090720'), +('20150820004659'), +('20150820022416'), +('20150820025358'), +('20150824133916'), +('20150826020407'), +('20150826061843'), +('20150828011415'), +('20150828155329'), +('20150829023459'), +('20150829024549'), +('20150829081822'), +('20150829130302'), +('20150831070611'), +('20150831093918'), +('20150901004812'), +('20150901004910'), +('20150906025009'), +('20150906065702'), +('20150906083453'), +('20150906090419'), +('20150906091723'), +('20150907064144'), +('20150907064547'), +('20150907152238'), +('20150909062619'), +('20150911031029'), +('20150911064528'), +('20150914063751'), +('20150915063302'), +('20150917022239'), +('20150917071652'), +('20150917081214'), +('20150918004521'), +('20150918005722'), +('20150918063404'), +('20150918134804'), +('20150924063215'), +('20150925025200'), +('20150925060939'), +('20150928090128'), +('20150930011457'), +('20151013023237'), +('20151013081912'), +('20151013091057'), +('20151013092356'), +('20151014012627'), +('20151014013243'), +('20151014023806'), +('20151020013352'), +('20151020014759'), +('20151020021234'), +('20151022071611'), +('20151022071804'), +('20151028060607'), +('20151029030006'), +('20151102083844'), +('20151102084419'), +('20151102085318'), +('20151102090519'), +('20151103011119'), +('20151104020233'), +('20151104024335'), +('20151104032831'), +('20151104070007'), +('20151104070455'), +('20151104073902'), +('20151104090032'), +('20151109073857'), +('20151109080256'), +('20151110011003'), +('20151112072948'), +('20151113025341'), +('20151113025459'), +('20151113025524'), +('20151113025549'), +('20151113025721'), +('20151113025751'), +('20151116020842'), +('20151116065904'), +('20151116071721'), +('20151117033430'), +('20151117075939'), +('20151118014720'), +('20151118015638'), +('20151118031602'), +('20151119124148'), +('20151120021958'), +('20151120115137'), +('20151120134208'), +('20151124032319'), +('20151125064914'), +('20151126160252'), +('20151127011351'), +('20151130031446'), +('20151130032658'), +('20151130033906'), +('20151130064556'), +('20151202064455'), +('20151203030635'), +('20151203072815'), +('20151204030143'), +('20151204062220'), +('20151208015409'), +('20151208025236'), +('20151208032013'), +('20151208073241'), +('20151209085900'), +('20151209085942'), +('20151215070238'), +('20151215105425'), +('20151216025539'), +('20151216030610'), +('20151217051447'), +('20151218022014'), +('20151218110033'), +('20151223062932'), +('20151224090313'), +('20151229022049'), +('20151229045505'), +('20151230015410'), +('20151230015904'), +('20151230022443'), +('20151231012634'), +('20151231023235'), +('20151231023610'), +('20160104082423'), +('20160105014033'), +('20160105073350'), +('20160106065255'), +('20160107050736'), +('20160108021447'), +('20160108024752'), +('20160108093752'), +('20160111064927'), +('20160111065137'), +('20160111065215'), +('20160111065530'), +('20160111071348'), +('20160111071411'), +('20160111071529'), +('20160111071558'), +('20160111080833'), +('20160111080914'), +('20160112085834'), +('20160113023045'), +('20160113023137'), +('20160113024927'), +('20160113063514'), +('20160113064153'), +('20160113090435'), +('20160114022833'), +('20160114022928'), +('20160114131753'), +('20160115021923'), +('20160115022341'), +('20160115023749'), +('20160115125217'), +('20160116034925'), +('20160118014219'), +('20160118083751'), +('20160119034447'), +('20160120032758'), +('20160121070232'), +('20160122023014'), +('20160122083400'), +('20160122083507'), +('20160122094805'), +('20160122094829'), +('20160122142844'), +('20160122143138'), +('20160126024429'), +('20160126031857'), +('20160128024452'), +('20160202034530'), +('20160220100507'), +('20160222064143'), +('20160223021227'), +('20160223031843'), +('20160223073859'), +('20160224032046'), +('20160224074034'), +('20160225024759'), +('20160303103231'), +('20160304154005'), +('20160304234903'), +('20160309022930'), +('20160309024051'), +('20160309072649'), +('20160310033019'), +('20160311072540'), +('20160311072622'), +('20160311072718'), +('20160311072819'), +('20160316055201'), +('20160317070611'), +('20160317090350'), +('20160321071740'), +('20160321073042'), +('20160321073107'), +('20160321073227'), +('20160321075815'), +('20160321080116'), +('20160321080336'), +('20160321080412'), +('20160321080825'), +('20160321085313'), +('20160322032610'), +('20160324052634'), +('20160324074942'), +('20160325030146'), +('20160325030423'), +('20160328022312'), +('20160328022623'), +('20160329014316'), +('20160330095711'), +('20160331063938'), +('20160405021915'), +('20160408074854'), +('20160414055511'), +('20160414060838'), +('20160415025623'), +('20160415030447'), +('20160418074429'), +('20160419061745'), +('20160419074016'), +('20160421011543'), +('20160426084709'), +('20160427061847'), +('20160427070237'), +('20160428065243'), +('20160429015956'), +('20160429030819'), +('20160504060751'), +('20160506085852'), +('20160506104128'), +('20160509025404'), +('20160511055221'), +('20160513012705'), +('20160513021204'), +('20160513120002'), +('20160517013659'), +('20160517091224'), +('20160518031514'), +('20160518060243'), +('20160519070718'), +('20160523085440'), +('20160526093715'), +('20160531021244'), +('20160601073753'), +('20160606064856'), +('20160612030537'), +('20160612043259'), +('20160613064914'), +('20160613065840'), +('20160614072229'), +('20160622033322'), +('20160622074138'), +('20160624032138'), +('20160624054614'), +('20160624055127'), +('20160624103411'), +('20160627074232'), +('20160627090316'), +('20160629030320'), +('20160629081520'), +('20160629084146'), +('20160629094716'), +('20160630112733'), +('20160707031248'), +('20160708005533'), +('20160708091258'), +('20160709015740'), +('20160715091215'), +('20160718064146'), +('20160719013955'), +('20160720094503'), +('20160721075236'), +('20160722074421'), +('20160725062343'), +('20160725091759'), +('20160727020247'), +('20160727065357'), +('20160728041513'), +('20160728041943'), +('20160728075947'), +('20160729020903'), +('20160729124038'), +('20160729124833'), +('20160810080942'), +('20160810081337'), +('20160811084401'), +('20160824073554'), +('20160830090214'), +('20160905084821'), +('20160907055119'), +('20160907061917'), +('20160913063446'), +('20160914073340'), +('20160918024056'), +('20160918024214'), +('20160918033136'), +('20160918074635'), +('20160921062340'), +('20160923024443'), +('20161008015936'), +('20161009053958'), +('20161011012114'), +('20161014085016'), +('20161015013348'), +('20161015054820'), +('20161015102324'), +('20161018082432'), +('20161019020422'), +('20161020055047'), +('20161027070249'), +('20161028053000'), +('20161111064007'), +('20161111070615'), +('20161111071624'), +('20161111081619'), +('20161114092115'), +('20161115082005'), +('20161117015856'), +('20161117060138'), +('20161121063025'), +('20161121091826'), +('20161125024643'), +('20161128030405'), +('20161128072528'), +('20161129032534'), +('20161129033440'), +('20161129084352'), +('20161130031415'), +('20161201015458'), +('20161201073217'), +('20161201083030'), +('20161202024209'), +('20161202073523'), +('20161206061652'), +('20161208015939'), +('20161213074134'), +('20161214060728'), +('20161214080008'), +('20161216031906'), +('20161220062249'), +('20161220090638'), +('20161220090826'), +('20161220093609'), +('20161221055334'), +('20161221060341'), +('20161221060853'), +('20161221065228'), +('20161221065841'), +('20161221070253'), +('20161221070623'), +('20161222033007'), +('20161222063638'), +('20161223025155'), +('20161223030701'), +('20161223083022'), +('20161227085308'), +('20161228070235'), +('20161228091749'), +('20161230005953'), +('20161230061940'), +('20170105024224'), +('20170106024520'), +('20170111021557'), +('20170111030006'), +('20170112072122'), +('20170112082231'), +('20170117161330'), +('20170119072629'), +('20170119084215'), +('20170120021457'), +('20170120120614'), +('20170207060207'), +('20170209020934'), +('20170210082105'), +('20170217004513'), +('20170217092541'), +('20170217092859'), +('20170217104309'), +('20170218074506'), +('20170219025424'), +('20170219062646'), +('20170219070127'), +('20170220060000'), +('20170220060210'), +('20170220065632'), +('20170222072150'), +('20170227074837'), +('20170228133958'), +('20170302020239'), +('20170302032957'), +('20170302073836'), +('20170302094330'), +('20170303030731'), +('20170303071513'), +('20170306070453'), +('20170307082304'), +('20170307092931'), +('20170307093928'), +('20170309024921'), +('20170309062850'), +('20170310011834'), +('20170310014056'), +('20170310032024'), +('20170310053903'), +('20170310072101'), +('20170314072825'), +('20170314081550'), +('20170314082632'), +('20170314085929'), +('20170315103005'), +('20170317022123'), +('20170317022508'), +('20170317022557'), +('20170320054808'), +('20170321081658'), +('20170321102722'), +('20170322033103'), +('20170322095511'), +('20170323081518'), +('20170324054735'), +('20170324090202'), +('20170328064900'), +('20170328065349'), +('20170328065735'), +('20170328081152'), +('20170328082148'), +('20170330084904'), +('20170331013652'), +('20170401055830'), +('20170405075018'), +('20170410085204'), +('20170410085945'), +('20170410092257'), +('20170411013813'), +('20170411093519'), +('20170412023151'), +('20170412063958'), +('20170412075557'), +('20170413030447'), +('20170413032641'), +('20170413064458'), +('20170413065659'), +('20170414023452'), +('20170414024741'), +('20170414084212'), +('20170416064210'), +('20170417081351'), +('20170419070551'), +('20170419112951'), +('20170419132939'), +('20170420080141'), +('20170420081959'), +('20170425064652'), +('20170425072017'), +('20170425085926'), +('20170425092430'), +('20170426020613'), +('20170426024708'), +('20170426024822'), +('20170426060122'), +('20170427011453'), +('20170427013052'), +('20170427031044'), +('20170502083644'), +('20170502091943'), +('20170503062237'), +('20170503062507'), +('20170503075321'), +('20170503085743'), +('20170504021749'), +('20170504065145'), +('20170504070210'), +('20170505025616'), +('20170505032131'), +('20170505085001'), +('20170508081347'), +('20170509080544'), +('20170511020541'), +('20170515070741'), +('20170515071837'), +('20170515073053'), +('20170517020032'), +('20170518015629'), +('20170518064248'), +('20170522062153'), +('20170522071931'), +('20170522130310'), +('20170523011829'), +('20170526022745'), +('20170526023023'), +('20170526062330'), +('20170526062907'), +('20170526063836'), +('20170526073920'), +('20170526090359'), +('20170602021309'), +('20170607015139'), +('20170607021803'), +('20170609061623'), +('20170614020255'), +('20170615070234'), +('20170615080332'), +('20170615105442'), +('20170619091405'), +('20170621023044'), +('20170622013100'), +('20170623030431'), +('20170626022454'), +('20170626031135'), +('20170626055814'), +('20170627073830'), +('20170704074622'), +('20170705064602'), +('20170705071652'), +('20170705073342'), +('20170705083812'), +('20170705090958'), +('20170705091953'), +('20170706024154'), +('20170706071415'), +('20170711091159'), +('20170712023923'), +('20170713024020'), +('20170713030017'), +('20170717083910'), +('20170718013325'), +('20170718022342'), +('20170718080353'), +('20170720013004'), +('20170721015724'), +('20170721022106'), +('20170721060845'), +('20170728080308'), +('20170728082516'), +('20170802012507'), +('20170804062817'), +('20170807063211'), +('20170808021426'), +('20170808033437'), +('20170810012934'), +('20170811055836'), +('20170817092910'), +('20170822032004'), +('20170822032223'), +('20170822032810'), +('20170822062358'), +('20170822080604'), +('20170824103529'), +('20170825031026'), +('20170825032003'), +('20170825113413'), +('20170827023117'), +('20170829021122'), +('20170830032124'), +('20170830093154'), +('20170831015104'), +('20170831015613'), +('20170831022201'), +('20170831022550'), +('20170831092348'), +('20170904071627'), +('20170904082600'), +('20170904091629'), +('20170907021641'), +('20170907025441'), +('20170907061723'), +('20170907100131'), +('20170908020109'), +('20170908115908'), +('20170911033152'), +('20170912024832'), +('20170912090828'), +('20170914013811'), +('20170914024926'), +('20170915085332'), +('20170918014832'), +('20170918090054'), +('20170918092326'), +('20170920022714'), +('20170920065705'), +('20170921084836'), +('20170922015144'), +('20170922091816'), +('20170922112450'), +('20170922114504'), +('20170926012936'), +('20170927015114'), +('20170930023907'), +('20170930024003'), +('20170930081820'), +('20170930082930'), +('20170930122738'), +('20171010071751'), +('20171011084944'), +('20171012073054'), +('20171012101648'), +('20171013081923'), +('20171013083722'), +('20171013115401'), +('20171014070618'), +('20171014074021'), +('20171014080052'), +('20171014095120'), +('20171019065522'), +('20171020011305'), +('20171023115525'), +('20171024014724'), +('20171024015602'), +('20171024015824'), +('20171024020826'), +('20171024030645'), +('20171024081725'), +('20171026105403'), +('20171027090248'), +('20171027090356'), +('20171027090458'), +('20171027110314'), +('20171030070711'), +('20171030072123'), +('20171030085925'), +('20171031025843'), +('20171031062353'), +('20171031072755'), +('20171101020347'), +('20171101022807'), +('20171103031157'), +('20171106030726'), +('20171106083916'), +('20171107013142'), +('20171108032131'), +('20171108080344'), +('20171109022624'), +('20171109060716'), +('20171109065843'), +('20171110083046'), +('20171113062848'), +('20171113084709'), +('20171114070152'), +('20171115023919'), +('20171115032026'), +('20171115071239'), +('20171115084833'), +('20171116015944'), +('20171117015511'), +('20171117031934'), +('20171117082126'), +('20171117093339'), +('20171121063613'), +('20171121072336'), +('20171121080141'), +('20171122015449'), +('20171122080410'), +('20171122081525'), +('20171122091118'), +('20171123022414'), +('20171123065703'), +('20171123070319'), +('20171124071537'), +('20171124072840'), +('20171124080022'), +('20171124080516'), +('20171124081330'), +('20171124120750'), +('20171124122621'), +('20171128032158'), +('20171129075555'), +('20171201092823'), +('20171208020535'), +('20171208031726'), +('20171208092415'), +('20171211091713'), +('20171212082837'), +('20171212093226'), +('20171212100049'), +('20171213062609'), +('20171213064646'), +('20171213072616'), +('20171213073348'), +('20171214021853'), +('20171214023018'), +('20171214025420'), +('20171214063652'), +('20171214084429'), +('20171214085019'), +('20171215010708'), +('20171215113239'), +('20171218031524'), +('20171219033623'), +('20171219054106'), +('20171219062652'), +('20171220013630'), +('20171221021043'), +('20171221054254'), +('20171221074055'), +('20171221083438'), +('20171221092115'), +('20171222013450'), +('20171222022504'), +('20171222060821'), +('20171222071113'), +('20171222075831'), +('20171222132047'), +('20171222152033'), +('20171225085155'), +('20171226060732'), +('20171226065503'), +('20171226070302'), +('20171226075551'), +('20171226092333'), +('20171226101132'), +('20171227065103'), +('20171227083935'), +('20171228085816'), +('20171228122117'), +('20171229082949'), +('20171229094541'), +('20180102022853'), +('20180104013923'), +('20180105023335'), +('20180105093310'), +('20180109081109'), +('20180110012234'), +('20180112121731'), +('20180115083549'), +('20180116030420'), +('20180118060556'), +('20180118073148'), +('20180118090936'), +('20180119083918'), +('20180122071811'), +('20180123082641'), +('20180124114615'), +('20180129090133'), +('20180131061311'), +('20180131064555'), +('20180131070154'), +('20180201091245'), +('20180202063413'), +('20180202091641'), +('20180204022311'), +('20180205083404'), +('20180206083254'), +('20180207013445'), +('20180207020017'), +('20180207024825'), +('20180207081311'), +('20180228024546'), +('20180228024951'), +('20180309075023'), +('20180313060218'), +('20180314022506'), +('20180314070401'), +('20180316064901'), +('20180316065917'), +('20180316071234'), +('20180316082825'), +('20180316123807'), +('20180318014622'), +('20180321072457'), +('20180321082129'), +('20180328074357'), +('20180330025749'), +('20180330071500'), +('20180403082849'), +('20180404031923'), +('20180404032519'), +('20180404060342'), +('20180408031817'), +('20180409082423'), +('20180409085809'), +('20180410005959'), +('20180410010815'), +('20180410011903'), +('20180410012604'), +('20180410023305'), +('20180410033026'), +('20180411015053'), +('20180411021857'), +('20180411030750'), +('20180411072015'), +('20180413012742'), +('20180415033808'), +('20180416070001'), +('20180416073019'), +('20180416082938'), +('20180418023500'), +('20180418023608'), +('20180418065309'), +('20180420025051'), +('20180420030114'), +('20180420072903'), +('20180424014459'), +('20180424032725'), +('20180425083336'), +('20180503074404'), +('20180504155310'), +('20180511031742'), +('20180515013318'), +('20180517032433'), +('20180517074054'), +('20180521030537'), +('20180522042604'), +('20180522062045'), +('20180522063657'), +('20180523021343'), +('20180523033339'), +('20180523072755'), +('20180524072611'), +('20180525091540'), +('20180525092331'), +('20180529064425'), +('20180531084726'), +('20180531091113'), +('20180531104205'), +('20180601080626'), +('20180604080213'), +('20180606091107'), +('20180607022655'), +('20180608013258'), +('20180608021656'), +('20180608082745'), +('20180612092939'), +('20180613071648'), +('20180614032357'), +('20180625080716'), +('20180627092727'), +('20180628062932'), +('20180629064058'), +('20180629112409'), +('20180703025928'), +('20180703030830'), +('20180710031834'), +('20180712024228'), +('20180713005958'), +('20180713092051'), +('20180713093156'), +('20180716032319'), +('20180716061450'), +('20180718024306'), +('20180718024839'), +('20180718085746'), +('20180719020018'), +('20180720081025'), +('20180723074456'), +('20180724010018'), +('20180726020714'), +('20180730023048'), +('20180730024428'), +('20180730082738'), +('20180731020501'), +('20180731023338'), +('20180731023445'), +('20180731024106'), +('20180801005016'), +('20180801080506'), +('20180805042542'), +('20180806030714'), +('20180806031346'), +('21'), +('22'), +('23'), +('24'), +('25'), +('26'), +('27'), +('28'), +('29'), +('3'), +('30'), +('31'), +('32'), +('33'), +('34'), +('35'), +('36'), +('37'), +('38'), +('39'), +('4'), +('40'), +('41'), +('42'), +('43'), +('44'), +('45'), +('46'), +('47'), +('48'), +('49'), +('5'), +('50'), +('51'), +('52'), +('53'), +('54'), +('55'), +('56'), +('57'), +('58'), +('59'), +('6'), +('60'), +('61'), +('62'), +('63'), +('64'), +('65'), +('66'), +('67'), +('68'), +('69'), +('7'), +('70'), +('71'), +('72'), +('73'), +('74'), +('75'), +('76'), +('77'), +('78'), +('79'), +('8'), +('80'), +('81'), +('82'), +('83'), +('84'), +('85'), +('86'), +('87'), +('88'), +('89'), +('9'), +('90'), +('91'), +('92'), +('93'), +('94'), +('95'), +('96'), +('97'), +('98'), +('99'); + + diff --git a/lib/assets/.keep b/lib/assets/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/lib/educoder.rb b/lib/educoder.rb new file mode 100644 index 000000000..0a07701ae --- /dev/null +++ b/lib/educoder.rb @@ -0,0 +1,11 @@ +#coding=utf-8 +# +# +module Educoder + # 调用时才加载 + autoload :TipException, "educoder/tip_exception" + autoload :Utils, "educoder/units" + autoload :Sms, "educoder/sms" + autoload :I18n, "educoder/i18n" + autoload :Ufile, "educoder/ufile" +end \ No newline at end of file diff --git a/lib/educoder/i18n.rb b/lib/educoder/i18n.rb new file mode 100644 index 000000000..4675f9537 --- /dev/null +++ b/lib/educoder/i18n.rb @@ -0,0 +1,167 @@ +module Educoder + module I18n + def self.included(base) + base.extend Educoder::I18n + end + + def l(*args) + case args.size + when 1 + ::I18n.t(*args) + when 2 + if args.last.is_a?(Hash) + ::I18n.t(*args) + elsif args.last.is_a?(String) + ::I18n.t(args.first, :value => args.last) + else + ::I18n.t(args.first, :count => args.last) + end + else + raise "Translation string with multiple values: #{args.first}" + end + end + + def l_or_humanize(s, options={}) + k = "#{options[:prefix]}#{s}".to_sym + ::I18n.t(k, :default => s.to_s.humanize) + end + + def l_hours(hours) + hours = hours.to_f + l((hours < 2.0 ? :label_f_hour : :label_f_hour_plural), :value => ("%.2f" % hours.to_f)) + end + + def ll(lang, str, value=nil) + ::I18n.t(str.to_s, :value => value, :locale => lang.to_s.gsub(%r{(.+)\-(.+)$}) { "#{$1}-#{$2.upcase}" }) + end + + def format_date(date) + return nil unless date + options = {} + options[:format] = Setting.date_format unless Setting.date_format.blank? + options[:locale] = User.current.language unless User.current.language.blank? + ::I18n.l(date.to_date, options) + end + + def format_time(time, include_date = true) + return nil unless time + options = {} + options[:format] = (Setting.time_format.blank? ? :time : Setting.time_format) + options[:locale] = User.current.language unless User.current.language.blank? + time = time.to_time if time.is_a?(String) + zone = User.current.time_zone + local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time) + (include_date ? "#{format_date(local)} " : "") + ::I18n.l(local, options) + end + + def day_name(day) + ::I18n.t('date.day_names')[day % 7] + end + + def day_letter(day) + ::I18n.t('date.abbr_day_names')[day % 7].first + end + + def month_name(month) + ::I18n.t('date.month_names')[month] + end + + def valid_languages + ::I18n.available_locales + end + + # Returns an array of languages names and code sorted by names, example: + # [["Deutsch", "de"], ["English", "en"] ...] + # + # The result is cached to prevent from loading all translations files. + def languages_options + ActionController::Base.cache_store.fetch "i18n/languages_options" do + valid_languages.map {|lang| [ll(lang.to_s, :general_lang_name), lang.to_s]}.sort {|x,y| x.first <=> y.first } + end + end + + def find_language(lang) + @@languages_lookup = valid_languages.inject({}) {|k, v| k[v.to_s.downcase] = v; k } + @@languages_lookup[lang.to_s.downcase] + end + + def set_language_if_valid(lang) + if l = find_language(lang) + ::I18n.locale = l + end + end + + def current_language + ::I18n.locale + end + + # Custom backend based on I18n::Backend::Simple with the following changes: + # * lazy loading of translation files + # * available_locales are determined by looking at translation file names + class Backend + (class << self; self; end).class_eval { public :include } + + module Implementation + include ::I18n::Backend::Base + + # Stores translations for the given locale in memory. + # This uses a deep merge for the translations hash, so existing + # translations will be overwritten by new ones only at the deepest + # level of the hash. + def store_translations(locale, data, options = {}) + locale = locale.to_sym + translations[locale] ||= {} + data = data.deep_symbolize_keys + translations[locale].deep_merge!(data) + end + + # Get available locales from the translations filenames + def available_locales + @available_locales ||= ::I18n.load_path.map {|path| File.basename(path, '.*')}.uniq.sort.map(&:to_sym) + end + + # Clean up translations + def reload! + @translations = nil + @available_locales = nil + super + end + + protected + + def init_translations(locale) + locale = locale.to_s + paths = ::I18n.load_path.select {|path| File.basename(path, '.*') == locale} + load_translations(paths) + translations[locale] ||= {} + end + + def translations + @translations ||= {} + end + + # Looks up a translation from the translations hash. Returns nil if + # eiher key is nil, or locale, scope or key do not exist as a key in the + # nested translations hash. Splits keys or scopes containing dots + # into multiple keys, i.e. currency.format is regarded the same as + # %w(currency format). + def lookup(locale, key, scope = [], options = {}) + init_translations(locale) unless translations.key?(locale) + keys = ::I18n.normalize_keys(locale, key, scope, options[:separator]) + + keys.inject(translations) do |result, _key| + _key = _key.to_sym + return nil unless result.is_a?(Hash) && result.has_key?(_key) + result = result[_key] + result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol) + result + end + end + end + + include Implementation + # Adds fallback to default locale for untranslated strings + include ::I18n::Backend::Fallbacks + end + end +end diff --git a/lib/educoder/sms.rb b/lib/educoder/sms.rb new file mode 100644 index 000000000..9d54a6df5 --- /dev/null +++ b/lib/educoder/sms.rb @@ -0,0 +1,77 @@ +#coding=utf-8 + +require 'net/https' +require 'uri' + +module Educoder + module Sms + def self.send(opt={}) + Rails.logger.info "#{opt[:mobile]} - #{opt[:code]}" + begin + o = sendYunpian(opt[:mobile], opt[:code], opt[:send_type], opt[:name], opt[:user_name], opt[:result]) + if o["code"] != 0 + Rails.logger.error "发送短信出错: #{o['code']}--#{o['msg']}" + end + return o["code"] + rescue => e + Rails.logger.error "发送短信出错: #{e}" + return false + end + end + + def self.notify_admin(opt) + opt[:name] = '管理员' + opt[:mobile] = ENV['NOTIDY_ADMIN_PHONE'] || '17680641960' + send(opt) + end + + def self.sendYunpian(mobile, code, send_type, name, user_name, result) + #修改为您的apikey.可在官网(http://www.yunpian.com)登录后用户中心首页看到 + apikey = EduSetting.find_by_name('sms_apikey').try(:value) + #指定模板发送接口HTTP地址 + send_tpl_sms_uri = URI.parse('https://sms.yunpian.com/v2/sms/single_send.json') + + params = {} + params['apikey'] = apikey + params['mobile'] = mobile + params['text'] = "" + if send_type.nil? + params['text'] = "【Edu实训】" + code + "(手机验证码)。如非本人操作,请忽略。" + elsif send_type == 'competition_start' + params['text'] = "【Edu实训】亲爱的#{user_name},你参与的#{name}将于#{result}开始,请及时参赛" + Rails.logger.info "#{params['text']}" + elsif send_type == 'subject_authorization' || send_type == 'shixun_authorization' + params['text'] = "【Edu实训】亲爱的#{user_name},您提交的#{name}#{send_type=='subject_authorization'?'实训路径':'实训'}发布申请#{result},请登录平台查看详情" + Rails.logger.info "#{params['text']}" + elsif send_type == 'authentication_pro' || send_type == 'authentication'|| send_type == 'trial_authorization' || send_type == 'project_info' + params['text'] = "【Edu实训】亲爱的#{user_name},您提交的#{send_type == 'authentication_pro'?'职业认证':(send_type == 'authentication'? '实名认证' : (send_type == 'project_info'?'加入申请':'试用申请' ))}#{result},请登录平台查看详情" + Rails.logger.info "#{params['text']}" + elsif send_type == "apply_pro_certification" || send_type == "apply_auth" + params['text'] = "【Edu实训】亲爱的#{name},有新的#{send_type == 'apply_pro_certification'?'职业':'实名'}认证申请,请尽快处理" + Rails.logger.info "#{params['text']}" + elsif send_type == "publish_subject" ||send_type == "publish_shixun"|| send_type == "user_apply_auth" || send_type == "discuss" + params['text'] = "【Edu实训】亲爱的#{name},有新的#{send_type == 'publish_subject'?'实训路径':(send_type == 'publish_shixun' ? '实训' : (send_type == 'discuss' ? '实训评论':'试用'))}申请发布,请尽快处理" + Rails.logger.info "#{params['text']}" + elsif send_type == 'join_course_multi_role' + params['text'] = "【Edu实训】亲爱的#{user_name},您的课堂#{name}有助教或者教师申请加入,请尽快审核" + Rails.logger.info "#{params['text']}" + elsif send_type == 'applied_project_info' + params['text'] = "【Edu实训】亲爱的#{user_name},您的项目#{name}有成员申请加入,请尽快审核" + Rails.logger.info "#{params['text']}" + end + + http = Net::HTTP.new(send_tpl_sms_uri.host, send_tpl_sms_uri.port) + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + http.use_ssl = true + begin + request = Net::HTTP::Post.new(send_tpl_sms_uri.request_uri) + request.set_form_data(params) + request['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8' + response = http.start { |http| http.request(request) } + ActiveSupport::JSON.decode(response.body) + rescue =>err + return nil + end + end + end +end \ No newline at end of file diff --git a/lib/educoder/tip_exception.rb b/lib/educoder/tip_exception.rb new file mode 100644 index 000000000..09f0228ac --- /dev/null +++ b/lib/educoder/tip_exception.rb @@ -0,0 +1,24 @@ +module Educoder + + class TipException < StandardError + attr_reader :status, :message + + def initialize(status=-1, message) + case status + when 403 + message = "您没有权限进行该操作" + when 404 + message = "您访问的页面不存在或已被删除" + end + @status = status + @message = message + + Rails.logger.info("############# #{@status}, #{@message}") + end + + def tip_json + {status: self.status, message: self.message} + end + end + +end \ No newline at end of file diff --git a/lib/educoder/ufile.rb b/lib/educoder/ufile.rb new file mode 100644 index 000000000..2a52b0af6 --- /dev/null +++ b/lib/educoder/ufile.rb @@ -0,0 +1,130 @@ +#coding=utf-8 +# +# ucloud 文件上传 +# + +require 'base64' +require 'openssl' +require 'faraday' + +module Educoder + class Ufile + PATH_PREFIX = %r{^/} + + def initialize(uploader={}) + @ucloud_public_key = uploader[:ucloud_public_key] + @ucloud_private_key = uploader[:ucloud_private_key] + @ucloud_public_read = uploader[:ucloud_public_read] + @ucloud_bucket = @ucloud_public_read ? uploader[:ucloud_public_bucket] : uploader[:ucloud_private_bucket] + @ucloud_bucket_host = @ucloud_public_read ? uploader[:ucloud_public_bucket_host] : uploader[:ucloud_private_bucket_host] + @ucloud_cdn_host = @ucloud_public_read ? uploader[:ucloud_public_cdn_host] : uploader[:ucloud_private_cdn_host] + @ucloud_private_expire_seconds = uploader[:ucloud_private_expire_seconds] || 300 + + unless @ucloud_cdn_host.include?('//') + raise "config.ucloud_cdn_host requirement include // http:// or https://, but you give: #{@ucloud_cdn_host}" + end + end + + # 上传文件 + def put(path, file, headers = {}) + path.sub!(PATH_PREFIX, '') + + response = conn.put(path, file.read) do |req| + req.headers = headers + token = authorization(req.method, headers['Content-Type'], path) + req.headers['Authorization'] = token + end + + if response.success? + true + else + raise 'Ucloud上传失败' + end + end + + # 读取文件 + def get(path) + path.sub!(PATH_PREFIX, '') + response = conn.get(url(path)) + + if response.success? + return response + else + raise 'Ucloud Get File Fail' + end + end + + # 删除文件 + def delete(path) + path.sub!(PATH_PREFIX, '') + response = conn.delete(url(path)) do |req| + req.headers['Authorization'] = authorization(req.method, nil, path) + end + + if response.success? + true + else + raise 'Ucloud Get File Fail' + end + end + + def url(path) + if @ucloud_public_read + public_get_url(path) + else + private_get_url(path) + end + end + + # 公开的访问地址 + def public_get_url(path) + path.sub!(PATH_PREFIX, '') + [@ucloud_cdn_host, path].join('/') + end + + # 私有空间访问地址 + def private_get_url(path) + public_get_url(path) + privite_get_url_auth(path) + end + + private + + def conn + @conn ||= begin + Faraday.new(url: @ucloud_bucket_host) do |req| + req.request :url_encoded + req.adapter Faraday.default_adapter + end + end + end + + # 私密查看url的认证信息 + def privite_get_url_auth(path) + expired_ts = private_expire_ts + signed_str = signature(string_to_sign('GET', nil, path, expired_ts)) + "?UCloudPublicKey=#{@ucloud_public_key}&Expires=#{expired_ts}&Signature=#{signed_str}" + end + + def private_expire_ts + @ucloud_private_expire_seconds + Time.now.to_i + end + + def authorization(http_method, content_type, path) + signed_str = signature(string_to_sign(http_method, content_type, path)) + "UCloud " + @ucloud_public_key + ":" + signed_str + end + + def signature(str) + Base64.strict_encode64(OpenSSL::HMAC.digest('sha1', @ucloud_private_key, str)) + end + + def string_to_sign(http_method, ori_content_type, path, expired_ts = nil) + http_verb = "#{http_method.upcase}\n" + content_md5 = "\n" + content_type = "#{ori_content_type}\n" + timestamp = "#{expired_ts}\n" + full_path = "/#{@ucloud_bucket}/#{path}" + http_verb + content_md5 + content_type + timestamp + full_path + end + end +end \ No newline at end of file diff --git a/lib/educoder/units.rb b/lib/educoder/units.rb new file mode 100644 index 000000000..8fca64a5f --- /dev/null +++ b/lib/educoder/units.rb @@ -0,0 +1,144 @@ +require 'fileutils' + +module Educoder + module Utils + class << self + # Returns the relative root url of the application + def relative_url_root + ActionController::Base.respond_to?('relative_url_root') ? + ActionController::Base.relative_url_root.to_s : + ActionController::Base.config.relative_url_root.to_s + end + + # Sets the relative root url of the application + def relative_url_root=(arg) + if ActionController::Base.respond_to?('relative_url_root=') + ActionController::Base.relative_url_root=arg + else + ActionController::Base.config.relative_url_root = arg + end + end + + # Generates a n bytes random hex string + # Example: + # random_hex(4) # => "89b8c729" + def random_hex(n) + SecureRandom.hex(n) + end + + def save_upload(upload, path) + directory = File.dirname(path) + unless File.exists?(directory) + FileUtils.mkdir_p directory + end + File.open(path, "wb") do |f| + if upload.respond_to?(:read) + buffer = "" + while (buffer = upload.read(8192)) + f.write(buffer) + yield buffer if block_given? + end + else + f.write(upload) + yield upload if block_given? + end + end + end + + def digest(diskfile) + md5 = Digest::MD5.new + File.open(diskfile, "rb") do |f| + buffer = "" + while (buffer = f.read(8192)) + md5.update(buffer) + end + end + md5.hexdigest + end + end + + module Shell + + module_function + + def shell_quote(str) + if Redmine::Platform.mswin? + '"' + str.gsub(/"/, '\\"') + '"' + else + "'" + str.gsub(/'/, "'\"'\"'") + "'" + end + end + + def shell_quote_command(command) + if Redmine::Platform.mswin? && RUBY_PLATFORM == 'java' + command + else + shell_quote(command) + end + end + end + + module DateCalculation + # Returns the number of working days between from and to + def working_days(from, to) + days = (to - from).to_i + if days > 0 + weeks = days / 7 + result = weeks * (7 - non_working_week_days.size) + days_left = days - weeks * 7 + start_cwday = from.cwday + days_left.times do |i| + unless non_working_week_days.include?(((start_cwday + i - 1) % 7) + 1) + result += 1 + end + end + result + else + 0 + end + end + + # Adds working days to the given date + def add_working_days(date, working_days) + if working_days > 0 + weeks = working_days / (7 - non_working_week_days.size) + result = weeks * 7 + days_left = working_days - weeks * (7 - non_working_week_days.size) + cwday = date.cwday + while days_left > 0 + cwday += 1 + unless non_working_week_days.include?(((cwday - 1) % 7) + 1) + days_left -= 1 + end + result += 1 + end + next_working_date(date + result) + else + date + end + end + + # Returns the date of the first day on or after the given date that is a working day + def next_working_date(date) + cwday = date.cwday + days = 0 + while non_working_week_days.include?(((cwday + days - 1) % 7) + 1) + days += 1 + end + date + days + end + + # Returns the index of non working week days (1=monday, 7=sunday) + def non_working_week_days + @non_working_week_days ||= begin + days = Setting.non_working_week_days + if days.is_a?(Array) && days.size < 7 + days.map(&:to_i) + else + [] + end + end + end + end + end +end diff --git a/lib/gitlab-cli/.rakeTasks b/lib/gitlab-cli/.rakeTasks new file mode 100644 index 000000000..ea716fd52 --- /dev/null +++ b/lib/gitlab-cli/.rakeTasks @@ -0,0 +1,7 @@ + + diff --git a/lib/gitlab-cli/Gemfile b/lib/gitlab-cli/Gemfile new file mode 100644 index 000000000..2b517aca7 --- /dev/null +++ b/lib/gitlab-cli/Gemfile @@ -0,0 +1,4 @@ +source 'http://gems.ruby-china.org/' + +# Specify your gem's dependencies in gitlab.gemspec +gemspec diff --git a/lib/gitlab-cli/LICENSE.txt b/lib/gitlab-cli/LICENSE.txt new file mode 100644 index 000000000..d3cbb5521 --- /dev/null +++ b/lib/gitlab-cli/LICENSE.txt @@ -0,0 +1,24 @@ +Copyright (c) 2012-2014 Nihad Abbasov +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/gitlab-cli/README.md b/lib/gitlab-cli/README.md new file mode 100644 index 000000000..1a1f0e4b3 --- /dev/null +++ b/lib/gitlab-cli/README.md @@ -0,0 +1,121 @@ +# Gitlab + +[![Build Status](https://travis-ci.org/NARKOZ/gitlab.png)](http://travis-ci.org/NARKOZ/gitlab) + +[website](http://narkoz.github.io/gitlab) | +[documentation](http://rubydoc.info/gems/gitlab/frames) + +Gitlab is a Ruby wrapper and CLI for the [GitLab API](https://github.com/gitlabhq/gitlabhq/tree/master/doc/api#gitlab-api). + +## Installation + +Install it from rubygems: + +```sh +gem install gitlab +``` + +Or add to a Gemfile: + +```ruby +gem 'gitlab' +# gem 'gitlab', :git => 'git://github.com/NARKOZ/gitlab.git' +``` + +## Usage + +Configuration example: + +```ruby +Gitlab.configure do |config| + config.endpoint = 'https://example.net/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT'] + config.private_token = 'qEsq1pt6HJPaNciie3MG' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN'] + # Optional + # config.user_agent = 'Custom User Agent' # user agent, default: 'Gitlab Ruby Gem [version]' + # config.sudo = 'user' # username for sudo mode, default: nil +end +``` + +(Note: If you are using Gitlab.com's hosted service, your endpoint will be `https://gitlab.com/api/v3`) + +Usage examples: + +```ruby +# set an API endpoint +Gitlab.endpoint = 'http://example.net/api/v3' +# => "http://example.net/api/v3" + +# set a user private token +Gitlab.private_token = 'qEsq1pt6HJPaNciie3MG' +# => "qEsq1pt6HJPaNciie3MG" + +# list projects +Gitlab.projects(:per_page => 5) +# => [#1, "code"=>"brute", "name"=>"Brute", "description"=>nil, "path"=>"brute", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:56Z"}>, #2, "code"=>"mozart", "name"=>"Mozart", "description"=>nil, "path"=>"mozart", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:57Z"}>, #3, "code"=>"gitlab", "name"=>"Gitlab", "description"=>nil, "path"=>"gitlab", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:58Z"}>] + +# initialize a new client +g = Gitlab.client(:endpoint => 'https://api.example.com', :private_token => 'qEsq1pt6HJPaNciie3MG') +# => # + +# get a user +user = g.user +# => #1, "email"=>"john@example.com", "name"=>"John Smith", "bio"=>nil, "skype"=>"", "linkedin"=>"", "twitter"=>"john", "dark_scheme"=>false, "theme_id"=>1, "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}> + +# get a user's email +user.email +# => "john@example.com" + +# set a sudo mode to perform API calls as another user +Gitlab.sudo = 'other_user' +# => "other_user" + +# disable a sudo mode +Gitlab.sudo = nil +# => nil +``` + +For more information, refer to [documentation](http://rubydoc.info/gems/gitlab/frames). + +## CLI + +Usage examples: + +```sh +# list users +gitlab users + +# get current user +gitlab user + +# get a user +gitlab user 2 + +# filter output +gitlab user --only=id,username + +gitlab user --except=email,bio +``` + +## CLI Shell + +Usage examples: + +```sh +# start shell session +gitlab shell + +# list available commands +gitlab> help + +# list groups +gitlab> groups + +# protect a branch +gitlab> protect_branch 1 master +``` + +For more information, refer to [website](http://narkoz.github.io/gitlab). + +## License + +Released under the BSD 2-clause license. See LICENSE.txt for details. diff --git a/lib/gitlab-cli/Rakefile b/lib/gitlab-cli/Rakefile new file mode 100644 index 000000000..eebc77618 --- /dev/null +++ b/lib/gitlab-cli/Rakefile @@ -0,0 +1,9 @@ +require "bundler/gem_tasks" + +require 'rspec/core/rake_task' +RSpec::Core::RakeTask.new(:spec) do |spec| + spec.pattern = FileList['spec/**/*_spec.rb'] + spec.rspec_opts = ['--color', '--format d'] +end + +task :default => :spec diff --git a/lib/gitlab-cli/bin/gitlab b/lib/gitlab-cli/bin/gitlab new file mode 100755 index 000000000..02cc41fcc --- /dev/null +++ b/lib/gitlab-cli/bin/gitlab @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +$:.unshift File.expand_path('../../lib', __FILE__) + +require 'gitlab/cli' + +Gitlab::CLI.start(ARGV) diff --git a/lib/gitlab-cli/gitlab.gemspec b/lib/gitlab-cli/gitlab.gemspec new file mode 100644 index 000000000..11bd093d2 --- /dev/null +++ b/lib/gitlab-cli/gitlab.gemspec @@ -0,0 +1,26 @@ +# -*- encoding: utf-8 -*- +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'gitlab/version' + +Gem::Specification.new do |gem| + gem.name = "gitlab" + gem.version = Gitlab::VERSION + gem.authors = ["Nihad Abbasov"] + gem.email = ["mail@narkoz.me"] + gem.description = %q{Ruby client and CLI for GitLab API} + gem.summary = %q{A Ruby wrapper and CLI for the GitLab API} + gem.homepage = "https://github.com/narkoz/gitlab" + + gem.files = `git ls-files`.split($/) + gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } + gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) + gem.require_paths = ["lib"] + + gem.add_runtime_dependency 'httparty' + gem.add_runtime_dependency 'terminal-table' + + gem.add_development_dependency 'rake' + gem.add_development_dependency 'rspec' + gem.add_development_dependency 'webmock' +end diff --git a/lib/gitlab-cli/lib/gitlab.rb b/lib/gitlab-cli/lib/gitlab.rb new file mode 100644 index 000000000..a203a70a0 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab.rb @@ -0,0 +1,37 @@ +require 'gitlab/version' +require 'gitlab/objectified_hash' +require 'gitlab/configuration' +require 'gitlab/error' +require 'gitlab/request' +require 'gitlab/api' +require 'gitlab/client' + +module Gitlab + extend Configuration + + # Alias for Gitlab::Client.new + # + # @return [Gitlab::Client] + def self.client(options={}) + Gitlab::Client.new(options) + end + + # Delegate to Gitlab::Client + def self.method_missing(method, *args, &block) + return super unless client.respond_to?(method) + client.send(method, *args, &block) + end + + # Delegate to Gitlab::Client + def self.respond_to?(method) + return client.respond_to?(method) || super + end + + # Returns an unsorted array of available client methods. + # + # @return [Array] + def self.actions + hidden = /endpoint|private_token|user_agent|sudo|get|post|put|\Adelete\z|validate|set_request_defaults/ + (Gitlab::Client.instance_methods - Object.methods).reject {|e| e[hidden]} + end +end diff --git a/lib/gitlab-cli/lib/gitlab/api.rb b/lib/gitlab-cli/lib/gitlab/api.rb new file mode 100644 index 000000000..c2dfb7cfc --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/api.rb @@ -0,0 +1,17 @@ +module Gitlab + # @private + class API < Request + # @private + attr_accessor(*Configuration::VALID_OPTIONS_KEYS) + + # Creates a new API. + # @raise [Error:MissingCredentials] + def initialize(options={}) + options = Gitlab.options.merge(options) + Configuration::VALID_OPTIONS_KEYS.each do |key| + send("#{key}=", options[key]) + end + set_request_defaults @endpoint, @private_token, @sudo + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/cli.rb b/lib/gitlab-cli/lib/gitlab/cli.rb new file mode 100644 index 000000000..fa6d6d670 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/cli.rb @@ -0,0 +1,47 @@ +require 'gitlab' +require 'terminal-table/import' +require_relative 'cli_helpers' +require_relative 'shell' + +class Gitlab::CLI + extend Helpers + + def self.start(args) + command = args.shift.strip rescue 'help' + run(command, args) + end + + def self.run(cmd, args=[]) + case cmd + when 'help' + puts actions_table + when 'info' + endpoint = Gitlab.endpoint ? Gitlab.endpoint : 'not set' + private_token = Gitlab.private_token ? Gitlab.private_token : 'not set' + puts "Gitlab endpoint is #{endpoint}" + puts "Gitlab private token is #{private_token}" + puts "Ruby Version is #{RUBY_VERSION}" + puts "Gitlab Ruby Gem #{Gitlab::VERSION}" + when '-v', '--version' + puts "Gitlab Ruby Gem #{Gitlab::VERSION}" + when 'shell' + Gitlab::Shell.start + else + unless valid_command?(cmd) + puts "Unknown command. Run `gitlab help` for a list of available commands." + exit(1) + end + + if args.any? && (args.last.start_with?('--only=') || args.last.start_with?('--except=')) + command_args = args[0..-2] + else + command_args = args + end + + confirm_command(cmd) + + data = gitlab_helper(cmd, command_args) { exit(1) } + output_table(cmd, args, data) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/cli_helpers.rb b/lib/gitlab-cli/lib/gitlab/cli_helpers.rb new file mode 100644 index 000000000..93293d388 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/cli_helpers.rb @@ -0,0 +1,175 @@ +class Gitlab::CLI + # Defines methods related to CLI output and formatting. + module Helpers + extend self + + # Returns filtered required fields. + # + # @return [Array] + def required_fields(args) + if args.any? && args.last.start_with?('--only=') + args.last.gsub('--only=', '').split(',') + else + [] + end + end + + # Returns filtered excluded fields. + # + # @return [Array] + def excluded_fields(args) + if args.any? && args.last.start_with?('--except=') + args.last.gsub('--except=', '').split(',') + else + [] + end + end + + # Confirms command is valid. + # + # @return [Boolean] + def valid_command?(cmd) + command = cmd.is_a?(Symbol) ? cmd : cmd.to_sym + Gitlab.actions.include?(command) + end + + # Confirms command with a desctructive action. + # + # @return [String] + def confirm_command(cmd) + if cmd.start_with?('remove_') || cmd.start_with?('delete_') + puts "Are you sure? (y/n)" + if %w(y yes).include?($stdin.gets.to_s.strip.downcase) + puts 'Proceeding..' + else + puts 'Command aborted.' + exit(1) + end + end + end + + # Table with available commands. + # + # @return [String] + def actions_table + client = Gitlab::Client.new(endpoint: '') + actions = Gitlab.actions + methods = [] + + actions.each do |action| + methods << { + name: action, + owner: client.method(action).owner.to_s.gsub('Gitlab::Client::', '') + } + end + + owners = methods.map {|m| m[:owner]}.uniq.sort + methods_c = methods.group_by {|m| m[:owner]} + methods_c = methods_c.map {|_, v| [_, v.sort_by {|hv| hv[:name]}] } + methods_c = Hash[methods_c.sort_by(&:first).map {|k, v| [k, v]}] + max_column_length = methods_c.values.max_by(&:size).size + + rows = max_column_length.times.map do |i| + methods_c.keys.map do |key| + methods_c[key][i] ? methods_c[key][i][:name] : '' + end + end + + table do |t| + t.title = "Available commands (#{actions.size} total)" + t.headings = owners + + rows.each do |row| + t.add_row row + end + end + end + + # Decides which table to use. + # + # @return [String] + def output_table(cmd, args, data) + case data + when Gitlab::ObjectifiedHash + puts single_record_table(data, cmd, args) + when Array + puts multiple_record_table(data, cmd, args) + else + puts data.inspect + end + end + + # Table for a single record. + # + # @return [String] + def single_record_table(data, cmd, args) + hash = data.to_h + keys = hash.keys.sort {|x, y| x.to_s <=> y.to_s } + keys = keys & required_fields(args) if required_fields(args).any? + keys = keys - excluded_fields(args) + + table do |t| + t.title = "Gitlab.#{cmd} #{args.join(', ')}" + + keys.each_with_index do |key, index| + case value = hash[key] + when Hash + value = 'Hash' + when nil + value = 'null' + end + + t.add_row [key, value] + t.add_separator unless keys.size - 1 == index + end + end + end + + # Table for multiple records. + # + # @return [String] + def multiple_record_table(data, cmd, args) + return 'No data' if data.empty? + + arr = data.map(&:to_h) + keys = arr.first.keys.sort {|x, y| x.to_s <=> y.to_s } + keys = keys & required_fields(args) if required_fields(args).any? + keys = keys - excluded_fields(args) + + table do |t| + t.title = "Gitlab.#{cmd} #{args.join(', ')}" + t.headings = keys + + arr.each_with_index do |hash, index| + values = [] + + keys.each do |key| + case value = hash[key] + when Hash + value = 'Hash' + when nil + value = 'null' + end + + values << value + end + + t.add_row values + t.add_separator unless arr.size - 1 == index + end + end + end + + # Helper function to call Gitlab commands with args. + def gitlab_helper(cmd, args=[]) + begin + data = args.any? ? Gitlab.send(cmd, *args) : Gitlab.send(cmd) + rescue => e + puts e.message + yield if block_given? + end + + data + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client.rb b/lib/gitlab-cli/lib/gitlab/client.rb new file mode 100644 index 000000000..a2616391f --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client.rb @@ -0,0 +1,18 @@ +module Gitlab + # Wrapper for the Gitlab REST API. + class Client < API + Dir[File.expand_path('../client/*.rb', __FILE__)].each {|f| require f} + + include Branches + include Groups + include Issues + include MergeRequests + include Milestones + include Notes + include Projects + include Repositories + include Snippets + include SystemHooks + include Users + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/branches.rb b/lib/gitlab-cli/lib/gitlab/client/branches.rb new file mode 100644 index 000000000..bbe55498b --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/branches.rb @@ -0,0 +1,79 @@ +class Gitlab::Client + # Defines methods related to repositories. + module Branches + # Gets a list of project repositiory branches. + # + # @example + # Gitlab.branches(42) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def branches(project, options={}) + get("/projects/#{project}/repository/branches", :query => options) + end + alias_method :repo_branches, :branches + + # Gets information about a repository branch. + # + # @example + # Gitlab.branch(3, 'api') + # Gitlab.repo_branch(5, 'master') + # + # @param [Integer] project The ID of a project. + # @param [String] branch The name of the branch. + # @return [Gitlab::ObjectifiedHash] + def branch(project, branch) + get("/projects/#{project}/repository/branches/#{branch}") + end + + alias_method :repo_branch, :branch + + # Protects a repository branch. + # + # @example + # Gitlab.protect_branch(3, 'api') + # Gitlab.repo_protect_branch(5, 'master') + # + # @param [Integer] project The ID of a project. + # @param [String] branch The name of the branch. + # @return [Gitlab::ObjectifiedHash] + def protect_branch(project, branch) + put("/projects/#{project}/repository/branches/#{branch}/protect") + end + alias_method :repo_protect_branch, :protect_branch + + # Unprotects a repository branch. + # + # @example + # Gitlab.unprotect_branch(3, 'api') + # Gitlab.repo_unprotect_branch(5, 'master') + # + # @param [Integer] project The ID of a project. + # @param [String] branch The name of the branch. + # @return [Gitlab::ObjectifiedHash] + def unprotect_branch(project, branch) + put("/projects/#{project}/repository/branches/#{branch}/unprotect") + end + alias_method :repo_unprotect_branch, :unprotect_branch + + # Creates a repository branch. Requires Gitlab >= 6.8.x + # + # @example + # Gitlab.create_branch(3, 'api') + # Gitlab.repo_create_branch(5, 'master') + # + # @param [Integer] project The ID of a project. + # @param [String] branch The name of the new branch. + # @param [String] ref Create branch from commit sha or existing branch + # @return [Gitlab::ObjectifiedHash] + def create_branch(project, branch, ref) + post("/projects/#{project}/repository/branches",:body => {:branch_name => branch, :ref => ref}) + end + alias_method :repo_create_branch, :create_branch + + end +end + diff --git a/lib/gitlab-cli/lib/gitlab/client/groups.rb b/lib/gitlab-cli/lib/gitlab/client/groups.rb new file mode 100644 index 000000000..66f5f5a74 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/groups.rb @@ -0,0 +1,88 @@ +class Gitlab::Client + # Defines methods related to groups. + module Groups + # Gets a list of groups. + # + # @example + # Gitlab.groups + # Gitlab.groups(:per_page => 40) + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def groups(options={}) + get("/groups", :query => options) + end + + # Gets a single group. + # + # @example + # Gitlab.group(42) + # + # @param [Integer] id The ID of a group. + # @return [Gitlab::ObjectifiedHash] + def group(id) + get("/groups/#{id}") + end + + # Creates a new group. + # + # @param [String] name The name of a group. + # @param [String] path The path of a group. + # @return [Gitlab::ObjectifiedHash] Information about created group. + def create_group(name, path) + body = {:name => name, :path => path} + post("/groups", :body => body) + end + + # Get a list of group members. + # + # @example + # Gitlab.group_members(1) + # Gitlab.group_members(1, :per_page => 40) + # + # @param [Integer] id The ID of a group. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def group_members(id, options={}) + get("/groups/#{id}/members", :query => options) + end + + # Adds a user to group. + # + # @example + # Gitlab.add_group_member(1, 2, 40) + # + # @param [Integer] team_id The group id to add a member to. + # @param [Integer] user_id The user id of the user to add to the team. + # @param [Integer] access_level Project access level. + # @return [Gitlab::ObjectifiedHash] Information about added team member. + def add_group_member(team_id, user_id, access_level) + post("/groups/#{team_id}/members", :body => {:user_id => user_id, :access_level => access_level}) + end + + # Removes user from user group. + # + # @example + # Gitlab.remove_group_member(1, 2) + # + # @param [Integer] team_id The group ID. + # @param [Integer] user_id The ID of a user. + # @return [Gitlab::ObjectifiedHash] Information about removed team member. + def remove_group_member(team_id, user_id) + delete("/groups/#{team_id}/members/#{user_id}") + end + + # Transfers a project to a group + # + # @param [Integer] id The ID of a group. + # @param [Integer] project_id The ID of a project. + def transfer_project_to_group(id, project_id) + body = {:id => id, :project_id => project_id} + post("/groups/#{id}/projects/#{project_id}", :body => body) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/issues.rb b/lib/gitlab-cli/lib/gitlab/client/issues.rb new file mode 100644 index 000000000..668953d1d --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/issues.rb @@ -0,0 +1,92 @@ +class Gitlab::Client + # Defines methods related to issues. + module Issues + # Gets a list of user's issues. + # Will return a list of project's issues if project ID passed. + # + # @example + # Gitlab.issues + # Gitlab.issues(5) + # Gitlab.issues(:per_page => 40) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def issues(project=nil, options={}) + if project.to_i.zero? + get("/issues", :query => options) + else + get("/projects/#{project}/issues", :query => options) + end + end + + # Gets a single issue. + # + # @example + # Gitlab.issue(5, 42) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] + def issue(project, id) + get("/projects/#{project}/issues/#{id}") + end + + # Creates a new issue. + # + # @param [Integer] project The ID of a project. + # @param [String] title The title of an issue. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The description of an issue. + # @option options [Integer] :assignee_id The ID of a user to assign issue. + # @option options [Integer] :milestone_id The ID of a milestone to assign issue. + # @option options [String] :labels Comma-separated label names for an issue. + # @return [Gitlab::ObjectifiedHash] Information about created issue. + def create_issue(project, title, options={}) + body = {:title => title}.merge(options) + post("/projects/#{project}/issues", :body => body) + end + + # Updates an issue. + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of an issue. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of an issue. + # @option options [String] :description The description of an issue. + # @option options [Integer] :assignee_id The ID of a user to assign issue. + # @option options [Integer] :milestone_id The ID of a milestone to assign issue. + # @option options [String] :labels Comma-separated label names for an issue. + # @option options [String] :state_event The state event of an issue ('close' or 'reopen'). + # @return [Gitlab::ObjectifiedHash] Information about updated issue. + def edit_issue(project, id, options={}) + put("/projects/#{project}/issues/#{id}", :body => options) + end + + # Closes an issue. + # + # @example + # Gitlab.close_issue(3, 42) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] Information about closed issue. + def close_issue(project, id) + put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'close'}) + end + + # Reopens an issue. + # + # @example + # Gitlab.reopen_issue(3, 42) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] Information about reopened issue. + def reopen_issue(project, id) + put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'reopen'}) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/merge_requests.rb b/lib/gitlab-cli/lib/gitlab/client/merge_requests.rb new file mode 100644 index 000000000..e15f7dfad --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/merge_requests.rb @@ -0,0 +1,135 @@ +class Gitlab::Client + # Defines methods related to merge requests. + module MergeRequests + # Gets a list of project merge requests. + # + # @example + # Gitlab.merge_requests(5) + # Gitlab.merge_requests(:per_page => 40) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def merge_requests(project, options={}) + get("/projects/#{project}/merge_requests", :query => options) + end + + # Gets a single merge request. + # + # @example + # Gitlab.merge_request(5, 36) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a merge request. + # @return 'source_branch', :target_branch => 'target_branch') + # Gitlab.create_merge_request(5, 'New merge request', + # :source_branch => 'source_branch', :target_branch => 'target_branch', :assignee_id => 42) + # + # @param [Integer] project The ID of a project. + # @param [String] title The title of a merge request. + # @param [Hash] options A customizable set of options. + # @option options [String] :source_branch (required) The source branch name. + # @option options [String] :target_branch (required) The target branch name. + # @option options [Integer] :assignee_id (optional) The ID of a user to assign merge request. + # @return [Gitlab::ObjectifiedHash] Information about created merge request. + def create_merge_request(project, title, gid, options={}) + check_attributes!(options, [:source_branch, :target_branch]) + + body = {:title => title}.merge(options) + post("/projects/#{project}/merge_requests?user_id=#{gid}", :body => body) + end + + # Updates a merge request. + # + # @example + # Gitlab.update_merge_request(5, 42, :title => 'New title') + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a merge request. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of a merge request. + # @option options [String] :source_branch The source branch name. + # @option options [String] :target_branch The target branch name. + # @option options [Integer] :assignee_id The ID of a user to assign merge request. + # @option options [String] :state_event New state (close|reopen|merge). + # @return [Gitlab::ObjectifiedHash] Information about updated merge request. + def update_merge_request(project, id, gid, options={}) + put("/projects/#{project}/merge_request/#{id}?user_id=#{gid}", :body => options) + end + + # Adds a comment to a merge request. + # + # @example + # Gitlab.create_merge_request_comment(5, 1, "Awesome merge!") + # Gitlab.create_merge_request_comment('gitlab', 1, "Awesome merge!") + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a merge request. + # @param [String] note The content of a comment. + # @return [Gitlab::ObjectifiedHash] Information about created merge request comment. + def create_merge_request_comment(project, id, note, gid) + post("/projects/#{project}/merge_request/#{id}/comments?user_id=#{gid}", :body => {:note => note}) + end + + # Get a list of merge request commits. + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - The ID of MR + def merge_request_commits(project, id) + get("/projects/#{project}/merge_request/#{id}/commits") + end + + # Shows information about the merge request including its files and changes. With GitLab 8.2 the return fields upvotes and downvotes are deprecated and always return 0. + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - The ID of MR + def merge_request_changes(project, id) + get("/projects/#{project}/merge_request/#{id}/changes") + end + + # Gets the comments on a merge request. + # + # @example + # Gitlab.merge_request_comments(5, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a merge request. + # @return [Gitlab::ObjectifiedHash] The merge request's comments. + def merge_request_comments(project, id) + get("/projects/#{project}/merge_request/#{id}/comments") + end + + # Accept a merge request. + # + # @example + # Gitlab.accept_pull_rquest(5, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a merge request. + # @return [Gitlab::ObjectifiedHash] + def accept_merge_rquest(project, id, gid) + put("/projects/#{project}/merge_request/#{id}/merge?user_id=#{gid}") + end + + private + + def check_attributes!(options, attrs) + attrs.each do |attr| + unless options.has_key?(attr) || options.has_key?(attr.to_s) + raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter") + end + end + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/milestones.rb b/lib/gitlab-cli/lib/gitlab/client/milestones.rb new file mode 100644 index 000000000..197b1f3c9 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/milestones.rb @@ -0,0 +1,57 @@ +class Gitlab::Client + # Defines methods related to milestones. + module Milestones + # Gets a list of project's milestones. + # + # @example + # Gitlab.milestones(5) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def milestones(project, options={}) + get("/projects/#{project}/milestones", :query => options) + end + + # Gets a single milestone. + # + # @example + # Gitlab.milestone(5, 36) + # + # @param [Integer, String] project The ID of a project. + # @param [Integer] id The ID of a milestone. + # @return [Gitlab::ObjectifiedHash] + def milestone(project, id) + get("/projects/#{project}/milestones/#{id}") + end + + # Creates a new milestone. + # + # @param [Integer] project The ID of a project. + # @param [String] title The title of a milestone. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The description of a milestone. + # @option options [String] :due_date The due date of a milestone. + # @return [Gitlab::ObjectifiedHash] Information about created milestone. + def create_milestone(project, title, options={}) + body = {:title => title}.merge(options) + post("/projects/#{project}/milestones", :body => body) + end + + # Updates a milestone. + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a milestone. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of a milestone. + # @option options [String] :description The description of a milestone. + # @option options [String] :due_date The due date of a milestone. + # @option options [String] :state_event The state of a milestone ('close' or 'activate'). + # @return [Gitlab::ObjectifiedHash] Information about updated milestone. + def edit_milestone(project, id, options={}) + put("/projects/#{project}/milestones/#{id}", :body => options) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/notes.rb b/lib/gitlab-cli/lib/gitlab/client/notes.rb new file mode 100644 index 000000000..9f53f4df1 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/notes.rb @@ -0,0 +1,106 @@ +class Gitlab::Client + # Defines methods related to notes. + module Notes + # Gets a list of projects notes. + # + # @example + # Gitlab.notes(5) + # + # @param [Integer] project The ID of a project. + # @return [Array] + def notes(project) + get("/projects/#{project}/notes") + end + + # Gets a list of notes for a issue. + # + # @example + # Gitlab.issue_notes(5, 10) + # + # @param [Integer] project The ID of a project. + # @param [Integer] issue The ID of an issue. + # @return [Array] + def issue_notes(project, issue) + get("/projects/#{project}/issues/#{issue}/notes") + end + + # Gets a list of notes for a snippet. + # + # @example + # Gitlab.snippet_notes(5, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] snippet The ID of a snippet. + # @return [Array] + def snippet_notes(project, snippet) + get("/projects/#{project}/snippets/#{snippet}/notes") + end + + # Gets a single wall note. + # + # @example + # Gitlab.note(5, 15) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a note. + # @return [Gitlab::ObjectifiedHash] + def note(project, id) + get("/projects/#{project}/notes/#{id}") + end + + # Gets a single issue note. + # + # @example + # Gitlab.issue_note(5, 10, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] issue The ID of an issue. + # @param [Integer] id The ID of a note. + # @return [Gitlab::ObjectifiedHash] + def issue_note(project, issue, id) + get("/projects/#{project}/issues/#{issue}/notes/#{id}") + end + + # Gets a single snippet note. + # + # @example + # Gitlab.snippet_note(5, 11, 3) + # + # @param [Integer] project The ID of a project. + # @param [Integer] snippet The ID of a snippet. + # @param [Integer] id The ID of an note. + # @return [Gitlab::ObjectifiedHash] + def snippet_note(project, snippet, id) + get("/projects/#{project}/snippets/#{snippet}/notes/#{id}") + end + + # Creates a new wall note. + # + # @param [Integer] project The ID of a project. + # @param [String] body The body of a note. + # @return [Gitlab::ObjectifiedHash] Information about created note. + def create_note(project, body) + post("/projects/#{project}/notes", :body => {:body => body}) + end + + # Creates a new issue note. + # + # @param [Integer] project The ID of a project. + # @param [Integer] issue The ID of an issue. + # @param [String] body The body of a note. + # @return [Gitlab::ObjectifiedHash] Information about created note. + def create_issue_note(project, issue, body) + post("/projects/#{project}/issues/#{issue}/notes", :body => {:body => body}) + end + + # Creates a new snippet note. + # + # @param [Integer] project The ID of a project. + # @param [Integer] snippet The ID of a snippet. + # @param [String] body The body of a note. + # @return [Gitlab::ObjectifiedHash] Information about created note. + def create_snippet_note(project, snippet, body) + post("/projects/#{project}/snippets/#{snippet}/notes", :body => {:body => body}) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/projects.rb b/lib/gitlab-cli/lib/gitlab/client/projects.rb new file mode 100644 index 000000000..4fd8851ad --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/projects.rb @@ -0,0 +1,328 @@ +class Gitlab::Client + # Defines methods related to projects. + module Projects + # Gets a list of projects owned by the authenticated user. + # + # @example + # Gitlab.projects + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @option options [String] :scope Scope of projects. 'owned' for list of projects owned by the authenticated user, 'all' to get all projects (admin only) + # @return [Array] + def projects(options={}) + if (options[:scope]) + get("/projects/#{options[:scope]}", :query => options) + else + get("/projects", :query => options) + end + end + + def current_user_project(user_id, project_name) + get("/projects/current_user_projects?user_id=#{user_id}&project_name=#{project_name}") + end + + # Gets information about a project. + # + # @example + # Gitlab.project(3) + # Gitlab.project('gitlab') + # + # @param [Integer, String] id The ID or name of a project. + # @return [Gitlab::ObjectifiedHash] + def project(id) + get("/projects/#{id}") + end + + # Gets a list of project events. + # + # @example + # Gitlab.project_events(42) + # Gitlab.project_events('gitlab') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def project_events(project, options={}) + get("/projects/#{project}/events", :query => options) + end + + # Creates a new project. + # + # @example + # Gitlab.create_project('gitlab') + # Gitlab.create_project('viking', :description => 'Awesome project') + # Gitlab.create_project('Red', :wall_enabled => false) + # + # @param [String] name The name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The description of a project. + # @option options [String] :default_branch The default branch of a project. + # @option options [String] :group_id The group in which to create a project. + # @option options [String] :namespace_id The namespace in which to create a project. + # @option options [Boolean] :wiki_enabled The wiki integration for a project (0 = false, 1 = true). + # @option options [Boolean] :wall_enabled The wall functionality for a project (0 = false, 1 = true). + # @option options [Boolean] :issues_enabled The issues integration for a project (0 = false, 1 = true). + # @option options [Boolean] :snippets_enabled The snippets integration for a project (0 = false, 1 = true). + # @option options [Boolean] :merge_requests_enabled The merge requests functionality for a project (0 = false, 1 = true). + # @option options [Boolean] :public The setting for making a project public (0 = false, 1 = true). + # @option options [Integer] :user_id The user/owner id of a project. + # @return [Gitlab::ObjectifiedHash] Information about created project. + def create_project(name, options={}) + url = options[:user_id] ? "/projects/user/#{options[:user_id]}" : "/projects" + post(url, :body => {:name => name}.merge(options)) + end + + # Updates a project team member to a specified access level. + # id (required) - The ID of a project + # name (optional) - project name + # path (optional) - repository name for project + # description (optional) - short project description + # default_branch (optional) + # issues_enabled (optional) + # merge_requests_enabled (optional) + # wiki_enabled (optional) + # snippets_enabled (optional) + # public (optional) - if true same as setting visibility_level = 20 + # visibility_level (optional) + + def edit_project(id, name, path) + put("/projects/#{id}", :body => {:name => name, :path => path}) + end + + # Deletes a project. + # + # @example + # Gitlab.delete_project(4) + # + # @param [Integer, String] id The ID or name of a project. + # @return [Gitlab::ObjectifiedHash] Information about deleted project. + def delete_project(id) + delete("/projects/#{id}") + end + + # Gets a list of project team members. + # + # @example + # Gitlab.team_members(42) + # Gitlab.team_members('gitlab') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :query The search query. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def team_members(project, options={}) + get("/projects/#{project}/members", :query => options) + end + + # Gets a project team member. + # + # @example + # Gitlab.team_member('gitlab', 2) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a project team member. + # @return [Gitlab::ObjectifiedHash] + def team_member(project, id) + get("/projects/#{project}/members/#{id}") + end + + # Adds a user to project team. + # + # @example + # Gitlab.add_team_member('gitlab', 2, 40) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a user. + # @param [Integer] access_level The access level to project. + # @param [Hash] options A customizable set of options. + # @return [Gitlab::ObjectifiedHash] Information about added team member. + def add_team_member(project, id, access_level) + post("/projects/#{project}/members", :body => {:user_id => id, :access_level => access_level}) + end + + # Updates a team member's project access level. + # + # @example + # Gitlab.edit_team_member('gitlab', 3, 20) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a user. + # @param [Integer] access_level The access level to project. + # @param [Hash] options A customizable set of options. + # @return [Array] Information about updated team member. + def edit_team_member(project, id, access_level) + put("/projects/#{project}/members/#{id}", :body => {:access_level => access_level}) + end + + # Removes a user from project team. + # + # @example + # Gitlab.remove_team_member('gitlab', 2) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a user. + # @param [Hash] options A customizable set of options. + # @return [Gitlab::ObjectifiedHash] Information about removed team member. + def remove_team_member(project, id) + delete("/projects/#{project}/members/#{id}") + end + + # Gets a list of project hooks. + # + # @example + # Gitlab.project_hooks(42) + # Gitlab.project_hooks('gitlab') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def project_hooks(project, options={}) + get("/projects/#{project}/hooks", :query => options) + end + + # Gets a project hook. + # + # @example + # Gitlab.project_hook(42, 5) + # Gitlab.project_hook('gitlab', 5) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a hook. + # @return [Gitlab::ObjectifiedHash] + def project_hook(project, id) + get("/projects/#{project}/hooks/#{id}") + end + + # Adds a new hook to the project. + # + # @example + # Gitlab.add_project_hook(42, 'https://api.example.net/v1/webhooks/ci') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] url The hook URL. + # @param [Hash] options Events list (`{push_events: true, merge_requests_events: false}`). + # @return [Gitlab::ObjectifiedHash] Information about added hook. + def add_project_hook(project, url, options = {}) + available_events = [:push_events, :merge_requests_events, :issues_events] + passed_events = available_events.select { |event| options[event] } + events = Hash[passed_events.map { |event| [event, options[event]] }] + + post("/projects/#{project}/hooks", :body => {:url => url}.merge(events)) + end + + # Updates a project hook URL. + # + # @example + # Gitlab.edit_project_hook(42, 1, 'https://api.example.net/v1/webhooks/ci') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of the hook. + # @param [String] url The hook URL. + # @return [Gitlab::ObjectifiedHash] Information about updated hook. + def edit_project_hook(project, id, url) + put("/projects/#{project}/hooks/#{id}", :body => {:url => url}) + end + + # Deletes a hook from project. + # + # @example + # Gitlab.delete_project_hook('gitlab', 4) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] id The ID of the hook. + # @return [Gitlab::ObjectifiedHash] Information about deleted hook. + def delete_project_hook(project, id) + delete("/projects/#{project}/hooks/#{id}") + end + + # Forks a project into the user namespace of the authenticated user. + # @param [Integer] - The ID of the project to be forked + def fork(gpid, gid) + post ("/projects/fork/#{gpid}?user_id=#{gid}") + # post("/projects/fork/#{id}") + end + + # Mark this project as forked from the other + # + # @example + # Gitlab.make_forked(42, 24) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of the project it is forked from. + # @return [Gitlab::ObjectifiedHash] Information about the forked project. + def make_forked_from(project, id) + post("/projects/#{project}/fork/#{id}") + end + + # Remove a forked_from relationship for a project. + # + # @example + # Gitlab.remove_forked(42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] project The ID of the project it is forked from + # @return [Gitlab::ObjectifiedHash] Information about the forked project. + def remove_forked(project) + delete("/projects/#{project}/fork") + end + + # Gets a project deploy keys. + # + # @example + # Gitlab.deploy_keys(42) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def deploy_keys(project, options={}) + get("/projects/#{project}/keys", :query => options) + end + + # Gets a single project deploy key. + # + # @example + # Gitlab.deploy_key(42, 1) + # + # @param [Integer, String] project The ID of a project. + # @param [Integer] id The ID of a deploy key. + # @return [Gitlab::ObjectifiedHash] + def deploy_key(project, id) + get("/projects/#{project}/keys/#{id}") + end + + # Creates a new deploy key. + # + # @example + # Gitlab.create_deploy_key(42, 'My Key', 'Key contents') + # + # @param [Integer] project The ID of a project. + # @param [String] title The title of a deploy key. + # @param [String] key The content of a deploy key. + # @return [Gitlab::ObjectifiedHash] Information about created deploy key. + def create_deploy_key(project, title, key) + post("/projects/#{project}/keys", body: {title: title, key: key}) + end + + # Deletes a deploy key from project. + # + # @example + # Gitlab.delete_deploy_key(42, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a deploy key. + # @return [Gitlab::ObjectifiedHash] Information about deleted deploy key. + def delete_deploy_key(project, id) + delete("/projects/#{project}/keys/#{id}") + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/repositories.rb b/lib/gitlab-cli/lib/gitlab/client/repositories.rb new file mode 100644 index 000000000..c88337f52 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/repositories.rb @@ -0,0 +1,213 @@ +class Gitlab::Client + # Defines methods related to repositories. + module Repositories + + def trees(project, options={}) + get "/projects/#{project}/repository/tree", query: options + end + alias_method :repo_trees, :trees + + def files(project, file_path, ref) + get "/projects/#{project}/repository/files", query: {file_path: file_path, ref: ref} + end + alias_method :repo_files, :files + + def file_blob(project, options={}) + get("/projects/#{project}/repository/blobs", query: options) + end + # Gets a list of project repository tags. + # + # @example + # Gitlab.tags(42) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def tags(project, options={}) + get("/projects/#{project}/repository/tags", :query => options) + end + alias_method :repo_tags, :tags + + # Creates a new project repository tag. + # + # @example + # Gitlab.create_tag(42,'new_tag','master') + # + # @param [Integer] project The ID of a project. + # @param [String] tag_name The name of the new tag. + # @param [String] ref The ref (commit sha, branch name, or another tag) the tag will point to. + # @return [Gitlab::ObjectifiedHash] + def create_tag(project, tag_name, ref) + post("/projects/#{project}/repository/tags", body: {tag_name: tag_name, ref: ref}) + end + alias_method :repo_create_tag, :create_tag + + # Gets a list of project commits. + # + # @example + # Gitlab.commits('viking') + # Gitlab.repo_commits('gitlab', :ref_name => 'api') + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :ref_name The branch or tag name of a project repository. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @option options [String] :search The obj of results's search value. + # @return [Array] + def commits(project, options={}) + get("/projects/#{project}/repository/commits", :query => options) + end + alias_method :repo_commits, :commits + + # Gets a list of project commits. + # + # @example + # Gitlab.commits('viking') + # Gitlab.repo_commits('gitlab', :ref_name => 'api') + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :ref_name The branch or tag name of a project repository. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def commits_total_count(project, options={}) + get("/projects/#{project}/repository/commits_total_count", :query => options) + end + alias_method :repo_commits, :commits_total_count + + # Gets total project commits. + # + # @example + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :rev The branch or tag name of a project repository. + # @return [Hash] + def user_static(project, options={}) + get("/projects/#{project}/repository/user_static", :query => options) + end + + def get_branch_commit_id(project, git_tree, ref_name) + get("/projects/#{project}/repository/get_branch_commit_id?git_tree=#{git_tree}&ref_name=#{ref_name}") + end + + + # Gets a specific commit identified by the commit hash or name of a branch or tag. + # + # @example + # Gitlab.commit(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + # Gitlab.repo_commit(3, 'ed899a2f4b50b4370feeea94676502b42383c746') + # + # @param [Integer] project The ID of a project. + # @param [String] sha The commit hash or name of a repository branch or tag + # @return [Gitlab::ObjectifiedHash] + def commit(project, sha) + get("/projects/#{project}/repository/commits/#{sha}") + end + alias_method :repo_commit, :commit + + # Gets a statics of project repository. + # + # @example + # Gitlab.commits('viking') + # Gitlab.repo_commits('gitlab', :ref_name => 'api') + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :ref_name The branch or tag name of a project repository. + # @option options [String] :creator The user name of a project repository. + # @option options [Integer] :period Statistics over time. 1:total 2:one month 3:one week + # @return [Array] + def rep_stats(project, options={}) + get("/projects/#{project}/repository/rep_stats", :query => options) + end + alias_method :repo_rep_stats, :rep_stats + + def rep_stats_week(project, options={}) + get("/projects/#{project}/repository/rep_stats_week", :query => options) + end + alias_method :repo_rep_stats, :rep_stats + + def rep_stats_month(project, options={}) + get("/projects/#{project}/repository/rep_stats_month", :query => options) + end + alias_method :repo_rep_stats, :rep_stats + + def rep_user_stats(project, options={}) + get("/projects/#{project}/repository/rep_user_stats", :query => options) + end + alias_method :repo_rep_stats, :rep_stats + + # static all users + def admin_rep_stats_week(project, options={}) + get("/projects/#{project}/repository/admin_rep_stats_week", :query => options) + end + alias_method :repo_rep_stats, :rep_stats + + def admin_rep_stats_month(project, options={}) + get("/projects/#{project}/repository/admin_rep_stats_month", :query => options) + end + alias_method :repo_rep_stats, :rep_stats + + def admin_rep_stats_all(project, options={}) + get("/projects/#{project}/repository/admin_rep_stats_all", :query => options) + end + alias_method :repo_rep_stats, :rep_stats + + # Gets a tree activities of project repository. + # + # @example + # Gitlab.commits('viking') + # Gitlab.repo_commits('gitlab', :ref_name => 'api') + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :ref_name The branch or tag name of a project repository. + # @option options [String] :creator The user name of a project repository. + # @option options [Integer] :period Statistics over time. 1:total 2:one month 3:one week + # @return [Array] + def rep_last_changes(project, options={}) + get("/projects/#{project}/repository/rep_last_changes", :query => options) + end + alias_method :repo_rep_stats, :rep_stats + + # Get the diff of a commit in a project. + # + # @example + # Gitlab.commit_diff(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + # Gitlab.repo_commit_diff(3, 'ed899a2f4b50b4370feeea94676502b42383c746') + # + # @param [Integer] project The ID of a project. + # @param [String] sha The name of a repository branch or tag or if not given the default branch. + # @return [Gitlab::ObjectifiedHash] + def commit_diff(project, sha) + get("/projects/#{project}/repository/commits/#{sha}/diff") + end + alias_method :repo_commit_diff, :commit_diff + + # Get the commits count of each contributor in a project + # @param [Integer] project the ID fo a project. + # @return [Gitlab::ObjectifiedHash] + def contributors(project) + get("/projects/#{project}/repository/contributors") + end + + # Get an archive of the repository + # @param [Integer] project the ID fo a project. + # sha (optional) - The commit SHA to download defaults to the tip of the default branch + # @return [Gitlab::ObjectifiedHash] + def project_archive(project, sha) + get("/projects/#{project}/repository/archive?sha=#{sha}") + end + + # update file + def edit_file(project, username, options={}) + put("/projects/#{project}/repository/files?username=#{username}", :body => options) + end + + alias_method :repo_project_archive, :project_archive + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/snippets.rb b/lib/gitlab-cli/lib/gitlab/client/snippets.rb new file mode 100644 index 000000000..aac985609 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/snippets.rb @@ -0,0 +1,86 @@ +class Gitlab::Client + # Defines methods related to snippets. + module Snippets + # Gets a list of project's snippets. + # + # @example + # Gitlab.snippets(42) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Gitlab::ObjectifiedHash] + def snippets(project, options={}) + get("/projects/#{project}/snippets", :query => options) + end + + # Gets information about a snippet. + # + # @example + # Gitlab.snippet(2, 14) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a snippet. + # @return [Gitlab::ObjectifiedHash] + def snippet(project, id) + get("/projects/#{project}/snippets/#{id}") + end + + # Creates a new snippet. + # + # @example + # Gitlab.create_snippet(42, {:title => 'REST', :file_name => 'api.rb', :code => 'some code'}) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :title (required) The title of a snippet. + # @option options [String] :file_name (required) The name of a snippet file. + # @option options [String] :code (required) The content of a snippet. + # @option options [String] :lifetime (optional) The expiration date of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about created snippet. + def create_snippet(project, options={}) + check_attributes!(options, [:title, :file_name, :code]) + post("/projects/#{project}/snippets", :body => options) + end + + # Updates a snippet. + # + # @example + # Gitlab.edit_snippet(42, 34, :file_name => 'README.txt') + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a snippet. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of a snippet. + # @option options [String] :file_name The name of a snippet file. + # @option options [String] :code The content of a snippet. + # @option options [String] :lifetime The expiration date of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about updated snippet. + def edit_snippet(project, id, options={}) + put("/projects/#{project}/snippets/#{id}", :body => options) + end + + # Deletes a snippet. + # + # @example + # Gitlab.delete_snippet(2, 14) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about deleted snippet. + def delete_snippet(project, id) + delete("/projects/#{project}/snippets/#{id}") + end + + private + + def check_attributes!(options, attrs) + attrs.each do |attr| + unless options.has_key?(attr) || options.has_key?(attr.to_s) + raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter") + end + end + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/system_hooks.rb b/lib/gitlab-cli/lib/gitlab/client/system_hooks.rb new file mode 100644 index 000000000..d8903c6de --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/system_hooks.rb @@ -0,0 +1,58 @@ +class Gitlab::Client + # Defines methods related to system hooks. + module SystemHooks + # Gets a list of system hooks. + # + # @example + # Gitlab.hooks + # Gitlab.system_hooks + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def hooks(options={}) + get("/hooks", query: options) + end + alias_method :system_hooks, :hooks + + # Adds a new system hook. + # + # @example + # Gitlab.add_hook('http://example.com/hook') + # Gitlab.add_system_hook('https://api.example.net/v1/hook') + # + # @param [String] url The hook URL. + # @return [Gitlab::ObjectifiedHash] + def add_hook(url) + post("/hooks", :body => {:url => url}) + end + alias_method :add_system_hook, :add_hook + + # Tests a system hook. + # + # @example + # Gitlab.hook(3) + # Gitlab.system_hook(12) + # + # @param [Integer] id The ID of a system hook. + # @return [Array] + def hook(id) + get("/hooks/#{id}") + end + alias_method :system_hook, :hook + + # Deletes a new system hook. + # + # @example + # Gitlab.delete_hook(3) + # Gitlab.delete_system_hook(12) + # + # @param [Integer] id The ID of a system hook. + # @return [Gitlab::ObjectifiedHash] + def delete_hook(id) + delete("/hooks/#{id}") + end + alias_method :delete_system_hook, :delete_hook + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/users.rb b/lib/gitlab-cli/lib/gitlab/client/users.rb new file mode 100644 index 000000000..6eabe097f --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/users.rb @@ -0,0 +1,131 @@ +class Gitlab::Client + # Defines methods related to users. + module Users + # Gets a list of users. + # + # @example + # Gitlab.users + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def users(options={}) + get("/users", :query => options) + end + + # Gets information about a user. + # Will return information about an authorized user if no ID passed. + # + # @example + # Gitlab.user + # Gitlab.user(2) + # + # @param [Integer] id The ID of a user. + # @return [Gitlab::ObjectifiedHash] + def user(id=nil) + id.to_i.zero? ? get("/user") : get("/users/#{id}") + end + + # Creates a new user. + # Requires authentication from an admin account. + # + # @param [String] email The email of a user. + # @param [String] password The password of a user. + # @param [Hash] options A customizable set of options. + # @option options [String] :name The name of a user. Defaults to email. + # @option options [String] :skype The skype of a user. + # @option options [String] :linkedin The linkedin of a user. + # @option options [String] :twitter The twitter of a user. + # @option options [Integer] :projects_limit The limit of projects for a user. + # @return [Gitlab::ObjectifiedHash] Information about created user. + def create_user(email, password, options={}) + body = {:email => email, :password => password, :name => email}.merge(options) + post("/users", :body => body) + end + + # Updates a user. + # + # @param [Integer] id The ID of a user. + # @param [Hash] options A customizable set of options. + # @option options [String] email The email of a user. + # @option options [String] password The password of a user. + # @option options [String] :name The name of a user. Defaults to email. + # @option options [String] :skype The skype of a user. + # @option options [String] :linkedin The linkedin of a user. + # @option options [String] :twitter The twitter of a user. + # @option options [Integer] :projects_limit The limit of projects for a user. + # @return [Gitlab::ObjectifiedHash] Information about created user. + def edit_user(user_id, options={}) + put("/users/#{user_id}", :body => options) + end + + def edit_user_email(user_id, options={}) + put("/users/#{user_id}/email", :body => options) + end + + def delete_user(user_id) + delete("/users/#{user_id}") + end + + # Creates a new user session. + # + # @example + # Gitlab.session('jack@example.com', 'secret12345') + # + # @param [String] email The email of a user. + # @param [String] password The password of a user. + # @return [Gitlab::ObjectifiedHash] + # @note This method doesn't require private_token to be set. + def session(email, password) + post("/session", :body => {:email => email, :password => password}) + end + + # Gets a list of user's SSH keys. + # + # @example + # Gitlab.ssh_keys + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def ssh_keys(options={}) + get("/user/keys", :query => options) + end + + # Gets information about SSH key. + # + # @example + # Gitlab.ssh_key(1) + # + # @param [Integer] id The ID of a user's SSH key. + # @return [Gitlab::ObjectifiedHash] + def ssh_key(id) + get("/user/keys/#{id}") + end + + # Creates a new SSH key. + # + # @example + # Gitlab.create_ssh_key('key title', 'key body') + # + # @param [String] title The title of an SSH key. + # @param [String] key The SSH key body. + # @return [Gitlab::ObjectifiedHash] Information about created SSH key. + def create_ssh_key(title, key) + post("/user/keys", :body => {:title => title, :key => key}) + end + + # Deletes an SSH key. + # + # @example + # Gitlab.delete_ssh_key(1) + # + # @param [Integer] id The ID of a user's SSH key. + # @return [Gitlab::ObjectifiedHash] Information about deleted SSH key. + def delete_ssh_key(id) + delete("/user/keys/#{id}") + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/configuration.rb b/lib/gitlab-cli/lib/gitlab/configuration.rb new file mode 100644 index 000000000..30a2d092e --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/configuration.rb @@ -0,0 +1,39 @@ +module Gitlab + # Defines constants and methods related to configuration. + module Configuration + # An array of valid keys in the options hash when configuring a Gitlab::API. + VALID_OPTIONS_KEYS = [:endpoint, :private_token, :user_agent, :sudo, :httparty].freeze + + # The user agent that will be sent to the API endpoint if none is set. + DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}".freeze + + # @private + attr_accessor(*VALID_OPTIONS_KEYS) + + # Sets all configuration options to their default values + # when this module is extended. + def self.extended(base) + base.reset + end + + # Convenience method to allow configuration options to be set in a block. + def configure + yield self + end + + # Creates a hash of options and their values. + def options + VALID_OPTIONS_KEYS.inject({}) do |option, key| + option.merge!(key => send(key)) + end + end + + # Resets all configuration options to the defaults. + def reset + self.endpoint = ENV['GITLAB_API_ENDPOINT'] + self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN'] + self.sudo = nil + self.user_agent = DEFAULT_USER_AGENT + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/error.rb b/lib/gitlab-cli/lib/gitlab/error.rb new file mode 100644 index 000000000..177d261d6 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/error.rb @@ -0,0 +1,45 @@ +module Gitlab + module Error + # Custom error class for rescuing from all Gitlab errors. + class Error < StandardError; end + + # Raise when attributes are missing. + class MissingAttributes < Error; end + + # Raised when API endpoint credentials not configured. + class MissingCredentials < Error; end + + # Raised when impossible to parse response body. + class Parsing < Error; end + + # Raised when API endpoint returns the HTTP status code 400. + class BadRequest < Error; end + + # Raised when API endpoint returns the HTTP status code 401. + class Unauthorized < Error; end + + # Raised when API endpoint returns the HTTP status code 403. + class Forbidden < Error; end + + # Raised when API endpoint returns the HTTP status code 404. + class NotFound < Error; end + + # Raised when API endpoint returns the HTTP status code 405. + class MethodNotAllowed < Error; end + + # Raised when API endpoint returns the HTTP status code 406. + class DataNotAccepted < Error; end + + # Raised when API endpoint returns the HTTP status code 409. + class Conflict < Error; end + + # Raised when API endpoint returns the HTTP status code 500. + class InternalServerError < Error; end + + # Raised when API endpoint returns the HTTP status code 502. + class BadGateway < Error; end + + # Raised when API endpoint returns the HTTP status code 503. + class ServiceUnavailable < Error; end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/help.rb b/lib/gitlab-cli/lib/gitlab/help.rb new file mode 100644 index 000000000..ccd2f2ffc --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/help.rb @@ -0,0 +1,44 @@ +require 'gitlab' +require 'gitlab/cli_helpers' + +module Gitlab::Help + extend Gitlab::CLI::Helpers + + def self.get_help(methods,cmd=nil) + help = '' + + if cmd.nil? || cmd == 'help' + help = actions_table + else + ri_cmd = `which ri`.chomp + + if $? == 0 + namespace = methods.select {|m| m[:name] === cmd }.map {|m| m[:owner]+'.'+m[:name] }.shift + + if namespace + begin + ri_output = `#{ri_cmd} -T #{namespace} 2>&1`.chomp + + if $? == 0 + ri_output.gsub!(/#{cmd}\((.*?)\)/, cmd+' \1') + ri_output.gsub!(/Gitlab\./, 'gitlab> ') + ri_output.gsub!(/Gitlab\..+$/, '') + ri_output.gsub!(/\,\s?/, ' ') + help = ri_output + else + help = "Ri docs not found for #{namespace}, please install the docs to use 'help'" + end + rescue => e + puts e.message + end + else + help = "Unknown command: #{cmd}" + end + else + help = "'ri' tool not found in your PATH, please install it to use the help." + end + end + + puts help + end +end diff --git a/lib/gitlab-cli/lib/gitlab/objectified_hash.rb b/lib/gitlab-cli/lib/gitlab/objectified_hash.rb new file mode 100644 index 000000000..11436da93 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/objectified_hash.rb @@ -0,0 +1,24 @@ +module Gitlab + # Converts hashes to the objects. + class ObjectifiedHash + # Creates a new ObjectifiedHash object. + def initialize(hash) + @hash = hash + @data = hash.inject({}) do |data, (key,value)| + value = ObjectifiedHash.new(value) if value.is_a? Hash + data[key.to_s] = value + data + end + end + + def to_hash + @hash + end + alias_method :to_h, :to_hash + + # Delegate to ObjectifiedHash. + def method_missing(key) + @data.key?(key.to_s) ? @data[key.to_s] : nil + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/request.rb b/lib/gitlab-cli/lib/gitlab/request.rb new file mode 100644 index 000000000..49c6ef8ef --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/request.rb @@ -0,0 +1,116 @@ +require 'httparty' +require 'json' + +module Gitlab + # @private + class Request + include HTTParty + format :json + headers 'Accept' => 'application/json' + parser Proc.new { |body, _| parse(body) } + + attr_accessor :private_token + + # Converts the response body to an ObjectifiedHash. + def self.parse(body) + body = decode(body) + + if body.is_a? Hash + ObjectifiedHash.new body + elsif body.is_a? Array + body.collect! { |e| ObjectifiedHash.new(e) } + elsif body == true + body + else + raise Error::Parsing.new "Couldn't parse a response body" + end + end + + # Decodes a JSON response into Ruby object. + def self.decode(response) + begin + JSON.load response + rescue JSON::ParserError + raise Error::Parsing.new "The response is not a valid JSON" + end + end + + def get(path, options={}) + set_httparty_config(options) + set_private_token_header(options) + validate self.class.get(path, options) + end + + def post(path, options={}) + set_httparty_config(options) + set_private_token_header(options, path) + validate self.class.post(path, options) + end + + def put(path, options={}) + set_httparty_config(options) + set_private_token_header(options) + validate self.class.put(path, options) + end + + def delete(path, options={}) + set_httparty_config(options) + set_private_token_header(options) + validate self.class.delete(path, options) + end + + # Checks the response code for common errors. + # Returns parsed response for successful requests. + def validate(response) + # case response.code + # when 400; raise Error::BadRequest.new error_message(response) + # when 401; raise Error::Unauthorized.new error_message(response) + # when 403; raise Error::Forbidden.new error_message(response) + # when 404; raise Error::NotFound.new error_message(response) + # when 405; raise Error::MethodNotAllowed.new error_message(response) + # when 406; raise Error::DataNotAccepted.new error_message(response) + # when 409; raise Error::Conflict.new error_message(response) + # when 500; raise Error::InternalServerError.new error_message(response) + # when 502; raise Error::BadGateway.new error_message(response) + # when 503; raise Error::ServiceUnavailable.new error_message(response) + # end + + response.parsed_response + end + + # Sets a base_uri and default_params for requests. + # @raise [Error::MissingCredentials] if endpoint not set. + def set_request_defaults(endpoint, private_token, sudo=nil) + raise Error::MissingCredentials.new("Please set an endpoint to API") unless endpoint + @private_token = private_token + + self.class.base_uri endpoint + self.class.default_params :sudo => sudo + self.class.default_params.delete(:sudo) if sudo.nil? + end + + private + + # Sets a PRIVATE-TOKEN header for requests. + # @raise [Error::MissingCredentials] if private_token not set. + def set_private_token_header(options, path=nil) + unless path == '/session' + raise Error::MissingCredentials.new("Please set a private_token for user") unless @private_token + options[:headers] = {'PRIVATE-TOKEN' => @private_token} + end + end + + # Set HTTParty configuration + # @see https://github.com/jnunemaker/httparty + def set_httparty_config(options) + if self.httparty + options.merge!(self.httparty) + end + end + + def error_message(response) + "Server responded with code #{response.code}, message: #{response.parsed_response.message}. " \ + "Request URI: #{response.request.base_uri}#{response.request.path}" + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/shell.rb b/lib/gitlab-cli/lib/gitlab/shell.rb new file mode 100644 index 000000000..58925b649 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/shell.rb @@ -0,0 +1,51 @@ +require 'gitlab' +require 'gitlab/help' +require 'gitlab/cli_helpers' +require 'readline' + +class Gitlab::Shell + extend Gitlab::CLI::Helpers + + def self.start + actions = Gitlab.actions + + comp = proc { |s| actions.map(&:to_s).grep(/^#{Regexp.escape(s)}/) } + + Readline.completion_proc = comp + Readline.completion_append_character = ' ' + + client = Gitlab::Client.new(endpoint: '') + + while buf = Readline.readline('gitlab> ', true) + next if buf.nil? || buf.empty? + break if buf == 'exit' + + buf = buf.scan(/["][^"]+["]|\S+/).map { |word| word.gsub(/^['"]|['"]$/,'') } + cmd = buf.shift + args = buf.count > 0 ? buf : [] + + if cmd == 'help' + methods = [] + + actions.each do |action| + methods << { + name: action.to_s, + owner: client.method(action).owner.to_s + } + end + + args[0].nil? ? Gitlab::Help.get_help(methods) : Gitlab::Help.get_help(methods, args[0]) + next + end + + data = if actions.include?(cmd.to_sym) + confirm_command(cmd) + gitlab_helper(cmd, args) + else + "'#{cmd}' is not a valid command. See the 'help' for a list of valid commands." + end + + output_table(cmd, args, data) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/version.rb b/lib/gitlab-cli/lib/gitlab/version.rb new file mode 100644 index 000000000..a1783b69e --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/version.rb @@ -0,0 +1,3 @@ +module Gitlab + VERSION = "3.2.0" +end diff --git a/lib/gitlab-cli/spec/fixtures/branch.json b/lib/gitlab-cli/spec/fixtures/branch.json new file mode 100644 index 000000000..8756f9f65 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/branch.json @@ -0,0 +1 @@ +{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected": true} diff --git a/lib/gitlab-cli/spec/fixtures/branches.json b/lib/gitlab-cli/spec/fixtures/branches.json new file mode 100644 index 000000000..94aa47570 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/branches.json @@ -0,0 +1 @@ +[{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"}},{"name":"dashboard-feed","commit":{"id":"f8f6ff065eccc6ede4d35ed87a09bb962b84ca25","parents":[{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e"}],"tree":"e17f2157143d550891d4669c10b7446e4739bc6d","message":"add projects atom feed","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-31T23:42:02-07:00","committed_date":"2012-05-31T23:42:02-07:00"}},{"name":"master","commit":{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e","parents":[{"id":"af226ae9c9af406c8a0e0bbdf364563495c2f432"},{"id":"e851cb07762aa464aae10e8b4b28de87c1a6f925"}],"tree":"6c6845838039f01723d91f395a1d2fa1dcc82522","message":"Merge pull request #868 from SaitoWu/bugfix/encoding\n\nBugfix/encoding","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-05-30T00:24:43-07:00","committed_date":"2012-05-30T00:24:43-07:00"}},{"name":"preview_notes","commit":{"id":"3749e0d99ac6bfbc65889b1b7a5310e14e7fe89a","parents":[{"id":"2483181f2c3d4ea7d2c68147b19bc07fc3937b0c"}],"tree":"f8c56161b0d6561568f088df9961362eb1ece88b","message":"pass project_id to notes preview path","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-08-09T23:46:27-07:00","committed_date":"2012-08-09T23:46:27-07:00"}},{"name":"refactoring","commit":{"id":"7c7761099cae83f59fe5780340e100be890847b2","parents":[{"id":"058d80b3363dd4fc4417ca4f60f76119188a2470"}],"tree":"d7d4a94c700dc0e84ee943019213d2358a49c413","message":"fix deprecation warnings","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-29T07:16:28-07:00","committed_date":"2012-05-29T07:16:28-07:00"}}] diff --git a/lib/gitlab-cli/spec/fixtures/comment_merge_request.json b/lib/gitlab-cli/spec/fixtures/comment_merge_request.json new file mode 100644 index 000000000..742f33377 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/comment_merge_request.json @@ -0,0 +1 @@ +{"note":"Cool Merge Request!","author":{"id":1,"username":"jsmith","email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-07-11T01:32:18Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/create_branch.json b/lib/gitlab-cli/spec/fixtures/create_branch.json new file mode 100644 index 000000000..a24df91a2 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/create_branch.json @@ -0,0 +1 @@ +{"name":"api","commit":{ "id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","message":"API: expose issues project id","parent_ids":["949b1df930bedace1dbd755aaa4a82e8c451a616"],"authored_date":"2012-07-25T04:22:21-07:00","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","committed_date":"2012-07-25T04:22:21-07:00","committer_name":"Nihad Abbasov","committer_email":"narkoz.2008@gmail.com"},"protected": false} diff --git a/lib/gitlab-cli/spec/fixtures/create_merge_request.json b/lib/gitlab-cli/spec/fixtures/create_merge_request.json new file mode 100644 index 000000000..c27435168 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/create_merge_request.json @@ -0,0 +1 @@ +{"id":2,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/error_already_exists.json b/lib/gitlab-cli/spec/fixtures/error_already_exists.json new file mode 100644 index 000000000..d1070f560 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/error_already_exists.json @@ -0,0 +1 @@ +{"message": "409 Already exists"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group.json b/lib/gitlab-cli/spec/fixtures/group.json new file mode 100644 index 000000000..16620ad6b --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group.json @@ -0,0 +1,60 @@ +{"id": 10, "name": "GitLab-Group", "path": "gitlab-group", "owner_id": 6, "projects": [ + { + "id": 9, + "name": "mojito", + "description": null, + "default_branch": "master", + "owner": { + "id": 6, + "username": "jose", + "email": "jose@abc.com", + "name": "Jose Jose", + "blocked": false, + "created_at": "2013-02-06T06:54:06Z" + }, + "path": "mojito", + "path_with_namespace": "gitlab-group/mojito", + "issues_enabled": true, + "merge_requests_enabled": true, + "wall_enabled": true, + "wiki_enabled": true, + "created_at": "2013-02-06T16:59:15Z", + "namespace": { + "created_at": "2013-02-06T16:58:22Z", + "id": 10, + "name": "GitLab-Group", + "owner_id": 6, + "path": "gitlab-group", + "updated_at": "2013-02-06T16:58:22Z" + } + }, + { + "id": 10, + "name": "gitlabhq", + "description": null, + "default_branch": null, + "owner": { + "id": 6, + "username": "randx", + "email": "randx@github.com", + "name": "Dmitry Z", + "blocked": false, + "created_at": "2013-02-06T06:54:06Z" + }, + "path": "gitlabhq", + "path_with_namespace": "gitlab-group/gitlabhq", + "issues_enabled": true, + "merge_requests_enabled": true, + "wall_enabled": true, + "wiki_enabled": true, + "created_at": "2013-02-06T17:02:31Z", + "namespace": { + "created_at": "2013-02-06T16:58:22Z", + "id": 10, + "name": "GitLab-Group", + "owner_id": 6, + "path": "gitlab-group", + "updated_at": "2013-02-06T16:58:22Z" + } + } +]} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_create.json b/lib/gitlab-cli/spec/fixtures/group_create.json new file mode 100644 index 000000000..67445f68b --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group_create.json @@ -0,0 +1 @@ +{"id":3,"name":"Gitlab-Group","path":"gitlab-group","owner_id":1} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_member.json b/lib/gitlab-cli/spec/fixtures/group_member.json new file mode 100644 index 000000000..feef54322 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group_member.json @@ -0,0 +1 @@ +{"id":2,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-09-04T18:15:30Z","access_level":10} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_member_delete.json b/lib/gitlab-cli/spec/fixtures/group_member_delete.json new file mode 100644 index 000000000..ff052edf6 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group_member_delete.json @@ -0,0 +1 @@ +{"created_at":"2013-09-04T18:18:15Z","group_access":10,"group_id":3,"id":2,"notification_level":3,"updated_at":"2013-09-04T18:18:15Z","user_id":2} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_members.json b/lib/gitlab-cli/spec/fixtures/group_members.json new file mode 100644 index 000000000..02ddc1089 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group_members.json @@ -0,0 +1 @@ +[{"id":1,"username":"eraymond","email":"eraymond@local.host","name":"Edward Raymond","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50},{"id":1,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/groups.json b/lib/gitlab-cli/spec/fixtures/groups.json new file mode 100644 index 000000000..5811774aa --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/groups.json @@ -0,0 +1,2 @@ +[{"id": 3,"name": "ThreeGroup","path": "threegroup","owner_id": 1},{"id": 5,"name": "Five-Group","path": "five-group","owner_id": 2},{"id": 8,"name": "Eight Group","path": "eight-group","owner_id": 6} +] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/issue.json b/lib/gitlab-cli/spec/fixtures/issue.json new file mode 100644 index 000000000..9f70318a7 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/issue.json @@ -0,0 +1 @@ +{"id":33,"project_id":3,"title":"Beatae possimus nostrum nihil reiciendis laboriosam nihil delectus alias accusantium dolor unde.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/issues.json b/lib/gitlab-cli/spec/fixtures/issues.json new file mode 100644 index 000000000..62e4cadd2 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/issues.json @@ -0,0 +1 @@ +[{"id":1,"project_id":1,"title":"Culpa eius recusandae suscipit autem distinctio dolorum.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":6,"project_id":2,"title":"Ut in dolorum omnis sed sit aliquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":12,"project_id":3,"title":"Veniam et tempore quidem eum reprehenderit cupiditate non aut velit eaque.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":21,"project_id":1,"title":"Vitae ea aliquam et quo eligendi sapiente voluptatum labore hic nihil culpa.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":26,"project_id":2,"title":"Quo enim est nihil atque placeat voluptas neque eos voluptas.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":32,"project_id":3,"title":"Deserunt tenetur impedit est beatae voluptas voluptas quaerat quisquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/key.json b/lib/gitlab-cli/spec/fixtures/key.json new file mode 100644 index 000000000..cd21098ce --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/key.json @@ -0,0 +1 @@ +{"id":1,"title":"narkoz@helium","key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkUsh42Nh1yefGd1jbSELn5XsY8p5Oxmau0/1HqHnjuYOaj5X+kHccFDwtmtg9Ox8ua/+WptNsiE8IUwsD3zKgEjajgwq3gMeeFdxfXwM+tEvHOOMV9meRrgRWGYCToPbT6sR7/YMAYa7cPqWSpx/oZhYfz4XtoMv3ZZT1fZMmx3MY3HwXwW8j+obJyN2K4LN0TFi9RPgWWYn0DCyb9OccmABimt3i74WoJ/OT8r6/7swce8+OSe0Q2wBhyTtvxg2vtUcoek8Af+EZaUMBwSEzEsocOCzwQvjF5XUk5o7dJ8nP8W3RE60JWX57t16eQm7lBmumLYfszpn2isd6W7a1 narkoz@helium"} diff --git a/lib/gitlab-cli/spec/fixtures/keys.json b/lib/gitlab-cli/spec/fixtures/keys.json new file mode 100644 index 000000000..db3bbea83 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/keys.json @@ -0,0 +1 @@ +[{"id":1,"title":"narkoz@helium","key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkUsh42Nh1yefGd1jbSELn5XsY8p5Oxmau0/1HqHnjuYOaj5X+kHccFDwtmtg9Ox8ua/+WptNsiE8IUwsD3zKgEjajgwq3gMeeFdxfXwM+tEvHOOMV9meRrgRWGYCToPbT6sR7/YMAYa7cPqWSpx/oZhYfz4XtoMv3ZZT1fZMmx3MY3HwXwW8j+obJyN2K4LN0TFi9RPgWWYn0DCyb9OccmABimt3i74WoJ/OT8r6/7swce8+OSe0Q2wBhyTtvxg2vtUcoek8Af+EZaUMBwSEzEsocOCzwQvjF5XUk5o7dJ8nP8W3RE60JWX57t16eQm7lBmumLYfszpn2isd6W7a1 narkoz@helium"}] diff --git a/lib/gitlab-cli/spec/fixtures/merge_request.json b/lib/gitlab-cli/spec/fixtures/merge_request.json new file mode 100644 index 000000000..5278f4664 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/merge_request.json @@ -0,0 +1 @@ +{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/merge_request_comments.json b/lib/gitlab-cli/spec/fixtures/merge_request_comments.json new file mode 100644 index 000000000..4e507668a --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/merge_request_comments.json @@ -0,0 +1 @@ +[{"note":"this is the 1st comment on the 2merge merge request","author":{"id":11,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}},{"note":"another discussion point on the 2merge request","author":{"id":12,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}}] diff --git a/lib/gitlab-cli/spec/fixtures/merge_requests.json b/lib/gitlab-cli/spec/fixtures/merge_requests.json new file mode 100644 index 000000000..33153c0cf --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/merge_requests.json @@ -0,0 +1 @@ +[{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}}] diff --git a/lib/gitlab-cli/spec/fixtures/milestone.json b/lib/gitlab-cli/spec/fixtures/milestone.json new file mode 100644 index 000000000..94ea3d360 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/milestone.json @@ -0,0 +1 @@ +{"id":1,"project_id":3,"title":"3.0","description":"","due_date":"2012-10-22","closed":false,"updated_at":"2012-09-17T10:15:31Z","created_at":"2012-09-17T10:15:31Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/milestones.json b/lib/gitlab-cli/spec/fixtures/milestones.json new file mode 100644 index 000000000..f9e309af6 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/milestones.json @@ -0,0 +1 @@ +[{"id":1,"project_id":3,"title":"3.0","description":"","due_date":"2012-10-22","closed":false,"updated_at":"2012-09-17T10:15:31Z","created_at":"2012-09-17T10:15:31Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/note.json b/lib/gitlab-cli/spec/fixtures/note.json new file mode 100644 index 000000000..9cff90727 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/note.json @@ -0,0 +1 @@ +{"id":1201,"body":"The solution is rather tricky","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"created_at":"2012-11-27T19:16:44Z"} diff --git a/lib/gitlab-cli/spec/fixtures/notes.json b/lib/gitlab-cli/spec/fixtures/notes.json new file mode 100644 index 000000000..e8fa27bf7 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/notes.json @@ -0,0 +1 @@ +[{"id":1201,"body":"The solution is rather tricky","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"created_at":"2012-11-27T19:16:44Z"},{"id":1207,"body":"I know, right?","author":{"id":1,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"created_at":"2012-11-27T19:58:21Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/project.json b/lib/gitlab-cli/spec/fixtures/project.json new file mode 100644 index 000000000..1f4f96028 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project.json @@ -0,0 +1 @@ +{"id":3,"code":"gitlab","name":"Gitlab","description":null,"path":"gitlab","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"public":false,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:58Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_commit.json b/lib/gitlab-cli/spec/fixtures/project_commit.json new file mode 100644 index 000000000..ab29f6b7d --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_commit.json @@ -0,0 +1,13 @@ +{ + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "dmitriy.zaporozhets@gmail.com", + "created_at": "2012-09-20T09:06:12+03:00", + "committed_date": "2012-09-20T09:06:12+03:00", + "authored_date": "2012-09-20T09:06:12+03:00", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ] +} diff --git a/lib/gitlab-cli/spec/fixtures/project_commit_diff.json b/lib/gitlab-cli/spec/fixtures/project_commit_diff.json new file mode 100644 index 000000000..1c3ce0173 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_commit_diff.json @@ -0,0 +1,10 @@ +{ + "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files", + "new_path": "doc/update/5.4-to-6.0.md", + "old_path": "doc/update/5.4-to-6.0.md", + "a_mode": null, + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false +} diff --git a/lib/gitlab-cli/spec/fixtures/project_commits.json b/lib/gitlab-cli/spec/fixtures/project_commits.json new file mode 100644 index 000000000..58cb5020d --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_commits.json @@ -0,0 +1 @@ +[{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","short_id":"f7dd067490f","title":"API: expose issues project id","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T04:22:21-07:00"},{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616","short_id":"949b1df930b","title":"API: update docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T02:35:41-07:00"},{"id":"1b95c8bff351f6718ec31ac1de1e48c57bc95d44","short_id":"1b95c8bff35","title":"API: ability to get project by id","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T02:18:30-07:00"},{"id":"92d98f5a0c28bffd7b070cda190b07ab72667d58","short_id":"92d98f5a0c2","title":"Merge pull request #1118 from patthoyts/pt/ldap-missing-password","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:51:06-07:00"},{"id":"60d3e94874964a626f105d3598e1c122addcf43e","short_id":"60d3e948749","title":"Merge pull request #1122 from patthoyts/pt/missing-log","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:50:34-07:00"},{"id":"b683a71aa1230f17f9df47661c77dfeae27027de","short_id":"b683a71aa12","title":"Merge pull request #1135 from NARKOZ/api","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:48:00-07:00"},{"id":"fbb41100db35cf2def2c8b4d896b7015d56bd15b","short_id":"fbb41100db3","title":"update help section with issues API docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:52:43-07:00"},{"id":"eca823c1c7cef45cc18c6ab36d2327650c85bfc3","short_id":"eca823c1c7c","title":"Merge branch 'master' into api","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:46:36-07:00"},{"id":"024e0348904179a8dea81c01e27a5f014cf57499","short_id":"024e0348904","title":"update API docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:25:01-07:00"},{"id":"7b33d8cbcab3b0ee5789ec607455ab62130db69f","short_id":"7b33d8cbcab","title":"add issues API","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:19:51-07:00"},{"id":"6035ad7e1fe519d0c6a42731790183889e3ba31d","short_id":"6035ad7e1fe","title":"Create the githost.log file if necessary.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-21T07:32:04-07:00"},{"id":"a2d244ec062f3348f6cd1c5218c6097402c5f562","short_id":"a2d244ec062","title":"Handle LDAP missing credentials error with a flash message.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-21T01:04:05-07:00"},{"id":"8b7e404b5b6944e9c92cc270b2e5d0005781d49d","short_id":"8b7e404b5b6","title":"Up to 2.7.0","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:53:55-07:00"},{"id":"11721b0dbe82c35789be3e4fa8e14663934b2ff5","short_id":"11721b0dbe8","title":"Help section for system hooks completed","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:47:57-07:00"},{"id":"9c8a1e651716212cf50a623d98e03b8dbdb2c64a","short_id":"9c8a1e65171","title":"Fix system hook example","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:32:42-07:00"},{"id":"4261acda90ff4c61326d80cba026ae76e8551f8f","short_id":"4261acda90f","title":"move SSH keys tab closer to begining","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:27:09-07:00"},{"id":"a69fc5dd23bd502fd36892a80eec21a4c53891f8","short_id":"a69fc5dd23b","title":"Endless event loading for dsahboard","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:23:05-07:00"},{"id":"860fa1163a5fbdfec2bb01ff2d584351554dee29","short_id":"860fa1163a5","title":"Merge pull request #1117 from patthoyts/pt/user-form","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-20T14:23:49-07:00"},{"id":"787e5e94acf5e20280416c9fda105ef5b77576b3","short_id":"787e5e94acf","title":"Fix english on the edit user form.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-20T14:18:42-07:00"},{"id":"9267cb04b0b3fdf127899c4b7e636dc27fac06d3","short_id":"9267cb04b0b","title":"Merge branch 'refactoring_controllers' of dev.gitlabhq.com:gitlabhq","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-20T07:24:56-07:00"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_delete_key.json b/lib/gitlab-cli/spec/fixtures/project_delete_key.json new file mode 100644 index 000000000..9ff868332 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_delete_key.json @@ -0,0 +1,8 @@ +{ + "created_at": "2013-10-05T15:05:26Z", + "fingerprint": "5c:b5:e6:b0:f5:31:65:3f:a6:b5:59:86:32:cc:15:e1", + "id": 2, + "key": "ssh-rsa ...", + "updated_at": "2013-10-05T15:05:26Z", + "user_id": null +} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_events.json b/lib/gitlab-cli/spec/fixtures/project_events.json new file mode 100644 index 000000000..e9fa22fe4 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_events.json @@ -0,0 +1 @@ +[{"title":null,"project_id":2,"action_name":"opened","target_id":null,"target_type":null,"author_id":1,"data":{"before":"ac0c1aa3898d6dea54d7868ea6f9c45fd5e30c59","after":"66350dbb62a221bc619b665aef3e1e7d3b306747","ref":"refs/heads/master","user_id":1,"user_name":"Administrator","project_id":2,"repository":{"name":"gitlab-ci","url":"git@demo.gitlab.com:gitlab/gitlab-ci.git","description":"Continuous integration server for gitlabhq | Coordinator","homepage":"http://demo.gitlab.com/gitlab/gitlab-ci"},"commits":[{"id":"8cf469b039931bab37bbf025e6b69287ea3cfb0e","message":"Modify screenshot\n\nSigned-off-by: Dmitriy Zaporozhets \u003Cdummy@gmail.com\u003E","timestamp":"2014-05-20T10:34:27+00:00","url":"http://demo.gitlab.com/gitlab/gitlab-ci/commit/8cf469b039931bab37bbf025e6b69287ea3cfb0e","author":{"name":"Dummy","email":"dummy@gmail.com"}},{"id":"66350dbb62a221bc619b665aef3e1e7d3b306747","message":"Edit some code\n\nSigned-off-by: Dmitriy Zaporozhets \u003Cdummy@gmail.com\u003E","timestamp":"2014-05-20T10:35:15+00:00","url":"http://demo.gitlab.com/gitlab/gitlab-ci/commit/66350dbb62a221bc619b665aef3e1e7d3b306747","author":{"name":"Dummy","email":"dummy@gmail.com"}}],"total_commits_count":2},"target_title":null,"created_at":"2014-05-20T10:35:26.240Z"},{"title":null,"project_id":2,"action_name":"opened","target_id":2,"target_type":"MergeRequest","author_id":1,"data":null,"target_title":" Morbi et cursus leo. Sed eget vestibulum sapien","created_at":"2014-05-20T10:24:11.917Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/project_for_user.json b/lib/gitlab-cli/spec/fixtures/project_for_user.json new file mode 100644 index 000000000..5ffc888f4 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_for_user.json @@ -0,0 +1 @@ +{"id":1,"code":"brute","name":"Brute","description":null,"path":"brute","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Owner","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:56Z"} diff --git a/lib/gitlab-cli/spec/fixtures/project_fork_link.json b/lib/gitlab-cli/spec/fixtures/project_fork_link.json new file mode 100644 index 000000000..f1490dfa7 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_fork_link.json @@ -0,0 +1 @@ +{"created_at":"2013-07-03T13:51:48Z","forked_from_project_id":24,"forked_to_project_id":42,"id":1,"updated_at":"2013-07-03T13:51:48Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_hook.json b/lib/gitlab-cli/spec/fixtures/project_hook.json new file mode 100644 index 000000000..323741cf3 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_hook.json @@ -0,0 +1 @@ +{"id":1,"url":"https://api.example.net/v1/webhooks/ci"} diff --git a/lib/gitlab-cli/spec/fixtures/project_hooks.json b/lib/gitlab-cli/spec/fixtures/project_hooks.json new file mode 100644 index 000000000..e70d4122c --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_hooks.json @@ -0,0 +1 @@ +[{"id":1,"url":"https://api.example.net/v1/webhooks/ci"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_issues.json b/lib/gitlab-cli/spec/fixtures/project_issues.json new file mode 100644 index 000000000..87fb2fb18 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_issues.json @@ -0,0 +1 @@ +[{"id":36,"project_id":3,"title":"Eos ut modi et laudantium quasi porro voluptas sed.","description":null,"labels":[],"milestone":null,"assignee":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":35,"project_id":3,"title":"Ducimus illo in iure voluptatem dolores labore.","description":null,"labels":[],"milestone":null,"assignee":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":34,"project_id":3,"title":"Rem tempora voluptatum atque eum sit nihil neque.","description":null,"labels":[],"milestone":null,"assignee":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":33,"project_id":3,"title":"Beatae possimus nostrum nihil reiciendis laboriosam nihil delectus alias accusantium dolor unde.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":32,"project_id":3,"title":"Deserunt tenetur impedit est beatae voluptas voluptas quaerat quisquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":16,"project_id":3,"title":"Numquam earum aut laudantium reprehenderit voluptatem aut.","description":null,"labels":[],"milestone":null,"assignee":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":15,"project_id":3,"title":"Qui veritatis voluptas fuga voluptate voluptas cupiditate.","description":null,"labels":[],"milestone":null,"assignee":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":14,"project_id":3,"title":"In assumenda et ipsa qui debitis voluptatem incidunt.","description":null,"labels":[],"milestone":null,"assignee":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":13,"project_id":3,"title":"Illo eveniet consequatur enim iste provident facilis rerum voluptatem et architecto aut.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":12,"project_id":3,"title":"Veniam et tempore quidem eum reprehenderit cupiditate non aut velit eaque.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_key.json b/lib/gitlab-cli/spec/fixtures/project_key.json new file mode 100644 index 000000000..6dd70d23e --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_key.json @@ -0,0 +1,6 @@ +{ + "id": 2, + "title": "Key Title", + "key": "ssh-rsa ...", + "created_at": "2013-09-22T18:34:32Z" +} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_keys.json b/lib/gitlab-cli/spec/fixtures/project_keys.json new file mode 100644 index 000000000..0a3869d3a --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_keys.json @@ -0,0 +1,6 @@ +[{ + "id": 2, + "title": "Key Title", + "key": "ssh-rsa ...", + "created_at": "2013-09-22T18:34:32Z" +}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_tags.json b/lib/gitlab-cli/spec/fixtures/project_tags.json new file mode 100644 index 000000000..1e2fb96cb --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_tags.json @@ -0,0 +1 @@ +[{"name":"v2.8.2","commit":{"id":"a502f67c0b358cc6b391df0c5dca48375c21fcad","parents":[{"id":"4381084af341684240b1a671d368511afcf5774a"}],"tree":"1612068bdd20de5d14b3096cfa4c621e2051ed4c","message":"Up to 2.8.2","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-24T02:03:48-07:00","committed_date":"2012-08-24T02:03:48-07:00"}},{"name":"v2.8.1","commit":{"id":"ed2b53cd1c34c421b23208eeb502a141a6829f9d","parents":[{"id":"7ab587a47791e371f5c109c14097a5d1d7776ea5"}],"tree":"b7393b0b33b777583b285e85b423c4e5ab7f859f","message":"Up to 2.8.1","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-22T23:17:18-07:00","committed_date":"2012-08-22T23:17:18-07:00"}},{"name":"v2.8.0pre","commit":{"id":"b2c6ba97a25d299e83c51493d7bc770c13b8ed1a","parents":[{"id":"05da3801f53f06fdc529b4f3820af1380039f245"},{"id":"66399d558da45fb9cd3ea972a47a4f7bb12bfc8d"}],"tree":"36ad53f35bce1fe3f2a4a5f840e7b1bdbfed9c82","message":"Merge pull request #1230 from tsigo/hooray_apostrophes\n\nCorrect usage of \"Can't\"","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-16T14:11:08-07:00","committed_date":"2012-08-16T14:11:08-07:00"}},{"name":"v2.8.0","commit":{"id":"5c7ed6fa26b47ac71ff6ba04720d85df6d74b200","parents":[{"id":"d1daeba1736ba145fe525ce08a91f29495a3abf1"}],"tree":"4fc230ff2dbc0e75f27321eac2976aba5a6d323d","message":"Up to 2.8","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-21T15:15:26-07:00","committed_date":"2012-08-21T15:15:26-07:00"}},{"name":"v2.7.0pre","commit":{"id":"72a571724d84d112f98a5543c971e9b3b9da1383","parents":[{"id":"3ac840ff06e0ee5b349c52b5a8c02e803a17eec3"},{"id":"990b9217d9a55e26a53d4143d4a3c89123384327"}],"tree":"64b104df5d956e21e0749dc8e70849d1989de36f","message":"Merge pull request #1096 from moregeek/show-flash-note-when-destroying-a-project\n\nshow flash notice after deletion of a project","author":{"name":"Valeriy Sizov","email":"vsv2711@gmail.com"},"committer":{"name":"Valeriy Sizov","email":"vsv2711@gmail.com"},"authored_date":"2012-07-18T05:35:42-07:00","committed_date":"2012-07-18T05:35:42-07:00"}},{"name":"v2.7.0","commit":{"id":"8b7e404b5b6944e9c92cc270b2e5d0005781d49d","parents":[{"id":"11721b0dbe82c35789be3e4fa8e14663934b2ff5"}],"tree":"89fe8c5ff58daaedea07a910cffb14b04ebcc828","message":"Up to 2.7.0","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-07-21T00:53:55-07:00","committed_date":"2012-07-21T00:53:55-07:00"}},{"name":"v2.6.3","commit":{"id":"666cdb22792dd955a286b9993d6235b4cdd68b4b","parents":[{"id":"d92446df1fdba87101c92c90b1c34eb2f1eebef4"}],"tree":"888173aa4c12a4920d318c35b950095d3505673d","message":"up to 2.6.3","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-26T09:20:47-07:00","committed_date":"2012-06-26T09:21:28-07:00"}},{"name":"v2.6.2","commit":{"id":"39fecb554f172a0c8ea00316e612e1d37efc7200","parents":[{"id":"68389588d664100590b1a6ca7eedd50860b7e9bc"}],"tree":"53accb25e0b9d038d550cf387753bde15fe4ad19","message":"Up to 2.6.2","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-22T13:50:58-07:00","committed_date":"2012-06-22T13:50:58-07:00"}},{"name":"v2.6.1","commit":{"id":"d92a22c9e627268eca697bbd9b660d8c335df953","parents":[{"id":"193804516b8b0783c850981456e947f888ff51bb"}],"tree":"4ac1b5225f597ab55372cb5e950b121d6f55e386","message":"Up to 2.6.1","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-22T12:49:03-07:00","committed_date":"2012-06-22T12:49:03-07:00"}},{"name":"v2.6.0","commit":{"id":"b32465712becfbcf83d63b1e6eff7d1483fdabea","parents":[{"id":"1903f6ade027df0f10ef96b9439495eeda07482c"}],"tree":"ffbc05fd0f1771c1602c956df9556260048c7167","message":"Up to 2.6","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-21T10:25:23-07:00","committed_date":"2012-06-21T10:25:23-07:00"}},{"name":"v2.5.0","commit":{"id":"cc8369144db2147d2956e8dd7d314e9a7dfd4fbb","parents":[{"id":"1b2068eaa91e5002d01a220c65da21dad8ccb071"}],"tree":"666a442e00689911169e8cc336c5ce60d014854c","message":"Prevent app crash in case if encoding failed","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-05-22T04:57:04-07:00","committed_date":"2012-05-22T04:57:04-07:00"}},{"name":"v2.4.2","commit":{"id":"f18339c26d673c5f8b4c19776036fd42a0de30aa","parents":[{"id":"c937d06c3c98e9ffce8ec1132203eaff6bf7b231"},{"id":"35e602f19c83585d64aa2043ed26eeb8cd7b40e2"}],"tree":"5101f0cd8e395fee1996764298a202437757e85b","message":"Merge branch 'master' of github.com:gitlabhq/gitlabhq","author":{"name":"Zevs","email":"vsv2711@gmail.com"},"committer":{"name":"Zevs","email":"vsv2711@gmail.com"},"authored_date":"2012-04-29T14:24:59-07:00","committed_date":"2012-04-29T14:24:59-07:00"}},{"name":"v2.4.1","commit":{"id":"d97a9aa4a44ff9f452144fad348fd9d7e3b48260","parents":[{"id":"21f3da23589d50038728393f0badc6255b5762ca"}],"tree":"905c33874b064778199f806749d5688e33d64be3","message":"fixed email markdown","author":{"name":"gitlabhq","email":"m@gitlabhq.com"},"committer":{"name":"gitlabhq","email":"m@gitlabhq.com"},"authored_date":"2012-04-23T05:32:56-07:00","committed_date":"2012-04-23T05:32:56-07:00"}},{"name":"v2.4.0pre","commit":{"id":"1845429268364e75bffdeb1075de8f1606e157ec","parents":[{"id":"45b18365d5f409f196a02a4e6e2b77b8ebef909b"}],"tree":"423c70246fa7ffd8804b26628fea34bdb2b22846","message":"Use try for commit prev_commit_id detection","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-04-19T13:35:35-07:00","committed_date":"2012-04-19T13:35:35-07:00"}},{"name":"v2.4.0","commit":{"id":"204c66461ed519eb0078be7e8ac8a6cb56834753","parents":[{"id":"511d07c47c9bf3a18bfa276d452c899369432a22"}],"tree":"9416c777cccf87d348f5705078e82f3f97485e19","message":"corrected exception for automerge","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-04-22T06:49:45-07:00","committed_date":"2012-04-22T06:49:45-07:00"}},{"name":"v2.3.1","commit":{"id":"fa8219e0a753e642a6f1dbdfc010d01ae8a949ee","parents":[{"id":"81da8e46f24913ccf42d3e2644962cbcbc0f9c2e"}],"tree":"5debfcd6d17f9d582aace6ac9b80db27d5c1fe36","message":"better MR list, dashboard pollished","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-22T13:57:04-07:00","committed_date":"2012-03-22T13:57:04-07:00"}},{"name":"v2.3.0pre","commit":{"id":"cadf12c60cc27c5b0b8273c1de4b190a0e88bd7d","parents":[{"id":"724ea16c348bc61cf7cb3dbe362c6f30cff1b2c7"}],"tree":"6f4c22761fd2dee405d3fbf38f9dd835bb3c8694","message":"Merged activities & projects pages","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-19T15:05:35-07:00","committed_date":"2012-03-19T15:05:35-07:00"}},{"name":"v2.3.0","commit":{"id":"b57faf9282d7df6cdd62953d474652a0ae2e6896","parents":[{"id":"cadf12c60cc27c5b0b8273c1de4b190a0e88bd7d"}],"tree":"f0d5b826df373191b4681452fc2ae4c5970cef4a","message":"Push events polished","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-20T14:59:35-07:00","committed_date":"2012-03-20T14:59:35-07:00"}},{"name":"v2.2.0pre","commit":{"id":"6a445b42003007cbb6c06f477c4d7a0b175688c1","parents":[{"id":"22f4c1908d0fc2dbce02e74ed03bf65f028d78d6"}],"tree":"9c60577833f6ca717acdebfa66140124c88e8471","message":"fixed forgot password form","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-02-20T10:37:37-08:00","committed_date":"2012-02-20T10:37:37-08:00"}},{"name":"v2.2.0","commit":{"id":"9e6d0710e927aa8ea834b8a9ae9f277be617ac7d","parents":[{"id":"8c40aab120dbc5507ab9cc8d7ad8e2519d6e9f25"},{"id":"6ea87c47f0f8a24ae031c3fff17bc913889ecd00"}],"tree":"86c831ab21236f21ffa5b97c752369612ce41b39","message":"Merge pull request #443 from CedricGatay/fix/incorrectLineNumberingInDiff\n\nIncorrect line numbering in diff","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-02-22T07:14:54-08:00","committed_date":"2012-02-22T07:14:54-08:00"}},{"name":"v2.1.0","commit":{"id":"98d6492582d232ed86525aa31ccbf280f4cbdaef","parents":[{"id":"611c5a87ab0c083a43785323b09cc47f554c3ba4"}],"tree":"1689b3cad580a18fd9b429ee0b33dac21c9f5a48","message":"removed broken migration","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-01-22T10:52:06-08:00","committed_date":"2012-01-22T10:52:06-08:00"}},{"name":"v2.0.0","commit":{"id":"9a2a8612769d472503b367fa35e99f6fb2876704","parents":[{"id":"2f7b67161952fc9ab322eba6878511b5f2dd5cf1"}],"tree":"26cdb4e66b5e664fe4bcd57d011c54c9c9c26ded","message":"Design tab for profile. Colorscheme as db value","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2011-12-20T12:47:09-08:00","committed_date":"2011-12-20T12:47:09-08:00"}},{"name":"v1.2.2","commit":{"id":"139a332293b9d8c4e5436619036e093483d8347f","parents":[{"id":"ade12da9488bea19d12505c371ead35686a1436e"}],"tree":"365d57f4df5c5dcac69b666cf6d2bfd8ef058008","message":"updated readme","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-25T14:30:51-08:00","committed_date":"2011-11-25T14:30:51-08:00"}},{"name":"v1.2.1","commit":{"id":"7ebba27db21719c0035bab65fea92a4780051c73","parents":[{"id":"b56024100d40457a998f83adae3cdc830c997cda"},{"id":"a4fbe13fce87cb6ff2a27a2574ae25bf1dad145c"}],"tree":"b121a7576af1503a96954ce9a94598a68579e053","message":"Merge branch 'master' of dev.gitlabhq.com:gitlabhq","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-22T13:15:09-08:00","committed_date":"2011-11-22T13:15:09-08:00"}},{"name":"v1.2.0pre","commit":{"id":"86829cae50857b5edf74b935380c6f68a19c2282","parents":[{"id":"a6b99319381c2d62ec4b92d64805e8de8965859e"}],"tree":"6aab9d13000584fa96fb3cb34d94f3b122bd1143","message":"fixed min height for menu","author":{"name":"gitlabhq","email":"m@gitlabhq.com"},"committer":{"name":"gitlabhq","email":"m@gitlabhq.com"},"authored_date":"2011-11-22T06:03:27-08:00","committed_date":"2011-11-22T06:03:27-08:00"}},{"name":"v1.2.0","commit":{"id":"b56024100d40457a998f83adae3cdc830c997cda","parents":[{"id":"4451b8df8ad6d4b6d79fbce77687c6c2fd37d0a9"}],"tree":"f402cbb6d54526a32b30968c98410bae97b27c8d","message":"lil style fixes","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-22T09:57:25-08:00","committed_date":"2011-11-22T09:57:25-08:00"}},{"name":"v1.1.0pre","commit":{"id":"6b030fd41d697e327d2935b406cba70b6a460504","parents":[{"id":"3a2b273316fb29d63b489906f85d9b5329377258"}],"tree":"63b1fdb2a0f135f7074f6a94da14543b8450dd71","message":"1.1pre1","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-21T10:04:41-07:00","committed_date":"2011-10-21T10:04:41-07:00"}},{"name":"v1.1.0","commit":{"id":"ba8048d71019b5aaa1f92ee5c3415bfddaa9babb","parents":[{"id":"6b030fd41d697e327d2935b406cba70b6a460504"}],"tree":"4db2b5f4f9b374dd1be3579459bc5947c225c9ba","message":"v1.1.0","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-22T06:07:26-07:00","committed_date":"2011-10-22T06:07:26-07:00"}},{"name":"v1.0.2","commit":{"id":"3a2b273316fb29d63b489906f85d9b5329377258","parents":[{"id":"757ea634665e475bf69c1ec962040a0511ee8aeb"},{"id":"c374eb80ff9fb71d37faffc15714bf98b632d3e5"}],"tree":"e0d8170e61a9468a7bb5d4e63305171ec1efa6bf","message":"Merge pull request #40 from vslinko/patch-1\n\nIncrease max key length. Some keys has comment after key string.","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2011-10-18T23:30:06-07:00","committed_date":"2011-10-18T23:30:06-07:00"}},{"name":"v1.0.1","commit":{"id":"7b5799a97998b68416f1b6233ce427135c99165a","parents":[{"id":"0541b3f3c5dcd291d144c83d9731c75ee811b4e0"},{"id":"7b67480c76db8b9a9ccdc80015cc500dc6d26892"}],"tree":"e052185e9dd72a1b1a04d59a5f9efbf3c0369601","message":"Merge branch '1x' of github.com:gitlabhq/gitlabhq into 1x","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-14T15:16:44-07:00","committed_date":"2011-10-14T15:16:44-07:00"}}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/projects.json b/lib/gitlab-cli/spec/fixtures/projects.json new file mode 100644 index 000000000..deab4c5f3 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/projects.json @@ -0,0 +1 @@ +[{"id":1,"code":"brute","name":"Brute","description":null,"path":"brute","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:56Z"},{"id":2,"code":"mozart","name":"Mozart","description":null,"path":"mozart","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:57Z"},{"id":3,"code":"gitlab","name":"Gitlab","description":null,"path":"gitlab","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:58Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/protect_branch.json b/lib/gitlab-cli/spec/fixtures/protect_branch.json new file mode 100644 index 000000000..f71ebd5d4 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/protect_branch.json @@ -0,0 +1 @@ +{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected":true} diff --git a/lib/gitlab-cli/spec/fixtures/session.json b/lib/gitlab-cli/spec/fixtures/session.json new file mode 100644 index 000000000..e4f5ba35f --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/session.json @@ -0,0 +1 @@ +{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","private_token":"qEsq1pt6HJPaNciie3MG"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/snippet.json b/lib/gitlab-cli/spec/fixtures/snippet.json new file mode 100644 index 000000000..34e9d994d --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/snippet.json @@ -0,0 +1 @@ +{"id":1,"title":"Rails Console ActionMailer","file_name":"mailer_test.rb","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"expires_at":"2012-09-24T00:00:00Z","updated_at":"2012-09-17T09:51:42Z","created_at":"2012-09-17T09:51:42Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/snippets.json b/lib/gitlab-cli/spec/fixtures/snippets.json new file mode 100644 index 000000000..106f88f3f --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/snippets.json @@ -0,0 +1 @@ +[{"id":1,"title":"Rails Console ActionMailer","file_name":"mailer_test.rb","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"expires_at":"2012-09-24T00:00:00Z","updated_at":"2012-09-17T09:51:42Z","created_at":"2012-09-17T09:51:42Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/system_hook.json b/lib/gitlab-cli/spec/fixtures/system_hook.json new file mode 100644 index 000000000..e2f485bea --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/system_hook.json @@ -0,0 +1 @@ +{"id": 3, "url": "http://example.com/hook", "created_at": "2013-10-02T10:15:31Z"} diff --git a/lib/gitlab-cli/spec/fixtures/system_hook_test.json b/lib/gitlab-cli/spec/fixtures/system_hook_test.json new file mode 100644 index 000000000..2c104c62b --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/system_hook_test.json @@ -0,0 +1 @@ +{ "event_name": "project_create", "name": "Ruby", "path": "ruby", "project_id": 1, "owner_name": "Someone", "owner_email": "example@gitlabhq.com" } diff --git a/lib/gitlab-cli/spec/fixtures/system_hooks.json b/lib/gitlab-cli/spec/fixtures/system_hooks.json new file mode 100644 index 000000000..9c529e6fa --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/system_hooks.json @@ -0,0 +1 @@ +[{"id": 3, "url": "http://example.com/hook", "created_at": "2013-10-02T10:15:31Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/tag.json b/lib/gitlab-cli/spec/fixtures/tag.json new file mode 100644 index 000000000..74584bdf0 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/tag.json @@ -0,0 +1 @@ +{"name": "v1.0.0","commit": {"id": "2695effb5807a22ff3d138d593fd856244e155e7","parents": [],"message": "Initial commit","authored_date": "2012-05-28T04:42:42-07:00","author_name": "John Smith","author email": "john@example.com","committer_name": "Jack Smith","committed_date": "2012-05-28T04:42:42-07:00","committer_email": "jack@example.com"},"protected": false} diff --git a/lib/gitlab-cli/spec/fixtures/team_member.json b/lib/gitlab-cli/spec/fixtures/team_member.json new file mode 100644 index 000000000..fd3ac3852 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/team_member.json @@ -0,0 +1 @@ +{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","access_level":40} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/team_members.json b/lib/gitlab-cli/spec/fixtures/team_members.json new file mode 100644 index 000000000..a2fe19e3b --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/team_members.json @@ -0,0 +1 @@ +[{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","access_level":40},{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":20},{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":6,"email":"faye.watsica@rohanwalter.com","name":"Ambrose Hansen","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":7,"email":"maida@walshtorp.name","name":"Alana Hahn","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":20}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/unprotect_branch.json b/lib/gitlab-cli/spec/fixtures/unprotect_branch.json new file mode 100644 index 000000000..307df4039 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/unprotect_branch.json @@ -0,0 +1 @@ +{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected":false} diff --git a/lib/gitlab-cli/spec/fixtures/update_merge_request.json b/lib/gitlab-cli/spec/fixtures/update_merge_request.json new file mode 100644 index 000000000..735819ff3 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/update_merge_request.json @@ -0,0 +1 @@ +{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"A different new feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/user.json b/lib/gitlab-cli/spec/fixtures/user.json new file mode 100644 index 000000000..4e0daca50 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/user.json @@ -0,0 +1 @@ +{"id":1,"email":"john@example.com","name":"John Smith","bio":null,"skype":"","linkedin":"","twitter":"john","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:41:56Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/users.json b/lib/gitlab-cli/spec/fixtures/users.json new file mode 100644 index 000000000..14c6388bf --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/users.json @@ -0,0 +1 @@ +[{"id":1,"email":"john@example.com","name":"John Smith","bio":null,"skype":"","linkedin":"","twitter":"john","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:41:56Z"},{"id":2,"email":"jack@example.com","name":"Jack Smith","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":6,"email":"faye.watsica@rohanwalter.com","name":"Ambrose Hansen","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":7,"email":"maida@walshtorp.name","name":"Alana Hahn","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/gitlab/cli_spec.rb b/lib/gitlab-cli/spec/gitlab/cli_spec.rb new file mode 100644 index 000000000..a23139cb1 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/cli_spec.rb @@ -0,0 +1,80 @@ +require 'spec_helper' + +describe Gitlab::CLI do + describe ".run" do + context "when command is version" do + it "should show gem version" do + output = capture_output { Gitlab::CLI.run('-v') } + expect(output).to eq("Gitlab Ruby Gem #{Gitlab::VERSION}\n") + end + end + + context "when command is info" do + it "should show environment info" do + output = capture_output { Gitlab::CLI.run('info') } + expect(output).to include("Gitlab endpoint is") + expect(output).to include("Gitlab private token is") + expect(output).to include("Ruby Version is") + expect(output).to include("Gitlab Ruby Gem") + end + end + + context "when command is help" do + it "should show available actions" do + output = capture_output { Gitlab::CLI.run('help') } + expect(output).to include('Available commands') + expect(output).to include('MergeRequests') + expect(output).to include('team_members') + end + end + + context "when command is user" do + before do + stub_get("/user", "user") + @output = capture_output { Gitlab::CLI.run('user') } + end + + it "should show executed command" do + expect(@output).to include('Gitlab.user') + end + + it "should show user data" do + expect(@output).to include('name') + expect(@output).to include('John Smith') + end + end + end + + describe ".start" do + context "when command with excluded fields" do + before do + stub_get("/user", "user") + args = ['user', '--except=id,email,name'] + @output = capture_output { Gitlab::CLI.start(args) } + end + + it "should show user data with excluded fields" do + expect(@output).to_not include('John Smith') + expect(@output).to include('bio') + expect(@output).to include('created_at') + end + end + + context "when command with required fields" do + before do + stub_get("/user", "user") + args = ['user', '--only=id,email,name'] + @output = capture_output { Gitlab::CLI.start(args) } + end + + it "should show user data with required fields" do + expect(@output).to include('id') + expect(@output).to include('name') + expect(@output).to include('email') + expect(@output).to include('John Smith') + expect(@output).to_not include('bio') + expect(@output).to_not include('created_at') + end + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/branches_spec.rb b/lib/gitlab-cli/spec/gitlab/client/branches_spec.rb new file mode 100644 index 000000000..92c6a9a27 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/branches_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :repo_branches } + it { should respond_to :repo_branch } + it { should respond_to :repo_protect_branch } + it { should respond_to :repo_unprotect_branch } + + describe ".branches" do + before do + stub_get("/projects/3/repository/branches", "branches") + @branches = Gitlab.branches(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/branches")).to have_been_made + end + + it "should return an array of repository branches" do + expect(@branches).to be_an Array + expect(@branches.first.name).to eq("api") + end + end + + describe ".branch" do + before do + stub_get("/projects/3/repository/branches/api", "branch") + @branch = Gitlab.branch(3, "api") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/branches/api")).to have_been_made + end + + it "should return information about a repository branch" do + expect(@branch.name).to eq("api") + end + end + + describe ".protect_branch" do + before do + stub_put("/projects/3/repository/branches/api/protect", "protect_branch") + @branch = Gitlab.protect_branch(3, "api") + end + + it "should get the correct resource" do + expect(a_put("/projects/3/repository/branches/api/protect")).to have_been_made + end + + it "should return information about a protected repository branch" do + expect(@branch.name).to eq("api") + expect(@branch.protected).to eq(true) + end + end + + describe ".unprotect_branch" do + before do + stub_put("/projects/3/repository/branches/api/unprotect", "unprotect_branch") + @branch = Gitlab.unprotect_branch(3, "api") + end + + it "should get the correct resource" do + expect(a_put("/projects/3/repository/branches/api/unprotect")).to have_been_made + end + + it "should return information about an unprotected repository branch" do + expect(@branch.name).to eq("api") + expect(@branch.protected).to eq(false) + end + end + + describe ".create_branch" do + context "with branch name" do + before do + stub_post("/projects/3/repository/branches", "create_branch") + @branch = Gitlab.create_branch(3, "api","master") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/branches")).to have_been_made + end + + it "should return information about a new repository branch" do + expect(@branch.name).to eq("api") + end + end + context "with commit hash" do + before do + stub_post("/projects/3/repository/branches", "create_branch") + @branch = Gitlab.create_branch(3, "api","949b1df930bedace1dbd755aaa4a82e8c451a616") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/branches")).to have_been_made + end + + it "should return information about a new repository branch" do + expect(@branch.name).to eq("api") + end + end + end + +end diff --git a/lib/gitlab-cli/spec/gitlab/client/groups_spec.rb b/lib/gitlab-cli/spec/gitlab/client/groups_spec.rb new file mode 100644 index 000000000..7336a3bdd --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/groups_spec.rb @@ -0,0 +1,111 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".groups" do + before do + stub_get("/groups", "groups") + stub_get("/groups/3", "group") + @group = Gitlab.group(3) + @groups = Gitlab.groups + end + + it "should get the correct resource" do + expect(a_get("/groups")).to have_been_made + expect(a_get("/groups/3")).to have_been_made + end + + it "should return an array of Groups" do + expect(@groups).to be_an Array + expect(@groups.first.path).to eq("threegroup") + end + end + + describe ".create_group" do + before do + stub_post("/groups", "group_create") + @group = Gitlab.create_group('GitLab-Group', 'gitlab-path') + end + + it "should get the correct resource" do + expect(a_post("/groups"). + with(:body => {:path => 'gitlab-path', :name => 'GitLab-Group'})).to have_been_made + end + + it "should return information about a created group" do + expect(@group.name).to eq("Gitlab-Group") + expect(@group.path).to eq("gitlab-group") + end + end + + describe ".transfer_project_to_group" do + before do + stub_post("/projects", "project") + @project = Gitlab.create_project('Gitlab') + stub_post("/groups", "group_create") + @group = Gitlab.create_group('GitLab-Group', 'gitlab-path') + + stub_post("/groups/#{@group.id}/projects/#{@project.id}", "group_create") + @group_transfer = Gitlab.transfer_project_to_group(@group.id,@project.id) + end + + it "should post to the correct resource" do + expect(a_post("/groups/#{@group.id}/projects/#{@project.id}").with(:body => {:id => @group.id.to_s, :project_id => @project.id.to_s})).to have_been_made + end + + it "should return information about the group" do + expect(@group_transfer.name).to eq(@group.name) + expect(@group_transfer.path).to eq(@group.path) + expect(@group_transfer.id).to eq(@group.id) + end + end + + describe ".group_members" do + before do + stub_get("/groups/3/members", "group_members") + @members = Gitlab.group_members(3) + end + + it "should get the correct resource" do + expect(a_get("/groups/3/members")).to have_been_made + end + + it "should return information about a group members" do + expect(@members).to be_an Array + expect(@members.size).to eq(2) + expect(@members[1].name).to eq("John Smith") + end + end + + describe ".add_group_member" do + before do + stub_post("/groups/3/members", "group_member") + @member = Gitlab.add_group_member(3, 1, 40) + end + + it "should get the correct resource" do + expect(a_post("/groups/3/members"). + with(:body => {:user_id => '1', :access_level => '40'})).to have_been_made + end + + it "should return information about an added member" do + expect(@member.name).to eq("John Smith") + end + end + + describe ".remove_group_member" do + before do + stub_delete("/groups/3/members/1", "group_member_delete") + @group = Gitlab.remove_group_member(3, 1) + end + + it "should get the correct resource" do + expect(a_delete("/groups/3/members/1")).to have_been_made + end + + it "should return information about the group the member was removed from" do + expect(@group.group_id).to eq(3) + end + end + + +end diff --git a/lib/gitlab-cli/spec/gitlab/client/issues_spec.rb b/lib/gitlab-cli/spec/gitlab/client/issues_spec.rb new file mode 100644 index 000000000..1a34699fe --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/issues_spec.rb @@ -0,0 +1,122 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".issues" do + context "with project ID passed" do + before do + stub_get("/projects/3/issues", "project_issues") + @issues = Gitlab.issues(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues")).to have_been_made + end + + it "should return an array of project's issues" do + expect(@issues).to be_an Array + expect(@issues.first.project_id).to eq(3) + end + end + + context "without project ID passed" do + before do + stub_get("/issues", "issues") + @issues = Gitlab.issues + end + + it "should get the correct resource" do + expect(a_get("/issues")).to have_been_made + end + + it "should return an array of user's issues" do + expect(@issues).to be_an Array + expect(@issues.first.closed).to be_falsey + expect(@issues.first.author.name).to eq("John Smith") + end + end + end + + describe ".issue" do + before do + stub_get("/projects/3/issues/33", "issue") + @issue = Gitlab.issue(3, 33) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues/33")).to have_been_made + end + + it "should return information about an issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".create_issue" do + before do + stub_post("/projects/3/issues", "issue") + @issue = Gitlab.create_issue(3, 'title') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/issues"). + with(:body => {:title => 'title'})).to have_been_made + end + + it "should return information about a created issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".edit_issue" do + before do + stub_put("/projects/3/issues/33", "issue") + @issue = Gitlab.edit_issue(3, 33, :title => 'title') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/issues/33"). + with(:body => {:title => 'title'})).to have_been_made + end + + it "should return information about an edited issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".close_issue" do + before do + stub_put("/projects/3/issues/33", "issue") + @issue = Gitlab.close_issue(3, 33) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/issues/33"). + with(:body => {:state_event => 'close'})).to have_been_made + end + + it "should return information about an closed issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".reopen_issue" do + before do + stub_put("/projects/3/issues/33", "issue") + @issue = Gitlab.reopen_issue(3, 33) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/issues/33"). + with(:body => {:state_event => 'reopen'})).to have_been_made + end + + it "should return information about an reopened issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb b/lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb new file mode 100644 index 000000000..7c2253f73 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb @@ -0,0 +1,124 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".merge_requests" do + before do + stub_get("/projects/3/merge_requests", "merge_requests") + @merge_requests = Gitlab.merge_requests(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_requests")).to have_been_made + end + + it "should return an array of project's merge requests" do + expect(@merge_requests).to be_an Array + expect(@merge_requests.first.project_id).to eq(3) + end + end + + describe ".merge_request" do + before do + stub_get("/projects/3/merge_request/1", "merge_request") + @merge_request = Gitlab.merge_request(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_request/1")).to have_been_made + end + + it "should return information about a merge request" do + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + end + end + + describe ".create_merge_request" do + before do + stub_post("/projects/3/merge_requests", "create_merge_request") + end + + it "should fail if it doesn't have a source_branch" do + expect { + Gitlab.create_merge_request(3, 'New merge request', :target_branch => 'master') + }.to raise_error Gitlab::Error::MissingAttributes + end + + it "should fail if it doesn't have a target_branch" do + expect { + Gitlab.create_merge_request(3, 'New merge request', :source_branch => 'dev') + }.to raise_error Gitlab::Error::MissingAttributes + end + + it "should return information about a merge request" do + @merge_request = Gitlab.create_merge_request(3, 'New feature', + :source_branch => 'api', + :target_branch => 'master' + ) + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + expect(@merge_request.title).to eq('New feature') + end + end + + describe ".update_merge_request" do + before do + stub_put("/projects/3/merge_request/2", "update_merge_request") + @merge_request = Gitlab.update_merge_request(3, 2, + :assignee_id => '1', + :target_branch => 'master', + :title => 'A different new feature' + ) + end + + it "should return information about a merge request" do + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + expect(@merge_request.title).to eq('A different new feature') + end + end + + describe ".merge_request_comments" do + before do + stub_get("/projects/3/merge_request/2/comments", "merge_request_comments") + @merge_request = Gitlab.merge_request_comments(3, 2) + end + + it "should return merge request's comments" do + expect(@merge_request).to be_an Array + expect(@merge_request.length).to eq(2) + expect(@merge_request[0].note).to eq("this is the 1st comment on the 2merge merge request") + expect(@merge_request[0].author.id).to eq(11) + expect(@merge_request[1].note).to eq("another discussion point on the 2merge request") + expect(@merge_request[1].author.id).to eq(12) + end + end + + describe ".merge_request_comments" do + before do + stub_get("/projects/3/merge_request/2/comments", "merge_request_comments") + @merge_request = Gitlab.merge_request_comments(3, 2) + end + + it "should return merge request's comments" do + expect(@merge_request).to be_an Array + expect(@merge_request.length).to eq(2) + expect(@merge_request[0].note).to eq("this is the 1st comment on the 2merge merge request") + expect(@merge_request[0].author.id).to eq(11) + expect(@merge_request[1].note).to eq("another discussion point on the 2merge request") + expect(@merge_request[1].author.id).to eq(12) + end + end + + describe ".create_merge_request_comment" do + before do + stub_post("/projects/3/merge_request/2/comments", "comment_merge_request") + end + + it "should return information about a merge request" do + @merge_request = Gitlab.create_merge_request_comment(3, 2, 'Cool Merge Request!') + expect(@merge_request.note).to eq('Cool Merge Request!') + @merge_request.author.id == 1 + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb b/lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb new file mode 100644 index 000000000..5ec7f3e34 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".milestones" do + before do + stub_get("/projects/3/milestones", "milestones") + @milestones = Gitlab.milestones(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/milestones")).to have_been_made + end + + it "should return an array of project's milestones" do + expect(@milestones).to be_an Array + expect(@milestones.first.project_id).to eq(3) + end + end + + describe ".milestone" do + before do + stub_get("/projects/3/milestones/1", "milestone") + @milestone = Gitlab.milestone(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/milestones/1")).to have_been_made + end + + it "should return information about a milestone" do + expect(@milestone.project_id).to eq(3) + end + end + + describe ".create_milestone" do + before do + stub_post("/projects/3/milestones", "milestone") + @milestone = Gitlab.create_milestone(3, 'title') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/milestones"). + with(:body => {:title => 'title'})).to have_been_made + end + + it "should return information about a created milestone" do + expect(@milestone.project_id).to eq(3) + end + end + + describe ".edit_milestone" do + before do + stub_put("/projects/3/milestones/33", "milestone") + @milestone = Gitlab.edit_milestone(3, 33, :title => 'title') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/milestones/33"). + with(:body => {:title => 'title'})).to have_been_made + end + + it "should return information about an edited milestone" do + expect(@milestone.project_id).to eq(3) + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/notes_spec.rb b/lib/gitlab-cli/spec/gitlab/client/notes_spec.rb new file mode 100644 index 000000000..78cd520d0 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/notes_spec.rb @@ -0,0 +1,156 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe "notes" do + context "when wall notes" do + before do + stub_get("/projects/3/notes", "notes") + @notes = Gitlab.notes(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/notes")).to have_been_made + end + + it "should return an array of notes" do + expect(@notes).to be_an Array + expect(@notes.first.author.name).to eq("John Smith") + end + end + + context "when issue notes" do + before do + stub_get("/projects/3/issues/7/notes", "notes") + @notes = Gitlab.issue_notes(3, 7) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues/7/notes")).to have_been_made + end + + it "should return an array of notes" do + expect(@notes).to be_an Array + expect(@notes.first.author.name).to eq("John Smith") + end + end + + context "when snippet notes" do + before do + stub_get("/projects/3/snippets/7/notes", "notes") + @notes = Gitlab.snippet_notes(3, 7) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/7/notes")).to have_been_made + end + + it "should return an array of notes" do + expect(@notes).to be_an Array + expect(@notes.first.author.name).to eq("John Smith") + end + end + end + + describe "note" do + context "when wall note" do + before do + stub_get("/projects/3/notes/1201", "note") + @note = Gitlab.note(3, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when issue note" do + before do + stub_get("/projects/3/issues/7/notes/1201", "note") + @note = Gitlab.issue_note(3, 7, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues/7/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when snippet note" do + before do + stub_get("/projects/3/snippets/7/notes/1201", "note") + @note = Gitlab.snippet_note(3, 7, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/7/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + end + + describe "create note" do + context "when wall note" do + before do + stub_post("/projects/3/notes", "note") + @note = Gitlab.create_note(3, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/notes"). + with(:body => {:body => 'The solution is rather tricky'})).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when issue note" do + before do + stub_post("/projects/3/issues/7/notes", "note") + @note = Gitlab.create_issue_note(3, 7, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/issues/7/notes"). + with(:body => {:body => 'The solution is rather tricky'})).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when snippet note" do + before do + stub_post("/projects/3/snippets/7/notes", "note") + @note = Gitlab.create_snippet_note(3, 7, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/snippets/7/notes"). + with(:body => {:body => 'The solution is rather tricky'})).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/projects_spec.rb b/lib/gitlab-cli/spec/gitlab/client/projects_spec.rb new file mode 100644 index 000000000..754a27c9f --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/projects_spec.rb @@ -0,0 +1,357 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".projects" do + before do + stub_get("/projects", "projects") + @projects = Gitlab.projects + end + + it "should get the correct resource" do + expect(a_get("/projects")).to have_been_made + end + + it "should return an array of projects" do + expect(@projects).to be_an Array + expect(@projects.first.name).to eq("Brute") + expect(@projects.first.owner.name).to eq("John Smith") + end + end + + describe ".project" do + before do + stub_get("/projects/3", "project") + @project = Gitlab.project(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3")).to have_been_made + end + + it "should return information about a project" do + expect(@project.name).to eq("Gitlab") + expect(@project.owner.name).to eq("John Smith") + end + end + + describe ".project_events" do + before do + stub_get("/projects/2/events", "project_events") + @events = Gitlab.project_events(2) + end + + it "should get the correct resource" do + expect(a_get("/projects/2/events")).to have_been_made + end + + it "should return an array of events" do + expect(@events).to be_an Array + expect(@events.size).to eq(2) + end + + it "should return the action name of the event" do + expect(@events.first.action_name).to eq("opened") + end + end + + describe ".create_project" do + before do + stub_post("/projects", "project") + @project = Gitlab.create_project('Gitlab') + end + + it "should get the correct resource" do + expect(a_post("/projects")).to have_been_made + end + + it "should return information about a created project" do + expect(@project.name).to eq("Gitlab") + expect(@project.owner.name).to eq("John Smith") + end + end + + describe ".create_project for user" do + before do + stub_post("/users", "user") + @owner = Gitlab.create_user("john@example.com", "pass", {name: 'John Owner'}) + stub_post("/projects/user/#{@owner.id}", "project_for_user") + @project = Gitlab.create_project('Brute', {:user_id => @owner.id}) + end + + it "should return information about a created project" do + expect(@project.name).to eq("Brute") + expect(@project.owner.name).to eq("John Owner") + end + end + + describe ".delete_project" do + before do + stub_delete("/projects/Gitlab", "project") + @project = Gitlab.delete_project('Gitlab') + end + + it "should get the correct resource" do + expect(a_delete("/projects/Gitlab")).to have_been_made + end + + it "should return information about a deleted project" do + expect(@project.name).to eq("Gitlab") + expect(@project.owner.name).to eq("John Smith") + end + end + + describe ".team_members" do + before do + stub_get("/projects/3/members", "team_members") + @team_members = Gitlab.team_members(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/members")).to have_been_made + end + + it "should return an array of team members" do + expect(@team_members).to be_an Array + expect(@team_members.first.name).to eq("John Smith") + end + end + + describe ".team_member" do + before do + stub_get("/projects/3/members/1", "team_member") + @team_member = Gitlab.team_member(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/members/1")).to have_been_made + end + + it "should return information about a team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".add_team_member" do + before do + stub_post("/projects/3/members", "team_member") + @team_member = Gitlab.add_team_member(3, 1, 40) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/members"). + with(:body => {:user_id => '1', :access_level => '40'})).to have_been_made + end + + it "should return information about an added team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".edit_team_member" do + before do + stub_put("/projects/3/members/1", "team_member") + @team_member = Gitlab.edit_team_member(3, 1, 40) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/members/1"). + with(:body => {:access_level => '40'})).to have_been_made + end + + it "should return information about an edited team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".remove_team_member" do + before do + stub_delete("/projects/3/members/1", "team_member") + @team_member = Gitlab.remove_team_member(3, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/members/1")).to have_been_made + end + + it "should return information about a removed team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".project_hooks" do + before do + stub_get("/projects/1/hooks", "project_hooks") + @hooks = Gitlab.project_hooks(1) + end + + it "should get the correct resource" do + expect(a_get("/projects/1/hooks")).to have_been_made + end + + it "should return an array of hooks" do + expect(@hooks).to be_an Array + expect(@hooks.first.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".project_hook" do + before do + stub_get("/projects/1/hooks/1", "project_hook") + @hook = Gitlab.project_hook(1, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/1/hooks/1")).to have_been_made + end + + it "should return information about a hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".add_project_hook" do + context "without specified events" do + before do + stub_post("/projects/1/hooks", "project_hook") + @hook = Gitlab.add_project_hook(1, "https://api.example.net/v1/webhooks/ci") + end + + it "should get the correct resource" do + body = {:url => "https://api.example.net/v1/webhooks/ci"} + expect(a_post("/projects/1/hooks").with(:body => body)).to have_been_made + end + + it "should return information about an added hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + context "with specified events" do + before do + stub_post("/projects/1/hooks", "project_hook") + @hook = Gitlab.add_project_hook(1, "https://api.example.net/v1/webhooks/ci", push_events: true, merge_requests_events: true) + end + + it "should get the correct resource" do + body = {:url => "https://api.example.net/v1/webhooks/ci", push_events: "true", merge_requests_events: "true"} + expect(a_post("/projects/1/hooks").with(:body => body)).to have_been_made + end + + it "should return information about an added hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + end + + describe ".edit_project_hook" do + before do + stub_put("/projects/1/hooks/1", "project_hook") + @hook = Gitlab.edit_project_hook(1, 1, "https://api.example.net/v1/webhooks/ci") + end + + it "should get the correct resource" do + body = {:url => "https://api.example.net/v1/webhooks/ci"} + expect(a_put("/projects/1/hooks/1").with(:body => body)).to have_been_made + end + + it "should return information about an edited hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".delete_project_hook" do + before do + stub_delete("/projects/1/hooks/1", "project_hook") + @hook = Gitlab.delete_project_hook(1, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/1/hooks/1")).to have_been_made + end + + it "should return information about a deleted hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".make_forked_from" do + before do + stub_post("/projects/42/fork/24", "project_fork_link") + @forked_project_link = Gitlab.make_forked_from(42, 24) + end + + it "should get the correct resource" do + expect(a_post("/projects/42/fork/24")).to have_been_made + end + + it "should return information about a forked project" do + expect(@forked_project_link.forked_from_project_id).to eq(24) + expect(@forked_project_link.forked_to_project_id).to eq(42) + end + end + + describe ".remove_forked" do + before do + stub_delete("/projects/42/fork", "project_fork_link") + @forked_project_link = Gitlab.remove_forked(42) + end + + it "should be sent to correct resource" do + expect(a_delete("/projects/42/fork")).to have_been_made + end + + it "should return information about an unforked project" do + expect(@forked_project_link.forked_to_project_id).to eq(42) + end + end + + describe ".deploy_keys" do + before do + stub_get("/projects/42/keys", "project_keys") + @deploy_keys = Gitlab.deploy_keys(42) + end + + it "should get the correct resource" do + expect(a_get("/projects/42/keys")).to have_been_made + end + + it "should return project deploy keys" do + expect(@deploy_keys).to be_an Array + expect(@deploy_keys.first.id).to eq 2 + expect(@deploy_keys.first.title).to eq "Key Title" + expect(@deploy_keys.first.key).to match(/ssh-rsa/) + end + end + + describe ".deploy_key" do + before do + stub_get("/projects/42/keys/2", "project_key") + @deploy_key = Gitlab.deploy_key(42, 2) + end + + it "should get the correct resource" do + expect(a_get("/projects/42/keys/2")).to have_been_made + end + + it "should return project deploy key" do + expect(@deploy_key.id).to eq 2 + expect(@deploy_key.title).to eq "Key Title" + expect(@deploy_key.key).to match(/ssh-rsa/) + end + end + + describe ".delete_deploy_key" do + before do + stub_delete("/projects/42/keys/2", "project_delete_key") + @deploy_key = Gitlab.delete_deploy_key(42, 2) + end + + it "should get the correct resource" do + expect(a_delete("/projects/42/keys/2")).to have_been_made + end + + it "should return information about a deleted key" do + expect(@deploy_key.id).to eq(2) + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb b/lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb new file mode 100644 index 000000000..0bcc8de5b --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb @@ -0,0 +1,92 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :repo_tags } + it { should respond_to :repo_create_tag } + it { should respond_to :repo_branches } + it { should respond_to :repo_branch } + it { should respond_to :repo_commits } + it { should respond_to :repo_commit } + it { should respond_to :repo_commit_diff } + + describe ".tags" do + before do + stub_get("/projects/3/repository/tags", "project_tags") + @tags = Gitlab.tags(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/tags")).to have_been_made + end + + it "should return an array of repository tags" do + expect(@tags).to be_an Array + expect(@tags.first.name).to eq("v2.8.2") + end + end + + describe ".create_tag" do + before do + stub_post("/projects/3/repository/tags", "tag") + @tag = Gitlab.create_tag(3, 'v1.0.0', '2695effb5807a22ff3d138d593fd856244e155e7') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/tags")).to have_been_made + end + + it "should return information about a new repository tag" do + expect(@tag.name).to eq("v1.0.0") + end + end + + describe ".commits" do + before do + stub_get("/projects/3/repository/commits", "project_commits"). + with(:query => {:ref_name => "api"}) + @commits = Gitlab.commits(3, :ref_name => "api") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits"). + with(:query => {:ref_name => "api"})).to have_been_made + end + + it "should return an array of repository commits" do + expect(@commits).to be_an Array + expect(@commits.first.id).to eq("f7dd067490fe57505f7226c3b54d3127d2f7fd46") + end + end + + describe ".commit" do + before do + stub_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6", "project_commit") + @commit = Gitlab.commit(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6")) + .to have_been_made + end + + it "should return a repository commit" do + expect(@commit.id).to eq("6104942438c14ec7bd21c6cd5bd995272b3faff6") + end + end + + describe ".commit_diff" do + before do + stub_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/diff", "project_commit_diff") + @diff = Gitlab.commit_diff(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/diff")) + .to have_been_made + end + + it "should return a diff of a commit" do + expect(@diff.new_path).to eq("doc/update/5.4-to-6.0.md") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb b/lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb new file mode 100644 index 000000000..751c4d0b9 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".snippets" do + before do + stub_get("/projects/3/snippets", "snippets") + @snippets = Gitlab.snippets(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets")).to have_been_made + end + + it "should return an array of project's snippets" do + expect(@snippets).to be_an Array + expect(@snippets.first.file_name).to eq("mailer_test.rb") + end + end + + describe ".snippet" do + before do + stub_get("/projects/3/snippets/1", "snippet") + @snippet = Gitlab.snippet(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/1")).to have_been_made + end + + it "should return information about a snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".create_snippet" do + before do + stub_post("/projects/3/snippets", "snippet") + @snippet = Gitlab.create_snippet(3, {:title => 'API', :file_name => 'api.rb', :code => 'code'}) + end + + it "should get the correct resource" do + body = {:title => 'API', :file_name => 'api.rb', :code => 'code'} + expect(a_post("/projects/3/snippets").with(:body => body)).to have_been_made + end + + it "should return information about a new snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".edit_snippet" do + before do + stub_put("/projects/3/snippets/1", "snippet") + @snippet = Gitlab.edit_snippet(3, 1, :file_name => 'mailer_test.rb') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/snippets/1"). + with(:body => {:file_name => 'mailer_test.rb'})).to have_been_made + end + + it "should return information about an edited snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".delete_snippet" do + before do + stub_delete("/projects/3/snippets/1", "snippet") + @snippet = Gitlab.delete_snippet(3, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/snippets/1")).to have_been_made + end + + it "should return information about a deleted snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb b/lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb new file mode 100644 index 000000000..754e86845 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :system_hooks } + it { should respond_to :add_system_hook } + it { should respond_to :system_hook } + it { should respond_to :delete_system_hook } + + describe ".hooks" do + before do + stub_get("/hooks", "system_hooks") + @hooks = Gitlab.hooks + end + + it "should get the correct resource" do + expect(a_get("/hooks")).to have_been_made + end + + it "should return an array of system hooks" do + expect(@hooks).to be_an Array + expect(@hooks.first.url).to eq("http://example.com/hook") + end + end + + describe ".add_hook" do + before do + stub_post("/hooks", "system_hook") + @hook = Gitlab.add_hook("http://example.com/hook") + end + + it "should get the correct resource" do + expect(a_post("/hooks")).to have_been_made + end + + it "should return information about a added system hook" do + expect(@hook.url).to eq("http://example.com/hook") + end + end + + describe ".hook" do + before do + stub_get("/hooks/3", "system_hook_test") + @hook = Gitlab.hook(3) + end + it "should get the correct resource" do + expect(a_get("/hooks/3")).to have_been_made + end + + it "should return information about a added system hook" do + expect(@hook.event_name).to eq("project_create") + expect(@hook.project_id).to eq(1) + end + end + + describe ".delete_hook" do + before do + stub_delete("/hooks/3", "system_hook") + @hook = Gitlab.delete_hook(3) + end + + it "should get the correct resource" do + expect(a_delete("/hooks/3")).to have_been_made + end + + it "should return information about a deleted system hook" do + expect(@hook.url).to eq("http://example.com/hook") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/users_spec.rb b/lib/gitlab-cli/spec/gitlab/client/users_spec.rb new file mode 100644 index 000000000..cfbc7d50c --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/users_spec.rb @@ -0,0 +1,192 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".users" do + before do + stub_get("/users", "users") + @users = Gitlab.users + end + + it "should get the correct resource" do + expect(a_get("/users")).to have_been_made + end + + it "should return an array of users" do + expect(@users).to be_an Array + expect(@users.first.email).to eq("john@example.com") + end + end + + describe ".user" do + context "with user ID passed" do + before do + stub_get("/users/1", "user") + @user = Gitlab.user(1) + end + + it "should get the correct resource" do + expect(a_get("/users/1")).to have_been_made + end + + it "should return information about a user" do + expect(@user.email).to eq("john@example.com") + end + end + + context "without user ID passed" do + before do + stub_get("/user", "user") + @user = Gitlab.user + end + + it "should get the correct resource" do + expect(a_get("/user")).to have_been_made + end + + it "should return information about an authorized user" do + expect(@user.email).to eq("john@example.com") + end + end + end + + describe ".create_user" do + context "when successful request" do + before do + stub_post("/users", "user") + @user = Gitlab.create_user("email", "pass") + end + + it "should get the correct resource" do + body = {:email => "email", :password => "pass", :name => "email"} + expect(a_post("/users").with(:body => body)).to have_been_made + end + + it "should return information about a created user" do + expect(@user.email).to eq("john@example.com") + end + end + + context "when bad request" do + it "should throw an exception" do + stub_post("/users", "error_already_exists", 409) + expect { + Gitlab.create_user("email", "pass") + }.to raise_error(Gitlab::Error::Conflict, "Server responded with code 409, message: 409 Already exists. Request URI: #{Gitlab.endpoint}/users") + end + end + end + + describe ".edit_user" do + before do + @options = { :name => "Roberto" } + stub_put("/users/1", "user").with(:body => @options) + @user = Gitlab.edit_user(1, @options) + end + + it "should get the correct resource" do + expect(a_put("/users/1").with(:body => @options)).to have_been_made + end + end + + describe ".session" do + after do + Gitlab.endpoint = 'https://api.example.com' + Gitlab.private_token = 'secret' + end + + before do + stub_request(:post, "#{Gitlab.endpoint}/session"). + to_return(:body => load_fixture('session'), :status => 200) + @session = Gitlab.session("email", "pass") + end + + context "when endpoint is not set" do + it "should raise Error::MissingCredentials" do + Gitlab.endpoint = nil + expect { + Gitlab.session("email", "pass") + }.to raise_error(Gitlab::Error::MissingCredentials, 'Please set an endpoint to API') + end + end + + context "when private_token is not set" do + it "should not raise Error::MissingCredentials" do + Gitlab.private_token = nil + expect { Gitlab.session("email", "pass") }.to_not raise_error + end + end + + context "when endpoint is set" do + it "should get the correct resource" do + expect(a_request(:post, "#{Gitlab.endpoint}/session")).to have_been_made + end + + it "should return information about a created session" do + expect(@session.email).to eq("john@example.com") + expect(@session.private_token).to eq("qEsq1pt6HJPaNciie3MG") + end + end + end + + describe ".ssh_keys" do + before do + stub_get("/user/keys", "keys") + @keys = Gitlab.ssh_keys + end + + it "should get the correct resource" do + expect(a_get("/user/keys")).to have_been_made + end + + it "should return an array of SSH keys" do + expect(@keys).to be_an Array + expect(@keys.first.title).to eq("narkoz@helium") + end + end + + describe ".ssh_key" do + before do + stub_get("/user/keys/1", "key") + @key = Gitlab.ssh_key(1) + end + + it "should get the correct resource" do + expect(a_get("/user/keys/1")).to have_been_made + end + + it "should return information about an SSH key" do + expect(@key.title).to eq("narkoz@helium") + end + end + + describe ".create_ssh_key" do + before do + stub_post("/user/keys", "key") + @key = Gitlab.create_ssh_key("title", "body") + end + + it "should get the correct resource" do + body = {:title => "title", :key => "body"} + expect(a_post("/user/keys").with(:body => body)).to have_been_made + end + + it "should return information about a created SSH key" do + expect(@key.title).to eq("narkoz@helium") + end + end + + describe ".delete_ssh_key" do + before do + stub_delete("/user/keys/1", "key") + @key = Gitlab.delete_ssh_key(1) + end + + it "should get the correct resource" do + expect(a_delete("/user/keys/1")).to have_been_made + end + + it "should return information about a deleted SSH key" do + expect(@key.title).to eq("narkoz@helium") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb b/lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb new file mode 100644 index 000000000..5a166dc7b --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe Gitlab::ObjectifiedHash do + before do + @hash = {a: 1, b: 2} + @oh = Gitlab::ObjectifiedHash.new @hash + end + + it "should objectify hash" do + expect(@oh.a).to eq(@hash[:a]) + expect(@oh.b).to eq(@hash[:b]) + end + + describe "#to_hash" do + it "should return an original hash" do + expect(@oh.to_hash).to eq(@hash) + end + + it "should have an alias #to_h" do + expect(@oh.respond_to?(:to_h)).to be_truthy + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/request_spec.rb b/lib/gitlab-cli/spec/gitlab/request_spec.rb new file mode 100644 index 000000000..29125d08d --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/request_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe Gitlab::Request do + it { should respond_to :get } + it { should respond_to :post } + it { should respond_to :put } + it { should respond_to :delete } + + describe ".default_options" do + it "should have default values" do + default_options = Gitlab::Request.default_options + expect(default_options).to be_a Hash + expect(default_options[:parser]).to be_a Proc + expect(default_options[:format]).to eq(:json) + expect(default_options[:headers]).to eq({'Accept' => 'application/json'}) + expect(default_options[:default_params]).to be_nil + end + end + + describe ".parse" do + it "should return ObjectifiedHash" do + body = JSON.unparse({a: 1, b: 2}) + expect(Gitlab::Request.parse(body)).to be_an Gitlab::ObjectifiedHash + end + end + + describe "#set_request_defaults" do + context "when endpoint is not set" do + it "should raise Error::MissingCredentials" do + expect { + Gitlab::Request.new.set_request_defaults(nil, 1234000) + }.to raise_error(Gitlab::Error::MissingCredentials, 'Please set an endpoint to API') + end + end + + context "when endpoint is set" do + it "should set base_uri" do + Gitlab::Request.new.set_request_defaults('http://rabbit-hole.example.org', 1234000) + expect(Gitlab::Request.base_uri).to eq("http://rabbit-hole.example.org") + end + + it "should set default_params" do + Gitlab::Request.new.set_request_defaults('http://rabbit-hole.example.org', 1234000, 'sudoer') + expect(Gitlab::Request.default_params).to eq({:sudo => 'sudoer'}) + end + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab_spec.rb b/lib/gitlab-cli/spec/gitlab_spec.rb new file mode 100644 index 000000000..7a1ada4d2 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe Gitlab do + after { Gitlab.reset } + + describe ".client" do + it "should be a Gitlab::Client" do + expect(Gitlab.client).to be_a Gitlab::Client + end + end + + describe ".actions" do + it "should return an array of client methods" do + actions = Gitlab.actions + expect(actions).to be_an Array + expect(actions.first).to be_a Symbol + expect(actions.sort.first).to match(/add_/) + end + end + + describe ".endpoint=" do + it "should set endpoint" do + Gitlab.endpoint = 'https://api.example.com' + expect(Gitlab.endpoint).to eq('https://api.example.com') + end + end + + describe ".private_token=" do + it "should set private_token" do + Gitlab.private_token = 'secret' + expect(Gitlab.private_token).to eq('secret') + end + end + + describe ".sudo=" do + it "should set sudo" do + Gitlab.sudo = 'user' + expect(Gitlab.sudo).to eq('user') + end + end + + describe ".user_agent" do + it "should return default user_agent" do + expect(Gitlab.user_agent).to eq(Gitlab::Configuration::DEFAULT_USER_AGENT) + end + end + + describe ".user_agent=" do + it "should set user_agent" do + Gitlab.user_agent = 'Custom User Agent' + expect(Gitlab.user_agent).to eq('Custom User Agent') + end + end + + describe ".configure" do + Gitlab::Configuration::VALID_OPTIONS_KEYS.each do |key| + it "should set #{key}" do + Gitlab.configure do |config| + config.send("#{key}=", key) + expect(Gitlab.send(key)).to eq(key) + end + end + end + end +end diff --git a/lib/gitlab-cli/spec/spec_helper.rb b/lib/gitlab-cli/spec/spec_helper.rb new file mode 100644 index 000000000..06d57c84e --- /dev/null +++ b/lib/gitlab-cli/spec/spec_helper.rb @@ -0,0 +1,74 @@ +require 'rspec' +require 'webmock/rspec' + +require File.expand_path('../../lib/gitlab', __FILE__) +require File.expand_path('../../lib/gitlab/cli', __FILE__) + +def capture_output + out = StringIO.new + $stdout = out + $stderr = out + yield + $stdout = STDOUT + $stderr = STDERR + out.string +end + +def load_fixture(name) + File.new(File.dirname(__FILE__) + "/fixtures/#{name}.json") +end + +RSpec.configure do |config| + config.before(:all) do + Gitlab.endpoint = 'https://api.example.com' + Gitlab.private_token = 'secret' + end +end + +# GET +def stub_get(path, fixture) + stub_request(:get, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). + to_return(:body => load_fixture(fixture)) +end + +def a_get(path) + a_request(:get, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) +end + +# POST +def stub_post(path, fixture, status_code=200) + stub_request(:post, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). + to_return(:body => load_fixture(fixture), :status => status_code) +end + +def a_post(path) + a_request(:post, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) +end + +# PUT +def stub_put(path, fixture) + stub_request(:put, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). + to_return(:body => load_fixture(fixture)) +end + +def a_put(path) + a_request(:put, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) +end + +# DELETE +def stub_delete(path, fixture) + stub_request(:delete, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). + to_return(:body => load_fixture(fixture)) +end + +def a_delete(path) + a_request(:delete, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) +end diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/lib/tasks/course_end.rake b/lib/tasks/course_end.rake new file mode 100644 index 000000000..d8e87eacf --- /dev/null +++ b/lib/tasks/course_end.rake @@ -0,0 +1,10 @@ +#coding=utf-8 +namespace :course do + desc "course end" + task :end => :environment do + courses = Course.where("end_date <= '#{Date.today}' and is_end = 0") + courses.each do |course| + course.update_attribute(:is_end, 1) + end + end +end \ No newline at end of file diff --git a/lib/tasks/exercise_close_to_deadline_warn.rake b/lib/tasks/exercise_close_to_deadline_warn.rake new file mode 100644 index 000000000..598755db0 --- /dev/null +++ b/lib/tasks/exercise_close_to_deadline_warn.rake @@ -0,0 +1,46 @@ +#coding=utf-8 +#需要在0点以后执行 +namespace :exercise_deadline_warn do + desc "exercise deadline warn" + task :deadline_warn => :environment do + puts "--------------------------------exercise_nearly_end start" + # 统一设置发布时间的测验 + exercises = Exercise.where("exercise_status = 2 and unified_setting = 1 and end_time <=? and end_time > ?", Time.now + 86400, Time.now + 82800) + exercises.each do |exercise| + if exercise.tidings.where(:parent_container_type => "NearlyEnd").count == 0 + course = exercise.course + tid_str = "" + exercise.exercise_users.where(:commit_status => 0).find_each do |student| + tid_str += "," if tid_str != "" + tid_str += "(#{student.user_id}, #{exercise.user_id}, #{exercise.id}, 'Exercise', #{exercise.id}, 'NearlyEnd', #{course.id}, 'Course', 0, 'Exercise', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + + # 分组设置发布时间的测验 + exercise_group_settings = ExerciseGroupSetting.where("end_time <=? and end_time > ?", Time.now + 86400, Time.now + 82800) + exercise_group_settings.each do |exercise_group| + exercise = exercise_group.exercise + if exercise.present? + course = exercise.course + members = course.course_members.where(:course_group_id => exercise_group.course_group_id) + if exercise.tidings.where(:parent_container_type => "NearlyEnd", :user_id => members.map(&:user_id)).count == 0 + tid_str = "" + exercise.exercise_users.where(:commit_status => 0, :user_id => members.map(&:user_id)).find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id},#{exercise.user_id}, #{exercise.id}, 'Exercise', #{exercise.id}, 'NearlyEnd', #{course.id}, 'Course', 0, 'Exercise', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + end + puts "--------------------------------exercise_nearly_end end" + end +end \ No newline at end of file diff --git a/lib/tasks/exercise_publish.rake b/lib/tasks/exercise_publish.rake new file mode 100644 index 000000000..8a13154cc --- /dev/null +++ b/lib/tasks/exercise_publish.rake @@ -0,0 +1,211 @@ +#coding=utf-8 + +namespace :exercise_publish do + desc "publish exercise and end exercise" + def get_mulscore(question, user) + ecs = ExerciseAnswer.where("user_id =? and exercise_question_id =?", user.id, question.id) + arr = [] + ecs.each do |ec| + arr << ec.exercise_choice.choice_position + end + #arr = arr.sort + str = arr.sort.join("") + return str + end + + def tran_base64_decode64 str + if str.blank? + str + else + s_size = str.size % 4 + if s_size != 0 + str += "=" * (4 - s_size) + end + Base64.decode64(str.tr("-_", "+/")).force_encoding("utf-8") + end + end + + # def calculate_student_score(exercise, user) + # score = 0 + # score1 = 0 + # score2 = 0 + # score3 = 0 + # score4 = 0 + # exercise_qustions = exercise.exercise_questions + # exercise_qustions.each do |question| + # if question.question_type != 5 + # answer = question.exercise_answers.where("#{ExerciseAnswer.table_name}.user_id = #{user.id}") + # if question.question_type == 3 + # standard_answer =[] + # question.exercise_standard_answers.each do |answer| + # standard_answer << answer.answer_text.strip.downcase + # end + # else + # standard_answer = question.exercise_standard_answers.first + # end + # + # unless answer.empty? + # # 问答题有多个答案 + # if question.question_type == 3 && !standard_answer.empty? + # if standard_answer.include?(answer.first.answer_text.strip.downcase) + # score1 = score1+ question.question_score unless question.question_score.nil? + # end + # elsif question.question_type == 1 && !standard_answer.nil? + # if answer.first.exercise_choice.choice_position == standard_answer.exercise_choice_id + # score2 = score2 + question.question_score unless question.question_score.nil? + # end + # elsif question.question_type == 2 && !standard_answer.nil? + # arr = get_mulscore(question, user) + # if arr.to_i == standard_answer.exercise_choice_id + # score3 = score3 + question.question_score unless question.question_score.nil? + # end + # end + # end + # else + # question.exercise_shixun_challenges.each do |exercise_cha| + # game = Game.where(:user_id => user.id, :challenge_id => exercise_cha.challenge_id).first + # if game.present? + # exercise_cha_score = 0 + # answer_status = 0 + # cha_path = exercise_cha.challenge.path.present? ? exercise_cha.challenge.path.split(";") : [] + # challeng_path = cha_path.reject(&:blank?)[0].try(:strip) + # if game.status == 2 && game.final_score >= 0 + # exercise_cha_score = exercise_cha.question_score + # answer_status = 1 + # end + # if exercise_cha.exercise_shixun_answers.where(:user_id => user.id).empty? + # if GameCode.where(:game_id => game.try(:id), :path => challeng_path).first.present? + # game_code = GameCode.where(:game_id => game.try(:id), :path => challeng_path).first + # code = game_code.try(:new_code) + # else + # begin + # g = Gitlab.client + # Rails.logger.info "commit_exercise_path---- #{challeng_path}" + # if game.present? + # code = g.files(game.myshixun.gpid, challeng_path, "master").try(:content) + # else + # code = g.files(question.shixun.gpid, challeng_path, "master").try(:content) + # end + # code = tran_base64_decode64(code) + # rescue Exception => e + # @error_messages = e.message + # Rails.logger.info "commit_exercise---- #{@error_messages}" + # end + # end + # ExerciseShixunAnswer.create(:exercise_question_id => question.id, :exercise_shixun_challenge_id => exercise_cha.id, :user_id => user.id, + # :score => exercise_cha_score, :answer_text => code, :status => answer_status) + # + # end + # score4 += exercise_cha_score + # end + # end + # end + # end + # score = score1 + score2 + score3 + score4 + # end + + task :publish => :environment do + Rails.logger.info("log--------------------------------exercise_publish start") + puts "--------------------------------exercise_publish start" + exercises = Exercise.where("publish_time is not null and exercise_status = 1 and publish_time <=?",Time.now) + exercises.each do |exercise| + exercise.update_column('exercise_status', 2) + course = exercise.course + tid_str = "" + course.teachers.find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id}, #{exercise.user_id}, #{exercise.id}, 'Exercise', #{exercise.id}, 'ExercisePublish', #{course.id}, 'Course', 0, 'Exercise', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if exercise.unified_setting + course.student.find_each do |student| + tid_str += "," if tid_str != "" + tid_str += "(#{student.student_id}, #{exercise.user_id}, #{exercise.id}, 'Exercise', #{exercise.id}, 'ExercisePublish', #{course.id}, 'Course', 0, 'Exercise', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + + if exercise.exercise_users.count == 0 + str = "" + course.student.find_each do |student| + str += "," if str != "" + str += "(#{student.user_id}, #{exercise.id}, 0, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + + if str != "" + sql = "insert into exercise_users (user_id, exercise_id, commit_status, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + + if exercise.course_acts.size == 0 + exercise.course_acts << CourseActivity.new(:user_id => exercise.user_id,:course_id => exercise.course_id) + end + end + + # 分组设置发布时间的测验 + exercise_group_settings = ExerciseGroupSetting.where("publish_time < ? and publish_time > ?", Time.now + 1800, Time.now - 1800) + exercise_group_settings.each do |exercise_group| + exercise = exercise_group.exercise + if exercise.present? + course = exercise.course + exercise.update_attributes(:exercise_status => 2) if exercise.exercise_status == 1 + tid_str = "" + members = course.students.where(:course_group_id => exercise_group.course_group_id) + members.find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id},#{exercise.user_id}, #{exercise.id}, 'Exercise', #{exercise.id}, 'ExercisePublish', #{course.id}, 'Course', 0, 'Exercise', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + Rails.logger.info("log--------------------------------exercise_publish end") + puts "--------------------------------exercise_publish end" + end + + task :end => :environment do + exercises = Exercise.where("end_time <=? and exercise_status = 2",Time.now) + exercises.each do |exercise| + course = exercise.course + exercise.update_column('exercise_status', 3) + + exercise.exercise_users.each do |exercise_user| + if exercise_user.commit_status == 0 && !exercise_user.start_at.nil? + exercise_user.update_attributes(:commit_status => 1, :end_at => Time.now, :status => true) + + s_score = calculate_student_score(exercise, exercise_user.user)[:total_score] + exercise_user.update_attributes(:objective_score => s_score, :score => (s_score + (exercise_user.subjective_score && exercise_user.subjective_score > 0 ? exercise_user.subjective_score : 0))) + if exercise_user.user.exercise_answer.where(:exercise_question_id => exercise.exercise_questions.where(:question_type => 4).map(&:id)).empty? + exercise_user.update_attributes(:subjective_score => 0) + end + end + end + end + + all_exercises = Exercise.where("end_time > ? and exercise_status = 2",Time.now) + exercise_ids = all_exercises.blank? ? "(-1)" : "(" + all_exercises.map(&:id).join(",") + ")" + ExerciseGroupSetting.where("end_time <= '#{Time.now}' and exercise_id in #{exercise_ids}").each do |exercise_setting| + exercise = exercise_setting.exercise + + users = exercise.course.students.where(:course_group_id => exercise_setting.course_group_id) + exercise_users = exercise.exercise_users.where(:user_id => users.map(&:user_id)) + + exercise_users.each do |exercise_user| + if exercise_user.commit_status == 0 && !exercise_user.start_at.nil? + exercise_user.update_attributes(:commit_status => 1, :end_at => Time.now, :status => true) + + s_score = calculate_student_score(exercise, exercise_user.user)[:total_score] + exercise_user.update_attributes(:objective_score => s_score, :score => (s_score + (exercise_user.subjective_score && exercise_user.subjective_score > 0 ? exercise_user.subjective_score : 0))) + if exercise_user.user.exercise_answer.where(:exercise_question_id => exercise.exercise_questions.where(:question_type => 4).map(&:id)).empty? + exercise_user.update_attributes(:subjective_score => 0) + end + end + end + end + end +end diff --git a/lib/tasks/gitlab.rake b/lib/tasks/gitlab.rake new file mode 100644 index 000000000..396f197d3 --- /dev/null +++ b/lib/tasks/gitlab.rake @@ -0,0 +1,33 @@ +namespace :sync do + desc "sync repository for myshixun" + task :myshixun => :environment do + g = Gitlab.client + myshixuns = Myshixun.where("repo_name is null") + myshixuns.find_each do |myshixun| + begin + puts myshixun.identifier + repo_name = g.project(myshixun.gpid).path_with_namespace + puts repo_name + myshixun.update_column(:repo_name, repo_name) + rescue Exception => e + Rails.logger.error("e.message") + end + end + end + + + task :shixun => :environment do + g = Gitlab.client + shixuns = Shixun.where("repo_name is null") + shixuns.find_each do |shixun| + begin + puts shixun.identifier + repo_name = g.project(shixun.gpid).path_with_namespace + puts repo_name + shixun.update_column(:repo_name, repo_name) + rescue Exception => e + Rails.logger.error("e.message") + end + end + end +end diff --git a/lib/tasks/graduation_task.rake b/lib/tasks/graduation_task.rake new file mode 100644 index 000000000..dada0303d --- /dev/null +++ b/lib/tasks/graduation_task.rake @@ -0,0 +1,112 @@ +namespace :graduation_task do + desc "start/end/comment graduation tasks" + + task :publish => :environment do + tasks = GraduationTask.where("publish_time is not null and publish_time <= '#{Time.now}' and status = 0") + tasks.each do |task| + task.update_attributes(status: 1) + course = task.course + members = course.course_members + if !course.nil? && !members.empty? + tid_str = "" + members.find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id}, #{task.user_id}, #{task.id}, 'GraduationTask', #{task.id}, 'TaskPublish', + #{course.id}, 'Course', 0, 'GraduationTask', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, + updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + + if task.course_acts.size == 0 + task.course_acts << CourseActivity.new(user_id: task.user_id, course_id: task.course_id) + end + end + end + + task :nearly_end => :environment do + tasks = GraduationTask.where("end_time <=? and end_time > ?", Time.now + 86400, Time.now + 82800) + tasks.each do |task| + if task.tidings.where(parent_container_type: "NearlyEnd").count == 0 + course = task.course + tid_str = "" + task.graduation_works.where(work_status: 0).find_each do |student| + tid_str += "," if tid_str != "" + tid_str += "(#{student.user_id}, #{task.user_id}, #{task.id}, 'GraduationTask', #{task.id}, 'NearlyEnd', + #{course.id}, 'Course', 0, 'GraduationTask', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, + updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + end + + task :end => :environment do + tasks = GraduationTask.where("end_time <= '#{Time.now}' and status = 1") + tasks.each do |task| + task.update_attributes(status: 2) + end + end + + task :cross_comment_start => :environment do + tasks = GraduationTask.where("cross_comment = 1 and comment_time is not null and comment_time <= '#{Time.now}' and status = 2") + tasks.each do |task| + if task.comment_status == 4 + course = task.course + task.graduation_task_group_assignations.each do |assignation| + graduation_group = assignation.graduation_group + assign_group = assignation.assign_group + if graduation_group.present? && assign_group.present? + course_group_ids = course.teacher_course_groups.where(course_member_id: graduation_group.course_members.pluck(:id)).pluck(:course_group_id) + graduation_works = task.graduation_works.where(user_id: course.course_members.where(:course_group_id => course_group_ids).map(&:user_id), + work_status: [1, 2]) + if assign_group.course_members.count <= task.comment_num + graduation_works.each do |work| + assign_group.course_members.each do |member| + work.graduation_work_comment_assignations << GraduationWorkCommentAssignation.new( + graduation_group_id: assign_group.id, user_id: member.user_id, graduation_task_id: task.id) + end + end + else + member_user_ids = assign_group.course_members.pluck(:user_id) + count = 0 + graduation_works.each do |work| + for i in 1 .. task.comment_num + assign_user_id = member_user_ids[count % member_user_ids.size] + work.graduation_work_comment_assignations << GraduationWorkCommentAssignation.new( + graduation_group_id: assign_group.id, user_id: assign_user_id, graduation_task_id: task.id) + count += 1 + end + end + end + end + end + end + task.update_attributes(status: 3) + tid_str = "" + task.course.teachers.find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id}, #{task.user_id}, #{task.id}, 'GraduationTask', #{task.id}, 'CrossComment', + #{task.course.id}, 'Course', 0, 'GraduationTask', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, + updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + +end \ No newline at end of file diff --git a/lib/tasks/homework_endtime.rake b/lib/tasks/homework_endtime.rake new file mode 100644 index 000000000..feba02670 --- /dev/null +++ b/lib/tasks/homework_endtime.rake @@ -0,0 +1,109 @@ +#coding=utf-8 + +namespace :homework_endtime do + desc "send a message for Job deadline" + task :message => :environment do + # 统一设置发布时间的作业 + homeworks = HomeworkCommon.where("unified_setting = 1 and end_time <=? and end_time > ?", Time.now + 86400, Time.now + 82800) + homeworks.each do |homework| + if homework.tidings.where(:parent_container_type => "NearlyEnd").count == 0 + course = homework.course + tid_str = "" + homework.student_works.where(:work_status => 0).find_each do |student| + tid_str += "," if tid_str != "" + tid_str += "(#{student.user_id}, #{homework.user_id}, #{homework.id}, 'HomeworkCommon', #{homework.id}, + 'NearlyEnd', #{course.id}, 'Course', 0, 'HomeworkCommon', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, + updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + + # 分组设置发布时间的作业 + homework_group_settings = HomeworkGroupSetting.where("end_time <=? and end_time > ?", Time.now + 86400, Time.now + 82800) + homework_group_settings.each do |homework_group| + homework = homework_group.homework_common + if homework.present? + course = homework.course + members = course.students.where(:course_group_id => homework_group.course_group_id) + if homework.tidings.where(:parent_container_type => "NearlyEnd", :user_id => members.pluck(:user_id)).count == 0 + tid_str = "" + homework.student_works.where(:work_status => 0, :user_id => members.pluck(:user_id)).find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id}, #{homework.user_id}, #{homework.id}, 'HomeworkCommon', #{homework.id}, + 'NearlyEnd', #{course.id}, 'Course', 0, 'HomeworkCommon', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, + updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + end + end + + # 匿评截止时间快到了 + task :evaluation_nearly_end => :environment do + homework_detail_manuals = HomeworkDetailManual.where("homework_detail_manuals.comment_status = 3 and evaluation_end <=? + and evaluation_end > ? ", Time.now + 86400, Time.now + 82800) + homework_detail_manuals.each do |homework_detail_manual| + homework_common = homework_detail_manual.homework_common + if homework_common.present? + # 取出分配匿评的[student_work_id,user_id]的二维数组 + eva_distribution_ids = StudentWorksEvaluationDistribution.where(:student_work_id => homework_common.student_works.map(&:id)). + map{|a| [a.student_work_id, a.user_id]} + # 取出学生已评分的[student_work_id,user_id]的二维数组 + work_score_ids = StudentWorksScore.where(:student_work_id => homework_common.student_works.map(&:id), :reviewer_role => 3). + map{|a| [a.student_work_id, a.user_id]} + tid_str = "" + # 已参与匿评但未完成全部匿评任务的user_id + user_ids = (eva_distribution_ids - work_score_ids).map{|a| a[1]} + user_ids.uniq.each do |user_id| + tid_str += "," if tid_str != "" + tid_str += "(#{user_id}, #{homework_common.user_id}, #{homework_common.id}, 'HomeworkCommon', #{homework_common.id}, + 'EvaluationNearlyEnd', #{homework_common.course_id}, 'Course', 0, 'HomeworkCommon', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, + updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + end + + # 匿评申诉截止时间快到了 + task :appeal_nearly_end => :environment do + homework_detail_manuals = HomeworkDetailManual.where("homework_detail_manuals.comment_status = 4 and appeal_time <=? + and appeal_time > ?", Time.now + 86400, Time.now + 82800) + homework_detail_manuals.each do |homework_detail_manual| + homework_common = homework_detail_manual.homework_common + if homework_common.present? + eva_distribution = StudentWorksEvaluationDistribution.where(:student_work_id => homework_common.student_works.map(&:id)) + tid_str = "" + eva_distribution.pluck(:user_id).uniq.each do |user_id| + tid_str += "," if tid_str != "" + tid_str += "(#{user_id}, #{homework_common.user_id}, #{homework_common.id}, 'HomeworkCommon', #{homework_common.id}, + 'AppealNearlyEnd', #{homework_common.course_id}, 'Course', 0, 'HomeworkCommon', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, + updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + end +end diff --git a/lib/tasks/homework_evaluation.rake b/lib/tasks/homework_evaluation.rake new file mode 100644 index 000000000..84c7c888f --- /dev/null +++ b/lib/tasks/homework_evaluation.rake @@ -0,0 +1,183 @@ +#coding=utf-8 + +namespace :homework_evaluation do + desc "start and end evaluation" + + def get_assigned_homeworks(student_works, n, index) + student_works += student_works + student_works[index + 1..index + n] + end + + #自动开启匿评的任务 + task :start_evaluation => :environment do + Rails.logger.info("log--------------------------------start_evaluation start") + puts "--------------------------------start_evaluation start" + homework_detail_manuals = HomeworkDetailManual.where("evaluation_start <= '#{Time.now}' and + (homework_detail_manuals.comment_status < 3)") + homework_detail_manuals.each do |homework_detail_manual| + homework_common = homework_detail_manual.homework_common + if homework_common.anonymous_comment + if homework_common.homework_group_settings.where("end_time is null or end_time > '#{Time.now}'").count == 0 + if homework_common.homework_type == "group" + student_works = homework_common.student_works.where("work_status != 0").group(:group_id) + else + student_works = homework_common.student_works.has_committed + end + if student_works.present? && student_works.length >= 2 + if homework_common.homework_type == "group" + student_work_projects = homework_common.student_works.where("work_status != 0").shuffle + student_work_projects.each_with_index do |pro_work, pro_index| + n = homework_detail_manual.evaluation_num + n = (n < student_works.size && n != -1) ? n : student_works.size - 1 + work_index = -1 + student_works.each_with_index do |stu_work, stu_index| + if stu_work.group_id.to_i == pro_work.group_id.to_i + work_index = stu_index + end + end + assigned_homeworks = get_assigned_homeworks(student_works, n, work_index) + assigned_homeworks.each do |h| + student_works_evaluation_distributions = StudentWorksEvaluationDistribution.new(user_id: pro_work.user_id, student_work_id: h.id) + student_works_evaluation_distributions.save + end + + #更新CourseHomeworkStatistics中该学生的待匿评数 + # course_statistics = CourseHomeworkStatistics.find_by_course_id_and_user_id(homework_common.course_id, pro_work.user_id) + # course_statistics.update_attribute('un_evaluation_work_num', course_statistics.un_evaluation_work_num + n) if course_statistics + end + else + student_works = student_works.shuffle + student_works.each_with_index do |work, index| + user = work.user + n = homework_detail_manual.evaluation_num + n = (n < student_works.size && n != -1) ? n : student_works.size - 1 + assigned_homeworks = get_assigned_homeworks(student_works, n, index) + assigned_homeworks.each do |h| + student_works_evaluation_distributions = StudentWorksEvaluationDistribution.new(user_id: user.id, student_work_id: h.id) + student_works_evaluation_distributions.save + end + + #更新CourseHomeworkStatistics中该学生的待匿评数 + # course_statistics = CourseHomeworkStatistics.find_by_course_id_and_user_id(homework_common.course_id, user.id) + # course_statistics.update_attribute('un_evaluation_work_num', course_statistics.un_evaluation_work_num + n) if course_statistics + end + end + homework_detail_manual.update_column('comment_status', 3) + # 匿评开启消息邮件通知,# 所有人 + str = "" + homework_common.course.course_members.pluck(:user_id).uniq.each do |user_id| + str += "," if str != "" + str += "('#{user_id}', '#{homework_common.user_id}', '#{homework_common.id}','HomeworkCommon','#{homework_common.id}', + 'AnonymousComment',#{homework_common.course_id},'Course',0,'HomeworkCommon', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if str != "" + sql = "insert into tidings (user_id,trigger_user_id,container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + else + #作业数小于2,启动失败, 只给老师和助教发 + extra = "作品数量低于两个,无法开启匿评" + end + else + extra = "存在尚未截止的分班,无法开启匿评" + end + if extra.present? + str = '' + homework_common.course.teachers.each do |mem| + str += "," if str != "" + str += "('#{mem.user.id}', '#{homework_common.user_id}', '#{homework_common.id}','HomeworkCommon','#{homework_common.id}', + 'AnonymousCommentFail',#{homework_common.course_id},'Course',0,'System','#{extra}', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if str != "" + sql = "insert into tidings (user_id,trigger_user_id,container_id, container_type,parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, extra, created_at, + updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + homework_detail_manual.update_attributes(:evaluation_start => nil, :evaluation_end => nil, :absence_penalty => 0, + :evaluation_num => 0, :appeal_time => nil, :appeal_penalty => 0) + homework_common.update_attributes(:anonymous_comment => 0, :anonymous_appeal => 0) + end + end + end + + Rails.logger.info("log--------------------------------start_evaluation end") + puts "--------------------------------start_evaluation end" + end + + #自动关闭匿评的任务 + task :end_evaluation => :environment do + homework_detail_manuals = HomeworkDetailManual.where("evaluation_end <= '#{Time.now}' and homework_detail_manuals.comment_status = 3") + homework_detail_manuals.each do |homework_detail_manual| + homework_common = homework_detail_manual.homework_common + if homework_common.anonymous_comment #开启匿评状态才可关闭匿评 + #计算缺评扣分 参与匿评 + work_ids = "(" + homework_common.student_works.has_committed.map(&:id).join(",") + ")" + + homework_common.student_works.where("work_status != 0").each do |student_work| + absence_penalty_count = student_work.user.student_works_evaluation_distributions.where("student_work_id IN #{work_ids}").count - + student_work.user.student_works_scores.where("student_work_id IN #{work_ids} and reviewer_role = 3").count + + student_work.absence_penalty = absence_penalty_count > 0 ? absence_penalty_count * homework_detail_manual.absence_penalty : 0 + student_work.save + + #更新CourseHomeworkStatistics中该学生的待匿评数和缺评数 + # absence_penalty_count = absence_penalty_count > 0 ? absence_penalty_count : 0 + # course_statistics = CourseHomeworkStatistics.find_by_course_id_and_user_id(homework_common.course_id, student_work.user_id) + # course_statistics.update_attribute('un_evaluation_work_num', (course_statistics.un_evaluation_work_num - absence_penalty_count) < 0 ? 0 : + # (course_statistics.un_evaluation_work_num - absence_penalty_count)) if course_statistics + # course_statistics.update_attribute('absence_evaluation_work_num', course_statistics.absence_evaluation_work_num + absence_penalty_count) if course_statistics + end + + # 未参与匿评 + if homework_common.homework_detail_manual.no_anon_penalty == 0 + all_dis_eva = StudentWorksEvaluationDistribution.where("student_work_id IN #{work_ids}") + has_sw_count = all_dis_eva.select("distinct user_id").count + anon_count = all_dis_eva.count / has_sw_count + homework_common.student_works.where("work_status != 0").each do |student_work| + if student_work.user.student_works_evaluation_distributions.where("student_work_id IN #{work_ids}").count == 0 + student_work.absence_penalty = homework_detail_manual.absence_penalty * anon_count + student_work.save + end + end + end + + if homework_common.anonymous_appeal + homework_detail_manual.update_column('comment_status', 4) + # 申诉开启 + eva_distribution = StudentWorksEvaluationDistribution.where(:student_work_id => homework_common.student_works.pluck(:id)) + str = "" + eva_distribution.pluck(:user_id).uniq.each do |user_id| + str += "," if str != "" + str += "(#{user_id}, #{homework_common.user_id}, #{homework_common.id}, 'HomeworkCommon', #{homework_common.id}, + 'AnonymousAppeal', #{homework_common.course_id}, 'Course', 0, 'HomeworkCommon', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if str != "" + sql = "insert into tidings (user_id,trigger_user_id,container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + else + homework_detail_manual.update_column('comment_status', 5) + end + # 匿评关闭消息通知 给所有人发 + # course = homework_common.course + # course.members.each do |m| + # homework_common.course_messages << CourseMessage.new(:user_id => m.user_id, :course_id => course.id, :viewed => false, :status => 3) + # end + # 邮件通知 + # Mailer.send_mail_anonymous_comment_close(homework_common).deliver + end + end + end + + #自动关闭申诉的任务 + task :end_appeal => :environment do + homework_detail_manuals = HomeworkDetailManual.where("appeal_time <= '#{Time.now}' and homework_detail_manuals.comment_status = 4") + homework_detail_manuals.update_all(:comment_status => 5) + end +end diff --git a/lib/tasks/homework_publishtime.rake b/lib/tasks/homework_publishtime.rake new file mode 100644 index 000000000..f6a4325cd --- /dev/null +++ b/lib/tasks/homework_publishtime.rake @@ -0,0 +1,280 @@ +#coding=utf-8 + +namespace :homework_publishtime do + desc "start publish homework and end homework" + + # 作业的分班设置时间 + def homework_group_setting homework, group_id + setting = nil + if homework.homework_group_settings.where(:course_group_id => group_id).first + setting = homework.homework_group_settings.where(:course_group_id => group_id).first + else + setting = homework + end + setting + end + + task :publish => :environment do + Rails.logger.info("log--------------------------------homework_publish start") + homework_commons = HomeworkCommon.includes(:homework_detail_manual).where(homework_detail_manuals: {comment_status: 0}) + .where("publish_time is not null and publish_time <= '#{Time.now}'") + homework_commons.each do |homework| + homework_detail_manual = homework.homework_detail_manual + homework_detail_manual.update_column('comment_status', 1) + course = homework.course + students = course.students + if !course.nil? && !students.empty? + tid_str = "" + course.teachers.find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id}, #{homework.user_id}, #{homework.id}, 'HomeworkCommon', #{homework.id}, 'HomeworkPublish', + #{course.id}, 'Course', 0, 'HomeworkCommon', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if homework.unified_setting + students.each do |student| + tid_str += "," if tid_str != "" + tid_str += "(#{student.user_id}, #{homework.user_id}, #{homework.id}, 'HomeworkCommon', #{homework.id}, + 'HomeworkPublish', #{course.id}, 'Course', 0, 'HomeworkCommon', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + + HomeworkPublishUpdateWorkStatusJob.perform_now(nil, homework.id) + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, + updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + + if homework.course_acts.size == 0 + homework.course_acts << CourseActivity.new(:user_id => homework.user_id,:course_id => homework.course_id) + end + end + + # 分组设置发布时间的作业 + homework_group_settings = HomeworkGroupSetting.where("publish_time < ? and publish_time > ?", Time.now + 900, Time.now - 900) + homework_group_settings.each do |homework_group| + homework = homework_group.homework_common + if homework.present? + course = homework.course + homework_detail_manual = homework.homework_detail_manual + homework_detail_manual.update_column('comment_status', 1) if homework_detail_manual.comment_status == 0 + + tid_str = "" + members = course.students.where(:course_group_id => homework_group.course_group_id) + members.find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id}, #{homework.user_id}, #{homework.id}, 'HomeworkCommon', #{homework.id}, 'HomeworkPublish', + #{course.id}, 'Course', 0, 'HomeworkCommon', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', + '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, + parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, + updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + + HomeworkPublishUpdateWorkStatusJob.perform_now([homework_group.id], homework.id) + + end + end + Rails.logger.info("log--------------------------------homework_publish end") + end + + task :end => :environment do + Rails.logger.info("log--------------------------------homework_publish_end start") + homework_commons = HomeworkCommon.includes(:homework_detail_manual).where(homework_detail_manuals: {comment_status: 1}) + .where("homework_type = 4 and end_time <= '#{Time.now}'") + homework_commons.each do |homework| + # homework_challenge_settings = homework.homework_challenge_settings + homework.homework_detail_manual.update_column("comment_status", 2) + + if homework.allow_late + if homework.unified_setting + student_works = homework.student_works.where("work_status != 0") + # none_student_works = homework.student_works.where("work_status = 0") + else + setting = homework.homework_group_settings.where(:end_time => homework.end_time) + unless setting.blank? + users = homework.course.students.where(:course_group_id => setting.map(&:course_group_id)) + user_ids = users.blank? ? "(-1)" : "(" + users.map(&:user_id).join(",") + ")" + student_works = homework.student_works.where("work_status != 0 and user_id in #{user_ids}") + # none_student_works = homework.student_works.where("work_status = 0 and user_id in #{user_ids}") + end + end + + student_works.joins(:myshixun).where("myshixuns.status != 1").update_all(late_penalty: homework.late_penalty) if student_works.present? + + else + HomeworksService.new.update_student_eff_score homework + end + +=begin + student_works.each do |student_work| + member = Member.find_by_sql("select course_group_id from members where course_id = #{homework.course_id} and + user_id = #{student_work.user_id}").first + setting_time = homework_group_setting homework, member.try(:course_group_id) + games = student_work.myshixun.games.where(:challenge_id => homework_challenge_settings.map(&:challenge_id)) + unless games.select{|game| game.status == 2}.size == games.size + student_work.work_status = 2 + student_work.late_penalty = homework.late_penalty + score = student_work.final_score.to_i - student_work.late_penalty + student_work.work_score = format("%.2f",(score < 0 ? 0 : score).to_f) + student_work.cost_time = homework.allow_late ? student_work.cost_time : (Time.now.to_i - setting_time.publish_time.to_i) + sql = "update student_works set late_penalty = #{student_work.late_penalty}, work_status = 2, work_score = + #{student_work.work_score}, cost_time = #{student_work.cost_time} where id = #{student_work.id}" + ActiveRecord::Base.connection.execute sql + end + # myshixun = student_work.myshixun + # final_score = 0 + # homework_challenge_settings.each do |setting| + # game = myshixun.games.where(:challenge_id => setting.challenge_id, :status => 2).first + # unless game.nil? + # final_score += homework.homework_detail_manual.answer_open_evaluation ? setting.score : (game.final_score >= 0 ? + # setting.score : 0) + # end + # end + end +=end +=begin + none_student_works.each do |student_work| + myshixun = Myshixun.where(:shixun_id => homework.homework_commons_shixuns.shixun_id, :user_id => student_work.user_id).first + if myshixun + student_work.update_attributes(:work_status => myshixun.is_complete? ? 1 : 2, :late_penalty => myshixun.is_complete? ? 0 : + homework.late_penalty, :commit_time => myshixun.created_at, :update_time => myshixun.updated_at, :myshixun_id => myshixun.id) + student_work.late_penalty = myshixun.is_complete? ? 0 : homework.late_penalty + final_score = 0 + homework_challenge_settings.each do |setting| + game = myshixun.games.where(:challenge_id => setting.challenge_id, :status => 2).first + unless game.nil? + final_score += homework.homework_detail_manual.answer_open_evaluation ? setting.score : (game.final_score >= 0 ? + setting.score : 0) + end + end + student_work.update_column("final_score", format("%.2f",final_score.to_f)) + score = student_work.final_score - student_work.late_penalty + student_work.update_column("work_score", format("%.2f",(score < 0 ? 0 : score).to_f)) if score + end + end +=end + end + all_homework_commons = HomeworkCommon.includes(:homework_detail_manual).where(homework_detail_manuals: {comment_status: 1}) + .where("homework_type = 4 and end_time > '#{Time.now}'") + homework_ids = all_homework_commons.blank? ? "(-1)" : "(" + all_homework_commons.map(&:id).join(",") + ")" + HomeworkGroupSetting.where("end_time <= '#{Time.now}' and homework_common_id in #{homework_ids}").each do |homework_setting| + homework = homework_setting.homework_common + + if homework.allow_late + # homework_challenge_settings = homework.homework_challenge_settings + + users = homework.course.students.where(:course_group_id => homework_setting.course_group_id) + user_ids = users.blank? ? "(-1)" : "(" + users.map(&:user_id).join(",") + ")" + student_works = homework.student_works.where("work_status != 0 and user_id in #{user_ids}") + student_works.joins(:myshixun).where("myshixuns.status != 1").update_all(late_penalty: homework.late_penalty) if student_works.present? + else + # HomeworksService.new.update_student_eff_score homework # 分班设置的不需要另外算效率分 + end + + # none_student_works = homework.student_works.where("work_status = 0 and user_id in #{user_ids}") + +=begin + student_works.each do |student_work| + games = student_work.myshixun.games.where(:challenge_id => homework_challenge_settings.map(&:challenge_id)) + unless games.select{|game| game.status == 2}.size == games.size + student_work.late_penalty = homework.late_penalty + student_work.work_status = 2 + score = student_work.final_score.to_i - student_work.late_penalty + student_work.work_score = format("%.2f",(score < 0 ? 0 : score).to_f) + student_work.cost_time = homework.allow_late ? student_work.cost_time : (Time.now.to_i - homework_setting.publish_time.to_i) + sql = "update student_works set late_penalty = #{student_work.late_penalty}, work_status = 2, work_score = + #{student_work.work_score} where id = #{student_work.id}" + ActiveRecord::Base.connection.execute sql + end + # myshixun = student_work.myshixun + # final_score = 0 + # homework_challenge_settings.each do |setting| + # game = myshixun.games.where(:challenge_id => setting.challenge_id, :status => 2).first + # unless game.nil? + # final_score += homework.homework_detail_manual.answer_open_evaluation ? setting.score : (game.final_score >= 0 ? + # setting.score : 0) + # end + # end + end +=end +=begin + none_student_works.each do |student_work| + myshixun = Myshixun.where(:shixun_id => homework.homework_commons_shixuns.shixun_id, :user_id => student_work.user_id).first + if myshixun + student_work.update_attributes(:work_status => myshixun.is_complete? ? 1 : 2, :late_penalty => myshixun.is_complete? ? 0 : homework.late_penalty, :commit_time => myshixun.created_at, :update_time => myshixun.updated_at, :myshixun_id => myshixun.id) + student_work.late_penalty = myshixun.is_complete? ? 0 : homework.late_penalty + final_score = 0 + homework_challenge_settings.each do |setting| + game = myshixun.games.where(:challenge_id => setting.challenge_id, :status => 2).first + unless game.nil? + final_score += homework.homework_detail_manual.answer_open_evaluation ? setting.score : (game.final_score >= 0 ? setting.score : 0) + end + end + student_work.update_column("final_score", format("%.2f",final_score.to_f)) + score = student_work.final_score - student_work.late_penalty + student_work.update_column("work_score", format("%.2f",(score < 0 ? 0 : score).to_f)) if score + end + end +=end + end + Rails.logger.info("log--------------------------------homework_publish_end end") + end + + task :archive => :environment do + Rails.logger.info("log--------------------------------homework_archive start") + homework_commons = HomeworkCommon.joins(:homework_detail_manual).where("homework_type = 4 and allow_late = 1 and + late_time <= ? and late_time > ? and homework_detail_manuals.comment_status != 6", Time.now, Time.now - 900) + homework_commons.each do |homework| + HomeworksService.new.update_student_eff_score homework + +=begin + homework_detail_manual = homework.homework_detail_manual + homework_detail_manual.update_column('comment_status', 6) + if homework.homework_type == 4 && homework.allow_late + homework_challenge_settings = homework.homework_challenge_settings + + homework.student_works.where("work_status != 0").each do |student_work| + myshixun = student_work.myshixun + final_score = 0 + homework_challenge_settings.each do |setting| + game = myshixun.games.where(:challenge_id => setting.challenge_id, :status => 2).first + unless game.nil? + final_score += homework.homework_detail_manual.answer_open_evaluation ? setting.score : (game.final_score >= 0 ? setting.score : 0) + end + end + student_work.update_column("final_score", format("%.2f",final_score.to_f)) + score = student_work.final_score - student_work.late_penalty + student_work.update_column("work_score", format("%.2f",(score < 0 ? 0 : score).to_f)) + end + + homework.student_works.where("work_status = 0").each do |student_work| + myshixun = Myshixun.where(:shixun_id => homework.homework_commons_shixuns.shixun_id, :user_id => student_work.user_id).first + if myshixun + student_work.update_attributes(:work_status => 2, :late_penalty => homework.late_penalty, :commit_time => myshixun.created_at, :update_time => myshixun.updated_at, :myshixun_id => myshixun.id) + student_work.late_penalty = homework.late_penalty + final_score = 0 + homework_challenge_settings.each do |setting| + game = myshixun.games.where(:challenge_id => setting.challenge_id, :status => 2).first + unless game.nil? + final_score += homework.homework_detail_manual.answer_open_evaluation ? setting.score : (game.final_score >= 0 ? setting.score : 0) + end + end + student_work.update_column("final_score", format("%.2f",final_score.to_f)) + score = student_work.final_score - student_work.late_penalty + student_work.update_column("work_score", format("%.2f",(score < 0 ? 0 : score).to_f)) if score + end + end + end +=end + end + Rails.logger.info("log--------------------------------homework_archive end") + end +end \ No newline at end of file diff --git a/lib/tasks/poll_publish.rake b/lib/tasks/poll_publish.rake new file mode 100644 index 000000000..c33ad3afb --- /dev/null +++ b/lib/tasks/poll_publish.rake @@ -0,0 +1,137 @@ +#coding=utf-8 + +namespace :poll_publish do + desc "publish poll and end poll" + + task :publish => :environment do + puts "--------------------------------poll_publish start" + # 统一设置发布时间的问卷 + polls = Poll.where("publish_time is not null and polls_status = 1 and publish_time <=?",Time.now) + polls.each do |poll| + poll.update_attributes(:polls_status => 2) + course = poll.course + tid_str = "" + course.teachers.find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id}, #{poll.user_id}, #{poll.id}, 'Poll', #{poll.id}, 'PollPublish', #{course.id}, 'Course', 0, 'Poll', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if poll.unified_setting + course.students.find_each do |student| + tid_str += "," if tid_str != "" + tid_str += "(#{student.user_id}, #{poll.user_id}, #{poll.id}, 'Poll', #{poll.id}, 'PollPublish', #{course.id}, 'Course', 0, 'Poll', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + + if poll.poll_users.count == 0 + str = "" + course.students.find_each do |student| + str += "," if str != "" + str += "(#{student.user_id},#{poll.id}, 0, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + + if str != "" + sql = "insert into poll_users (user_id, poll_id, commit_status, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + + if poll.course_acts.size == 0 + poll.course_acts << CourseActivity.new(:user_id => poll.user_id,:course_id => poll.course_id) + end + end + + # 分组设置发布时间的问卷 + poll_group_settings = PollGroupSetting.where("publish_time < ? and publish_time > ?", Time.now + 900, Time.now - 900) + poll_group_settings.each do |poll_group| + poll = poll_group.poll + if poll.present? + course = poll.course + poll.update_attributes(:polls_status => 2) if poll.polls_status == 1 + + tid_str = "" + members = course.course_members.where(:course_group_id => poll_group.course_group_id) + members.find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id},#{poll.user_id}, #{poll.id}, 'Poll', #{poll.id}, 'PollPublish', #{course.id}, 'Course', 0, 'Poll', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + + puts "--------------------------------poll_publish end" + end + + task :nearly_end => :environment do + puts "--------------------------------poll_nearly_end start" + # 统一设置发布时间的问卷 + polls = Poll.where("polls_status = 2 and unified_setting = 1 and end_time <=? and end_time > ?", Time.now + 86400, Time.now + 84600) + polls.each do |poll| + if poll.tidings.where(:parent_container_type => "NearlyEnd").count == 0 + course = poll.course + tid_str = "" + poll.poll_users.where(:commit_status => 0).find_each do |user| + tid_str += "," if tid_str != "" + tid_str += "(#{user.user_id}, #{poll.user_id}, #{poll.id}, 'Poll', #{poll.id}, 'NearlyEnd', #{course.id}, 'Course', 0, 'Poll', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + + # 分组设置发布时间的问卷 + poll_group_settings = PollGroupSetting.where("end_time <=? and end_time > ?", Time.now + 86400, Time.now + 84600) + poll_group_settings.each do |poll_group| + poll = poll_group.poll + if poll.present? + course = poll.course + members = course.course_members.where(:course_group_id => poll_group.course_group_id) + if poll.tidings.where(:parent_container_type => "NearlyEnd", :user_id => members.map(&:user_id)).count == 0 + tid_str = "" + poll.poll_users.where(:commit_status => 0, :user_id => members.map(&:user_id)).find_each do |member| + tid_str += "," if tid_str != "" + tid_str += "(#{member.user_id},#{poll.user_id}, #{poll.id}, 'Poll', #{poll.id}, 'NearlyEnd', #{course.id}, 'Course', 0, 'Poll', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if tid_str != "" + tid_sql = "insert into tidings (user_id, trigger_user_id, container_id, container_type, parent_container_id, parent_container_type, belong_container_id, belong_container_type, viewed, tiding_type, created_at, updated_at) values" + tid_str + ActiveRecord::Base.connection.execute tid_sql + end + end + end + end + puts "--------------------------------poll_nearly_end end" + end + + task :end => :environment do + polls = Poll.where("polls_status = 2 and unified_setting = 1 and end_time <=?",Time.now) + polls.each do |poll| + poll.update_attributes(:polls_status => 3) + poll.poll_users.each do |poll_user| + if poll_user.commit_status == 0 && !poll_user.start_at.nil? + poll_user.update_attributes(:commit_status => 1, :end_at => Time.now) + end + end + end + + PollGroupSetting.where("end_time < ? and end_time > ?", Time.now + 1800, Time.now - 1800).each do |poll_setting| + poll = poll_setting.poll + + users = poll.course.course_members.where(:course_group_id => poll_setting.course_group_id) + poll_users = poll.poll_users.where(:user_id => users.map(&:user_id)) + + poll_users.each do |poll_user| + if poll_user.commit_status == 0 && !poll_user.start_at.nil? + poll_user.update_attributes(:commit_status => 1, :end_at => Time.now) + end + end + end + end +end diff --git a/lib/tasks/resource_publish.rake b/lib/tasks/resource_publish.rake new file mode 100644 index 000000000..7872a6ce4 --- /dev/null +++ b/lib/tasks/resource_publish.rake @@ -0,0 +1,13 @@ +#coding=utf-8 + +namespace :resource_publish do + desc "start publish resource" + task :publish => :environment do + Rails.logger.info("log--------------------------------resource_publish start") + attachments = Attachment.where("publish_time < '#{Time.now}' and is_publish = 0") + attachments.each do |attachment| + attachment.update_attributes(:is_publish => 1) + end + Rails.logger.info("log--------------------------------resource_publish end") + end +end \ No newline at end of file diff --git a/lib/tasks/user_profile_completed_transfer.rake b/lib/tasks/user_profile_completed_transfer.rake new file mode 100644 index 000000000..c50a047c1 --- /dev/null +++ b/lib/tasks/user_profile_completed_transfer.rake @@ -0,0 +1,22 @@ +desc 'transfer user profile completed data' +task transfer_user_profile_completed: :environment do + buffer_size = 1000 + + ids = [] + User.includes(:user_extension).find_each do |user| + extension = user.user_extension + next if extension.blank? || user.lastname.blank? || user.mail.blank? || extension.school_id.blank? || extension.identity.blank? + + ids << user.id + if ids.size == buffer_size + batch_update_user_profile_completed(ids) + ids.clear + end + end + + batch_update_user_profile_completed(ids) if ids.present? +end + +def batch_update_user_profile_completed(ids) + User.connection.execute("UPDATE users SET profile_completed = true WHERE id IN (#{ids.join(',')})") +end \ No newline at end of file diff --git a/log/.keep b/log/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/public/123.html b/public/123.html new file mode 100644 index 000000000..e69de29bb diff --git a/public/404.html b/public/404.html new file mode 100644 index 000000000..060ccca96 --- /dev/null +++ b/public/404.html @@ -0,0 +1,67 @@ + + + + The page you were looking for doesn't exist (404) + + + + + + +
    +
    +

    The page you were looking for doesn't exist.

    +

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

    +
    +

    If you are the application owner check the logs for more information.

    +
    + + diff --git a/public/422.html b/public/422.html new file mode 100644 index 000000000..bd97e059f --- /dev/null +++ b/public/422.html @@ -0,0 +1,67 @@ + + + + The change you wanted was rejected (422) + + + + + + +
    +
    +

    The change you wanted was rejected.

    +

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

    +
    +

    If you are the application owner check the logs for more information.

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

    We're sorry, but something went wrong.

    +
    +

    If you are the application owner check the logs for more information.

    +
    + + diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png new file mode 100644 index 000000000..e69de29bb diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 000000000..e69de29bb diff --git a/public/assets/kindeditor/kindeditor.js b/public/assets/kindeditor/kindeditor.js new file mode 100644 index 000000000..1df0f835a --- /dev/null +++ b/public/assets/kindeditor/kindeditor.js @@ -0,0 +1,6272 @@ +//function dump_obj(myObject) { +// var s = ""; +// for (var property in myObject) { +// s = s + "\n "+property +": " + myObject[property] ; +// } +// alert(s) +/******************************************************************************* +* KindEditor - WYSIWYG HTML Editor for Internet +* Copyright (C) 2006-2013 kindsoft.net +* +* @author Roddy +* @website http://www.kindsoft.net/ +* @licence http://www.kindsoft.net/license.php +* @version 4.1.10 (2013-11-23) +*******************************************************************************/ +(function (window, undefined) { + if (window.KindEditor) { + return; + } +if (!window.console) { + window.console = {}; +} +if (!console.log) { + console.log = function () {}; +} +var _VERSION = '4.1.10 (2013-11-23)', + _ua = navigator.userAgent.toLowerCase(), + _IE = _ua.indexOf('msie') > -1 && _ua.indexOf('opera') == -1, + _NEWIE = _ua.indexOf('msie') == -1 && _ua.indexOf('trident') > -1, + _GECKO = _ua.indexOf('gecko') > -1 && _ua.indexOf('khtml') == -1, + _WEBKIT = _ua.indexOf('applewebkit') > -1, + _OPERA = _ua.indexOf('opera') > -1, + _MOBILE = _ua.indexOf('mobile') > -1, + _IOS = /ipad|iphone|ipod/.test(_ua), + _QUIRKS = document.compatMode != 'CSS1Compat', + _IERANGE = !window.getSelection, + _matches = /(?:msie|firefox|webkit|opera)[\/:\s](\d+)/.exec(_ua), + _V = _matches ? _matches[1] : '0', + _TIME = new Date().getTime(); +function _isArray(val) { + if (!val) { + return false; + } + return Object.prototype.toString.call(val) === '[object Array]'; +} +function _isFunction(val) { + if (!val) { + return false; + } + return Object.prototype.toString.call(val) === '[object Function]'; +} +function _inArray(val, arr) { + for (var i = 0, len = arr.length; i < len; i++) { + if (val === arr[i]) { + return i; + } + } + return -1; +} +function _each(obj, fn) { + if (_isArray(obj)) { + for (var i = 0, len = obj.length; i < len; i++) { + if (fn.call(obj[i], i, obj[i]) === false) { + break; + } + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if (fn.call(obj[key], key, obj[key]) === false) { + break; + } + } + } + } +} +function _trim(str) { + return str.replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, ''); +} +function _inString(val, str, delimiter) { + delimiter = delimiter === undefined ? ',' : delimiter; + return (delimiter + str + delimiter).indexOf(delimiter + val + delimiter) >= 0; +} +function _addUnit(val, unit) { + unit = unit || 'px'; + //return val && /^\d+$/.test(val) ? val + unit : val; + return val && /^-?\d+(?:\.\d+)?$/.test(val) ? val + unit : val; +} +function _removeUnit(val) { + var match; + return val && (match = /(\d+)/.exec(val)) ? parseInt(match[1], 10) : 0; +} +function _escape(val) { + return val.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); +} +function _unescape(val) { + return val.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/&/g, '&'); +} +function _toCamel(str) { + var arr = str.split('-'); + str = ''; + _each(arr, function(key, val) { + str += (key > 0) ? val.charAt(0).toUpperCase() + val.substr(1) : val; + }); + return str; +} +function _toHex(val) { + function hex(d) { + var s = parseInt(d, 10).toString(16).toUpperCase(); + return s.length > 1 ? s : '0' + s; + } + return val.replace(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/ig, + function($0, $1, $2, $3) { + return '#' + hex($1) + hex($2) + hex($3); + } + ); +} +function _toMap(val, delimiter) { + delimiter = delimiter === undefined ? ',' : delimiter; + var map = {}, arr = _isArray(val) ? val : val.split(delimiter), match; + _each(arr, function(key, val) { + if ((match = /^(\d+)\.\.(\d+)$/.exec(val))) { + for (var i = parseInt(match[1], 10); i <= parseInt(match[2], 10); i++) { + map[i.toString()] = true; + } + } else { + map[val] = true; + } + }); + return map; +} +function _toArray(obj, offset) { + return Array.prototype.slice.call(obj, offset || 0); +} +function _undef(val, defaultVal) { + return val === undefined ? defaultVal : val; +} +function _invalidUrl(url) { + return !url || /[<>"]/.test(url); +} +function _addParam(url, param) { + return url.indexOf('?') >= 0 ? url + '&' + param : url + '?' + param; +} +function _extend(child, parent, proto) { + if (!proto) { + proto = parent; + parent = null; + } + var childProto; + if (parent) { + var fn = function () {}; + fn.prototype = parent.prototype; + childProto = new fn(); + _each(proto, function(key, val) { + childProto[key] = val; + }); + } else { + childProto = proto; + } + childProto.constructor = child; + child.prototype = childProto; + child.parent = parent ? parent.prototype : null; +} +function _json(text) { + var match; + if ((match = /\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))) { + text = match[0]; + } + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + if (/^[\],:{}\s]*$/. + test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). + replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). + replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + return eval('(' + text + ')'); + } + throw 'JSON parse error'; +} +var _round = Math.round; +var K = { + DEBUG : false, + VERSION : _VERSION, + IE : _IE, + GECKO : _GECKO, + WEBKIT : _WEBKIT, + OPERA : _OPERA, + V : _V, + TIME : _TIME, + each : _each, + isArray : _isArray, + isFunction : _isFunction, + inArray : _inArray, + inString : _inString, + trim : _trim, + addUnit : _addUnit, + removeUnit : _removeUnit, + escape : _escape, + unescape : _unescape, + toCamel : _toCamel, + toHex : _toHex, + toMap : _toMap, + toArray : _toArray, + undef : _undef, + invalidUrl : _invalidUrl, + addParam : _addParam, + extend : _extend, + json : _json +}; +var _INLINE_TAG_MAP = _toMap('a,abbr,acronym,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,img,input,ins,kbd,label,map,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'), + _BLOCK_TAG_MAP = _toMap('address,applet,blockquote,body,center,dd,dir,div,dl,dt,fieldset,form,frameset,h1,h2,h3,h4,h5,h6,head,hr,html,iframe,ins,isindex,li,map,menu,meta,noframes,noscript,object,ol,p,pre,script,style,table,tbody,td,tfoot,th,thead,title,tr,ul'), + _SINGLE_TAG_MAP = _toMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'), + _STYLE_TAG_MAP = _toMap('b,basefont,big,del,em,font,i,s,small,span,strike,strong,sub,sup,u'), + _CONTROL_TAG_MAP = _toMap('img,table,input,textarea,button'), + _PRE_TAG_MAP = _toMap('pre,style,script'), + _NOSPLIT_TAG_MAP = _toMap('html,head,body,td,tr,table,ol,ul,li'), + _AUTOCLOSE_TAG_MAP = _toMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'), + _FILL_ATTR_MAP = _toMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'), + _VALUE_TAG_MAP = _toMap('input,button,textarea,select'); +// Begining of modification by Macrow +function _getBasePath() { + var refPath = '/assets/kindeditor/'; + var els = document.getElementsByTagName('script'), src; + for (var i = 0, len = els.length; i < len; i++) { + src = els[i].src || ''; + if (/(kindeditor|application)[\w\-\.]*\.js/.test(src)) { + return src.substring(0, src.indexOf('assets')) + refPath; + } + } + return refPath; +} +// End of modification by Macrow +K.basePath = _getBasePath(); +K.options = { + placeholder : '', + local_storage_mdu : '', + local_storage_id : '', + designMode : true, + fullscreenMode : false, + filterMode : true, + wellFormatMode : true, + shadowMode : true, + loadStyleMode : true, + basePath : K.basePath, + emotionsBasePath: '', //TODO http://forge.trustie.net + themesPath : K.basePath + 'themes/', + langPath : K.basePath + 'lang/', + pluginsPath : K.basePath + 'plugins/', + themeType : 'default', + langType : 'zh_CN', + urlType : '', + newlineTag : 'p', + resizeType : 1, + syncType : 'form', + pasteType : 2, + dialogAlignType : 'page', + useContextmenu : true, + fullscreenShortcut : false, + bodyClass : 'ke-content', + indentChar : '\t', + cssPath : K.basePath +'plugins/code/previewcode.css', + cssData : 'font{color:black;}', + minWidth : 650, + minHeight : 100, + minChangeSize : 1, + zIndex : 811213, + items : ['code','emoticons','fontname', + 'forecolor', 'hilitecolor', 'bold', '|', 'justifyleft', 'justifycenter', 'insertorderedlist','insertunorderedlist', '|', + 'formatblock', 'fontsize', '|','indent', 'outdent', + '|','imagedirectupload','table', 'media', 'preview',"more" + ], + noDisableItems : ['source', 'fullscreen'], + colorTable : [ + ['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'], + ['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'], + ['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'], + ['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000'] + ], + fontSizeTable : ['选中的字体大小:','9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px'], + htmlTags : { + font : ['id', 'class', 'color', 'size', 'face', '.background-color'], + span : [ + 'id', 'class', '.color', '.background-color', '.font-size', '.font-family', '.background', + '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.line-height', 'data-user-id' + ], + div : [ + 'id', 'class', 'align', '.border', '.margin', '.padding', '.text-align', '.color', + '.background-color', '.font-size', '.font-family', '.font-weight', '.background', + '.font-style', '.text-decoration', '.vertical-align', '.margin-left' + ], + table: [ + 'id', 'class', 'border', 'cellspacing', 'cellpadding', 'width', 'height', 'align', 'bordercolor', + '.padding', '.margin', '.border','.border-color', 'bgcolor', '.text-align', '.color', '.background-color', + '.font-size', '.font-family', '.font-weight', '.font-style', '.text-decoration', '.background', + '.width', '.height', '.border-collapse','.table-layout' + ], + 'td,th': [ + 'id', 'class', 'align', 'valign', 'width', 'height', 'colspan', 'rowspan', 'bgcolor', + '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.font-weight', + '.font-style', '.text-decoration', '.vertical-align', '.background', '.border','.border-color', '.text-overflow','.overflow','.white-space' + ], + a : ['id', 'class', 'href', 'target', 'name','data-method','data-remote','rel'], + embed : ['id', 'class', 'src', 'width', 'height', 'type', 'loop', 'autostart', 'quality', '.width', '.height', 'align', 'allowscriptaccess'], + img : ['id', 'class', 'src', 'width', 'height', 'border', 'alt', 'title', 'align', '.width', '.height', '.border'], + 'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6' : [ + 'id', 'class', 'align', '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.background', + '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.text-indent', '.margin-left', '.margin', '.border', '.padding' + ], + pre : ['id', 'class'], + hr : ['id', 'class', '.page-break-after'], + 'br,tbody,tr,strong,b,sub,sup,em,i,u,strike,s,del' : ['id', 'class'], + iframe : ['id', 'class', 'src', 'frameborder', 'width', 'height', '.width', '.height'] + }, + layout : '
    ' +}; +var _useCapture = false; +var _INPUT_KEY_MAP = _toMap('8,9,13,32,46,48..57,59,61,65..90,106,109..111,188,190..192,219..222'); +var _CURSORMOVE_KEY_MAP = _toMap('33..40'); +var _CHANGE_KEY_MAP = {}; +_each(_INPUT_KEY_MAP, function(key, val) { + _CHANGE_KEY_MAP[key] = val; +}); +_each(_CURSORMOVE_KEY_MAP, function(key, val) { + _CHANGE_KEY_MAP[key] = val; +}); +function _bindEvent(el, type, fn) { + if (el.addEventListener){ + el.addEventListener(type, fn, _useCapture); + } else if (el.attachEvent){ + el.attachEvent('on' + type, fn); + } +} +function _unbindEvent(el, type, fn) { + if (el.removeEventListener){ + el.removeEventListener(type, fn, _useCapture); + } else if (el.detachEvent){ + el.detachEvent('on' + type, fn); + } +} +var _EVENT_PROPS = ('altKey,attrChange,attrName,bubbles,button,cancelable,charCode,clientX,clientY,ctrlKey,currentTarget,' + + 'data,detail,eventPhase,fromElement,handler,keyCode,metaKey,newValue,offsetX,offsetY,originalTarget,pageX,' + + 'pageY,prevValue,relatedNode,relatedTarget,screenX,screenY,shiftKey,srcElement,target,toElement,view,wheelDelta,which').split(','); +function KEvent(el, event) { + this.init(el, event); +} +_extend(KEvent, { + init : function(el, event) { + var self = this, doc = el.ownerDocument || el.document || el; + self.event = event; + _each(_EVENT_PROPS, function(key, val) { + self[val] = event[val]; + }); + if (!self.target) { + self.target = self.srcElement || doc; + } + if (self.target.nodeType === 3) { + self.target = self.target.parentNode; + } + if (!self.relatedTarget && self.fromElement) { + self.relatedTarget = self.fromElement === self.target ? self.toElement : self.fromElement; + } + if (self.pageX == null && self.clientX != null) { + var d = doc.documentElement, body = doc.body; + self.pageX = self.clientX + (d && d.scrollLeft || body && body.scrollLeft || 0) - (d && d.clientLeft || body && body.clientLeft || 0); + self.pageY = self.clientY + (d && d.scrollTop || body && body.scrollTop || 0) - (d && d.clientTop || body && body.clientTop || 0); + } + if (!self.which && ((self.charCode || self.charCode === 0) ? self.charCode : self.keyCode)) { + self.which = self.charCode || self.keyCode; + } + if (!self.metaKey && self.ctrlKey) { + self.metaKey = self.ctrlKey; + } + if (!self.which && self.button !== undefined) { + self.which = (self.button & 1 ? 1 : (self.button & 2 ? 3 : (self.button & 4 ? 2 : 0))); + } + switch (self.which) { + case 186 : + self.which = 59; + break; + case 187 : + case 107 : + case 43 : + self.which = 61; + break; + case 189 : + case 45 : + self.which = 109; + break; + case 42 : + self.which = 106; + break; + case 47 : + self.which = 111; + break; + case 78 : + self.which = 110; + break; + } + if (self.which >= 96 && self.which <= 105) { + self.which -= 48; + } + }, + preventDefault : function() { + var ev = this.event; + if (ev.preventDefault) { + ev.preventDefault(); + } else { + ev.returnValue = false; + } + }, + stopPropagation : function() { + var ev = this.event; + if (ev.stopPropagation) { + ev.stopPropagation(); + } else { + ev.cancelBubble = true; + } + }, + stop : function() { + this.preventDefault(); + this.stopPropagation(); + } +}); +var _eventExpendo = 'kindeditor_' + _TIME, _eventId = 0, _eventData = {}; +function _getId(el) { + return el[_eventExpendo] || null; +} +function _setId(el) { + el[_eventExpendo] = ++_eventId; + return _eventId; +} +function _removeId(el) { + try { + delete el[_eventExpendo]; + } catch(e) { + if (el.removeAttribute) { + el.removeAttribute(_eventExpendo); + } + } +} +function _bind(el, type, fn) { + if (type.indexOf(',') >= 0) { + _each(type.split(','), function() { + _bind(el, this, fn); + }); + return; + } + var id = _getId(el); + if (!id) { + id = _setId(el); + } + if (_eventData[id] === undefined) { + _eventData[id] = {}; + } + var events = _eventData[id][type]; + if (events && events.length > 0) { + _unbindEvent(el, type, events[0]); + } else { + _eventData[id][type] = []; + _eventData[id].el = el; + } + events = _eventData[id][type]; + if (events.length === 0) { + events[0] = function(e) { + var kevent = e ? new KEvent(el, e) : undefined; + _each(events, function(i, event) { + if (i > 0 && event) { + event.call(el, kevent); + } + }); + }; + } + if (_inArray(fn, events) < 0) { + events.push(fn); + } + _bindEvent(el, type, events[0]); +} +function _unbind(el, type, fn) { + if (type && type.indexOf(',') >= 0) { + _each(type.split(','), function() { + _unbind(el, this, fn); + }); + return; + } + var id = _getId(el); + if (!id) { + return; + } + if (type === undefined) { + if (id in _eventData) { + _each(_eventData[id], function(key, events) { + if (key != 'el' && events.length > 0) { + _unbindEvent(el, key, events[0]); + } + }); + delete _eventData[id]; + _removeId(el); + } + return; + } + if (!_eventData[id]) { + return; + } + var events = _eventData[id][type]; + if (events && events.length > 0) { + if (fn === undefined) { + _unbindEvent(el, type, events[0]); + delete _eventData[id][type]; + } else { + _each(events, function(i, event) { + if (i > 0 && event === fn) { + events.splice(i, 1); + } + }); + if (events.length == 1) { + _unbindEvent(el, type, events[0]); + delete _eventData[id][type]; + } + } + var count = 0; + _each(_eventData[id], function() { + count++; + }); + if (count < 2) { + delete _eventData[id]; + _removeId(el); + } + } +} +function _fire(el, type) { + if (type.indexOf(',') >= 0) { + _each(type.split(','), function() { + _fire(el, this); + }); + return; + } + var id = _getId(el); + if (!id) { + return; + } + var events = _eventData[id][type]; + if (_eventData[id] && events && events.length > 0) { + events[0](); + } +} +function _ctrl(el, key, fn) { + var self = this; + key = /^\d{2,}$/.test(key) ? key : key.toUpperCase().charCodeAt(0); + _bind(el, 'keydown', function(e) { + if (e.ctrlKey && e.which == key && !e.shiftKey && !e.altKey) { + fn.call(el); + e.stop(); + } + }); +} +var _readyFinished = false; +function _ready(fn) { + if (_readyFinished) { + fn(KindEditor); + return; + } + var loaded = false; + function readyFunc() { + if (!loaded) { + loaded = true; + fn(KindEditor); + _readyFinished = true; + } + } + function ieReadyFunc() { + if (!loaded) { + try { + document.documentElement.doScroll('left'); + } catch(e) { + setTimeout(ieReadyFunc, 100); + return; + } + readyFunc(); + } + } + function ieReadyStateFunc() { + if (document.readyState === 'complete') { + readyFunc(); + } + } + if (document.addEventListener) { + _bind(document, 'DOMContentLoaded', readyFunc); + } else if (document.attachEvent) { + _bind(document, 'readystatechange', ieReadyStateFunc); + var toplevel = false; + try { + toplevel = window.frameElement == null; + } catch(e) {} + if (document.documentElement.doScroll && toplevel) { + ieReadyFunc(); + } + } + _bind(window, 'load', readyFunc); +} +if (window.attachEvent) { + window.attachEvent('onunload', function() { + _each(_eventData, function(key, events) { + if (events.el) { + _unbind(events.el); + } + }); + }); +} +K.ctrl = _ctrl; +K.ready = _ready; +function _getCssList(css) { + var list = {}, + reg = /\s*([\w\-]+)\s*:([^;]*)(;|$)/g, + match; + while ((match = reg.exec(css))) { + var key = _trim(match[1].toLowerCase()), + val = _trim(_toHex(match[2])); + list[key] = val; + } + return list; +} +function _getAttrList(tag) { + var list = {}, + reg = /\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g, + match; + while ((match = reg.exec(tag))) { + var key = (match[1] || match[2] || match[4] || match[6]).toLowerCase(), + val = (match[2] ? match[3] : (match[4] ? match[5] : match[7])) || ''; + list[key] = val; + } + return list; +} +function _addClassToTag(tag, className) { + if (/\s+class\s*=/.test(tag)) { + tag = tag.replace(/(\s+class=["']?)([^"']*)(["']?[\s>])/, function($0, $1, $2, $3) { + if ((' ' + $2 + ' ').indexOf(' ' + className + ' ') < 0) { + return $2 === '' ? $1 + className + $3 : $1 + $2 + ' ' + className + $3; + } else { + return $0; + } + }); + } else { + tag = tag.substr(0, tag.length - 1) + ' class="' + className + '">'; + } + return tag; +} +function _formatCss(css) { + var str = ''; + _each(_getCssList(css), function(key, val) { + str += key + ':' + val + ';'; + }); + return str; +} +function _formatUrl(url, mode, host, pathname) { + mode = _undef(mode, '').toLowerCase(); + if (url.substr(0, 5) != 'data:') { + url = url.replace(/([^:])\/\//g, '$1/'); + } + if (_inArray(mode, ['absolute', 'relative', 'domain']) < 0) { + return url; + } + host = host || location.protocol + '//' + location.host; + if (pathname === undefined) { + var m = location.pathname.match(/^(\/.*)\//); + pathname = m ? m[1] : ''; + } + var match; + if ((match = /^(\w+:\/\/[^\/]*)/.exec(url))) { + if (match[1] !== host) { + return url; + } + } else if (/^\w+:/.test(url)) { + return url; + } + function getRealPath(path) { + var parts = path.split('/'), paths = []; + for (var i = 0, len = parts.length; i < len; i++) { + var part = parts[i]; + if (part == '..') { + if (paths.length > 0) { + paths.pop(); + } + } else if (part !== '' && part != '.') { + paths.push(part); + } + } + return '/' + paths.join('/'); + } + if (/^\//.test(url)) { + url = host + getRealPath(url.substr(1)); + } else if (!/^\w+:\/\//.test(url)) { + url = host + getRealPath(pathname + '/' + url); + } + function getRelativePath(path, depth) { + if (url.substr(0, path.length) === path) { + var arr = []; + for (var i = 0; i < depth; i++) { + arr.push('..'); + } + var prefix = '.'; + if (arr.length > 0) { + prefix += '/' + arr.join('/'); + } + if (pathname == '/') { + prefix += '/'; + } + return prefix + url.substr(path.length); + } else { + if ((match = /^(.*)\//.exec(path))) { + return getRelativePath(match[1], ++depth); + } + } + } + if (mode === 'relative') { + url = getRelativePath(host + pathname, 0).substr(2); + } else if (mode === 'absolute') { + if (url.substr(0, host.length) === host) { + url = url.substr(host.length); + } + } + return url; +} +function _formatHtml(html, htmlTags, urlType, wellFormatted, indentChar) { + if (html == null) { + html = ''; + } + urlType = urlType || ''; + wellFormatted = _undef(wellFormatted, false); + indentChar = _undef(indentChar, '\t'); + var fontSizeList = 'xx-small,x-small,small,medium,large,x-large,xx-large'.split(','); + html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) { + return $1 + $2.replace(/<(?:br|br\s[^>]*)>/ig, '\n') + $3; + }); + html = html.replace(/<(?:br|br\s[^>]*)\s*\/?>\s*<\/p>/ig, '

    '); + html = html.replace(/(<(?:p|p\s[^>]*)>)\s*(<\/p>)/ig, '$1
    $2'); + html = html.replace(/\u200B/g, ''); + html = html.replace(/\u00A9/g, '©'); + html = html.replace(/\u00AE/g, '®'); + html = html.replace(/\u2003/g, ' '); + html = html.replace(/\u3000/g, ' '); + html = html.replace(/<[^>]+/g, function($0) { + return $0.replace(/\s+/g, ' '); + }); + var htmlTagMap = {}; + if (htmlTags) { + _each(htmlTags, function(key, val) { + var arr = key.split(','); + for (var i = 0, len = arr.length; i < len; i++) { + htmlTagMap[arr[i]] = _toMap(val); + } + }); + if (!htmlTagMap.script) { + html = html.replace(/(<(?:script|script\s[^>]*)>)([\s\S]*?)(<\/script>)/ig, ''); + } + if (!htmlTagMap.style) { + html = html.replace(/(<(?:style|style\s[^>]*)>)([\s\S]*?)(<\/style>)/ig, ''); + } + } + var re = /(\s*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>(\s*)/g; + var tagStack = []; + html = html.replace(re, function($0, $1, $2, $3, $4, $5, $6) { + var full = $0, + startNewline = $1 || '', + startSlash = $2 || '', + tagName = $3.toLowerCase(), + attr = $4 || '', + endSlash = $5 ? ' ' + $5 : '', + endNewline = $6 || ''; + if (htmlTags && !htmlTagMap[tagName]) { + return ''; + } + if (endSlash === '' && _SINGLE_TAG_MAP[tagName]) { + endSlash = ' /'; + } + if (_INLINE_TAG_MAP[tagName]) { + if (startNewline) { + startNewline = ' '; + } + if (endNewline) { + endNewline = ' '; + } + } + if (_PRE_TAG_MAP[tagName]) { + if (startSlash) { + endNewline = '\n'; + } else { + startNewline = '\n'; + } + } + if (wellFormatted && tagName == 'br') { + endNewline = '\n'; + } + if (_BLOCK_TAG_MAP[tagName] && !_PRE_TAG_MAP[tagName]) { + if (wellFormatted) { + if (startSlash && tagStack.length > 0 && tagStack[tagStack.length - 1] === tagName) { + tagStack.pop(); + } else { + tagStack.push(tagName); + } + startNewline = '\n'; + endNewline = '\n'; + for (var i = 0, len = startSlash ? tagStack.length : tagStack.length - 1; i < len; i++) { + startNewline += indentChar; + if (!startSlash) { + endNewline += indentChar; + } + } + if (endSlash) { + tagStack.pop(); + } else if (!startSlash) { + endNewline += indentChar; + } + } else { + startNewline = endNewline = ''; + } + } + //blockquote 单独加上style 之后再改成接口 给别的加上默认的 + if (attr !== '' || (tagName === 'blockquote')) { + var attrMap = _getAttrList(full); + if (tagName === 'font') { + var fontStyleMap = {}, fontStyle = ''; + _each(attrMap, function(key, val) { + if (key === 'color') { + fontStyleMap.color = val; + delete attrMap[key]; + } + if (key === 'size') { + fontStyleMap['font-size'] = fontSizeList[parseInt(val, 10) - 1] || ''; + delete attrMap[key]; + } + if (key === 'face') { + fontStyleMap['font-family'] = val; + delete attrMap[key]; + } + if (key === 'style') { + fontStyle = val; + } + }); + if (fontStyle && !/;$/.test(fontStyle)) { + fontStyle += ';'; + } + _each(fontStyleMap, function(key, val) { + if (val === '') { + return; + } + if (/\s/.test(val)) { + val = "'" + val + "'"; + } + fontStyle += key + ':' + val + ';'; + }); + attrMap.style = fontStyle; + } + _each(attrMap, function(key, val) { + if (_FILL_ATTR_MAP[key]) { + attrMap[key] = key; + } + if (_inArray(key, ['src', 'href']) >= 0) { + attrMap[key] = _formatUrl(val, urlType); + } + if (htmlTags && key !== 'style' && !htmlTagMap[tagName]['*'] && !htmlTagMap[tagName][key] || + tagName === 'body' && key === 'contenteditable' || + /^kindeditor_\d+$/.test(key)) { + delete attrMap[key]; + } + if (key === 'style' && val !== '') { + var styleMap = _getCssList(val); + _each(styleMap, function(k, v) { + if (htmlTags && !htmlTagMap[tagName].style && !htmlTagMap[tagName]['.' + k]) { + delete styleMap[k]; + } + }); + var style = ''; + _each(styleMap, function(k, v) { + style += k + ':' + v + ';'; + }); + attrMap.style = style; + } + }); + attr = ''; + if (tagName === 'blockquote') { + attrMap['style'] = "margin: 0 0 0 40px; border: none; padding: 0px;background: none;background-color: ;"; + } + _each(attrMap, function(key, val) { + if (key === 'style' && val === '') { + return; + } + val = val.replace(/"/g, '"'); + attr += ' ' + key + '="' + val + '"'; + }); + } + if (tagName === 'font') { + tagName = 'span'; + } + return startNewline + '<' + startSlash + tagName + attr + endSlash + '>' + endNewline; + }); + html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) { + return $1 + $2.replace(/\n/g, '\n') + $3; + }); + html = html.replace(/\n\s*\n/g, '\n'); + html = html.replace(/\n/g, '\n'); + return _trim(html); +} +function _clearMsWord(html, htmlTags) { + html = html.replace(//ig, '') + .replace(//ig, '') + .replace(/]*>[\s\S]*?<\/style>/ig, '') + .replace(/]*>[\s\S]*?<\/script>/ig, '') + .replace(/]+>[\s\S]*?<\/w:[^>]+>/ig, '') + .replace(/]+>[\s\S]*?<\/o:[^>]+>/ig, '') + .replace(/[\s\S]*?<\/xml>/ig, '') + .replace(/<(?:table|td)[^>]*>/ig, function(full) { + return full.replace(/border-bottom:([#\w\s]+)/ig, 'border:$1'); + }); + return _formatHtml(html, htmlTags); +} +function _mediaType(src) { + if (/\.(rm|rmvb)(\?|$)/i.test(src)) { + return 'audio/x-pn-realaudio-plugin'; + } + if (/\.(swf|flv)(\?|$)/i.test(src)) { + return 'application/x-shockwave-flash'; + } + return 'video/x-ms-asf-plugin'; +} +function _mediaClass(type) { + if (/realaudio/i.test(type)) { + return 'ke-rm'; + } + if (/flash/i.test(type)) { + return 'ke-flash'; + } + return 'ke-media'; +} +function _mediaAttrs(srcTag) { + return _getAttrList(unescape(srcTag)); +} +function _mediaEmbed(attrs,target) { + if(target && target === "media"){ + var html = [[],""); + html[0] = html[0].join(""); + html.push("/>"); + return html.join(""); + }else{ + var html = ' 0) { + style += 'width:' + width + 'px;'; + } + if (/\D/.test(height)) { + style += 'height:' + height + ';'; + } else if (height > 0) { + style += 'height:' + height + 'px;'; + } + var html = ''; + return html; +} +function _tmpl(str, data) { + var fn = new Function("obj", + "var p=[],print=function(){p.push.apply(p,arguments);};" + + "with(obj){p.push('" + + str.replace(/[\r\t\n]/g, " ") + .split("<%").join("\t") + .replace(/((^|%>)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + "');}return p.join('');"); + return data ? fn(data) : fn; +} +K.formatUrl = _formatUrl; +K.formatHtml = _formatHtml; +K.getCssList = _getCssList; +K.getAttrList = _getAttrList; +K.mediaType = _mediaType; +K.mediaAttrs = _mediaAttrs; +K.mediaEmbed = _mediaEmbed; +K.mediaImg = _mediaImg; +K.clearMsWord = _clearMsWord; +K.tmpl = _tmpl; +function _contains(nodeA, nodeB) { + if (nodeA.nodeType == 9 && nodeB.nodeType != 9) { + return true; + } + while ((nodeB = nodeB.parentNode)) { + if (nodeB == nodeA) { + return true; + } + } + return false; +} +var _getSetAttrDiv = document.createElement('div'); +_getSetAttrDiv.setAttribute('className', 't'); +var _GET_SET_ATTRIBUTE = _getSetAttrDiv.className !== 't'; +function _getAttr(el, key) { + key = key.toLowerCase(); + var val = null; + if (!_GET_SET_ATTRIBUTE && el.nodeName.toLowerCase() != 'script') { + var div = el.ownerDocument.createElement('div'); + div.appendChild(el.cloneNode(false)); + var list = _getAttrList(_unescape(div.innerHTML)); + if (key in list) { + val = list[key]; + } + } else { + try { + val = el.getAttribute(key, 2); + } catch(e) { + val = el.getAttribute(key, 1); + } + } + if (key === 'style' && val !== null) { + val = _formatCss(val); + } + return val; +} +function _queryAll(expr, root) { + var exprList = expr.split(','); + if (exprList.length > 1) { + var mergedResults = []; + _each(exprList, function() { + _each(_queryAll(this, root), function() { + if (_inArray(this, mergedResults) < 0) { + mergedResults.push(this); + } + }); + }); + return mergedResults; + } + root = root || document; + function escape(str) { + if (typeof str != 'string') { + return str; + } + return str.replace(/([^\w\-])/g, '\\$1'); + } + function stripslashes(str) { + return str.replace(/\\/g, ''); + } + function cmpTag(tagA, tagB) { + return tagA === '*' || tagA.toLowerCase() === escape(tagB.toLowerCase()); + } + function byId(id, tag, root) { + var arr = [], + doc = root.ownerDocument || root, + el = doc.getElementById(stripslashes(id)); + if (el) { + if (cmpTag(tag, el.nodeName) && _contains(root, el)) { + arr.push(el); + } + } + return arr; + } + function byClass(className, tag, root) { + var doc = root.ownerDocument || root, arr = [], els, i, len, el; + if (root.getElementsByClassName) { + els = root.getElementsByClassName(stripslashes(className)); + for (i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (cmpTag(tag, el.nodeName)) { + arr.push(el); + } + } + } else if (doc.querySelectorAll) { + els = doc.querySelectorAll((root.nodeName !== '#document' ? root.nodeName + ' ' : '') + tag + '.' + className); + for (i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (_contains(root, el)) { + arr.push(el); + } + } + } else { + els = root.getElementsByTagName(tag); + className = ' ' + className + ' '; + for (i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (el.nodeType == 1) { + var cls = el.className; + if (cls && (' ' + cls + ' ').indexOf(className) > -1) { + arr.push(el); + } + } + } + } + return arr; + } + function byName(name, tag, root) { + var arr = [], doc = root.ownerDocument || root, + els = doc.getElementsByName(stripslashes(name)), el; + for (var i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (cmpTag(tag, el.nodeName) && _contains(root, el)) { + if (el.getAttribute('name') !== null) { + arr.push(el); + } + } + } + return arr; + } + function byAttr(key, val, tag, root) { + var arr = [], els = root.getElementsByTagName(tag), el; + for (var i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (el.nodeType == 1) { + if (val === null) { + if (_getAttr(el, key) !== null) { + arr.push(el); + } + } else { + if (val === escape(_getAttr(el, key))) { + arr.push(el); + } + } + } + } + return arr; + } + function select(expr, root) { + var arr = [], matches; + matches = /^((?:\\.|[^.#\s\[<>])+)/.exec(expr); + var tag = matches ? matches[1] : '*'; + if ((matches = /#((?:[\w\-]|\\.)+)$/.exec(expr))) { + arr = byId(matches[1], tag, root); + } else if ((matches = /\.((?:[\w\-]|\\.)+)$/.exec(expr))) { + arr = byClass(matches[1], tag, root); + } else if ((matches = /\[((?:[\w\-]|\\.)+)\]/.exec(expr))) { + arr = byAttr(matches[1].toLowerCase(), null, tag, root); + } else if ((matches = /\[((?:[\w\-]|\\.)+)\s*=\s*['"]?((?:\\.|[^'"]+)+)['"]?\]/.exec(expr))) { + var key = matches[1].toLowerCase(), val = matches[2]; + if (key === 'id') { + arr = byId(val, tag, root); + } else if (key === 'class') { + arr = byClass(val, tag, root); + } else if (key === 'name') { + arr = byName(val, tag, root); + } else { + arr = byAttr(key, val, tag, root); + } + } else { + var els = root.getElementsByTagName(tag), el; + for (var i = 0, len = els.length; i < len; i++) { + el = els[i]; + if (el.nodeType == 1) { + arr.push(el); + } + } + } + return arr; + } + var parts = [], arr, re = /((?:\\.|[^\s>])+|[\s>])/g; + while ((arr = re.exec(expr))) { + if (arr[1] !== ' ') { + parts.push(arr[1]); + } + } + var results = []; + if (parts.length == 1) { + return select(parts[0], root); + } + var isChild = false, part, els, subResults, val, v, i, j, k, length, len, l; + for (i = 0, lenth = parts.length; i < lenth; i++) { + part = parts[i]; + if (part === '>') { + isChild = true; + continue; + } + if (i > 0) { + els = []; + for (j = 0, len = results.length; j < len; j++) { + val = results[j]; + subResults = select(part, val); + for (k = 0, l = subResults.length; k < l; k++) { + v = subResults[k]; + if (isChild) { + if (val === v.parentNode) { + els.push(v); + } + } else { + els.push(v); + } + } + } + results = els; + } else { + results = select(part, root); + } + if (results.length === 0) { + return []; + } + } + return results; +} +function _query(expr, root) { + var arr = _queryAll(expr, root); + return arr.length > 0 ? arr[0] : null; +} +K.query = _query; +K.queryAll = _queryAll; +function _get(val) { + return K(val)[0]; +} +function _getDoc(node) { + if (!node) { + return document; + } + return node.ownerDocument || node.document || node; +} +function _getWin(node) { + if (!node) { + return window; + } + var doc = _getDoc(node); + return doc.parentWindow || doc.defaultView; +} +function _setHtml(el, html) { + if (el.nodeType != 1) { + return; + } + var doc = _getDoc(el); + try { + el.innerHTML = '' + html; + var temp = doc.getElementById('__kindeditor_temp_tag__'); + temp.parentNode.removeChild(temp); + } catch(e) { + K(el).empty(); + K('@' + html, doc).each(function() { + el.appendChild(this); + }); + } +} +function _hasClass(el, cls) { + return _inString(cls, el.className, ' '); +} +function _setAttr(el, key, val) { + if (_IE && _V < 8 && key.toLowerCase() == 'class') { + key = 'className'; + } + el.setAttribute(key, '' + val); +} +function _removeAttr(el, key) { + if (_IE && _V < 8 && key.toLowerCase() == 'class') { + key = 'className'; + } + _setAttr(el, key, ''); + el.removeAttribute(key); +} +function _getNodeName(node) { + if (!node || !node.nodeName) { + return ''; + } + return node.nodeName.toLowerCase(); +} +function _computedCss(el, key) { + var self = this, win = _getWin(el), camelKey = _toCamel(key), val = ''; + if (win.getComputedStyle) { + var style = win.getComputedStyle(el, null); + val = style[camelKey] || style.getPropertyValue(key) || el.style[camelKey]; + } else if (el.currentStyle) { + val = el.currentStyle[camelKey] || el.style[camelKey]; + } + return val; +} +function _hasVal(node) { + return !!_VALUE_TAG_MAP[_getNodeName(node)]; +} +function _docElement(doc) { + doc = doc || document; + return _QUIRKS ? doc.body : doc.documentElement; +} +function _docHeight(doc) { + var el = _docElement(doc); + return Math.max(el.scrollHeight, el.clientHeight); +} +function _docWidth(doc) { + var el = _docElement(doc); + return Math.max(el.scrollWidth, el.clientWidth); +} +function _getScrollPos(doc) { + doc = doc || document; + var x, y; + if (_IE || _NEWIE || _OPERA) { + x = _docElement(doc).scrollLeft; + y = _docElement(doc).scrollTop; + } else { + x = _getWin(doc).scrollX; + y = _getWin(doc).scrollY; + } + return {x : x, y : y}; +} +function KNode(node) { + this.init(node); +} +_extend(KNode, { + init : function(node) { + var self = this; + node = _isArray(node) ? node : [node]; + var length = 0; + for (var i = 0, len = node.length; i < len; i++) { + if (node[i]) { + self[i] = node[i].constructor === KNode ? node[i][0] : node[i]; + length++; + } + } + self.length = length; + self.doc = _getDoc(self[0]); + self.name = _getNodeName(self[0]); + self.type = self.length > 0 ? self[0].nodeType : null; + self.win = _getWin(self[0]); + }, + each : function(fn) { + var self = this; + for (var i = 0; i < self.length; i++) { + if (fn.call(self[i], i, self[i]) === false) { + return self; + } + } + return self; + }, + bind : function(type, fn) { + this.each(function() { + _bind(this, type, fn); + }); + return this; + }, + unbind : function(type, fn) { + this.each(function() { + _unbind(this, type, fn); + }); + return this; + }, + fire : function(type) { + if (this.length < 1) { + return this; + } + _fire(this[0], type); + return this; + }, + hasAttr : function(key) { + if (this.length < 1) { + return false; + } + return !!_getAttr(this[0], key); + }, + attr : function(key, val) { + var self = this; + if (key === undefined) { + return _getAttrList(self.outer()); + } + if (typeof key === 'object') { + _each(key, function(k, v) { + self.attr(k, v); + }); + return self; + } + if (val === undefined) { + val = self.length < 1 ? null : _getAttr(self[0], key); + return val === null ? '' : val; + } + self.each(function() { + _setAttr(this, key, val); + }); + return self; + }, + removeAttr : function(key) { + this.each(function() { + _removeAttr(this, key); + }); + return this; + }, + get : function(i) { + if (this.length < 1) { + return null; + } + return this[i || 0]; + }, + eq : function(i) { + if (this.length < 1) { + return null; + } + return this[i] ? new KNode(this[i]) : null; + }, + hasClass : function(cls) { + if (this.length < 1) { + return false; + } + return _hasClass(this[0], cls); + }, + addClass : function(cls) { + this.each(function() { + if (!_hasClass(this, cls)) { + this.className = _trim(this.className + ' ' + cls); + } + }); + return this; + }, + removeClass : function(cls) { + this.each(function() { + if (_hasClass(this, cls)) { + this.className = _trim(this.className.replace(new RegExp('(^|\\s)' + cls + '(\\s|$)'), ' ')); + } + }); + return this; + }, + html : function(val) { + var self = this; + if (val === undefined) { + if (self.length < 1 || self.type != 1) { + return ''; + } + return _formatHtml(self[0].innerHTML); + } + self.each(function() { + _setHtml(this, val); + }); + return self; + }, + text : function() { + var self = this; + if (self.length < 1) { + return ''; + } + return _IE ? self[0].innerText : self[0].textContent; + }, + hasVal : function() { + if (this.length < 1) { + return false; + } + return _hasVal(this[0]); + }, + val : function(val) { + var self = this; + if (val === undefined) { + if (self.length < 1) { + return ''; + } + return self.hasVal() ? self[0].value : self.attr('value'); + } else { + self.each(function() { + if (_hasVal(this)) { + this.value = val; + } else { + _setAttr(this, 'value' , val); + } + }); + return self; + } + }, + css : function(key, val) { + var self = this; + if (key === undefined) { + return _getCssList(self.attr('style')); + } + if (typeof key === 'object') { + _each(key, function(k, v) { + self.css(k, v); + }); + return self; + } + if (val === undefined) { + if (self.length < 1) { + return ''; + } + return self[0].style[_toCamel(key)] || _computedCss(self[0], key) || ''; + } + self.each(function() { + this.style[_toCamel(key)] = val; + }); + return self; + }, + width : function(val) { + var self = this; + if (val === undefined) { + if (self.length < 1) { + return 0; + } + return self[0].offsetWidth; + } + return self.css('width', _addUnit(val)); + }, + height : function(val) { + var self = this; + if (val === undefined) { + if (self.length < 1) { + return 0; + } + return self[0].offsetHeight; + } + return self.css('height', _addUnit(val)); + }, + opacity : function(val) { + this.each(function() { + if (this.style.opacity === undefined) { + this.style.filter = val == 1 ? '' : 'alpha(opacity=' + (val * 100) + ')'; + } else { + this.style.opacity = val == 1 ? '' : val; + } + }); + return this; + }, + data : function(key, val) { + var self = this; + key = 'kindeditor_data_' + key; + if (val === undefined) { + if (self.length < 1) { + return null; + } + return self[0][key]; + } + this.each(function() { + this[key] = val; + }); + return self; + }, + pos : function() { + var self = this, node = self[0], x = 0, y = 0; + if (node) { + if (node.getBoundingClientRect) { + var box = node.getBoundingClientRect(), + pos = _getScrollPos(self.doc); + x = box.left + pos.x; + y = box.top + pos.y; + } else { + while (node) { + x += node.offsetLeft; + y += node.offsetTop; + node = node.offsetParent; + } + } + } + return {x : _round(x), y : _round(y)}; + }, + clone : function(bool) { + if (this.length < 1) { + return new KNode([]); + } + return new KNode(this[0].cloneNode(bool)); + }, + append : function(expr) { + this.each(function() { + if (this.appendChild) { + this.appendChild(_get(expr)); + } + }); + return this; + }, + appendTo : function(expr) { + this.each(function() { + _get(expr).appendChild(this); + }); + return this; + }, + before : function(expr) { + this.each(function() { + this.parentNode.insertBefore(_get(expr), this); + }); + return this; + }, + after : function(expr) { + this.each(function() { + if (this.nextSibling) { + this.parentNode.insertBefore(_get(expr), this.nextSibling); + } else { + this.parentNode.appendChild(_get(expr)); + } + }); + return this; + }, + replaceWith : function(expr) { + var nodes = []; + this.each(function(i, node) { + _unbind(node); + var newNode = _get(expr); + node.parentNode.replaceChild(newNode, node); + nodes.push(newNode); + }); + return K(nodes); + }, + empty : function() { + var self = this; + self.each(function(i, node) { + var child = node.firstChild; + while (child) { + if (!node.parentNode) { + return; + } + var next = child.nextSibling; + child.parentNode.removeChild(child); + child = next; + } + }); + return self; + }, + remove : function(keepChilds) { + var self = this; + self.each(function(i, node) { + if (!node.parentNode) { + return; + } + _unbind(node); + if (keepChilds) { + var child = node.firstChild; + while (child) { + var next = child.nextSibling; + node.parentNode.insertBefore(child, node); + child = next; + } + } + node.parentNode.removeChild(node); + delete self[i]; + }); + self.length = 0; + return self; + }, + show : function(val) { + var self = this; + if (val === undefined) { + val = self._originDisplay || ''; + } + if (self.css('display') != 'none') { + return self; + } + return self.css('display', val); + }, + hide : function() { + var self = this; + if (self.length < 1) { + return self; + } + self._originDisplay = self[0].style.display; + return self.css('display', 'none'); + }, + outer : function() { + var self = this; + if (self.length < 1) { + return ''; + } + var div = self.doc.createElement('div'), html; + div.appendChild(self[0].cloneNode(true)); + html = _formatHtml(div.innerHTML); + div = null; + return html; + }, + isSingle : function() { + return !!_SINGLE_TAG_MAP[this.name]; + }, + isInline : function() { + return !!_INLINE_TAG_MAP[this.name]; + }, + isBlock : function() { + return !!_BLOCK_TAG_MAP[this.name]; + }, + isStyle : function() { + return !!_STYLE_TAG_MAP[this.name]; + }, + isControl : function() { + return !!_CONTROL_TAG_MAP[this.name]; + }, + contains : function(otherNode) { + if (this.length < 1) { + return false; + } + return _contains(this[0], _get(otherNode)); + }, + parent : function() { + if (this.length < 1) { + return null; + } + var node = this[0].parentNode; + return node ? new KNode(node) : null; + }, + children : function() { + if (this.length < 1) { + return new KNode([]); + } + var list = [], child = this[0].firstChild; + while (child) { + if (child.nodeType != 3 || _trim(child.nodeValue) !== '') { + list.push(child); + } + child = child.nextSibling; + } + return new KNode(list); + }, + first : function() { + var list = this.children(); + return list.length > 0 ? list.eq(0) : null; + }, + last : function() { + var list = this.children(); + return list.length > 0 ? list.eq(list.length - 1) : null; + }, + index : function() { + if (this.length < 1) { + return -1; + } + var i = -1, sibling = this[0]; + while (sibling) { + i++; + sibling = sibling.previousSibling; + } + return i; + }, + prev : function() { + if (this.length < 1) { + return null; + } + var node = this[0].previousSibling; + return node ? new KNode(node) : null; + }, + next : function() { + if (this.length < 1) { + return null; + } + var node = this[0].nextSibling; + return node ? new KNode(node) : null; + }, + scan : function(fn, order) { + if (this.length < 1) { + return; + } + order = (order === undefined) ? true : order; + function walk(node) { + var n = order ? node.firstChild : node.lastChild; + while (n) { + var next = order ? n.nextSibling : n.previousSibling; + if (fn(n) === false) { + return false; + } + if (walk(n) === false) { + return false; + } + n = next; + } + } + walk(this[0]); + return this; + } +}); +_each(('blur,focus,focusin,focusout,load,resize,scroll,unload,click,dblclick,' + + 'mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,' + + 'change,select,submit,keydown,keypress,keyup,error,contextmenu').split(','), function(i, type) { + KNode.prototype[type] = function(fn) { + return fn ? this.bind(type, fn) : this.fire(type); + }; +}); +var _K = K; +K = function(expr, root) { + if (expr === undefined || expr === null) { + return; + } + function newNode(node) { + if (!node[0]) { + node = []; + } + return new KNode(node); + } + if (typeof expr === 'string') { + if (root) { + root = _get(root); + } + var length = expr.length; + if (expr.charAt(0) === '@') { + expr = expr.substr(1); + } + if (expr.length !== length || /<.+>/.test(expr)) { + var doc = root ? root.ownerDocument || root : document, + div = doc.createElement('div'), list = []; + div.innerHTML = '' + expr; + for (var i = 0, len = div.childNodes.length; i < len; i++) { + var child = div.childNodes[i]; + if (child.id == '__kindeditor_temp_tag__') { + continue; + } + list.push(child); + } + return newNode(list); + } + return newNode(_queryAll(expr, root)); + } + if (expr && expr.constructor === KNode) { + return expr; + } + if (expr.toArray) { + expr = expr.toArray(); + } + if (_isArray(expr)) { + return newNode(expr); + } + return newNode(_toArray(arguments)); +}; +_each(_K, function(key, val) { + K[key] = val; +}); +K.NodeClass = KNode; +window.KindEditor = K; +var _START_TO_START = 0, + _START_TO_END = 1, + _END_TO_END = 2, + _END_TO_START = 3, + _BOOKMARK_ID = 0; +function _updateCollapsed(range) { + range.collapsed = (range.startContainer === range.endContainer && range.startOffset === range.endOffset); + return range; +} +function _copyAndDelete(range, isCopy, isDelete) { + var doc = range.doc, nodeList = []; + function splitTextNode(node, startOffset, endOffset) { + var length = node.nodeValue.length, centerNode; + if (isCopy) { + var cloneNode = node.cloneNode(true); + if (startOffset > 0) { + centerNode = cloneNode.splitText(startOffset); + } else { + centerNode = cloneNode; + } + if (endOffset < length) { + centerNode.splitText(endOffset - startOffset); + } + } + if (isDelete) { + var center = node; + if (startOffset > 0) { + center = node.splitText(startOffset); + range.setStart(node, startOffset); + } + if (endOffset < length) { + var right = center.splitText(endOffset - startOffset); + range.setEnd(right, 0); + } + nodeList.push(center); + } + return centerNode; + } + function removeNodes() { + if (isDelete) { + range.up().collapse(true); + } + for (var i = 0, len = nodeList.length; i < len; i++) { + var node = nodeList[i]; + if (node.parentNode) { + node.parentNode.removeChild(node); + } + } + } + var copyRange = range.cloneRange().down(); + var start = -1, incStart = -1, incEnd = -1, end = -1, + ancestor = range.commonAncestor(), frag = doc.createDocumentFragment(); + if (ancestor.nodeType == 3) { + var textNode = splitTextNode(ancestor, range.startOffset, range.endOffset); + if (isCopy) { + frag.appendChild(textNode); + } + removeNodes(); + return isCopy ? frag : range; + } + function extractNodes(parent, frag) { + var node = parent.firstChild, nextNode; + while (node) { + var testRange = new KRange(doc).selectNode(node); + start = testRange.compareBoundaryPoints(_START_TO_END, range); + if (start >= 0 && incStart <= 0) { + incStart = testRange.compareBoundaryPoints(_START_TO_START, range); + } + if (incStart >= 0 && incEnd <= 0) { + incEnd = testRange.compareBoundaryPoints(_END_TO_END, range); + } + if (incEnd >= 0 && end <= 0) { + end = testRange.compareBoundaryPoints(_END_TO_START, range); + } + if (end >= 0) { + return false; + } + nextNode = node.nextSibling; + if (start > 0) { + if (node.nodeType == 1) { + if (incStart >= 0 && incEnd <= 0) { + if (isCopy) { + frag.appendChild(node.cloneNode(true)); + } + if (isDelete) { + nodeList.push(node); + } + } else { + var childFlag; + if (isCopy) { + childFlag = node.cloneNode(false); + frag.appendChild(childFlag); + } + if (extractNodes(node, childFlag) === false) { + return false; + } + } + } else if (node.nodeType == 3) { + var textNode; + if (node == copyRange.startContainer) { + textNode = splitTextNode(node, copyRange.startOffset, node.nodeValue.length); + } else if (node == copyRange.endContainer) { + textNode = splitTextNode(node, 0, copyRange.endOffset); + } else { + textNode = splitTextNode(node, 0, node.nodeValue.length); + } + if (isCopy) { + try { + frag.appendChild(textNode); + } catch(e) {} + } + } + } + node = nextNode; + } + } + extractNodes(ancestor, frag); + if (isDelete) { + range.up().collapse(true); + } + for (var i = 0, len = nodeList.length; i < len; i++) { + var node = nodeList[i]; + if (node.parentNode) { + node.parentNode.removeChild(node); + } + } + return isCopy ? frag : range; +} +function _moveToElementText(range, el) { + var node = el; + while (node) { + var knode = K(node); + if (knode.name == 'marquee' || knode.name == 'select') { + return; + } + node = node.parentNode; + } + try { + range.moveToElementText(el); + } catch(e) {} +} +function _getStartEnd(rng, isStart) { + var doc = rng.parentElement().ownerDocument, + pointRange = rng.duplicate(); + pointRange.collapse(isStart); + var parent = pointRange.parentElement(), + nodes = parent.childNodes; + if (nodes.length === 0) { + return {node: parent.parentNode, offset: K(parent).index()}; + } + var startNode = doc, startPos = 0, cmp = -1; + var testRange = rng.duplicate(); + _moveToElementText(testRange, parent); + for (var i = 0, len = nodes.length; i < len; i++) { + var node = nodes[i]; + cmp = testRange.compareEndPoints('StartToStart', pointRange); + if (cmp === 0) { + return {node: node.parentNode, offset: i}; + } + if (node.nodeType == 1) { + var nodeRange = rng.duplicate(), dummy, knode = K(node), newNode = node; + if (knode.isControl()) { + dummy = doc.createElement('span'); + knode.after(dummy); + newNode = dummy; + startPos += knode.text().replace(/\r\n|\n|\r/g, '').length; + } + _moveToElementText(nodeRange, newNode); + testRange.setEndPoint('StartToEnd', nodeRange); + if (cmp > 0) { + startPos += nodeRange.text.replace(/\r\n|\n|\r/g, '').length; + } else { + startPos = 0; + } + if (dummy) { + K(dummy).remove(); + } + } else if (node.nodeType == 3) { + testRange.moveStart('character', node.nodeValue.length); + startPos += node.nodeValue.length; + } + if (cmp < 0) { + startNode = node; + } + } + if (cmp < 0 && startNode.nodeType == 1) { + return {node: parent, offset: K(parent.lastChild).index() + 1}; + } + if (cmp > 0) { + while (startNode.nextSibling && startNode.nodeType == 1) { + startNode = startNode.nextSibling; + } + } + testRange = rng.duplicate(); + _moveToElementText(testRange, parent); + testRange.setEndPoint('StartToEnd', pointRange); + startPos -= testRange.text.replace(/\r\n|\n|\r/g, '').length; + if (cmp > 0 && startNode.nodeType == 3) { + var prevNode = startNode.previousSibling; + while (prevNode && prevNode.nodeType == 3) { + startPos -= prevNode.nodeValue.length; + prevNode = prevNode.previousSibling; + } + } + return {node: startNode, offset: startPos}; +} +function _getEndRange(node, offset) { + var doc = node.ownerDocument || node, + range = doc.body.createTextRange(); + if (doc == node) { + range.collapse(true); + return range; + } + if (node.nodeType == 1 && node.childNodes.length > 0) { + var children = node.childNodes, isStart, child; + if (offset === 0) { + child = children[0]; + isStart = true; + } else { + child = children[offset - 1]; + isStart = false; + } + if (!child) { + return range; + } + if (K(child).name === 'head') { + if (offset === 1) { + isStart = true; + } + if (offset === 2) { + isStart = false; + } + range.collapse(isStart); + return range; + } + if (child.nodeType == 1) { + var kchild = K(child), span; + if (kchild.isControl()) { + span = doc.createElement('span'); + if (isStart) { + kchild.before(span); + } else { + kchild.after(span); + } + child = span; + } + _moveToElementText(range, child); + range.collapse(isStart); + if (span) { + K(span).remove(); + } + return range; + } + node = child; + offset = isStart ? 0 : child.nodeValue.length; + } + var dummy = doc.createElement('span'); + K(node).before(dummy); + _moveToElementText(range, dummy); + range.moveStart('character', offset); + K(dummy).remove(); + return range; +} +function _toRange(rng) { + var doc, range; + function tr2td(start) { + if (K(start.node).name == 'tr') { + start.node = start.node.cells[start.offset]; + start.offset = 0; + } + } + if (_IERANGE) { + if (rng.item) { + doc = _getDoc(rng.item(0)); + range = new KRange(doc); + range.selectNode(rng.item(0)); + return range; + } + doc = rng.parentElement().ownerDocument; + var start = _getStartEnd(rng, true), + end = _getStartEnd(rng, false); + tr2td(start); + tr2td(end); + range = new KRange(doc); + range.setStart(start.node, start.offset); + range.setEnd(end.node, end.offset); + return range; + } + var startContainer = rng.startContainer; + doc = startContainer.ownerDocument || startContainer; + range = new KRange(doc); + range.setStart(startContainer, rng.startOffset); + range.setEnd(rng.endContainer, rng.endOffset); + return range; +} +function KRange(doc) { + this.init(doc); +} +_extend(KRange, { + init : function(doc) { + var self = this; + self.startContainer = doc; + self.startOffset = 0; + self.endContainer = doc; + self.endOffset = 0; + self.collapsed = true; + self.doc = doc; + }, + commonAncestor : function() { + function getParents(node) { + var parents = []; + while (node) { + parents.push(node); + node = node.parentNode; + } + return parents; + } + var parentsA = getParents(this.startContainer), + parentsB = getParents(this.endContainer), + i = 0, lenA = parentsA.length, lenB = parentsB.length, parentA, parentB; + while (++i) { + parentA = parentsA[lenA - i]; + parentB = parentsB[lenB - i]; + if (!parentA || !parentB || parentA !== parentB) { + break; + } + } + return parentsA[lenA - i + 1]; + }, + setStart : function(node, offset) { + var self = this, doc = self.doc; + self.startContainer = node; + self.startOffset = offset; + if (self.endContainer === doc) { + self.endContainer = node; + self.endOffset = offset; + } + return _updateCollapsed(this); + }, + setEnd : function(node, offset) { + var self = this, doc = self.doc; + self.endContainer = node; + self.endOffset = offset; + if (self.startContainer === doc) { + self.startContainer = node; + self.startOffset = offset; + } + return _updateCollapsed(this); + }, + setStartBefore : function(node) { + return this.setStart(node.parentNode || this.doc, K(node).index()); + }, + setStartAfter : function(node) { + return this.setStart(node.parentNode || this.doc, K(node).index() + 1); + }, + setEndBefore : function(node) { + return this.setEnd(node.parentNode || this.doc, K(node).index()); + }, + setEndAfter : function(node) { + return this.setEnd(node.parentNode || this.doc, K(node).index() + 1); + }, + selectNode : function(node) { + return this.setStartBefore(node).setEndAfter(node); + }, + selectNodeContents : function(node) { + var knode = K(node); + if (knode.type == 3 || knode.isSingle()) { + return this.selectNode(node); + } + var children = knode.children(); + if (children.length > 0) { + return this.setStartBefore(children[0]).setEndAfter(children[children.length - 1]); + } + return this.setStart(node, 0).setEnd(node, 0); + }, + collapse : function(toStart) { + if (toStart) { + return this.setEnd(this.startContainer, this.startOffset); + } + return this.setStart(this.endContainer, this.endOffset); + }, + compareBoundaryPoints : function(how, range) { + var rangeA = this.get(), rangeB = range.get(); + if (_IERANGE) { + var arr = {}; + arr[_START_TO_START] = 'StartToStart'; + arr[_START_TO_END] = 'EndToStart'; + arr[_END_TO_END] = 'EndToEnd'; + arr[_END_TO_START] = 'StartToEnd'; + var cmp = rangeA.compareEndPoints(arr[how], rangeB); + if (cmp !== 0) { + return cmp; + } + var nodeA, nodeB, nodeC, posA, posB; + if (how === _START_TO_START || how === _END_TO_START) { + nodeA = this.startContainer; + posA = this.startOffset; + } + if (how === _START_TO_END || how === _END_TO_END) { + nodeA = this.endContainer; + posA = this.endOffset; + } + if (how === _START_TO_START || how === _START_TO_END) { + nodeB = range.startContainer; + posB = range.startOffset; + } + if (how === _END_TO_END || how === _END_TO_START) { + nodeB = range.endContainer; + posB = range.endOffset; + } + if (nodeA === nodeB) { + var diff = posA - posB; + return diff > 0 ? 1 : (diff < 0 ? -1 : 0); + } + nodeC = nodeB; + while (nodeC && nodeC.parentNode !== nodeA) { + nodeC = nodeC.parentNode; + } + if (nodeC) { + return K(nodeC).index() >= posA ? -1 : 1; + } + nodeC = nodeA; + while (nodeC && nodeC.parentNode !== nodeB) { + nodeC = nodeC.parentNode; + } + if (nodeC) { + return K(nodeC).index() >= posB ? 1 : -1; + } + nodeC = K(nodeB).next(); + if (nodeC && nodeC.contains(nodeA)) { + return 1; + } + nodeC = K(nodeA).next(); + if (nodeC && nodeC.contains(nodeB)) { + return -1; + } + } else { + return rangeA.compareBoundaryPoints(how, rangeB); + } + }, + cloneRange : function() { + return new KRange(this.doc).setStart(this.startContainer, this.startOffset).setEnd(this.endContainer, this.endOffset); + }, + toString : function() { + var rng = this.get(), str = _IERANGE ? rng.text : rng.toString(); + return str.replace(/\r\n|\n|\r/g, ''); + }, + cloneContents : function() { + return _copyAndDelete(this, true, false); + }, + deleteContents : function() { + return _copyAndDelete(this, false, true); + }, + extractContents : function() { + return _copyAndDelete(this, true, true); + }, + insertNode : function(node) { + var self = this, + sc = self.startContainer, so = self.startOffset, + ec = self.endContainer, eo = self.endOffset, + firstChild, lastChild, c, nodeCount = 1; + if (node.nodeName.toLowerCase() === '#document-fragment') { + firstChild = node.firstChild; + lastChild = node.lastChild; + nodeCount = node.childNodes.length; + } + if (sc.nodeType == 1) { + c = sc.childNodes[so]; + if (c) { + sc.insertBefore(node, c); + if (sc === ec) { + eo += nodeCount; + } + } else { + sc.appendChild(node); + } + } else if (sc.nodeType == 3) { + if (so === 0) { + sc.parentNode.insertBefore(node, sc); + if (sc.parentNode === ec) { + eo += nodeCount; + } + } else if (so >= sc.nodeValue.length) { + if (sc.nextSibling) { + sc.parentNode.insertBefore(node, sc.nextSibling); + } else { + sc.parentNode.appendChild(node); + } + } else { + if (so > 0) { + c = sc.splitText(so); + } else { + c = sc; + } + sc.parentNode.insertBefore(node, c); + if (sc === ec) { + ec = c; + eo -= so; + } + } + } + if (firstChild) { + self.setStartBefore(firstChild).setEndAfter(lastChild); + } else { + self.selectNode(node); + } + if (self.compareBoundaryPoints(_END_TO_END, self.cloneRange().setEnd(ec, eo)) >= 1) { + return self; + } + return self.setEnd(ec, eo); + }, + surroundContents : function(node) { + node.appendChild(this.extractContents()); + return this.insertNode(node).selectNode(node); + }, + isControl : function() { + var self = this, + sc = self.startContainer, so = self.startOffset, + ec = self.endContainer, eo = self.endOffset, rng; + return sc.nodeType == 1 && sc === ec && so + 1 === eo && K(sc.childNodes[so]).isControl(); + }, + get : function(hasControlRange) { + var self = this, doc = self.doc, node, rng; + if (!_IERANGE) { + rng = doc.createRange(); + try { + rng.setStart(self.startContainer, self.startOffset); + rng.setEnd(self.endContainer, self.endOffset); + } catch (e) {} + return rng; + } + if (hasControlRange && self.isControl()) { + rng = doc.body.createControlRange(); + rng.addElement(self.startContainer.childNodes[self.startOffset]); + return rng; + } + var range = self.cloneRange().down(); + rng = doc.body.createTextRange(); + rng.setEndPoint('StartToStart', _getEndRange(range.startContainer, range.startOffset)); + rng.setEndPoint('EndToStart', _getEndRange(range.endContainer, range.endOffset)); + return rng; + }, + html : function() { + return K(this.cloneContents()).outer(); + }, + down : function() { + var self = this; + function downPos(node, pos, isStart) { + if (node.nodeType != 1) { + return; + } + var children = K(node).children(); + if (children.length === 0) { + return; + } + var left, right, child, offset; + if (pos > 0) { + left = children.eq(pos - 1); + } + if (pos < children.length) { + right = children.eq(pos); + } + if (left && left.type == 3) { + child = left[0]; + offset = child.nodeValue.length; + } + if (right && right.type == 3) { + child = right[0]; + offset = 0; + } + if (!child) { + return; + } + if (isStart) { + self.setStart(child, offset); + } else { + self.setEnd(child, offset); + } + } + downPos(self.startContainer, self.startOffset, true); + downPos(self.endContainer, self.endOffset, false); + return self; + }, + up : function() { + var self = this; + function upPos(node, pos, isStart) { + if (node.nodeType != 3) { + return; + } + if (pos === 0) { + if (isStart) { + self.setStartBefore(node); + } else { + self.setEndBefore(node); + } + } else if (pos == node.nodeValue.length) { + if (isStart) { + self.setStartAfter(node); + } else { + self.setEndAfter(node); + } + } + } + upPos(self.startContainer, self.startOffset, true); + upPos(self.endContainer, self.endOffset, false); + return self; + }, + enlarge : function(toBlock) { + var self = this; + self.up(); + function enlargePos(node, pos, isStart) { + var knode = K(node), parent; + if (knode.type == 3 || _NOSPLIT_TAG_MAP[knode.name] || !toBlock && knode.isBlock()) { + return; + } + if (pos === 0) { + while (!knode.prev()) { + parent = knode.parent(); + if (!parent || _NOSPLIT_TAG_MAP[parent.name] || !toBlock && parent.isBlock()) { + break; + } + knode = parent; + } + if (isStart) { + self.setStartBefore(knode[0]); + } else { + self.setEndBefore(knode[0]); + } + } else if (pos == knode.children().length) { + while (!knode.next()) { + parent = knode.parent(); + if (!parent || _NOSPLIT_TAG_MAP[parent.name] || !toBlock && parent.isBlock()) { + break; + } + knode = parent; + } + if (isStart) { + self.setStartAfter(knode[0]); + } else { + self.setEndAfter(knode[0]); + } + } + } + enlargePos(self.startContainer, self.startOffset, true); + enlargePos(self.endContainer, self.endOffset, false); + return self; + }, + shrink : function() { + var self = this, child, collapsed = self.collapsed; + while (self.startContainer.nodeType == 1 && (child = self.startContainer.childNodes[self.startOffset]) && child.nodeType == 1 && !K(child).isSingle()) { + self.setStart(child, 0); + } + if (collapsed) { + return self.collapse(collapsed); + } + while (self.endContainer.nodeType == 1 && self.endOffset > 0 && (child = self.endContainer.childNodes[self.endOffset - 1]) && child.nodeType == 1 && !K(child).isSingle()) { + self.setEnd(child, child.childNodes.length); + } + return self; + }, + createBookmark : function(serialize) { + var self = this, doc = self.doc, endNode, + startNode = K('', doc)[0]; + startNode.id = '__kindeditor_bookmark_start_' + (_BOOKMARK_ID++) + '__'; + if (!self.collapsed) { + endNode = startNode.cloneNode(true); + endNode.id = '__kindeditor_bookmark_end_' + (_BOOKMARK_ID++) + '__'; + } + if (endNode) { + self.cloneRange().collapse(false).insertNode(endNode).setEndBefore(endNode); + } + self.insertNode(startNode).setStartAfter(startNode); + return { + start : serialize ? '#' + startNode.id : startNode, + end : endNode ? (serialize ? '#' + endNode.id : endNode) : null + }; + }, + moveToBookmark : function(bookmark) { + var self = this, doc = self.doc, + start = K(bookmark.start, doc), end = bookmark.end ? K(bookmark.end, doc) : null; + if (!start || start.length < 1) { + return self; + } + self.setStartBefore(start[0]); + start.remove(); + if (end && end.length > 0) { + self.setEndBefore(end[0]); + end.remove(); + } else { + self.collapse(true); + } + return self; + }, + dump : function() { + console.log('--------------------'); + console.log(this.startContainer.nodeType == 3 ? this.startContainer.nodeValue : this.startContainer, this.startOffset); + console.log(this.endContainer.nodeType == 3 ? this.endContainer.nodeValue : this.endContainer, this.endOffset); + } +}); +function _range(mixed) { + if (!mixed.nodeName) { + return mixed.constructor === KRange ? mixed : _toRange(mixed); + } + return new KRange(mixed); +} +K.RangeClass = KRange; +K.range = _range; +K.START_TO_START = _START_TO_START; +K.START_TO_END = _START_TO_END; +K.END_TO_END = _END_TO_END; +K.END_TO_START = _END_TO_START; + +function _nativeCommand(doc, key, val) { + try { + doc.execCommand(key, false, val); + } catch(e) {} +} +function _nativeCommandValue(doc, key) { + var val = ''; + try { +// val = doc.query_nativeCommand(self.doc, name, val);Value(key); + val = doc.queryCommandValue(key); + } catch (e) {} + if (typeof val !== 'string') { + val = ''; + } + return val; +} +function _getSel(doc) { + var win = _getWin(doc); + return _IERANGE ? doc.selection : win.getSelection(); +} +function _getRng(doc) { + var sel = _getSel(doc), rng; + try { + if (sel.rangeCount > 0) { + rng = sel.getRangeAt(0); + } else { + rng = sel.createRange(); + } + } catch(e) {} + if (_IERANGE && (!rng || (!rng.item && rng.parentElement().ownerDocument !== doc))) { + return null; + } + return rng; +} +function _singleKeyMap(map) { + var newMap = {}, arr, v; + _each(map, function(key, val) { + arr = key.split(','); + for (var i = 0, len = arr.length; i < len; i++) { + v = arr[i]; + newMap[v] = val; + } + }); + return newMap; +} +function _hasAttrOrCss(knode, map) { + return _hasAttrOrCssByKey(knode, map, '*') || _hasAttrOrCssByKey(knode, map); +} +function _hasAttrOrCssByKey(knode, map, mapKey) { + mapKey = mapKey || knode.name; + if (knode.type !== 1) { + return false; + } + var newMap = _singleKeyMap(map); + if (!newMap[mapKey]) { + return false; + } + var arr = newMap[mapKey].split(','); + for (var i = 0, len = arr.length; i < len; i++) { + var key = arr[i]; + if (key === '*') { + return true; + } + var match = /^(\.?)([^=]+)(?:=([^=]*))?$/.exec(key); + var method = match[1] ? 'css' : 'attr'; + key = match[2]; + var val = match[3] || ''; + if (val === '' && knode[method](key) !== '') { + return true; + } + if (val !== '' && knode[method](key) === val) { + return true; + } + } + return false; +} +function _removeAttrOrCss(knode, map) { + if (knode.type != 1) { + return; + } + _removeAttrOrCssByKey(knode, map, '*'); + _removeAttrOrCssByKey(knode, map); +} +function _removeAttrOrCssByKey(knode, map, mapKey) { + mapKey = mapKey || knode.name; + if (knode.type !== 1) { + return; + } + var newMap = _singleKeyMap(map); + if (!newMap[mapKey]) { + return; + } + var arr = newMap[mapKey].split(','), allFlag = false; + for (var i = 0, len = arr.length; i < len; i++) { + var key = arr[i]; + if (key === '*') { + allFlag = true; + break; + } + var match = /^(\.?)([^=]+)(?:=([^=]*))?$/.exec(key); + key = match[2]; + if (match[1]) { + key = _toCamel(key); + if (knode[0].style[key]) { + knode[0].style[key] = ''; + } + } else { + knode.removeAttr(key); + } + } + if (allFlag) { + knode.remove(true); + } +} +function _getInnerNode(knode) { + var inner = knode; + while (inner.first()) { + inner = inner.first(); + } + return inner; +} +function _isEmptyNode(knode) { + if (knode.type != 1 || knode.isSingle()) { + return false; + } + return knode.html().replace(/<[^>]+>/g, '') === ''; +} +function _mergeWrapper(a, b) { + a = a.clone(true); + var lastA = _getInnerNode(a), childA = a, merged = false; + while (b) { + while (childA) { + if (childA.name === b.name) { + _mergeAttrs(childA, b.attr(), b.css()); + merged = true; + } + childA = childA.first(); + } + if (!merged) { + lastA.append(b.clone(false)); + } + merged = false; + b = b.first(); + } + return a; +} +function _wrapNode(knode, wrapper) { + wrapper = wrapper.clone(true); + if (knode.type == 3) { + _getInnerNode(wrapper).append(knode.clone(false)); + knode.replaceWith(wrapper); + return wrapper; + } + var nodeWrapper = knode, child; + while ((child = knode.first()) && child.children().length == 1) { + knode = child; + } + child = knode.first(); + var frag = knode.doc.createDocumentFragment(); + while (child) { + frag.appendChild(child[0]); + child = child.next(); + } + wrapper = _mergeWrapper(nodeWrapper, wrapper); + if (frag.firstChild) { + _getInnerNode(wrapper).append(frag); + } + nodeWrapper.replaceWith(wrapper); + return wrapper; +} +function _mergeAttrs(knode, attrs, styles) { + _each(attrs, function(key, val) { + if (key !== 'style') { + knode.attr(key, val); + } + }); + _each(styles, function(key, val) { + knode.css(key, val); + }); +} +function _inPreElement(knode) { + while (knode && knode.name != 'body') { + if (_PRE_TAG_MAP[knode.name] || knode.name == 'div' && knode.hasClass('ke-script')) { + return true; + } + knode = knode.parent(); + } + return false; +} +function KCmd(range) { + this.init(range); +} +_extend(KCmd, { + init : function(range) { + var self = this, doc = range.doc; + self.doc = doc; + self.win = _getWin(doc); + self.sel = _getSel(doc); + self.range = range; + }, + selection : function(forceReset) { + var self = this, doc = self.doc, rng = _getRng(doc); + self.sel = _getSel(doc); + if (rng) { + self.range = _range(rng); + if (K(self.range.startContainer).name == 'html') { + self.range.selectNodeContents(doc.body).collapse(false); + } + return self; + } + if (forceReset) { + self.range.selectNodeContents(doc.body).collapse(false); + } + return self; + }, + select : function(hasDummy) { + hasDummy = _undef(hasDummy, true); + var self = this, sel = self.sel, range = self.range.cloneRange().shrink(), + sc = range.startContainer, so = range.startOffset, + ec = range.endContainer, eo = range.endOffset, + doc = _getDoc(sc), win = self.win, rng, hasU200b = false; + if (hasDummy && sc.nodeType == 1 && range.collapsed) { + if (_IERANGE) { + var dummy = K(' ', doc); + range.insertNode(dummy[0]); + rng = doc.body.createTextRange(); + try { + rng.moveToElementText(dummy[0]); + } catch(ex) {} + rng.collapse(false); + rng.select(); + dummy.remove(); + win.focus(); + return self; + } + if (_WEBKIT) { + var children = sc.childNodes; + if (K(sc).isInline() || so > 0 && K(children[so - 1]).isInline() || children[so] && K(children[so]).isInline()) { + range.insertNode(doc.createTextNode('\u200B')); + hasU200b = true; + } + } + } + if (_IERANGE) { + try { + rng = range.get(true); + rng.select(); + } catch(e) {} + } else { + if (hasU200b) { + range.collapse(false); + } + rng = range.get(true); + sel.removeAllRanges(); + sel.addRange(rng); + if (doc !== document) { + var pos = K(rng.endContainer).pos(); + //win.scrollTo(pos.x, pos.y); + } + } + win.focus(); + return self; + }, + wrap : function(val) { + var self = this, doc = self.doc, range = self.range, wrapper; + wrapper = K(val, doc); + if (range.collapsed) { + range.shrink(); + range.insertNode(wrapper[0]).selectNodeContents(wrapper[0]); + return self; + } + if (wrapper.isBlock()) { + var copyWrapper = wrapper.clone(true), child = copyWrapper; + while (child.first()) { + child = child.first(); + } + child.append(range.extractContents()); + range.insertNode(copyWrapper[0]).selectNode(copyWrapper[0]); + return self; + } + range.enlarge(); + var bookmark = range.createBookmark(), ancestor = range.commonAncestor(), isStart = false; + K(ancestor).scan(function(node) { + if (!isStart && node == bookmark.start) { + isStart = true; + return; + } + if (isStart) { + if (node == bookmark.end) { + return false; + } + var knode = K(node); + if (_inPreElement(knode)) { + return; + } + if (knode.type == 3 && _trim(node.nodeValue).length > 0) { + var parent; + while ((parent = knode.parent()) && parent.isStyle() && parent.children().length == 1) { + knode = parent; + } + _wrapNode(knode, wrapper); + } + } + }); + range.moveToBookmark(bookmark); + return self; + }, + split : function(isStart, map) { + var range = this.range, doc = range.doc; + var tempRange = range.cloneRange().collapse(isStart); + var node = tempRange.startContainer, pos = tempRange.startOffset, + parent = node.nodeType == 3 ? node.parentNode : node, + needSplit = false, knode; + while (parent && parent.parentNode) { + knode = K(parent); + if (map) { + if (!knode.isStyle()) { + break; + } + if (!_hasAttrOrCss(knode, map)) { + break; + } + } else { + if (_NOSPLIT_TAG_MAP[knode.name]) { + break; + } + } + needSplit = true; + parent = parent.parentNode; + } + if (needSplit) { + var dummy = doc.createElement('span'); + range.cloneRange().collapse(!isStart).insertNode(dummy); + if (isStart) { + tempRange.setStartBefore(parent.firstChild).setEnd(node, pos); + } else { + tempRange.setStart(node, pos).setEndAfter(parent.lastChild); + } + var frag = tempRange.extractContents(), + first = frag.firstChild, last = frag.lastChild; + if (isStart) { + tempRange.insertNode(frag); + range.setStartAfter(last).setEndBefore(dummy); + } else { + parent.appendChild(frag); + range.setStartBefore(dummy).setEndBefore(first); + } + var dummyParent = dummy.parentNode; + if (dummyParent == range.endContainer) { + var prev = K(dummy).prev(), next = K(dummy).next(); + if (prev && next && prev.type == 3 && next.type == 3) { + range.setEnd(prev[0], prev[0].nodeValue.length); + } else if (!isStart) { + range.setEnd(range.endContainer, range.endOffset - 1); + } + } + dummyParent.removeChild(dummy); + } + return this; + }, + remove : function(map) { + var self = this, doc = self.doc, range = self.range; + range.enlarge(); + if (range.startOffset === 0) { + var ksc = K(range.startContainer), parent; + while ((parent = ksc.parent()) && parent.isStyle() && parent.children().length == 1) { + ksc = parent; + } + range.setStart(ksc[0], 0); + ksc = K(range.startContainer); + if (ksc.isBlock()) { + _removeAttrOrCss(ksc, map); + } + var kscp = ksc.parent(); + if (kscp && kscp.isBlock()) { + _removeAttrOrCss(kscp, map); + } + } + var sc, so; + if (range.collapsed) { + self.split(true, map); + sc = range.startContainer; + so = range.startOffset; + if (so > 0) { + var sb = K(sc.childNodes[so - 1]); + if (sb && _isEmptyNode(sb)) { + sb.remove(); + range.setStart(sc, so - 1); + } + } + var sa = K(sc.childNodes[so]); + if (sa && _isEmptyNode(sa)) { + sa.remove(); + } + if (_isEmptyNode(sc)) { + range.startBefore(sc); + sc.remove(); + } + range.collapse(true); + return self; + } + self.split(true, map); + self.split(false, map); + var startDummy = doc.createElement('span'), endDummy = doc.createElement('span'); + range.cloneRange().collapse(false).insertNode(endDummy); + range.cloneRange().collapse(true).insertNode(startDummy); + var nodeList = [], cmpStart = false; + K(range.commonAncestor()).scan(function(node) { + if (!cmpStart && node == startDummy) { + cmpStart = true; + return; + } + if (node == endDummy) { + return false; + } + if (cmpStart) { + nodeList.push(node); + } + }); + K(startDummy).remove(); + K(endDummy).remove(); + sc = range.startContainer; + so = range.startOffset; + var ec = range.endContainer, eo = range.endOffset; + if (so > 0) { + var startBefore = K(sc.childNodes[so - 1]); + if (startBefore && _isEmptyNode(startBefore)) { + startBefore.remove(); + range.setStart(sc, so - 1); + if (sc == ec) { + range.setEnd(ec, eo - 1); + } + } + var startAfter = K(sc.childNodes[so]); + if (startAfter && _isEmptyNode(startAfter)) { + startAfter.remove(); + if (sc == ec) { + range.setEnd(ec, eo - 1); + } + } + } + var endAfter = K(ec.childNodes[range.endOffset]); + if (endAfter && _isEmptyNode(endAfter)) { + endAfter.remove(); + } + var bookmark = range.createBookmark(true); + _each(nodeList, function(i, node) { + _removeAttrOrCss(K(node), map); + }); + range.moveToBookmark(bookmark); + return self; + }, + commonNode : function(map) { + var range = this.range; + var ec = range.endContainer, eo = range.endOffset, + node = (ec.nodeType == 3 || eo === 0) ? ec : ec.childNodes[eo - 1]; + function find(node) { + var child = node, parent = node; + while (parent) { + if (_hasAttrOrCss(K(parent), map)) { + return K(parent); + } + parent = parent.parentNode; + } + while (child && (child = child.lastChild)) { + if (_hasAttrOrCss(K(child), map)) { + return K(child); + } + } + return null; + } + var cNode = find(node); + if (cNode) { + return cNode; + } + if (node.nodeType == 1 || (ec.nodeType == 3 && eo === 0)) { + var prev = K(node).prev(); + if (prev) { + return find(prev); + } + } + return null; + }, + commonAncestor : function(tagName) { + var range = this.range, + sc = range.startContainer, so = range.startOffset, + ec = range.endContainer, eo = range.endOffset, + startNode = (sc.nodeType == 3 || so === 0) ? sc : sc.childNodes[so - 1], + endNode = (ec.nodeType == 3 || eo === 0) ? ec : ec.childNodes[eo - 1]; + function find(node) { + while (node) { + if (node.nodeType == 1) { + if (node.tagName.toLowerCase() === tagName) { + return node; + } + } + node = node.parentNode; + } + return null; + } + var start = find(startNode), end = find(endNode); + if (start && end && start === end) { + return K(start); + } + return null; + }, + state : function(key) { + var self = this, doc = self.doc, bool = false; + try { + bool = doc.queryCommandState(key); + } catch (e) {} + return bool; + }, + val : function(key) { + var self = this, doc = self.doc, range = self.range; + function lc(val) { + return val.toLowerCase(); + } + key = lc(key); + var val = '', knode; + if (key === 'fontfamily' || key === 'fontname') { + val = _nativeCommandValue(doc, 'fontname'); + val = val.replace(/['"]/g, ''); + return lc(val); + } + if (key === 'formatblock') { + val = _nativeCommandValue(doc, key); + if (val === '') { + knode = self.commonNode({'h1,h2,h3,h4,h5,h6,p,div,pre,address' : '*'}); + if (knode) { + val = knode.name; + } + } + if (val === 'Normal') { + val = 'p'; + } + return lc(val); + } + if (key === 'fontsize') { + knode = self.commonNode({'*' : '.font-size'}); + if (knode) { + val = knode.css('font-size'); + } + return lc(val); + } + if (key === 'forecolor') { + knode = self.commonNode({'*' : '.color'}); + if (knode) { + val = knode.css('color'); + } + val = _toHex(val); + if (val === '') { + val = 'default'; + } + return lc(val); + } + if (key === 'hilitecolor') { + knode = self.commonNode({'*' : '.background-color'}); + if (knode) { + val = knode.css('background-color'); + } + val = _toHex(val); + if (val === '') { + val = 'default'; + } + return lc(val); + } + return val; + }, + toggle : function(wrapper, map) { + var self = this; + if (self.commonNode(map)) { + self.remove(map); + } else { + self.wrap(wrapper); + } + return self.select(); + }, + bold : function() { + return this.toggle('', { + span : '.font-weight=bold', + strong : '*', + b : '*' + }); + }, + italic : function() { + return this.toggle('', { + span : '.font-style=italic', + em : '*', + i : '*' + }); + }, + underline : function() { + return this.toggle('', { + span : '.text-decoration=underline', + u : '*' + }); + }, + strikethrough : function() { + return this.toggle('', { + span : '.text-decoration=line-through', + s : '*' + }); + }, + forecolor : function(val) { + return this.wrap('').select(); + }, + hilitecolor : function(val) { + return this.wrap('').select(); + }, + fontsize : function(val) { + return this.wrap('').select(); + }, + fontname : function(val) { + return this.fontfamily(val); + }, + fontfamily : function(val) { + return this.wrap('').select(); + }, + removeformat : function() { + var map = { + '*' : '.font-weight,.font-style,.text-decoration,.color,.background-color,.font-size,.font-family,.text-indent' + }, + tags = _STYLE_TAG_MAP; + _each(tags, function(key, val) { + map[key] = '*'; + }); + this.remove(map); + return this.select(); + }, + inserthtml : function(val, quickMode) { + var self = this, range = self.range; + if (val === '') { + return self; + } + function pasteHtml(range, val) { + val = '' + val; + var rng = range.get(); + if (rng.item) { + rng.item(0).outerHTML = val; + } else { + rng.pasteHTML(val); + } + var temp = range.doc.getElementById('__kindeditor_temp_tag__'); + temp.parentNode.removeChild(temp); + var newRange = _toRange(rng); + range.setEnd(newRange.endContainer, newRange.endOffset); + range.collapse(false); + self.select(false); + } + function insertHtml(range, val) { + var doc = range.doc, + frag = doc.createDocumentFragment(); + K('@' + val, doc).each(function() { + frag.appendChild(this); + }); + range.deleteContents(); + range.insertNode(frag); + range.collapse(false); + self.select(false); + } + if (_IERANGE && quickMode) { + try { + pasteHtml(range, val); + } catch(e) { + insertHtml(range, val); + } + return self; + } + insertHtml(range, val); + return self; + }, + hr : function() { + return this.inserthtml('
    '); + }, + print : function() { + this.win.print(); + return this; + }, + insertimage : function(url, title, width, height, border, align) { + title = _undef(title, ''); + border = _undef(border, 0); + var html = ''; + return self.inserthtml(html); + } + if (range.isControl()) { + var node = K(range.startContainer.childNodes[range.startOffset]); + html += '>'; + node.after(K(html, doc)); + node.next().append(node); + range.selectNode(node[0]); + return self.select(); + } + function setAttr(node, url, type) { + K(node).attr('href', url).attr('data-ke-src', url); + if (type) { + K(node).attr('target', type); + } else { + K(node).removeAttr('target'); + } + } + var sc = range.startContainer, so = range.startOffset, + ec = range.endContainer, eo = range.endOffset; + if (sc.nodeType == 1 && sc === ec && so + 1 === eo) { + var child = sc.childNodes[so]; + if (child.nodeName.toLowerCase() == 'a') { + setAttr(child, url, type); + return self; + } + } + _nativeCommand(doc, 'createlink', '__kindeditor_temp_url__'); + K('a[href="__kindeditor_temp_url__"]', doc).each(function() { + setAttr(this, url, type); + }); + return self; + }, + unlink : function() { + var self = this, doc = self.doc, range = self.range; + self.select(); + if (range.collapsed) { + var a = self.commonNode({ a : '*' }); + if (a) { + range.selectNode(a.get()); + self.select(); + } + _nativeCommand(doc, 'unlink', null); + if (_WEBKIT && K(range.startContainer).name === 'img') { + var parent = K(range.startContainer).parent(); + if (parent.name === 'a') { + parent.remove(true); + } + } + } else { + _nativeCommand(doc, 'unlink', null); + } + return self; + } +}); +_each(('formatblock,selectall,justifyleft,justifycenter,justifyright,justifyfull,insertorderedlist,' + + 'insertunorderedlist,indent,outdent,subscript,superscript').split(','), function(i, name) { + KCmd.prototype[name] = function(val) { + var self = this; + self.select(); + _nativeCommand(self.doc, name, val); + if (_IERANGE && _inArray(name, 'justifyleft,justifycenter,justifyright,justifyfull'.split(',')) >= 0) { + self.selection(); + } + if (!_IERANGE || _inArray(name, 'formatblock,selectall,insertorderedlist,insertunorderedlist'.split(',')) >= 0) { + self.selection(); + } + + return self; + }; +}); +_each('cut,copy,paste'.split(','), function(i, name) { + KCmd.prototype[name] = function() { + var self = this; + if (!self.doc.queryCommandSupported(name)) { + throw 'not supported'; + } + self.select(); + _nativeCommand(self.doc, name, null); + return self; + }; +}); +function _cmd(mixed) { + if (mixed.nodeName) { + var doc = _getDoc(mixed); + mixed = _range(doc).selectNodeContents(doc.body).collapse(false); + } + return new KCmd(mixed); +} +K.CmdClass = KCmd; +K.cmd = _cmd; +function _drag(options) { + var moveEl = options.moveEl, + moveFn = options.moveFn, + clickEl = options.clickEl || moveEl, + beforeDrag = options.beforeDrag, + iframeFix = options.iframeFix === undefined ? true : options.iframeFix; + var docs = [document]; + if (iframeFix) { + K('iframe').each(function() { + var src = _formatUrl(this.src || '', 'absolute'); + if (/^https?:\/\//.test(src)) { + return; + } + var doc; + try { + doc = _iframeDoc(this); + } catch(e) {} + if (doc) { + var pos = K(this).pos(); + K(doc).data('pos-x', pos.x); + K(doc).data('pos-y', pos.y); + docs.push(doc); + } + }); + } + clickEl.mousedown(function(e) { + //新加的 + if(e.button !== 0 && e.button !== 1) { + return; + } + e.stopPropagation(); + var self = clickEl.get(), + x = _removeUnit(moveEl.css('left')), + y = _removeUnit(moveEl.css('top')), + width = moveEl.width(), + height = moveEl.height(), + pageX = e.pageX, + pageY = e.pageY; + if (beforeDrag) { + beforeDrag(); + } + function moveListener(e) { + e.preventDefault(); + var kdoc = K(_getDoc(e.target)); + var diffX = _round((kdoc.data('pos-x') || 0) + e.pageX - pageX); + var diffY = _round((kdoc.data('pos-y') || 0) + e.pageY - pageY); + moveFn.call(clickEl, x, y, width, height, diffX, diffY); + } + function selectListener(e) { + e.preventDefault(); + } + function upListener(e) { + e.preventDefault(); + K(docs).unbind('mousemove', moveListener) + .unbind('mouseup', upListener) + .unbind('selectstart', selectListener); + if (self.releaseCapture) { + self.releaseCapture(); + } + } + K(docs).mousemove(moveListener) + .mouseup(upListener) + .bind('selectstart', selectListener); + if (self.setCapture) { + self.setCapture(); + } + }); +} +function KWidget(options) { + this.init(options); +} +_extend(KWidget, { + init : function(options) { + var self = this; + self.name = options.name || ''; + self.doc = options.doc || document; + self.win = _getWin(self.doc); + self.x = _addUnit(options.x); + self.y = _addUnit(options.y); + self.z = options.z; + self.width = _addUnit(options.width); + self.height = _addUnit(options.height); + self.div = K('
    '); + self.options = options; + self._alignEl = options.alignEl; + if (self.width) { + self.div.css('width', self.width); + } + if (self.height) { + self.div.css('height', self.height); + } + if (self.z) { + self.div.css({ + position : 'absolute', + left : self.x, + top : self.y, + 'z-index' : self.z + }); + } + if (self.z && (self.x === undefined || self.y === undefined)) { + self.autoPos(self.width, self.height); + } + if (options.cls) { + self.div.addClass(options.cls); + } + if (options.shadowMode) { + self.div.addClass('ke-shadow'); + } + if (options.css) { + self.div.css(options.css); + } + if (options.src) { + K(options.src).replaceWith(self.div); + } else { + K(self.doc.body).append(self.div); + } + if (options.html) { + self.div.html(options.html); + } + if (options.autoScroll) { + if (_IE && _V < 7 || _QUIRKS) { + var scrollPos = _getScrollPos(); + K(self.win).bind('scroll', function(e) { + var pos = _getScrollPos(), + diffX = pos.x - scrollPos.x, + diffY = pos.y - scrollPos.y; + self.pos(_removeUnit(self.x) + diffX, _removeUnit(self.y) + diffY, false); + }); + } else { + self.div.css('position', 'fixed'); + } + } + }, + pos : function(x, y, updateProp) { + var self = this; + updateProp = _undef(updateProp, true); + if (x !== null) { + x = x < 0 ? 0 : _addUnit(x); + self.div.css('left', x); + if (updateProp) { + self.x = x; + } + } + if (y !== null) { + y = y < 0 ? 0 : _addUnit(y); + self.div.css('top', y); + if (updateProp) { + self.y = y; + } + } + return self; + }, + autoPos : function(width, height) { + var self = this, + w = _removeUnit(width) || 0, + h = _removeUnit(height) || 0, + scrollPos = _getScrollPos(); + if (self._alignEl) { + var knode = K(self._alignEl), + pos = knode.pos(), + diffX = _round(knode[0].clientWidth / 2 - w / 2), + diffY = _round(knode[0].clientHeight / 2 - h / 2); + x = diffX < 0 ? pos.x : pos.x + diffX; + y = diffY < 0 ? pos.y : pos.y + diffY; + } else { + var docEl = _docElement(self.doc); + x = _round(scrollPos.x + (docEl.clientWidth - w) / 2); + y = _round(scrollPos.y + (docEl.clientHeight - h) / 2); + } + if (!(_IE && _V < 7 || _QUIRKS)) { + x -= scrollPos.x; + y -= scrollPos.y; + } + return self.pos(x, y); + }, + remove : function() { + var self = this; + if (_IE && _V < 7 || _QUIRKS) { + K(self.win).unbind('scroll'); + } + self.div.remove(); + _each(self, function(i) { + self[i] = null; + }); + return this; + }, + show : function() { + this.div.show(); + return this; + }, + hide : function() { + this.div.hide(); + return this; + }, + draggable : function(options) { + var self = this; + options = options || {}; + options.moveEl = self.div; + options.moveFn = function(x, y, width, height, diffX, diffY) { + if ((x = x + diffX) < 0) { + x = 0; + } + if ((y = y + diffY) < 0) { + y = 0; + } + self.pos(x, y); + }; + _drag(options); + return self; + } +}); +function _widget(options) { + return new KWidget(options); +} +K.WidgetClass = KWidget; +K.widget = _widget; +function _iframeDoc(iframe) { + iframe = _get(iframe); + return iframe.contentDocument || iframe.contentWindow.document; +} +var html, _direction = ''; +if ((html = document.getElementsByTagName('html'))) { + _direction = html[0].dir; +} + +function _getInitHtml(themesPath, bodyClass, cssPath, cssData) { + var arr = [ + (_direction === '' ? '' : ''), + '', + '' + ]; + if (!_isArray(cssPath)) { + cssPath = [cssPath]; + } + _each(cssPath, function(i, path) { + if (path) { + arr.push(''); + } + }); + if (cssData) { + arr.push(''); + } + arr.push(''); + return arr.join('\n'); +} +function _elementVal(knode, val) { + if (knode.hasVal()) { + if (val === undefined) { + var html = knode.val(); + html = html.replace(/(<(?:p|p\s[^>]*)>) *(<\/p>)/ig, ''); + return html; + } + if(self.placeholder != ""){ + if(/^\s*<\w*\s*\w*\=\"\w*\"\s*\w*\=\"\w*\:\s*\#\d*\;\s*\w*\-\w*\:\s*\w*\;\"\>[\u4e00-\u9fa5]*[\,]*[\(]*[\u4e00-\u9fa5]*[\:]*[\u4e00-\u9fa5]*[\。]*[\)]*<\/\w*\>\s*$/.test(val)){ + return knode.val(""); + } + } + return knode.val(val); + } + if(self.placeholder != ""){ + if(/^\s*<\w*\s*\w*\=\"\w*\"\s*\w*\=\"\w*\:\s*\#\d*\;\s*\w*\-\w*\:\s*\w*\;\"\>[\u4e00-\u9fa5]*[\,]*[\(]*[\u4e00-\u9fa5]*[\:]*[\u4e00-\u9fa5]*[\。]*[\)]*<\/\w*\>\s*$/.test(val)){ + return knode.html(""); + } + } else{ + return knode.html(val); + } +} +function KEdit(options) { + this.init(options); +} +_extend(KEdit, KWidget, { + init : function(options) { + var self = this; + KEdit.parent.init.call(self, options); + self.srcElement = K(options.srcElement); + self.div.addClass('ke-edit'); + self.designMode = _undef(options.designMode, true); + self.beforeGetHtml = options.beforeGetHtml; + self.beforeSetHtml = options.beforeSetHtml; + self.afterSetHtml = options.afterSetHtml; + var themesPath = _undef(options.themesPath, ''), + bodyClass = options.bodyClass, + cssPath = options.cssPath, + cssData = options.cssData, + isDocumentDomain = location.protocol != 'res:' && location.host.replace(/:\d+/, '') !== document.domain, + srcScript = ('document.open();' + + (isDocumentDomain ? 'document.domain="' + document.domain + '";' : '') + + 'document.close();'), + iframeSrc = _IE ? ' src="javascript:void(function(){' + encodeURIComponent(srcScript) + '}())"' : ''; + self.iframe = K('').css('width', '100%'); + self.textarea = K('').css('width', '100%'); + self.tabIndex = isNaN(parseInt(options.tabIndex, 10)) ? self.srcElement.attr('tabindex') : parseInt(options.tabIndex, 10); + self.iframe.attr('tabindex', self.tabIndex); + self.textarea.attr('tabindex', self.tabIndex); + if (self.width) { + self.setWidth(self.width); + } + if (self.height) { + self.setHeight(self.height); + } + if (self.designMode) { + self.textarea.hide(); + } else { + self.iframe.hide(); + } + function ready() { + var doc = _iframeDoc(self.iframe); + doc.open(); + if (isDocumentDomain) { + doc.domain = document.domain; + } + + doc.write(_getInitHtml(themesPath, bodyClass, cssPath, cssData)); + doc.close(); + self.win = self.iframe[0].contentWindow; + self.doc = doc; + var cmd = _cmd(doc); + self.afterChange(function(e) { +// if (e.which == 8) { +// var range = cmd.range +// var bookmark = range.createBookmark(); +// cmd.doc.body.innerHTML = cmd.doc.body.innerHTML.replace(/

    \s*<\/p>/g,""); +// range.moveToBookmark(bookmark); +// } + cmd.selection(); + }); + if (_WEBKIT) { + K(doc).click(function(e) { + if (K(e.target).name === 'img') { + cmd.selection(true); + cmd.range.selectNode(e.target); + cmd.select(); + } + }); + } + if (_IE) { + self._mousedownHandler = function() { + var newRange = cmd.range.cloneRange(); + newRange.shrink(); + if (newRange.isControl()) { + self.blur(); + } + }; + K(document).mousedown(self._mousedownHandler); + K(doc).keydown(function(e) { + if (e.which == 8) { + cmd.selection(); + var rng = cmd.range; + if (rng.isControl()) { + rng.collapse(true); + K(rng.startContainer.childNodes[rng.startOffset]).remove(); + e.preventDefault(); + } + } + }); + } + self.cmd = cmd; + self.html(_elementVal(self.srcElement)); + if (_IE) { + doc.body.disabled = true; + doc.body.contentEditable = true; + doc.body.removeAttribute('disabled'); + } else { + doc.designMode = 'on'; + } + if (options.afterCreate) { + options.afterCreate.call(self); + } + } + if (isDocumentDomain) { + self.iframe.bind('load', function(e) { + self.iframe.unbind('load'); + if (_IE) { + ready(); + } else { + setTimeout(ready, 0); + } + }); + } + self.div.append(self.iframe); + self.div.append(self.textarea); + self.srcElement.hide(); + !isDocumentDomain && ready(); + }, + setWidth : function(val) { + var self = this; + val = _addUnit(val); + self.width = val; + self.div.css('width', val); + return self; + }, + setHeight : function(val) { + var self = this; + val = _addUnit(val); + self.height = val; + self.div.css('height', val); + self.iframe.css('height', val); + if ((_IE && _V < 8) || _QUIRKS) { + val = _addUnit(_removeUnit(val) - 2); + } + self.textarea.css('height', val); + return self; + }, + remove : function() { + var self = this, doc = self.doc; + K(doc.body).unbind(); + K(doc).unbind(); + K(self.win).unbind(); + if (self._mousedownHandler) { + K(document).unbind('mousedown', self._mousedownHandler); + } + _elementVal(self.srcElement, self.html()); + self.srcElement.show(); + doc.write(''); + self.iframe.unbind(); + self.textarea.unbind(); + KEdit.parent.remove.call(self); + }, + html : function(val, isFull) { + var self = this, doc = self.doc; + if (self.designMode) { + var body = doc.body; + if (val === undefined) { + if (isFull) { + val = '' + body.parentNode.innerHTML + ''; + } else { + val = body.innerHTML; + } + //yk + if (self.beforeGetHtml) { + val = self.beforeGetHtml(val); + } + if (_GECKO && val == '
    ') { + val = ''; + } + return val; + } + if (self.beforeSetHtml) { + val = self.beforeSetHtml(val); + } + if (_IE && _V >= 9) { + val = val.replace(/(<.*?checked=")checked(".*>)/ig, '$1$2'); + } + K(body).html(val); + if (self.afterSetHtml) { + self.afterSetHtml(); + } + return self; + } + if (val === undefined) { + return self.textarea.val(); + } + self.textarea.val(val); + return self; + }, + design : function(bool) { + var self = this, val; + if (bool === undefined ? !self.designMode : bool) { + if (!self.designMode) { + val = self.html(); + self.designMode = true; + + //self.html(val); + //self.textarea.hide(); + //self.iframe.show(); + //新加 + self.textarea.hide(); + self.html(val); + var iframe = self.iframe; + var height = _removeUnit(self.height); + iframe.height(height - 2); + iframe.show(); + setTimeout(function() { + iframe.height(height); + }, 0); + } + } else { + if (self.designMode) { + val = self.html(); + self.designMode = false; + self.html(val); + self.iframe.hide(); + self.textarea.show(); + } + } + return self.focus(); + }, + focus : function() { + var self = this; + self.designMode ? self.win.focus() : self.textarea[0].focus(); + return self; + }, + blur : function() { + var self = this; + if (_IE) { + var input = K('', self.div); + self.div.append(input); + input[0].focus(); + input.remove(); + } else { + self.designMode ? self.win.blur() : self.textarea[0].blur(); + } + return self; + }, + afterChange : function(fn) { + var self = this, doc = self.doc, body = doc.body; + K(doc).keyup(function(e) { + if (!e.ctrlKey && !e.altKey && _CHANGE_KEY_MAP[e.which]) { + fn(e); + } + }); + K(doc).mouseup(fn).contextmenu(fn); + K(self.win).blur(fn); + function timeoutHandler(e) { + setTimeout(function() { + fn(e); + }, 1); + } + K(body).bind('paste', timeoutHandler); + K(body).bind('cut', timeoutHandler); + return self; + } +}); +function _edit(options) { + return new KEdit(options); +} +K.EditClass = KEdit; +K.edit = _edit; +K.iframeDoc = _iframeDoc; +function _selectToolbar(name, fn) { + var self = this, + knode = self.get(name); + if (knode) { + if (knode.hasClass('ke-disabled')) { + return; + } + fn(knode); + } +} +function KToolbar(options) { + this.init(options); +} +_extend(KToolbar, KWidget, { + init : function(options) { + var self = this; + KToolbar.parent.init.call(self, options); + self.disableMode = _undef(options.disableMode, false); + self.noDisableItemMap = _toMap(_undef(options.noDisableItems, [])); + self._itemMap = {}; + self.div.addClass('ke-toolbar').bind('contextmenu,mousedown,mousemove', function(e) { + e.preventDefault(); + }).attr('unselectable', 'on'); + function find(target) { + var knode = K(target); + if (knode.hasClass('ke-outline')) { + return knode; + } + if (knode.hasClass('ke-toolbar-icon')) { + return knode.parent(); + } + } + function hover(e, method) { + var knode = find(e.target); + if (knode) { + if (knode.hasClass('ke-disabled')) { + return; + } + if (knode.hasClass('ke-selected')) { + return; + } + knode[method]('ke-on'); + } + } + self.div.mouseover(function(e) { + hover(e, 'addClass'); + }) + .mouseout(function(e) { + hover(e, 'removeClass'); + }) + .click(function(e) { + var knode = find(e.target); + if (knode) { + if (knode.hasClass('ke-disabled')) { + return; + } + self.options.click.call(this, e, knode.attr('data-name')); + } + }); + }, + get : function(name) { + //if(this._itemMap[name])return this._itemMap[name]; + //return this._itemMap[name]=K("span.ke-icon-"+name,this.div).parent() +// if (this._itemMap[name]) { +// return this._itemMap[name]; +// } +// if($("#define").css('display') == 'block'){ +// pdiv = $("#define") +// }else if($("#full").css('display') == 'block'){ +// pdiv = $("#full") +// } + var container = this.div; + if(!$("#define",container).is(':hidden')){ + pdiv = $("#define",container); + }else if(!$("#full",container).is(':hidden')){ + pdiv = $("#full",container); + } + return (this._itemMap[name] = K('span.ke-icon-' + name, this.div).parent()); + }, + select : function(name) { + _selectToolbar.call(this, name, function(knode) { + knode.addClass('ke-selected'); + }); + return self; + }, + unselect : function(name) { + _selectToolbar.call(this, name, function(knode) { + knode.removeClass('ke-selected').removeClass('ke-on'); + }); + return self; + }, + enable : function(name) { + var self = this, + knode = name.get ? name : self.get(name); + if (knode) { + knode.removeClass('ke-disabled'); + knode.opacity(1); + } + return self; + }, + disable : function(name) { + var self = this, + knode = name.get ? name : self.get(name); + if (knode) { + knode.removeClass('ke-selected').addClass('ke-disabled'); + knode.opacity(0.5); + } + return self; + }, + disableAll : function(bool, noDisableItems) { + var self = this, map = self.noDisableItemMap, item; + if (noDisableItems) { + map = _toMap(noDisableItems); + } + if (bool === undefined ? !self.disableMode : bool) { + K('span.ke-outline', self.div).each(function() { + var knode = K(this), + name = knode[0].getAttribute('data-name', 2); + if (!map[name]) { + self.disable(knode); + } + }); + self.disableMode = true; + } else { + K('span.ke-outline', self.div).each(function() { + var knode = K(this), + name = knode[0].getAttribute('data-name', 2); + if (!map[name]) { + self.enable(knode); + } + }); + self.disableMode = false; + } + return self; + } +}); +function _toolbar(options) { + return new KToolbar(options); +} +K.ToolbarClass = KToolbar; +K.toolbar = _toolbar; +function KMenu(options) { + this.init(options); +} +_extend(KMenu, KWidget, { + init : function(options) { + var self = this; + options.z = options.z || 811213; + KMenu.parent.init.call(self, options); + self.centerLineMode = _undef(options.centerLineMode, true); + self.div.addClass('ke-menu').bind('click,mousedown', function(e){ + e.stopPropagation(); + }).attr('unselectable', 'on'); + }, + addItem : function(item) { + var self = this; + if (item.title === '-') { + self.div.append(K('

    ')); + return; + } + var itemDiv = K('
    '), + leftDiv = K('
    '), + rightDiv = K('
    '), + height = _addUnit(item.height), + iconClass = _undef(item.iconClass, ''); + self.div.append(itemDiv); + if (height) { + itemDiv.css('height', height); + rightDiv.css('line-height', height); + } + var centerDiv; + if (self.centerLineMode) { + centerDiv = K('
    '); + if (height) { + centerDiv.css('height', height); + } + } + itemDiv.mouseover(function(e) { + K(this).addClass('ke-menu-item-on'); + if (centerDiv) { + centerDiv.addClass('ke-menu-item-center-on'); + } + }) + .mouseout(function(e) { + K(this).removeClass('ke-menu-item-on'); + if (centerDiv) { + centerDiv.removeClass('ke-menu-item-center-on'); + } + }) + .click(function(e) { + item.click.call(K(this)); + e.stopPropagation(); + }) + .append(leftDiv); + if (centerDiv) { + itemDiv.append(centerDiv); + } + itemDiv.append(rightDiv); + if (item.checked) { + iconClass = 'ke-icon-checked'; + } + if (iconClass !== '') { + leftDiv.html(''); + } + rightDiv.html(item.title); + return self; + }, + remove : function() { + var self = this; + if (self.options.beforeRemove) { + self.options.beforeRemove.call(self); + } + K('.ke-menu-item', self.div[0]).unbind(); + KMenu.parent.remove.call(self); + return self; + } +}); +function _menu(options) { + return new KMenu(options); +} +K.MenuClass = KMenu; +K.menu = _menu; +function KColorPicker(options) { + this.init(options); +} +_extend(KColorPicker, KWidget, { + init : function(options) { + var self = this; + options.z = options.z || 811213; + KColorPicker.parent.init.call(self, options); + var colors = options.colors || [ + ['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'], + ['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'], + ['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'], + ['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000'] + ]; + self.selectedColor = (options.selectedColor || '').toLowerCase(); + self._cells = []; + self.div.addClass('ke-colorpicker').bind('click,mousedown', function(e){ + e.stopPropagation(); + }).attr('unselectable', 'on'); + var table = self.doc.createElement('table'); + self.div.append(table); + table.className = 'ke-colorpicker-table'; + table.cellPadding = 0; + table.cellSpacing = 0; + table.border = 0; + var row = table.insertRow(0), cell = row.insertCell(0); + cell.colSpan = colors[0].length; + self._addAttr(cell, '', 'ke-colorpicker-cell-top'); + for (var i = 0; i < colors.length; i++) { + row = table.insertRow(i + 1); + for (var j = 0; j < colors[i].length; j++) { + cell = row.insertCell(j); + self._addAttr(cell, colors[i][j], 'ke-colorpicker-cell'); + } + } + }, + _addAttr : function(cell, color, cls) { + var self = this; + cell = K(cell).addClass(cls); + if (self.selectedColor === color.toLowerCase()) { + cell.addClass('ke-colorpicker-cell-selected'); + } + cell.attr('title', color || self.options.noColor); + cell.mouseover(function(e) { + K(this).addClass('ke-colorpicker-cell-on'); + }); + cell.mouseout(function(e) { + K(this).removeClass('ke-colorpicker-cell-on'); + }); + cell.click(function(e) { + e.stop(); + self.options.click.call(K(this), color); + }); + if (color) { + cell.append(K('
    ').css('background-color', color)); + } else { + cell.html(self.options.noColor); + } + K(cell).attr('unselectable', 'on'); + self._cells.push(cell); + }, + remove : function() { + var self = this; + _each(self._cells, function() { + this.unbind(); + }); + KColorPicker.parent.remove.call(self); + return self; + } +}); +function _colorpicker(options) { + return new KColorPicker(options); +} +K.ColorPickerClass = KColorPicker; +K.colorpicker = _colorpicker; +function KUploadButton(options) { + this.init(options); +} +_extend(KUploadButton, { + init : function(options) { + //dump_obj(options); + var self = this, + button = K(options.button), + fieldName = options.fieldName || 'file', + url = options.url || '', + title = button.val(), + extraParams = options.extraParams || {}, + cls = button[0].className || '', + target = options.target || 'kindeditor_upload_iframe_' + new Date().getTime(); + options.afterError = options.afterError || function(str) { + alert(str); + }; + var hiddenElements = []; + for(var k in extraParams){ + hiddenElements.push(''); + } + var html = [ + '
    ', + (options.target ? '' : ''), + (options.form ? '
    ' : '
    '), + '', + hiddenElements.join(''), + '', + '', + '', + (options.form ? '
    ' : ''), + '
    '].join(''); + var div = K(html, button.doc); + $(div).hide()// 如果 以后要用根据 http://kindeditor.net/docs/uploadbutton.html#k-uploadbutton-options来使用uploadButton,那么这里的button会 是隐藏的 + button.hide(); + button.before(div); + self.div = div; + if(options.ops!=undefined)options.ops.up_file_div = div;//options.ops是KindEditor.create()的options参数 + self.button = button; + self.iframe = options.target ? K('iframe[name="' + target + '"]') : K('iframe', div); + self.form = options.form ? K(options.form) : K('form', div); + self.fileBox = K('.ke-upload-file', div); + var width = options.width || K('.ke-button-common', div).width(); + K('.ke-upload-area', div).width(width); + self.options = options; + }, + submit : function() { + var self = this, + iframe = self.iframe; + iframe.bind('load', function() { + iframe.unbind(); + var tempForm = document.createElement('form'); + self.fileBox.before(tempForm); + K(tempForm).append(self.fileBox); + tempForm.reset(); + K(tempForm).remove(true); + var doc = K.iframeDoc(iframe), + pre = doc.getElementsByTagName('pre')[0], + str = '', data; + if (pre) { + str = pre.innerHTML; + } else { + str = doc.body.innerHTML; + } + str = _unescape(str); + iframe[0].src = 'javascript:false'; + try { + data = K.json(str); + } catch (e) { + self.options.afterError.call(self, '' + doc.body.parentNode.innerHTML + ''); + } + if (data) { + self.options.afterUpload.call(self, data); + } + }); + self.form[0].submit(); + return self; + }, + remove : function() { + var self = this; + if (self.fileBox) { + self.fileBox.unbind(); + } + self.iframe.remove(); + self.div.remove(); + self.button.show(); + return self; + } +}); +function _uploadbutton(options) { + return new KUploadButton(options); +} +K.UploadButtonClass = KUploadButton; +K.uploadbutton = _uploadbutton; +function _createButton(arg) { + arg = arg || {}; + var name = arg.name || '', + span = K(''), + btn = K(''); + if (arg.click) { + btn.click(arg.click); + } + span.append(btn); + return span; +} +function KDialog(options) { + this.init(options); +} +_extend(KDialog, KWidget, { + init : function(options) { + var self = this; + var shadowMode = _undef(options.shadowMode, true); + options.z = options.z || 811213; + options.shadowMode = false; + options.autoScroll = _undef(options.autoScroll, true); + KDialog.parent.init.call(self, options); + var title = options.title, + body = K(options.body, self.doc), + previewBtn = options.previewBtn, + yesBtn = options.yesBtn, + noBtn = options.noBtn, + closeBtn = options.closeBtn, + showMask = _undef(options.showMask, true); + self.div.addClass('ke-dialog').bind('click,mousedown', function(e){ + e.stopPropagation(); + }); + var contentDiv = K('
    ').appendTo(self.div); + if (_IE && _V < 7) { + self.iframeMask = K('').appendTo(self.div); + } else if (shadowMode) { + K('
    ').appendTo(self.div); + } + var headerDiv = K('
    '); + contentDiv.append(headerDiv); + headerDiv.html(title); + self.closeIcon = K('').click(closeBtn.click); + headerDiv.append(self.closeIcon); + self.draggable({ + clickEl : headerDiv, + beforeDrag : options.beforeDrag + }); + var bodyDiv = K('
    '); + contentDiv.append(bodyDiv); + bodyDiv.append(body); + var footerDiv = K(''); + if (previewBtn || yesBtn || noBtn) { + contentDiv.append(footerDiv); + } + _each([ + { btn : previewBtn, name : 'preview' }, + { btn : yesBtn, name : 'yes' }, + { btn : noBtn, name : 'no' } + ], function() { + if (this.btn) { + var button = _createButton(this.btn); + button.addClass('ke-dialog-' + this.name); + footerDiv.append(button); + } + }); + if (self.height) { + bodyDiv.height(_removeUnit(self.height) - headerDiv.height() - footerDiv.height()); + } + self.div.width(self.div.width()); + self.div.height(self.div.height()); + self.mask = null; + if (showMask) { + var docEl = _docElement(self.doc), + docWidth = Math.max(docEl.scrollWidth, docEl.clientWidth), + docHeight = Math.max(docEl.scrollHeight, docEl.clientHeight); + self.mask = _widget({ + x : 0, + y : 0, + z : self.z - 1, + cls : 'ke-dialog-mask', + width : docWidth, + height : docHeight + }); + } + self.autoPos(self.div.width(), self.div.height()); + self.footerDiv = footerDiv; + self.bodyDiv = bodyDiv; + self.headerDiv = headerDiv; + self.isLoading = false; + }, + setMaskIndex : function(z) { + var self = this; + self.mask.div.css('z-index', z); + }, + showLoading : function(msg) { + msg = _undef(msg, ''); + var self = this, body = self.bodyDiv; + self.loading = K('
    ' + msg + '
    ') + .width(body.width()).height(body.height()) + .css('top', self.headerDiv.height() + 'px'); + body.css('visibility', 'hidden').after(self.loading); + self.isLoading = true; + return self; + }, + hideLoading : function() { + this.loading && this.loading.remove(); + this.bodyDiv.css('visibility', 'visible'); + this.isLoading = false; + return this; + }, + remove : function() { + var self = this; + if (self.options.beforeRemove) { + self.options.beforeRemove.call(self); + } + self.mask && self.mask.remove(); + self.iframeMask && self.iframeMask.remove(); + self.closeIcon.unbind(); + K('input', self.div).unbind(); + K('button', self.div).unbind(); + self.footerDiv.unbind(); + self.bodyDiv.unbind(); + self.headerDiv.unbind(); + K('iframe', self.div).each(function() { + K(this).remove(); + }); + KDialog.parent.remove.call(self); + return self; + } +}); +function _dialog(options) { + return new KDialog(options); +} +K.DialogClass = KDialog; +K.dialog = _dialog; +function _tabs(options) { + var self = _widget(options), + remove = self.remove, + afterSelect = options.afterSelect, + div = self.div, + liList = []; + div.addClass('ke-tabs') + .bind('contextmenu,mousedown,mousemove', function(e) { + e.preventDefault(); + }); + var ul = K('
      '); + div.append(ul); + self.add = function(tab) { + var li = K('
    • ' + tab.title + '
    • '); + li.data('tab', tab); + liList.push(li); + ul.append(li); + }; + self.selectedIndex = 0; + self.select = function(index) { + self.selectedIndex = index; + _each(liList, function(i, li) { + li.unbind(); + if (i === index) { + li.addClass('ke-tabs-li-selected'); + K(li.data('tab').panel).show(''); + } else { + li.removeClass('ke-tabs-li-selected').removeClass('ke-tabs-li-on') + .mouseover(function() { + K(this).addClass('ke-tabs-li-on'); + }) + .mouseout(function() { + K(this).removeClass('ke-tabs-li-on'); + }) + .click(function() { + self.select(i); + }); + K(li.data('tab').panel).hide(); + } + }); + if (afterSelect) { + afterSelect.call(self, index); + } + }; + self.remove = function() { + _each(liList, function() { + this.remove(); + }); + ul.remove(); + remove.call(self); + }; + return self; +} +K.tabs = _tabs; +function _loadScript(url, fn) { + var head = document.getElementsByTagName('head')[0] || (_QUIRKS ? document.body : document.documentElement), + script = document.createElement('script'); + head.appendChild(script); + script.src = url; + script.charset = 'utf-8'; + script.onload = script.onreadystatechange = function() { + if (!this.readyState || this.readyState === 'loaded') { + if (fn) { + fn(); + } + script.onload = script.onreadystatechange = null; + head.removeChild(script); + } + }; +} +function _chopQuery(url) { + var index = url.indexOf('?'); + return index > 0 ? url.substr(0, index) : url; +} +function _loadStyle(url) { + var head = document.getElementsByTagName('head')[0] || (_QUIRKS ? document.body : document.documentElement), + link = document.createElement('link'), + absoluteUrl = _chopQuery(_formatUrl(url, 'absolute')); + var links = K('link[rel="stylesheet"]', head); + for (var i = 0, len = links.length; i < len; i++) { + if (_chopQuery(_formatUrl(links[i].href, 'absolute')) === absoluteUrl) { + return; + } + } + head.appendChild(link); + link.href = url; + link.rel = 'stylesheet'; +} +function _ajax(url, fn, method, param, dataType) { + method = method || 'GET'; + dataType = dataType || 'json'; + var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); + xhr.open(method, url, true); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4 && xhr.status == 200) { + if (fn) { + var data = _trim(xhr.responseText); + if (dataType == 'json') { + data = _json(data); + } + fn(data); + } + } + }; + if (method == 'POST') { + var params = []; + _each(param, function(key, val) { + params.push(encodeURIComponent(key) + '=' + encodeURIComponent(val)); + }); + try { + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + } catch (e) {} + xhr.send(params.join('&')); + } else { + xhr.send(null); + } +} +K.loadScript = _loadScript; +K.loadStyle = _loadStyle; +K.ajax = _ajax; +var _plugins = {}; +function _plugin(name, fn) { + if (name === undefined) { + return _plugins; + } + if (!fn) { + return _plugins[name]; + } + _plugins[name] = fn; +} +var _language = {}; +function _parseLangKey(key) { + var match, ns = 'core'; + if ((match = /^(\w+)\.(\w+)$/.exec(key))) { + ns = match[1]; + key = match[2]; + } + return { ns : ns, key : key }; +} +function _lang(mixed, langType) { + langType = langType === undefined ? K.options.langType : langType; + if (typeof mixed === 'string') { + if (!_language[langType]) { + return 'no language'; + } + var pos = mixed.length - 1; + if (mixed.substr(pos) === '.') { + return _language[langType][mixed.substr(0, pos)]; + } + var obj = _parseLangKey(mixed); + return _language[langType][obj.ns][obj.key]; + } + _each(mixed, function(key, val) { + var obj = _parseLangKey(key); + if (!_language[langType]) { + _language[langType] = {}; + } + if (!_language[langType][obj.ns]) { + _language[langType][obj.ns] = {}; + } + _language[langType][obj.ns][obj.key] = val; + }); +} +function _getImageFromRange(range, fn) { + if (range.collapsed) { + return; + } + range = range.cloneRange().up(); + var sc = range.startContainer, so = range.startOffset; + if (!_WEBKIT && !range.isControl()) { + return; + } + var img = K(sc.childNodes[so]); + if (!img || img.name != 'img') { + return; + } + if (fn(img)) { + return img; + } +} +function _bindContextmenuEvent() { + var self = this, doc = self.edit.doc; + K(doc).contextmenu(function(e) { + if (self.menu) { + self.hideMenu(); + } + if (!self.useContextmenu) { + e.preventDefault(); + return; + } + if (self._contextmenus.length === 0) { + return; + } + var maxWidth = 0, items = []; + _each(self._contextmenus, function() { + if (this.title == '-') { + items.push(this); + return; + } + if (this.cond && this.cond()) { + items.push(this); + if (this.width && this.width > maxWidth) { + maxWidth = this.width; + } + } + }); + while (items.length > 0 && items[0].title == '-') { + items.shift(); + } + while (items.length > 0 && items[items.length - 1].title == '-') { + items.pop(); + } + var prevItem = null; + _each(items, function(i) { + if (this.title == '-' && prevItem.title == '-') { + delete items[i]; + } + prevItem = this; + }); + if (items.length > 0) { + e.preventDefault(); + var pos = K(self.edit.iframe).pos(), + menu = _menu({ + x : pos.x + e.clientX, + y : pos.y + e.clientY, + width : maxWidth, + css : { visibility: 'hidden' }, + shadowMode : self.shadowMode + }); + _each(items, function() { + if (this.title) { + menu.addItem(this); + } + }); + var docEl = _docElement(menu.doc), + menuHeight = menu.div.height(); + if (e.clientY + menuHeight >= docEl.clientHeight - 100) { + menu.pos(menu.x, _removeUnit(menu.y) - menuHeight); + } + menu.div.css('visibility', 'visible'); + self.menu = menu; + } + }); +} +function _bindNewlineEvent() { + var self = this, doc = self.edit.doc, newlineTag = self.newlineTag; + if (_IE && newlineTag !== 'br') { + return; + } + if (_GECKO && _V < 3 && newlineTag !== 'p') { + return; + } + if (_OPERA && _V < 9) { + return; + } + var brSkipTagMap = _toMap('h1,h2,h3,h4,h5,h6,pre,li'), + pSkipTagMap = _toMap('p,h1,h2,h3,h4,h5,h6,pre,li,blockquote'); + function getAncestorTagName(range) { + var ancestor = K(range.commonAncestor()); + while (ancestor) { + if (ancestor.type == 1 && !ancestor.isStyle()) { + break; + } + ancestor = ancestor.parent(); + } + return ancestor.name; + } + K(doc).keydown(function(e) { + if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) { + return; + } + self.cmd.selection(); + var tagName = getAncestorTagName(self.cmd.range); + if (tagName == 'marquee' || tagName == 'select') { + return; + } + if (newlineTag === 'br' && !brSkipTagMap[tagName]) { + e.preventDefault(); + self.insertHtml('
      ' + (_IE && _V < 9 ? '' : '\u200B')); + return; + } + if (!pSkipTagMap[tagName]) { + _nativeCommand(doc, 'formatblock', '

      '); + } + }); + K(doc).keyup(function(e) { + if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) { + return; + } + if (newlineTag == 'br') { + return; + } + if (_GECKO) { + var root = self.cmd.commonAncestor('p'); + var a = self.cmd.commonAncestor('a'); + if (a && a.text() == '') { + a.remove(true); + self.cmd.range.selectNodeContents(root[0]).collapse(true); + self.cmd.select(); + } + return; + } + self.cmd.selection(); + var tagName = getAncestorTagName(self.cmd.range); + if (tagName == 'marquee' || tagName == 'select') { + return; + } + if (!pSkipTagMap[tagName]) { + _nativeCommand(doc, 'formatblock', '

      '); + } + var div = self.cmd.commonAncestor('div'); + if (div) { + var p = K('

      '), + child = div[0].firstChild; + while (child) { + var next = child.nextSibling; + p.append(child); + child = next; + } + div.before(p); + div.remove(); + self.cmd.range.selectNodeContents(p[0]); + self.cmd.select(); + } + }); +} +function _bindTabEvent() { + var self = this, doc = self.edit.doc; + K(doc).keydown(function(e) { + if (e.which == 9) { + e.preventDefault(); + if (self.afterTab) { + self.afterTab.call(self, e); + return; + } + var cmd = self.cmd, range = cmd.range; + range.shrink(); + if (range.collapsed && range.startContainer.nodeType == 1) { + range.insertNode(K('@ ', doc)[0]); + cmd.select(); + } + self.insertHtml('    '); + } + }); +} +function _bindFocusEvent() { + var self = this; + K(self.edit.textarea[0], self.edit.win).focus(function(e) { + if(/^\s*<\w*\s*\w*\=\"\w*\"\s*\w*\=\"\w*\:\s*\#\d*\;\s*\w*\-\w*\:\s*\w*\;\"\>[\u4e00-\u9fa5]*[\,]*[\u4e00-\u9fa5]*[\。]*<\/\w*\>\s*$/.test(self.edit.html())){ + self.edit.html(''); + } + if(typeof self.options.enable_at === 'function'){ + self.options.enable_at(); + } + if (self.afterFocus) { + self.afterFocus.call(self, e); + } + }).blur(function(e) { + if(self.isEmpty()) { + if (self.placeholder != "") { + self.edit.html("" + self.placeholder + ""); + } + // self.edit.html(self.placeholder); + // self.edit.html("" + self.placeholder + ""); + } + if (self.afterBlur) { + self.afterBlur.call(self, e); + } + }); +} +function _removeBookmarkTag(html) { + return _trim(html.replace(/]*id="?__kindeditor_bookmark_\w+_\d+__"?[^>]*><\/span>/ig, '')); +} +function _removeTempTag(html) { + return html.replace(/]+class="?__kindeditor_paste__"?[^>]*>[\s\S]*?<\/div>/ig, ''); +} +function _addBookmarkToStack(stack, bookmark) { + if (stack.length === 0) { + stack.push(bookmark); + return; + } + var prev = stack[stack.length - 1]; + if (_removeBookmarkTag(bookmark.html) !== _removeBookmarkTag(prev.html)) { + stack.push(bookmark); + } +} +function _undoToRedo(fromStack, toStack) { + var self = this, edit = self.edit, + body = edit.doc.body, + range, bookmark; + if (fromStack.length === 0) { + return self; + } + if (edit.designMode) { + range = self.cmd.range; + bookmark = range.createBookmark(true); + bookmark.html = body.innerHTML; + } else { + bookmark = { + html : body.innerHTML + }; + } + _addBookmarkToStack(toStack, bookmark); + var prev = fromStack.pop(); + if (_removeBookmarkTag(bookmark.html) === _removeBookmarkTag(prev.html) && fromStack.length > 0) { + prev = fromStack.pop(); + } + if (edit.designMode) { + edit.html(prev.html); + if (prev.start) { + range.moveToBookmark(prev); + self.select(); + } + } else { + K(body).html(_removeBookmarkTag(prev.html)); + } + return self; +} +function KEditor(options) { + var self = this; + self.options = {}; + function setOption(key, val) { + if (KEditor.prototype[key] === undefined) { + self[key] = val; + } + self.options[key] = val; + } + _each(options, function(key, val) { + setOption(key, options[key]); + }); + _each(K.options, function(key, val) { + if (self[key] === undefined) { + setOption(key, val); + } + }); + var se = K(self.srcElement || ' + +``` + +> Tip: Editor.md can auto append `"); + markdownTextarea = this.markdownTextarea = editor.children("textarea"); + } + + markdownTextarea.addClass(classNames.textarea.markdown).attr("placeholder", settings.placeholder); + + if (typeof markdownTextarea.attr("name") === "undefined" || markdownTextarea.attr("name") === "") + { + markdownTextarea.attr("name", (settings.name !== "") ? settings.name : id + "-markdown-doc"); + } + + var appendElements = [ + (!settings.readOnly) ? "" : "", + ( (settings.saveHTMLToTextarea) ? "" : "" ), + "
      ", + "
      ", + "
      " + ].join("\n"); + + editor.append(appendElements).addClass(classPrefix + "vertical"); + + if (settings.theme !== "") + { + editor.addClass(classPrefix + "theme-" + settings.theme); + } + + this.mask = editor.children("." + classPrefix + "mask"); + this.containerMask = editor.children("." + classPrefix + "container-mask"); + + if (settings.markdown !== "") + { + markdownTextarea.val(settings.markdown); + } + + if (settings.appendMarkdown !== "") + { + markdownTextarea.val(markdownTextarea.val() + settings.appendMarkdown); + } + + this.htmlTextarea = editor.children("." + classNames.textarea.html); + this.preview = editor.children("." + classPrefix + "preview"); + this.previewContainer = this.preview.children("." + classPrefix + "preview-container"); + + if (settings.previewTheme !== "") + { + this.preview.addClass(classPrefix + "preview-theme-" + settings.previewTheme); + } + + if (typeof define === "function" && define.amd) + { + if (typeof katex !== "undefined") + { + editormd.$katex = katex; + } + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(settings.path + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(settings.path + "codemirror/addon/search/matchesonscrollbar"); + } + } + + if ((typeof define === "function" && define.amd) || !settings.autoLoadModules) + { + if (typeof CodeMirror !== "undefined") { + editormd.$CodeMirror = CodeMirror; + } + + if (typeof marked !== "undefined") { + editormd.$marked = marked; + } + + this.setCodeMirror().setToolbar().loadedDisplay(); + } + else + { + this.loadQueues(); + } + + return this; + }, + + /** + * 所需组件加载队列 + * Required components loading queue + * + * @returns {editormd} 返回editormd的实例对象 + */ + + loadQueues : function() { + var _this = this; + var settings = this.settings; + var loadPath = settings.path; + + var loadFlowChartOrSequenceDiagram = function() { + + if (editormd.isIE8) + { + _this.loadedDisplay(); + + return ; + } + + if (settings.flowChart || settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "raphael.min", function() { + + editormd.loadScript(loadPath + "underscore.min", function() { + + if (!settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + } + else if (settings.flowChart && !settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + _this.loadedDisplay(); + }); + }); + } + else if (settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + }); + }); + } + }); + + }); + } + else + { + _this.loadedDisplay(); + } + }; + + editormd.loadCSS(loadPath + "codemirror/codemirror.min"); + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(loadPath + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(loadPath + "codemirror/addon/search/matchesonscrollbar"); + } + + if (settings.codeFold) + { + editormd.loadCSS(loadPath + "codemirror/addon/fold/foldgutter"); + } + + editormd.loadScript(loadPath + "codemirror/codemirror.min", function() { + editormd.$CodeMirror = CodeMirror; + + editormd.loadScript(loadPath + "codemirror/modes.min", function() { + + editormd.loadScript(loadPath + "codemirror/addons.min", function() { + + _this.setCodeMirror(); + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + _this.loadedDisplay(); + + return false; + } + + _this.setToolbar(); + + editormd.loadScript(loadPath + "marked.min", function() { + + editormd.$marked = marked; + + if (settings.previewCodeHighlight) + { + editormd.loadScript(loadPath + "prettify.min", function() { + loadFlowChartOrSequenceDiagram(); + }); + } + else + { + loadFlowChartOrSequenceDiagram(); + } + }); + + }); + + }); + + }); + + return this; + }, + + /** + * 设置 Editor.md 的整体主题,主要是工具栏 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setTheme : function(theme) { + var editor = this.editor; + var oldTheme = this.settings.theme; + var themePrefix = this.classPrefix + "theme-"; + + editor.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + this.settings.theme = theme; + + return this; + }, + + /** + * 设置 CodeMirror(编辑区)的主题 + * Setting CodeMirror (Editor area) theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setEditorTheme : function(theme) { + var settings = this.settings; + settings.editorTheme = theme; + + if (theme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + this.cm.setOption("theme", theme); + + return this; + }, + + /** + * setEditorTheme() 的别名 + * setEditorTheme() alias + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorTheme : function (theme) { + this.setEditorTheme(theme); + + return this; + }, + + /** + * 设置 Editor.md 的主题 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setPreviewTheme : function(theme) { + var preview = this.preview; + var oldTheme = this.settings.previewTheme; + var themePrefix = this.classPrefix + "preview-theme-"; + + preview.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + this.settings.previewTheme = theme; + + return this; + }, + + /** + * 配置和初始化CodeMirror组件 + * CodeMirror initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirror : function() { + var settings = this.settings; + var editor = this.editor; + + if (settings.editorTheme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + var codeMirrorConfig = { + mode : settings.mode, + theme : settings.editorTheme, + tabSize : settings.tabSize, + dragDrop : false, + autofocus : settings.autoFocus, + autoCloseTags : settings.autoCloseTags, + readOnly : (settings.readOnly) ? "nocursor" : false, + indentUnit : settings.indentUnit, + lineNumbers : settings.lineNumbers, + lineWrapping : settings.lineWrapping, + extraKeys : { + "Ctrl-Q": function(cm) { + cm.foldCode(cm.getCursor()); + } + }, + foldGutter : settings.codeFold, + gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + matchBrackets : settings.matchBrackets, + indentWithTabs : settings.indentWithTabs, + styleActiveLine : settings.styleActiveLine, + styleSelectedText : settings.styleSelectedText, + autoCloseBrackets : settings.autoCloseBrackets, + showTrailingSpace : settings.showTrailingSpace, + highlightSelectionMatches : ( (!settings.matchWordHighlight) ? false : { showToken: (settings.matchWordHighlight === "onselected") ? false : /\w/ } ) + }; + + this.codeEditor = this.cm = editormd.$CodeMirror.fromTextArea(this.markdownTextarea[0], codeMirrorConfig); + this.codeMirror = this.cmElement = editor.children(".CodeMirror"); + + if (settings.value !== "") + { + this.cm.setValue(settings.value); + } + + this.codeMirror.css({ + fontSize : settings.fontSize, + width : (!settings.watch) ? "100%" : "50%" + }); + + if (settings.autoHeight) + { + this.codeMirror.css("height", "auto"); + this.cm.setOption("viewportMargin", Infinity); + } + + if (!settings.lineNumbers) + { + this.codeMirror.find(".CodeMirror-gutters").css("border-right", "none"); + } + + return this; + }, + + /** + * 获取CodeMirror的配置选项 + * Get CodeMirror setting options + * + * @returns {Mixed} return CodeMirror setting option value + */ + + getCodeMirrorOption : function(key) { + return this.cm.getOption(key); + }, + + /** + * 配置和重配置CodeMirror的选项 + * CodeMirror setting options / resettings + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorOption : function(key, value) { + + this.cm.setOption(key, value); + + return this; + }, + + /** + * 添加 CodeMirror 键盘快捷键 + * Add CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + addKeyMap : function(map, bottom) { + this.cm.addKeyMap(map, bottom); + + return this; + }, + + /** + * 移除 CodeMirror 键盘快捷键 + * Remove CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + removeKeyMap : function(map) { + this.cm.removeKeyMap(map); + + return this; + }, + + /** + * 跳转到指定的行 + * Goto CodeMirror line + * + * @param {String|Intiger} line line number or "first"|"last" + * @returns {editormd} 返回editormd的实例对象 + */ + + gotoLine : function (line) { + + var settings = this.settings; + + if (!settings.gotoLine) + { + return this; + } + + var cm = this.cm; + var editor = this.editor; + var count = cm.lineCount(); + var preview = this.preview; + + if (typeof line === "string") + { + if(line === "last") + { + line = count; + } + + if (line === "first") + { + line = 1; + } + } + + if (typeof line !== "number") + { + alert("Error: The line number must be an integer."); + return this; + } + + line = parseInt(line) - 1; + + if (line > count) + { + alert("Error: The line number range 1-" + count); + + return this; + } + + cm.setCursor( {line : line, ch : 0} ); + + var scrollInfo = cm.getScrollInfo(); + var clientHeight = scrollInfo.clientHeight; + var coords = cm.charCoords({line : line, ch : 0}, "local"); + + cm.scrollTo(null, (coords.top + coords.bottom - clientHeight) / 2); + + if (settings.watch) + { + var cmScroll = this.codeMirror.find(".CodeMirror-scroll")[0]; + var height = $(cmScroll).height(); + var scrollTop = cmScroll.scrollTop; + var percent = (scrollTop / cmScroll.scrollHeight); + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= cmScroll.scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop(preview[0].scrollHeight * percent); + } + } + + cm.focus(); + + return this; + }, + + /** + * 扩展当前实例对象,可同时设置多个或者只设置一个 + * Extend editormd instance object, can mutil setting. + * + * @returns {editormd} this(editormd instance object.) + */ + + extend : function() { + if (typeof arguments[1] !== "undefined") + { + if (typeof arguments[1] === "function") + { + arguments[1] = $.proxy(arguments[1], this); + } + + this[arguments[0]] = arguments[1]; + } + + if (typeof arguments[0] === "object" && typeof arguments[0].length === "undefined") + { + $.extend(true, this, arguments[0]); + } + + return this; + }, + + /** + * 设置或扩展当前实例对象,单个设置 + * Extend editormd instance object, one by one + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + set : function (key, value) { + + if (typeof value !== "undefined" && typeof value === "function") + { + value = $.proxy(value, this); + } + + this[key] = value; + + return this; + }, + + /** + * 重新配置 + * Resetting editor options + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + config : function(key, value) { + var settings = this.settings; + + if (typeof key === "object") + { + settings = $.extend(true, settings, key); + } + + if (typeof key === "string") + { + settings[key] = value; + } + + this.settings = settings; + this.recreate(); + + return this; + }, + + /** + * 注册事件处理方法 + * Bind editor event handle + * + * @param {String} eventType event type + * @param {Function} callback 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + on : function(eventType, callback) { + var settings = this.settings; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = $.proxy(callback, this); + } + + return this; + }, + + /** + * 解除事件处理方法 + * Unbind editor event handle + * + * @param {String} eventType event type + * @returns {editormd} this(editormd instance object.) + */ + + off : function(eventType) { + var settings = this.settings; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = function(){}; + } + + return this; + }, + + /** + * 显示工具栏 + * Display toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + showToolbar : function(callback) { + var settings = this.settings; + + if(settings.readOnly) { + return this; + } + + if (settings.toolbar && (this.toolbar.length < 1 || this.toolbar.find("." + this.classPrefix + "menu").html() === "") ) + { + this.setToolbar(); + } + + settings.toolbar = true; + + this.toolbar.show(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 隐藏工具栏 + * Hide toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + hideToolbar : function(callback) { + var settings = this.settings; + + settings.toolbar = false; + this.toolbar.hide(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 页面滚动时工具栏的固定定位 + * Set toolbar in window scroll auto fixed position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarAutoFixed : function(fixed) { + + var state = this.state; + var editor = this.editor; + var toolbar = this.toolbar; + var settings = this.settings; + + if (typeof fixed !== "undefined") + { + settings.toolbarAutoFixed = fixed; + } + + var autoFixedHandle = function(){ + var $window = $(window); + var top = $window.scrollTop(); + + if (!settings.toolbarAutoFixed) + { + return false; + } + + if (top - editor.offset().top > 10 && top < editor.height()) + { + toolbar.css({ + position : "fixed", + width : editor.width() + "px", + left : ($window.width() - editor.width()) / 2 + "px" + }); + } + else + { + toolbar.css({ + position : "absolute", + width : "100%", + left : 0 + }); + } + }; + + if (!state.fullscreen && !state.preview && settings.toolbar && settings.toolbarAutoFixed) + { + $(window).bind("scroll", autoFixedHandle); + } + + return this; + }, + + /** + * 配置和初始化工具栏 + * Set toolbar and Initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbar : function() { + var settings = this.settings; + + if(settings.readOnly) { + return this; + } + + var editor = this.editor; + var preview = this.preview; + var classPrefix = this.classPrefix; + + var toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + + if (settings.toolbar && toolbar.length < 1) + { + var toolbarHTML = "
        "; + + editor.append(toolbarHTML); + toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + } + + if (!settings.toolbar) + { + toolbar.hide(); + + return this; + } + + toolbar.show(); + + var icons = (typeof settings.toolbarIcons === "function") ? settings.toolbarIcons() + : ((typeof settings.toolbarIcons === "string") ? editormd.toolbarModes[settings.toolbarIcons] : settings.toolbarIcons); + + var toolbarMenu = toolbar.find("." + this.classPrefix + "menu"), menu = ""; + var pullRight = false; + + for (var i = 0, len = icons.length; i < len; i++) + { + var name = icons[i]; + + if (name === "||") + { + pullRight = true; + } + else if (name === "|") + { + menu += "
      • |
      • "; + } + else + { + var isHeader = (/h(\d)/.test(name)); + var index = name; + + if (name === "watch" && !settings.watch) { + index = "unwatch"; + } + + var title = settings.lang.toolbar[index]; + var iconTexts = settings.toolbarIconTexts[index]; + var iconClass = settings.toolbarIconsClass[index]; + + title = (typeof title === "undefined") ? "" : title; + iconTexts = (typeof iconTexts === "undefined") ? "" : iconTexts; + iconClass = (typeof iconClass === "undefined") ? "" : iconClass; + + var menuItem = pullRight ? "
      • " : "
      • "; + + if (typeof settings.toolbarCustomIcons[name] !== "undefined" && typeof settings.toolbarCustomIcons[name] !== "function") + { + menuItem += settings.toolbarCustomIcons[name]; + } + else + { + menuItem += ""; + menuItem += ""+((isHeader) ? name.toUpperCase() : ( (iconClass === "") ? iconTexts : "") ) + ""; + menuItem += ""; + } + + menuItem += "
      • "; + + menu = pullRight ? menuItem + menu : menu + menuItem; + } + } + + toolbarMenu.html(menu); + + toolbarMenu.find("[title=\"Lowercase\"]").attr("title", settings.lang.toolbar.lowercase); + toolbarMenu.find("[title=\"ucwords\"]").attr("title", settings.lang.toolbar.ucwords); + + this.setToolbarHandler(); + this.setToolbarAutoFixed(); + + return this; + }, + + /** + * 工具栏图标事件处理对象序列 + * Get toolbar icons event handlers + * + * @param {Object} cm CodeMirror的实例对象 + * @param {String} name 要获取的事件处理器名称 + * @returns {Object} 返回处理对象序列 + */ + + dialogLockScreen : function() { + $.proxy(editormd.dialogLockScreen, this)(); + + return this; + }, + + dialogShowMask : function(dialog) { + $.proxy(editormd.dialogShowMask, this)(dialog); + + return this; + }, + + getToolbarHandles : function(name) { + var toolbarHandlers = this.toolbarHandlers = editormd.toolbarHandlers; + + return (name && typeof toolbarIconHandlers[name] !== "undefined") ? toolbarHandlers[name] : toolbarHandlers; + }, + + /** + * 工具栏图标事件处理器 + * Bind toolbar icons event handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarHandler : function() { + var _this = this; + var settings = this.settings; + + if (!settings.toolbar || settings.readOnly) { + return this; + } + + var toolbar = this.toolbar; + var cm = this.cm; + var classPrefix = this.classPrefix; + var toolbarIcons = this.toolbarIcons = toolbar.find("." + classPrefix + "menu > li > a"); + var toolbarIconHandlers = this.getToolbarHandles(); + + toolbarIcons.bind(editormd.mouseOrTouch("click", "touchend"), function(event) { + + var icon = $(this).children(".fa"); + var name = icon.attr("name"); + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (name === "") { + return ; + } + + _this.activeIcon = icon; + + if (typeof toolbarIconHandlers[name] !== "undefined") + { + $.proxy(toolbarIconHandlers[name], _this)(cm); + } + else + { + if (typeof settings.toolbarHandlers[name] !== "undefined") + { + $.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection); + } + } + + if (name !== "link" && name !== "reference-link" && name !== "image" && name !== "code-block" && + name !== "preformatted-text" && name !== "watch" && name !== "preview" && name !== "search" && name !== "fullscreen" && name !== "info") + { + cm.focus(); + } + + return false; + + }); + + return this; + }, + + /** + * 动态创建对话框 + * Creating custom dialogs + * + * @param {Object} options 配置项键值对 Key/Value + * @returns {dialog} 返回创建的dialog的jQuery实例对象 + */ + + createDialog : function(options) { + return $.proxy(editormd.createDialog, this)(options); + }, + + /** + * 创建关于Editor.md的对话框 + * Create about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + createInfoDialog : function() { + var _this = this; + var editor = this.editor; + var classPrefix = this.classPrefix; + + var infoDialogHTML = [ + "
        ", + "
        ", + "

        " + editormd.title + "v" + editormd.version + "

        ", + "

        " + this.lang.description + "

        ", + "

        " + editormd.homePage + "

        ", + "

        Copyright © 2015 Pandao, The MIT License.

        ", + "
        ", + "", + "
        " + ].join("\n"); + + editor.append(infoDialogHTML); + + var infoDialog = this.infoDialog = editor.children("." + classPrefix + "dialog-info"); + + infoDialog.find("." + classPrefix + "dialog-close").bind(editormd.mouseOrTouch("click", "touchend"), function() { + _this.hideInfoDialog(); + }); + + infoDialog.css("border", (editormd.isIE8) ? "1px solid #ddd" : "").css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 关于Editor.md对话居中定位 + * Editor.md dialog position handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + infoDialogPosition : function() { + var infoDialog = this.infoDialog; + + var _infoDialogPosition = function() { + infoDialog.css({ + top : ($(window).height() - infoDialog.height()) / 2 + "px", + left : ($(window).width() - infoDialog.width()) / 2 + "px" + }); + }; + + _infoDialogPosition(); + + $(window).resize(_infoDialogPosition); + + return this; + }, + + /** + * 显示关于Editor.md + * Display about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + showInfoDialog : function() { + + $("html,body").css("overflow-x", "hidden"); + + var _this = this; + var editor = this.editor; + var settings = this.settings; + var infoDialog = this.infoDialog = editor.children("." + this.classPrefix + "dialog-info"); + + if (infoDialog.length < 1) + { + this.createInfoDialog(); + } + + this.lockScreen(true); + + this.mask.css({ + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }).show(); + + infoDialog.css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 隐藏关于Editor.md + * Hide about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + hideInfoDialog : function() { + $("html,body").css("overflow-x", ""); + this.infoDialog.hide(); + this.mask.hide(); + this.lockScreen(false); + + return this; + }, + + /** + * 锁屏 + * lock screen + * + * @param {Boolean} lock Boolean 布尔值,是否锁屏 + * @returns {editormd} 返回editormd的实例对象 + */ + + lockScreen : function(lock) { + editormd.lockScreen(lock); + this.resize(); + + return this; + }, + + /** + * 编辑器界面重建,用于动态语言包或模块加载等 + * Recreate editor + * + * @returns {editormd} 返回editormd的实例对象 + */ + + recreate : function() { + var _this = this; + var editor = this.editor; + var settings = this.settings; + + this.codeMirror.remove(); + + this.setCodeMirror(); + + if (!settings.readOnly) + { + if (editor.find(".editormd-dialog").length > 0) { + editor.find(".editormd-dialog").remove(); + } + + if (settings.toolbar) + { + this.getToolbarHandles(); + this.setToolbar(); + } + } + + this.loadedDisplay(true); + + return this; + }, + + /** + * 高亮预览HTML的pre代码部分 + * highlight of preview codes + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewCodeHighlight : function() { + var settings = this.settings; + var previewContainer = this.previewContainer; + + if (settings.previewCodeHighlight) + { + previewContainer.find("pre").addClass("prettyprint linenums"); + + if (typeof prettyPrint !== "undefined") + { + prettyPrint(); + } + } + + return this; + }, + + /** + * 解析TeX(KaTeX)科学公式 + * TeX(KaTeX) Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + katexRender : function() { + + if (timer === null) + { + return this; + } + + this.previewContainer.find("." + editormd.classNames.tex).each(function(){ + var tex = $(this); + editormd.$katex.render(tex.text(), tex[0]); + + tex.find(".katex").css("font-size", "1.6em"); + }); + + return this; + }, + + /** + * 解析和渲染流程图及时序图 + * FlowChart and SequenceDiagram Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + flowChartAndSequenceDiagramRender : function() { + var $this = this; + var settings = this.settings; + var previewContainer = this.previewContainer; + + if (editormd.isIE8) { + return this; + } + + if (settings.flowChart) { + if (flowchartTimer === null) { + return this; + } + + previewContainer.find(".flowchart").flowChart(); + } + + if (settings.sequenceDiagram) { + previewContainer.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); + } + + var preview = $this.preview; + var codeMirror = $this.codeMirror; + var codeView = codeMirror.find(".CodeMirror-scroll"); + + var height = codeView.height(); + var scrollTop = codeView.scrollTop(); + var percent = (scrollTop / codeView[0].scrollHeight); + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= codeView[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + return this; + }, + + /** + * 注册键盘快捷键处理 + * Register CodeMirror keyMaps (keyboard shortcuts). + * + * @param {Object} keyMap KeyMap key/value {"(Ctrl/Shift/Alt)-Key" : function(){}} + * @returns {editormd} return this + */ + + registerKeyMaps : function(keyMap) { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + var toolbarHandlers = editormd.toolbarHandlers; + var disabledKeyMaps = settings.disabledKeyMaps; + + keyMap = keyMap || null; + + if (keyMap) + { + for (var i in keyMap) + { + if ($.inArray(i, disabledKeyMaps) < 0) + { + var map = {}; + map[i] = keyMap[i]; + + cm.addKeyMap(keyMap); + } + } + } + else + { + for (var k in editormd.keyMaps) + { + var _keyMap = editormd.keyMaps[k]; + var handle = (typeof _keyMap === "string") ? $.proxy(toolbarHandlers[_keyMap], _this) : $.proxy(_keyMap, _this); + + if ($.inArray(k, ["F9", "F10", "F11"]) < 0 && $.inArray(k, disabledKeyMaps) < 0) + { + var _map = {}; + _map[k] = handle; + + cm.addKeyMap(_map); + } + } + + $(window).keydown(function(event) { + + var keymaps = { + "120" : "F9", + "121" : "F10", + "122" : "F11" + }; + + if ( $.inArray(keymaps[event.keyCode], disabledKeyMaps) < 0 ) + { + switch (event.keyCode) + { + case 120: + $.proxy(toolbarHandlers["watch"], _this)(); + return false; + break; + + case 121: + $.proxy(toolbarHandlers["preview"], _this)(); + return false; + break; + + case 122: + $.proxy(toolbarHandlers["fullscreen"], _this)(); + return false; + break; + + default: + break; + } + } + }); + } + + return this; + }, + + /** + * 绑定同步滚动 + * + * @returns {editormd} return this + */ + + bindScrollEvent : function() { + + var _this = this; + var preview = this.preview; + var settings = this.settings; + var codeMirror = this.codeMirror; + var mouseOrTouch = editormd.mouseOrTouch; + + if (!settings.syncScrolling) { + return this; + } + + var cmBindScroll = function() { + codeMirror.find(".CodeMirror-scroll").bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + $.proxy(settings.onscroll, _this)(event); + }); + }; + + var cmUnbindScroll = function() { + codeMirror.find(".CodeMirror-scroll").unbind(mouseOrTouch("scroll", "touchmove")); + }; + + var previewBindScroll = function() { + + preview.bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + var codeView = codeMirror.find(".CodeMirror-scroll"); + + if(scrollTop === 0) + { + codeView.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight) + { + codeView.scrollTop(codeView[0].scrollHeight); + } + else + { + codeView.scrollTop(codeView[0].scrollHeight * percent); + } + + $.proxy(settings.onpreviewscroll, _this)(event); + }); + + }; + + var previewUnbindScroll = function() { + preview.unbind(mouseOrTouch("scroll", "touchmove")); + }; + + codeMirror.bind({ + mouseover : cmBindScroll, + mouseout : cmUnbindScroll, + touchstart : cmBindScroll, + touchend : cmUnbindScroll + }); + + if (settings.syncScrolling === "single") { + return this; + } + + preview.bind({ + mouseover : previewBindScroll, + mouseout : previewUnbindScroll, + touchstart : previewBindScroll, + touchend : previewUnbindScroll + }); + + return this; + }, + + bindChangeEvent : function() { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + + if (!settings.syncScrolling) { + return this; + } + + cm.on("change", function(_cm, changeObj) { + + if (settings.watch) + { + _this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + } + + timer = setTimeout(function() { + clearTimeout(timer); + _this.save(); + timer = null; + }, settings.delay); + }); + + return this; + }, + + /** + * 加载队列完成之后的显示处理 + * Display handle of the module queues loaded after. + * + * @param {Boolean} recreate 是否为重建编辑器 + * @returns {editormd} 返回editormd的实例对象 + */ + + loadedDisplay : function(recreate) { + + recreate = recreate || false; + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var settings = this.settings; + + this.containerMask.hide(); + + this.save(); + + if (settings.watch) { + preview.show(); + } + + editor.data("oldWidth", editor.width()).data("oldHeight", editor.height()); // 为了兼容Zepto + + this.resize(); + this.registerKeyMaps(); + + $(window).resize(function(){ + _this.resize(); + }); + + this.bindScrollEvent().bindChangeEvent(); + + if (!recreate) + { + $.proxy(settings.onload, this)(); + } + + this.state.loaded = true; + + return this; + }, + + /** + * 设置编辑器的宽度 + * Set editor width + * + * @param {Number|String} width 编辑器宽度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + width : function(width) { + + this.editor.css("width", (typeof width === "number") ? width + "px" : width); + this.resize(); + + return this; + }, + + /** + * 设置编辑器的高度 + * Set editor height + * + * @param {Number|String} height 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + height : function(height) { + + this.editor.css("height", (typeof height === "number") ? height + "px" : height); + this.resize(); + + return this; + }, + + /** + * 调整编辑器的尺寸和布局 + * Resize editor layout + * + * @param {Number|String} [width=null] 编辑器宽度值 + * @param {Number|String} [height=null] 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + resize : function(width, height) { + + width = width || null; + height = height || null; + + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var codeMirror = this.codeMirror; + + if (width) + { + editor.css("width", (typeof width === "number") ? width + "px" : width); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + editor.css("height", "auto"); + codeMirror.css("height", "auto"); + } + else + { + if (height) + { + editor.css("height", (typeof height === "number") ? height + "px" : height); + } + + if (state.fullscreen) + { + editor.height($(window).height()); + } + + if (settings.toolbar && !settings.readOnly) + { + codeMirror.css("margin-top", toolbar.height() + 1).height(editor.height() - toolbar.height()); + } + else + { + codeMirror.css("margin-top", 0).height(editor.height()); + } + } + + if(settings.watch) + { + codeMirror.width(editor.width() / 2); + preview.width((!state.preview) ? editor.width() / 2 : editor.width()); + + this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + + if (settings.toolbar && !settings.readOnly) + { + preview.css("top", toolbar.height() + 1); + } + else + { + preview.css("top", 0); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + preview.height(""); + } + else + { + var previewHeight = (settings.toolbar && !settings.readOnly) ? editor.height() - toolbar.height() : editor.height(); + + preview.height(previewHeight); + } + } + else + { + codeMirror.width(editor.width()); + preview.hide(); + } + + if (state.loaded) + { + $.proxy(settings.onresize, this)(); + } + + return this; + }, + + /** + * 解析和保存Markdown代码 + * Parse & Saving Markdown source code + * + * @returns {editormd} 返回editormd的实例对象 + */ + + save : function() { + + if (timer === null) + { + return this; + } + + var _this = this; + var state = this.state; + var settings = this.settings; + var cm = this.cm; + var cmValue = cm.getValue(); + var previewContainer = this.previewContainer; + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + this.markdownTextarea.val(cmValue); + + return this; + } + + var marked = editormd.$marked; + var markdownToC = this.markdownToC = []; + var rendererOptions = this.markedRendererOptions = { + toc : settings.toc, + tocm : settings.tocm, + tocStartLevel : settings.tocStartLevel, + pageBreak : settings.pageBreak, + taskList : settings.taskList, + emoji : settings.emoji, + tex : settings.tex, + atLink : settings.atLink, // for @link + emailLink : settings.emailLink, // for mail address auto link + flowChart : settings.flowChart, + sequenceDiagram : settings.sequenceDiagram, + previewCodeHighlight : settings.previewCodeHighlight, + }; + + var markedOptions = this.markedOptions = { + renderer : editormd.markedRenderer(markdownToC, rendererOptions), + gfm : true, + tables : true, + breaks : true, + pedantic : false, + sanitize : (settings.htmlDecode) ? false : true, // 关闭忽略HTML标签,即开启识别HTML标签,默认为false + smartLists : true, + smartypants : true + }; + + marked.setOptions(markedOptions); + + var newMarkdownDoc = editormd.$marked(cmValue, markedOptions); + + //console.info("cmValue", cmValue, newMarkdownDoc); + + newMarkdownDoc = editormd.filterHTMLTags(newMarkdownDoc, settings.htmlDecode); + + //console.error("cmValue", cmValue, newMarkdownDoc); + + this.markdownTextarea.text(cmValue); + + cm.save(); + + if (settings.saveHTMLToTextarea) + { + this.htmlTextarea.text(newMarkdownDoc); + } + + if(settings.watch || (!settings.watch && state.preview)) + { + previewContainer.html(newMarkdownDoc); + + this.previewCodeHighlight(); + + if (settings.toc) + { + var tocContainer = (settings.tocContainer === "") ? previewContainer : $(settings.tocContainer); + var tocMenu = tocContainer.find("." + this.classPrefix + "toc-menu"); + + tocContainer.attr("previewContainer", (settings.tocContainer === "") ? "true" : "false"); + + if (settings.tocContainer !== "" && tocMenu.length > 0) + { + tocMenu.remove(); + } + + editormd.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); + + if (settings.tocDropdown || tocContainer.find("." + this.classPrefix + "toc-menu").length > 0) + { + editormd.tocDropdownMenu(tocContainer, (settings.tocTitle !== "") ? settings.tocTitle : this.lang.tocTitle); + } + + if (settings.tocContainer !== "") + { + previewContainer.find(".markdown-toc").css("border", "none"); + } + } + + if (settings.tex) + { + if (!editormd.kaTeXLoaded && settings.autoLoadModules) + { + editormd.loadKaTeX(function() { + editormd.$katex = katex; + editormd.kaTeXLoaded = true; + _this.katexRender(); + }); + } + else + { + editormd.$katex = katex; + this.katexRender(); + } + } + + if (settings.flowChart || settings.sequenceDiagram) + { + flowchartTimer = setTimeout(function(){ + clearTimeout(flowchartTimer); + _this.flowChartAndSequenceDiagramRender(); + flowchartTimer = null; + }, 10); + } + + if (state.loaded) + { + $.proxy(settings.onchange, this)(); + } + } + + return this; + }, + + /** + * 聚焦光标位置 + * Focusing the cursor position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + focus : function() { + this.cm.focus(); + + return this; + }, + + /** + * 设置光标的位置 + * Set cursor position + * + * @param {Object} cursor 要设置的光标位置键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setCursor : function(cursor) { + this.cm.setCursor(cursor); + + return this; + }, + + /** + * 获取当前光标的位置 + * Get the current position of the cursor + * + * @returns {Cursor} 返回一个光标Cursor对象 + */ + + getCursor : function() { + return this.cm.getCursor(); + }, + + /** + * 设置光标选中的范围 + * Set cursor selected ranges + * + * @param {Object} from 开始位置的光标键值对象,例:{line:1, ch:0} + * @param {Object} to 结束位置的光标键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setSelection : function(from, to) { + + this.cm.setSelection(from, to); + + return this; + }, + + /** + * 获取光标选中的文本 + * Get the texts from cursor selected + * + * @returns {String} 返回选中文本的字符串形式 + */ + + getSelection : function() { + return this.cm.getSelection(); + }, + + /** + * 设置光标选中的文本范围 + * Set the cursor selection ranges + * + * @param {Array} ranges cursor selection ranges array + * @returns {Array} return this + */ + + setSelections : function(ranges) { + this.cm.setSelections(ranges); + + return this; + }, + + /** + * 获取光标选中的文本范围 + * Get the cursor selection ranges + * + * @returns {Array} return selection ranges array + */ + + getSelections : function() { + return this.cm.getSelections(); + }, + + /** + * 替换当前光标选中的文本或在当前光标处插入新字符 + * Replace the text at the current cursor selected or insert a new character at the current cursor position + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + replaceSelection : function(value) { + this.cm.replaceSelection(value); + + return this; + }, + + /** + * 在当前光标处插入新字符 + * Insert a new character at the current cursor position + * + * 同replaceSelection()方法 + * With the replaceSelection() method + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + insertValue : function(value) { + this.replaceSelection(value); + + return this; + }, + + /** + * 追加markdown + * append Markdown to editor + * + * @param {String} md 要追加的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + appendMarkdown : function(md) { + var settings = this.settings; + var cm = this.cm; + + cm.setValue(cm.getValue() + md); + + return this; + }, + + /** + * 设置和传入编辑器的markdown源文档 + * Set Markdown source document + * + * @param {String} md 要传入的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + setMarkdown : function(md) { + this.cm.setValue(md || this.settings.markdown); + + return this; + }, + + /** + * 获取编辑器的markdown源文档 + * Set Editor.md markdown/CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getMarkdown : function() { + return this.cm.getValue(); + }, + + /** + * 获取编辑器的源文档 + * Get CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getValue : function() { + return this.cm.getValue(); + }, + + /** + * 设置编辑器的源文档 + * Set CodeMirror value + * + * @param {String} value set code/value/string/text + * @returns {editormd} 返回editormd的实例对象 + */ + + setValue : function(value) { + this.cm.setValue(value); + + return this; + }, + + /** + * 清空编辑器 + * Empty CodeMirror editor container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + clear : function() { + this.cm.setValue(""); + + return this; + }, + + /** + * 获取解析后存放在Textarea的HTML源码 + * Get parsed html code from Textarea + * + * @returns {String} 返回HTML源码 + */ + + getHTML : function() { + if (!this.settings.saveHTMLToTextarea) + { + alert("Error: settings.saveHTMLToTextarea == false"); + + return false; + } + + return this.htmlTextarea.val(); + }, + + /** + * getHTML()的别名 + * getHTML (alias) + * + * @returns {String} Return html code 返回HTML源码 + */ + + getTextareaSavedHTML : function() { + return this.getHTML(); + }, + + /** + * 获取预览窗口的HTML源码 + * Get html from preview container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getPreviewedHTML : function() { + if (!this.settings.watch) + { + alert("Error: settings.watch == false"); + + return false; + } + + return this.previewContainer.html(); + }, + + /** + * 开启实时预览 + * Enable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + watch : function(callback) { + var settings = this.settings; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) + { + return this; + } + + this.state.watching = settings.watch = true; + this.preview.show(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.watch); + icon.removeClass(unWatchIcon).addClass(watchIcon); + } + + this.codeMirror.css("border-right", "1px solid #ddd").width(this.editor.width() / 2); + + timer = 0; + + this.save().resize(); + + if (!settings.onwatch) + { + settings.onwatch = callback || function() {}; + } + + $.proxy(settings.onwatch, this)(); + + return this; + }, + + /** + * 关闭实时预览 + * Disable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + unwatch : function(callback) { + var settings = this.settings; + this.state.watching = settings.watch = false; + this.preview.hide(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.unwatch); + icon.removeClass(watchIcon).addClass(unWatchIcon); + } + + this.codeMirror.css("border-right", "none").width(this.editor.width()); + + this.resize(); + + if (!settings.onunwatch) + { + settings.onunwatch = callback || function() {}; + } + + $.proxy(settings.onunwatch, this)(); + + return this; + }, + + /** + * 显示编辑器 + * Show editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + show : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.show(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器 + * Hide editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + hide : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.hide(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器部分,只预览HTML + * Enter preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewing : function() { + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var codeMirror = this.codeMirror; + var previewContainer = this.previewContainer; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) { + return this; + } + + if (settings.toolbar && toolbar) { + toolbar.toggle(); + toolbar.find(".fa[name=preview]").toggleClass("active"); + } + + codeMirror.toggle(); + + var escHandle = function(event) { + if (event.shiftKey && event.keyCode === 27) { + _this.previewed(); + } + }; + + if (codeMirror.css("display") === "none") // 为了兼容Zepto,而不使用codeMirror.is(":hidden") + { + this.state.preview = true; + + if (this.state.fullscreen) { + preview.css("background", "#fff"); + } + + editor.find("." + this.classPrefix + "preview-close-btn").show().bind(editormd.mouseOrTouch("click", "touchend"), function(){ + _this.previewed(); + }); + + if (!settings.watch) + { + this.save(); + } + else + { + previewContainer.css("padding", ""); + } + + previewContainer.addClass(this.classPrefix + "preview-active"); + + preview.show().css({ + position : "", + top : 0, + width : editor.width(), + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewing, this)(); + } + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.previewed(); + } + }, + + /** + * 显示编辑器部分,退出只预览HTML + * Exit preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewed : function() { + + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var previewContainer = this.previewContainer; + var previewCloseBtn = editor.find("." + this.classPrefix + "preview-close-btn"); + + this.state.preview = false; + + this.codeMirror.show(); + + if (settings.toolbar) { + toolbar.show(); + } + + preview[(settings.watch) ? "show" : "hide"](); + + previewCloseBtn.hide().unbind(editormd.mouseOrTouch("click", "touchend")); + + previewContainer.removeClass(this.classPrefix + "preview-active"); + + if (settings.watch) + { + previewContainer.css("padding", "20px"); + } + + preview.css({ + background : null, + position : "absolute", + width : editor.width() / 2, + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() - toolbar.height(), + top : (settings.toolbar) ? toolbar.height() : 0 + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewed, this)(); + } + + return this; + }, + + /** + * 编辑器全屏显示 + * Fullscreen show + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreen : function() { + + var _this = this; + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var fullscreenClass = this.classPrefix + "fullscreen"; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().toggleClass("active"); + } + + var escHandle = function(event) { + if (!event.shiftKey && event.keyCode === 27) + { + if (state.fullscreen) + { + _this.fullscreenExit(); + } + } + }; + + if (!editor.hasClass(fullscreenClass)) + { + state.fullscreen = true; + + $("html,body").css("overflow", "hidden"); + + editor.css({ + width : $(window).width(), + height : $(window).height() + }).addClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreen, this)(); + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.fullscreenExit(); + } + + return this; + }, + + /** + * 编辑器退出全屏显示 + * Exit fullscreen state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreenExit : function() { + + var editor = this.editor; + var settings = this.settings; + var toolbar = this.toolbar; + var fullscreenClass = this.classPrefix + "fullscreen"; + + this.state.fullscreen = false; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().removeClass("active"); + } + + $("html,body").css("overflow", ""); + + editor.css({ + width : editor.data("oldWidth"), + height : editor.data("oldHeight") + }).removeClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreenExit, this)(); + + return this; + }, + + /** + * 加载并执行插件 + * Load and execute the plugin + * + * @param {String} name plugin name / function name + * @param {String} path plugin load path + * @returns {editormd} 返回editormd的实例对象 + */ + + executePlugin : function(name, path) { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + + path = settings.pluginPath + path; + + if (typeof define === "function") + { + if (typeof this[name] === "undefined") + { + alert("Error: " + name + " plugin is not found, you are not load this plugin."); + + return this; + } + + this[name](cm); + + return this; + } + + if ($.inArray(path, editormd.loadFiles.plugin) < 0) + { + editormd.loadPlugin(path, function() { + editormd.loadPlugins[name] = _this[name]; + _this[name](cm); + }); + } + else + { + $.proxy(editormd.loadPlugins[name], this)(cm); + } + + return this; + }, + + /** + * 搜索替换 + * Search & replace + * + * @param {String} command CodeMirror serach commands, "find, fintNext, fintPrev, clearSearch, replace, replaceAll" + * @returns {editormd} return this + */ + + search : function(command) { + var settings = this.settings; + + if (!settings.searchReplace) + { + alert("Error: settings.searchReplace == false"); + return this; + } + + if (!settings.readOnly) + { + this.cm.execCommand(command || "find"); + } + + return this; + }, + + searchReplace : function() { + this.search("replace"); + + return this; + }, + + searchReplaceAll : function() { + this.search("replaceAll"); + + return this; + } + }; + + editormd.fn.init.prototype = editormd.fn; + + /** + * 锁屏 + * lock screen when dialog opening + * + * @returns {void} + */ + + editormd.dialogLockScreen = function() { + var settings = this.settings || {dialogLockScreen : true}; + + if (settings.dialogLockScreen) + { + $("html,body").css("overflow", "hidden"); + this.resize(); + } + }; + + /** + * 显示透明背景层 + * Display mask layer when dialog opening + * + * @param {Object} dialog dialog jQuery object + * @returns {void} + */ + + editormd.dialogShowMask = function(dialog) { + var editor = this.editor; + var settings = this.settings || {dialogShowMask : true}; + + dialog.css({ + top : ($(window).height() - dialog.height()) / 2 + "px", + left : ($(window).width() - dialog.width()) / 2 + "px" + }); + + if (settings.dialogShowMask) { + editor.children("." + this.classPrefix + "mask").css("z-index", parseInt(dialog.css("z-index")) - 1).show(); + } + }; + + editormd.toolbarHandlers = { + undo : function() { + this.cm.undo(); + }, + + redo : function() { + this.cm.redo(); + }, + + bold : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("**" + selection + "**"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + del : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("~~" + selection + "~~"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + italic : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("*" + selection + "*"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + quote : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("> " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("> " + selection); + } + + //cm.replaceSelection("> " + selection); + //cm.setCursor(cursor.line, (selection === "") ? cursor.ch + 2 : cursor.ch + selection.length + 2); + }, + + ucfirst : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.firstUpperCase(selection)); + cm.setSelections(selections); + }, + + ucwords : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.wordsFirstUpperCase(selection)); + cm.setSelections(selections); + }, + + uppercase : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toUpperCase()); + cm.setSelections(selections); + }, + + lowercase : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toLowerCase()); + cm.setSelections(selections); + }, + + h1 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("# " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("# " + selection); + } + }, + + h2 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("## " + selection); + cm.setCursor(cursor.line, cursor.ch + 3); + } + else + { + cm.replaceSelection("## " + selection); + } + }, + + h3 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("### " + selection); + cm.setCursor(cursor.line, cursor.ch + 4); + } + else + { + cm.replaceSelection("### " + selection); + } + }, + + h4 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("#### " + selection); + cm.setCursor(cursor.line, cursor.ch + 5); + } + else + { + cm.replaceSelection("#### " + selection); + } + }, + + h5 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("##### " + selection); + cm.setCursor(cursor.line, cursor.ch + 6); + } + else + { + cm.replaceSelection("##### " + selection); + } + }, + + h6 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("###### " + selection); + cm.setCursor(cursor.line, cursor.ch + 7); + } + else + { + cm.replaceSelection("###### " + selection); + } + }, + + "list-ul" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (selection === "") + { + cm.replaceSelection("- " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : "- " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + "list-ol" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if(selection === "") + { + cm.replaceSelection("1. " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : (i+1) + ". " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + hr : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(((cursor.ch !== 0) ? "\n\n" : "\n") + "------------\n\n"); + }, + + tex : function() { + if (!this.settings.tex) + { + alert("settings.tex === false"); + return this; + } + + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("$$" + selection + "$$"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + link : function() { + this.executePlugin("linkDialog", "link-dialog/link-dialog"); + }, + + "reference-link" : function() { + this.executePlugin("referenceLinkDialog", "reference-link-dialog/reference-link-dialog"); + }, + + pagebreak : function() { + if (!this.settings.pageBreak) + { + alert("settings.pageBreak === false"); + return this; + } + + var cm = this.cm; + var selection = cm.getSelection(); + + cm.replaceSelection("\r\n[========]\r\n"); + }, + + image : function() { + this.executePlugin("imageDialog", "image-dialog/image-dialog"); + }, + + code : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("`" + selection + "`"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "code-block" : function() { + this.executePlugin("codeBlockDialog", "code-block-dialog/code-block-dialog"); + }, + + "preformatted-text" : function() { + this.executePlugin("preformattedTextDialog", "preformatted-text-dialog/preformatted-text-dialog"); + }, + + table : function() { + this.executePlugin("tableDialog", "table-dialog/table-dialog"); + }, + + datetime : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var date = new Date(); + var langName = this.settings.lang.name; + var datefmt = editormd.dateFormat() + " " + editormd.dateFormat((langName === "zh-cn" || langName === "zh-tw") ? "cn-week-day" : "week-day"); + + cm.replaceSelection(datefmt); + }, + + emoji : function() { + this.executePlugin("emojiDialog", "emoji-dialog/emoji-dialog"); + }, + + "html-entities" : function() { + this.executePlugin("htmlEntitiesDialog", "html-entities-dialog/html-entities-dialog"); + }, + + "goto-line" : function() { + this.executePlugin("gotoLineDialog", "goto-line-dialog/goto-line-dialog"); + }, + + watch : function() { + this[this.settings.watch ? "unwatch" : "watch"](); + }, + + preview : function() { + this.previewing(); + }, + + fullscreen : function() { + this.fullscreen(); + }, + + clear : function() { + this.clear(); + }, + + search : function() { + this.search(); + }, + + help : function() { + this.executePlugin("helpDialog", "help-dialog/help-dialog"); + }, + + info : function() { + this.showInfoDialog(); + } + }; + + editormd.keyMaps = { + "Ctrl-1" : "h1", + "Ctrl-2" : "h2", + "Ctrl-3" : "h3", + "Ctrl-4" : "h4", + "Ctrl-5" : "h5", + "Ctrl-6" : "h6", + "Ctrl-B" : "bold", // if this is string == editormd.toolbarHandlers.xxxx + "Ctrl-D" : "datetime", + + "Ctrl-E" : function() { // emoji + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!this.settings.emoji) + { + alert("Error: settings.emoji == false"); + return ; + } + + cm.replaceSelection(":" + selection + ":"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-Alt-G" : "goto-line", + "Ctrl-H" : "hr", + "Ctrl-I" : "italic", + "Ctrl-K" : "code", + + "Ctrl-L" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("[" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-U" : "list-ul", + + "Shift-Ctrl-A" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!this.settings.atLink) + { + alert("Error: settings.atLink == false"); + return ; + } + + cm.replaceSelection("@" + selection); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "Shift-Ctrl-C" : "code", + "Shift-Ctrl-Q" : "quote", + "Shift-Ctrl-S" : "del", + "Shift-Ctrl-K" : "tex", // KaTeX + + "Shift-Alt-C" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(["```", selection, "```"].join("\n")); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 3); + } + }, + + "Shift-Ctrl-Alt-C" : "code-block", + "Shift-Ctrl-H" : "html-entities", + "Shift-Alt-H" : "help", + "Shift-Ctrl-E" : "emoji", + "Shift-Ctrl-U" : "uppercase", + "Shift-Alt-U" : "ucwords", + "Shift-Ctrl-Alt-U" : "ucfirst", + "Shift-Alt-L" : "lowercase", + + "Shift-Ctrl-I" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("![" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 4); + } + }, + + "Shift-Ctrl-Alt-I" : "image", + "Shift-Ctrl-L" : "link", + "Shift-Ctrl-O" : "list-ol", + "Shift-Ctrl-P" : "preformatted-text", + "Shift-Ctrl-T" : "table", + "Shift-Alt-P" : "pagebreak", + "F9" : "watch", + "F10" : "preview", + "F11" : "fullscreen", + }; + + /** + * 清除字符串两边的空格 + * Clear the space of strings both sides. + * + * @param {String} str string + * @returns {String} trimed string + */ + + var trim = function(str) { + return (!String.prototype.trim) ? str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "") : str.trim(); + }; + + editormd.trim = trim; + + /** + * 所有单词首字母大写 + * Words first to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var ucwords = function (str) { + return str.toLowerCase().replace(/\b(\w)|\s(\w)/g, function($1) { + return $1.toUpperCase(); + }); + }; + + editormd.ucwords = editormd.wordsFirstUpperCase = ucwords; + + /** + * 字符串首字母大写 + * Only string first char to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var firstUpperCase = function(str) { + return str.toLowerCase().replace(/\b(\w)/, function($1){ + return $1.toUpperCase(); + }); + }; + + var ucfirst = firstUpperCase; + + editormd.firstUpperCase = editormd.ucfirst = firstUpperCase; + + editormd.urls = { + atLinkBase : "https://github.com/" + }; + + editormd.regexs = { + atLink : /@(\w+)/g, + email : /(\w+)@(\w+)\.(\w+)\.?(\w+)?/g, + emailLink : /(mailto:)?([\w\.\_]+)@(\w+)\.(\w+)\.?(\w+)?/g, + emoji : /:([\w\+-]+):/g, + emojiDatetime : /(\d{2}:\d{2}:\d{2})/g, + twemoji : /:(tw-([\w]+)-?(\w+)?):/g, + fontAwesome : /:(fa-([\w]+)(-(\w+)){0,}):/g, + editormdLogo : /:(editormd-logo-?(\w+)?):/g, + pageBreak : /^\[[=]{8,}\]$/ + }; + + // Emoji graphics files url path + editormd.emoji = { + path : "http://www.emoji-cheat-sheet.com/graphics/emojis/", + ext : ".png" + }; + + // Twitter Emoji (Twemoji) graphics files url path + editormd.twemoji = { + path : "http://twemoji.maxcdn.com/36x36/", + ext : ".png" + }; + + /** + * 自定义marked的解析器 + * Custom Marked renderer rules + * + * @param {Array} markdownToC 传入用于接收TOC的数组 + * @returns {Renderer} markedRenderer 返回marked的Renderer自定义对象 + */ + + editormd.markedRenderer = function(markdownToC, options) { + var defaults = { + toc : true, // Table of contents + tocm : false, + tocStartLevel : 1, // Said from H1 to create ToC + pageBreak : true, + atLink : true, // for @link + emailLink : true, // for mail address auto link + taskList : false, // Enable Github Flavored Markdown task lists + emoji : false, // :emoji: , Support Twemoji, fontAwesome, Editor.md logo emojis. + tex : false, // TeX(LaTeX), based on KaTeX + flowChart : false, // flowChart.js only support IE9+ + sequenceDiagram : false, // sequenceDiagram.js only support IE9+ + }; + + var settings = $.extend(defaults, options || {}); + var marked = editormd.$marked; + var markedRenderer = new marked.Renderer(); + markdownToC = markdownToC || []; + + var regexs = editormd.regexs; + var atLinkReg = regexs.atLink; + var emojiReg = regexs.emoji; + var emailReg = regexs.email; + var emailLinkReg = regexs.emailLink; + var twemojiReg = regexs.twemoji; + var faIconReg = regexs.fontAwesome; + var editormdLogoReg = regexs.editormdLogo; + var pageBreakReg = regexs.pageBreak; + + markedRenderer.emoji = function(text) { + + text = text.replace(editormd.regexs.emojiDatetime, function($1) { + return $1.replace(/:/g, ":"); + }); + + var matchs = text.match(emojiReg); + + if (!matchs || !settings.emoji) { + return text; + } + + for (var i = 0, len = matchs.length; i < len; i++) + { + if (matchs[i] === ":+1:") { + matchs[i] = ":\\+1:"; + } + + text = text.replace(new RegExp(matchs[i]), function($1, $2){ + var faMatchs = $1.match(faIconReg); + var name = $1.replace(/:/g, ""); + + if (faMatchs) + { + for (var fa = 0, len1 = faMatchs.length; fa < len1; fa++) + { + var faName = faMatchs[fa].replace(/:/g, ""); + + return ""; + } + } + else + { + var emdlogoMathcs = $1.match(editormdLogoReg); + var twemojiMatchs = $1.match(twemojiReg); + + if (emdlogoMathcs) + { + for (var x = 0, len2 = emdlogoMathcs.length; x < len2; x++) + { + var logoName = emdlogoMathcs[x].replace(/:/g, ""); + return ""; + } + } + else if (twemojiMatchs) + { + for (var t = 0, len3 = twemojiMatchs.length; t < len3; t++) + { + var twe = twemojiMatchs[t].replace(/:/g, "").replace("tw-", ""); + return "\"twemoji-""; + } + } + else + { + var src = (name === "+1") ? "plus1" : name; + src = (src === "black_large_square") ? "black_square" : src; + src = (src === "moon") ? "waxing_gibbous_moon" : src; + + return "\":""; + } + } + }); + } + + return text; + }; + + markedRenderer.atLink = function(text) { + + if (atLinkReg.test(text)) + { + if (settings.atLink) + { + text = text.replace(emailReg, function($1, $2, $3, $4) { + return $1.replace(/@/g, "_#_@_#_"); + }); + + text = text.replace(atLinkReg, function($1, $2) { + return "" + $1 + ""; + }).replace(/_#_@_#_/g, "@"); + } + + if (settings.emailLink) + { + text = text.replace(emailLinkReg, function($1, $2, $3, $4, $5) { + return (!$2 && $.inArray($5, "jpg|jpeg|png|gif|webp|ico|icon|pdf".split("|")) < 0) ? ""+$1+"" : $1; + }); + } + + return text; + } + + return text; + }; + + markedRenderer.link = function (href, title, text) { + + if (this.options.sanitize) { + try { + var prot = decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase(); + } catch(e) { + return ""; + } + + if (prot.indexOf("javascript:") === 0) { + return ""; + } + } + + var out = "" + text.replace(/@/g, "@") + ""; + } + + if (title) { + out += " title=\"" + title + "\""; + } + + out += ">" + text + ""; + + return out; + }; + + markedRenderer.heading = function(text, level, raw) { + + var linkText = text; + var hasLinkReg = /\s*\]*)\>(.*)\<\/a\>\s*/; + var getLinkTextReg = /\s*\]+)\>([^\>]*)\<\/a\>\s*/g; + + if (hasLinkReg.test(text)) + { + var tempText = []; + text = text.split(/\]+)\>([^\>]*)\<\/a\>/); + + for (var i = 0, len = text.length; i < len; i++) + { + tempText.push(text[i].replace(/\s*href\=\"(.*)\"\s*/g, "")); + } + + text = tempText.join(" "); + } + + text = trim(text); + + var escapedText = text.toLowerCase().replace(/[^\w]+/g, "-"); + var toc = { + text : text, + level : level, + slug : escapedText + }; + + var isChinese = /^[\u4e00-\u9fa5]+$/.test(text); + var id = (isChinese) ? escape(text).replace(/\%/g, "") : text.toLowerCase().replace(/[^\w]+/g, "-"); + + markdownToC.push(toc); + + var headingHTML = ""; + + headingHTML += ""; + headingHTML += ""; + headingHTML += (hasLinkReg) ? this.atLink(this.emoji(linkText)) : this.atLink(this.emoji(text)); + headingHTML += ""; + + return headingHTML; + }; + + markedRenderer.pageBreak = function(text) { + if (pageBreakReg.test(text) && settings.pageBreak) + { + text = "
        "; + } + + return text; + }; + + markedRenderer.paragraph = function(text) { + var isTeXInline = /\$\$(.*)\$\$/g.test(text); + var isTeXLine = /^\$\$(.*)\$\$$/.test(text); + var isTeXAddClass = (isTeXLine) ? " class=\"" + editormd.classNames.tex + "\"" : ""; + var isToC = (settings.tocm) ? /^(\[TOC\]|\[TOCM\])$/.test(text) : /^\[TOC\]$/.test(text); + var isToCMenu = /^\[TOCM\]$/.test(text); + + if (!isTeXLine && isTeXInline) + { + text = text.replace(/(\$\$([^\$]*)\$\$)+/g, function($1, $2) { + return "" + $2.replace(/\$/g, "") + ""; + }); + } + else + { + text = (isTeXLine) ? text.replace(/\$/g, "") : text; + } + + var tocHTML = "
        " + text + "
        "; + + return (isToC) ? ( (isToCMenu) ? "
        " + tocHTML + "

        " : tocHTML ) + : ( (pageBreakReg.test(text)) ? this.pageBreak(text) : "" + this.atLink(this.emoji(text)) + "

        \n" ); + }; + + markedRenderer.code = function (code, lang, escaped) { + + if (lang === "seq" || lang === "sequence") + { + return "
        " + code + "
        "; + } + else if ( lang === "flow") + { + return "
        " + code + "
        "; + } + else if ( lang === "math" || lang === "latex" || lang === "katex") + { + return "

        " + code + "

        "; + } + else + { + + return marked.Renderer.prototype.code.apply(this, arguments); + } + }; + + markedRenderer.tablecell = function(content, flags) { + var type = (flags.header) ? "th" : "td"; + var tag = (flags.align) ? "<" + type +" style=\"text-align:" + flags.align + "\">" : "<" + type + ">"; + + return tag + this.atLink(this.emoji(content)) + "\n"; + }; + + markedRenderer.listitem = function(text) { + if (settings.taskList && /^\s*\[[x\s]\]\s*/.test(text)) + { + text = text.replace(/^\s*\[\s\]\s*/, " ") + .replace(/^\s*\[x\]\s*/, " "); + + return "
      • " + this.atLink(this.emoji(text)) + "
      • "; + } + else + { + return "
      • " + this.atLink(this.emoji(text)) + "
      • "; + } + }; + + return markedRenderer; + }; + + /** + * + * 生成TOC(Table of Contents) + * Creating ToC (Table of Contents) + * + * @param {Array} toc 从marked获取的TOC数组列表 + * @param {Element} container 插入TOC的容器元素 + * @param {Integer} startLevel Hx 起始层级 + * @returns {Object} tocContainer 返回ToC列表容器层的jQuery对象元素 + */ + + editormd.markdownToCRenderer = function(toc, container, tocDropdown, startLevel) { + + var html = ""; + var lastLevel = 0; + var classPrefix = this.classPrefix; + + startLevel = startLevel || 1; + + for (var i = 0, len = toc.length; i < len; i++) + { + var text = toc[i].text; + var level = toc[i].level; + + if (level < startLevel) { + continue; + } + + if (level > lastLevel) + { + html += ""; + } + else if (level < lastLevel) + { + html += (new Array(lastLevel - level + 2)).join(""); + } + else + { + html += ""; + } + + html += "
      • " + text + "
          "; + lastLevel = level; + } + + var tocContainer = container.find(".markdown-toc"); + + if ((tocContainer.length < 1 && container.attr("previewContainer") === "false")) + { + var tocHTML = "
          "; + + tocHTML = (tocDropdown) ? "
          " + tocHTML + "
          " : tocHTML; + + container.html(tocHTML); + + tocContainer = container.find(".markdown-toc"); + } + + if (tocDropdown) + { + tocContainer.wrap("

          "); + } + + tocContainer.html("
            ").children(".markdown-toc-list").html(html.replace(/\r?\n?\\<\/ul\>/g, "")); + + return tocContainer; + }; + + /** + * + * 生成TOC下拉菜单 + * Creating ToC dropdown menu + * + * @param {Object} container 插入TOC的容器jQuery对象元素 + * @param {String} tocTitle ToC title + * @returns {Object} return toc-menu object + */ + + editormd.tocDropdownMenu = function(container, tocTitle) { + + tocTitle = tocTitle || "Table of Contents"; + + var zindex = 400; + var tocMenus = container.find("." + this.classPrefix + "toc-menu"); + + tocMenus.each(function() { + var $this = $(this); + var toc = $this.children(".markdown-toc"); + var icon = ""; + var btn = "" + icon + tocTitle + ""; + var menu = toc.children("ul"); + var list = menu.find("li"); + + toc.append(btn); + + list.first().before("
          • " + tocTitle + " " + icon + "

          • "); + + $this.mouseover(function(){ + menu.show(); + + list.each(function(){ + var li = $(this); + var ul = li.children("ul"); + + if (ul.html() === "") + { + ul.remove(); + } + + if (ul.length > 0 && ul.html() !== "") + { + var firstA = li.children("a").first(); + + if (firstA.children(".fa").length < 1) + { + firstA.append( $(icon).css({ float:"right", paddingTop:"4px" }) ); + } + } + + li.mouseover(function(){ + ul.css("z-index", zindex).show(); + zindex += 1; + }).mouseleave(function(){ + ul.hide(); + }); + }); + }).mouseleave(function(){ + menu.hide(); + }); + }); + + return tocMenus; + }; + + /** + * 简单地过滤指定的HTML标签 + * Filter custom html tags + * + * @param {String} html 要过滤HTML + * @param {String} filters 要过滤的标签 + * @returns {String} html 返回过滤的HTML + */ + + editormd.filterHTMLTags = function(html, filters) { + + if (typeof html !== "string") { + html = new String(html); + } + + if (typeof filters !== "string") { + return html; + } + + var expression = filters.split("|"); + var filterTags = expression[0].split(","); + var attrs = expression[1]; + + for (var i = 0, len = filterTags.length; i < len; i++) + { + var tag = filterTags[i]; + + html = html.replace(new RegExp("\<\s*" + tag + "\s*([^\>]*)\>([^\>]*)\<\s*\/" + tag + "\s*\>", "igm"), ""); + } + + //return html; + + if (typeof attrs !== "undefined") + { + var htmlTagRegex = /\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/ig; + + if (attrs === "*") + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { + return "<" + $2 + ">" + $4 + ""; + }); + } + else if (attrs === "on*") + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { + var el = $("<" + $2 + ">" + $4 + ""); + var _attrs = $($1)[0].attributes; + var $attrs = {}; + + $.each(_attrs, function(i, e) { + if (e.nodeName !== '"') $attrs[e.nodeName] = e.nodeValue; + }); + + $.each($attrs, function(i) { + if (i.indexOf("on") === 0) { + delete $attrs[i]; + } + }); + + el.attr($attrs); + + var text = (typeof el[1] !== "undefined") ? $(el[1]).text() : ""; + + return el[0].outerHTML + text; + }); + } + else + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4) { + var filterAttrs = attrs.split(","); + var el = $($1); + el.html($4); + + $.each(filterAttrs, function(i) { + el.attr(filterAttrs[i], null); + }); + + return el[0].outerHTML; + }); + } + } + + return html; + }; + + /** + * 将Markdown文档解析为HTML用于前台显示 + * Parse Markdown to HTML for Font-end preview. + * + * @param {String} id 用于显示HTML的对象ID + * @param {Object} [options={}] 配置选项,可选 + * @returns {Object} div 返回jQuery对象元素 + */ + + editormd.markdownToHTML = function(id, options) { + var defaults = { + gfm : true, + toc : true, + tocm : false, + tocStartLevel : 1, + tocTitle : "目录", + tocDropdown : false, + tocContainer : "", + markdown : "", + markdownSourceCode : false, + htmlDecode : false, + autoLoadKaTeX : true, + pageBreak : true, + atLink : true, // for @link + emailLink : true, // for mail address auto link + tex : false, + taskList : false, // Github Flavored Markdown task lists + emoji : false, + flowChart : false, + sequenceDiagram : false, + previewCodeHighlight : true + }; + + editormd.$marked = marked; + + var div = $("#" + id); + var settings = div.settings = $.extend(true, defaults, options || {}); + var saveTo = div.find("textarea"); + + if (saveTo.length < 1) + { + div.append(""); + saveTo = div.find("textarea"); + } + + var markdownDoc = (settings.markdown === "") ? saveTo.val() : settings.markdown; + var markdownToC = []; + + var rendererOptions = { + toc : settings.toc, + tocm : settings.tocm, + tocStartLevel : settings.tocStartLevel, + taskList : settings.taskList, + emoji : settings.emoji, + tex : settings.tex, + pageBreak : settings.pageBreak, + atLink : settings.atLink, // for @link + emailLink : settings.emailLink, // for mail address auto link + flowChart : settings.flowChart, + sequenceDiagram : settings.sequenceDiagram, + previewCodeHighlight : settings.previewCodeHighlight, + }; + + var markedOptions = { + renderer : editormd.markedRenderer(markdownToC, rendererOptions), + gfm : settings.gfm, + tables : true, + breaks : true, + pedantic : false, + sanitize : (settings.htmlDecode) ? false : true, // 是否忽略HTML标签,即是否开启HTML标签解析,为了安全性,默认不开启 + smartLists : true, + smartypants : true + }; + + markdownDoc = new String(markdownDoc); + + var markdownParsed = marked(markdownDoc, markedOptions); + + markdownParsed = editormd.filterHTMLTags(markdownParsed, settings.htmlDecode); + + if (settings.markdownSourceCode) { + saveTo.text(markdownDoc); + } else { + saveTo.remove(); + } + + div.addClass("markdown-body " + this.classPrefix + "html-preview").append(markdownParsed); + + var tocContainer = (settings.tocContainer !== "") ? $(settings.tocContainer) : div; + + if (settings.tocContainer !== "") + { + tocContainer.attr("previewContainer", false); + } + + if (settings.toc) + { + div.tocContainer = this.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); + + if (settings.tocDropdown || div.find("." + this.classPrefix + "toc-menu").length > 0) + { + this.tocDropdownMenu(div, settings.tocTitle); + } + + if (settings.tocContainer !== "") + { + div.find(".editormd-toc-menu, .editormd-markdown-toc").remove(); + } + } + + if (settings.previewCodeHighlight) + { + div.find("pre").addClass("prettyprint linenums"); + prettyPrint(); + } + + if (!editormd.isIE8) + { + if (settings.flowChart) { + div.find(".flowchart").flowChart(); + } + + if (settings.sequenceDiagram) { + div.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); + } + } + + if (settings.tex) + { + var katexHandle = function() { + div.find("." + editormd.classNames.tex).each(function(){ + var tex = $(this); + katex.render(tex.html().replace(/</g, "<").replace(/>/g, ">"), tex[0]); + tex.find(".katex").css("font-size", "1.6em"); + }); + }; + + if (settings.autoLoadKaTeX && !editormd.$katex && !editormd.kaTeXLoaded) + { + this.loadKaTeX(function() { + editormd.$katex = katex; + editormd.kaTeXLoaded = true; + katexHandle(); + }); + } + else + { + katexHandle(); + } + } + + div.getMarkdown = function() { + return saveTo.val(); + }; + + return div; + }; + + // Editor.md themes, change toolbar themes etc. + // added @1.5.0 + editormd.themes = ["default", "dark"]; + + // Preview area themes + // added @1.5.0 + editormd.previewThemes = ["default", "dark"]; + + // CodeMirror / editor area themes + // @1.5.0 rename -> editorThemes, old version -> themes + editormd.editorThemes = [ + "default", "3024-day", "3024-night", + "ambiance", "ambiance-mobile", + "base16-dark", "base16-light", "blackboard", + "cobalt", + "eclipse", "elegant", "erlang-dark", + "lesser-dark", + "mbo", "mdn-like", "midnight", "monokai", + "neat", "neo", "night", + "paraiso-dark", "paraiso-light", "pastel-on-dark", + "rubyblue", + "solarized", + "the-matrix", "tomorrow-night-eighties", "twilight", + "vibrant-ink", + "xq-dark", "xq-light" + ]; + + editormd.loadPlugins = {}; + + editormd.loadFiles = { + js : [], + css : [], + plugin : [] + }; + + /** + * 动态加载Editor.md插件,但不立即执行 + * Load editor.md plugins + * + * @param {String} fileName 插件文件路径 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadPlugin = function(fileName, callback, into) { + callback = callback || function() {}; + + this.loadScript(fileName, function() { + editormd.loadFiles.plugin.push(fileName); + callback(); + }, into); + }; + + /** + * 动态加载CSS文件的方法 + * Load css file method + * + * @param {String} fileName CSS文件名 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadCSS = function(fileName, callback, into) { + into = into || "head"; + callback = callback || function() {}; + + var css = document.createElement("link"); + css.type = "text/css"; + css.rel = "stylesheet"; + css.onload = css.onreadystatechange = function() { + editormd.loadFiles.css.push(fileName); + callback(); + }; + + css.href = fileName + ".css"; + + if(into === "head") { + document.getElementsByTagName("head")[0].appendChild(css); + } else { + document.body.appendChild(css); + } + }; + + editormd.isIE = (navigator.appName == "Microsoft Internet Explorer"); + editormd.isIE8 = (editormd.isIE && navigator.appVersion.match(/8./i) == "8."); + + /** + * 动态加载JS文件的方法 + * Load javascript file method + * + * @param {String} fileName JS文件名 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadScript = function(fileName, callback, into) { + + into = into || "head"; + callback = callback || function() {}; + + var script = null; + script = document.createElement("script"); + script.id = fileName.replace(/[\./]+/g, "-"); + script.type = "text/javascript"; + script.src = fileName + ".js"; + + if (editormd.isIE8) + { + script.onreadystatechange = function() { + if(script.readyState) + { + if (script.readyState === "loaded" || script.readyState === "complete") + { + script.onreadystatechange = null; + editormd.loadFiles.js.push(fileName); + callback(); + } + } + }; + } + else + { + script.onload = function() { + editormd.loadFiles.js.push(fileName); + callback(); + }; + } + + if (into === "head") { + document.getElementsByTagName("head")[0].appendChild(script); + } else { + document.body.appendChild(script); + } + }; + + // 使用国外的CDN,加载速度有时会很慢,或者自定义URL + // You can custom KaTeX load url. + editormd.katexURL = { + css : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min", + js : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min" + }; + + editormd.kaTeXLoaded = false; + + /** + * 加载KaTeX文件 + * load KaTeX files + * + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + */ + + editormd.loadKaTeX = function (callback) { + editormd.loadCSS(editormd.katexURL.css, function(){ + editormd.loadScript(editormd.katexURL.js, callback || function(){}); + }); + }; + + /** + * 锁屏 + * lock screen + * + * @param {Boolean} lock Boolean 布尔值,是否锁屏 + * @returns {void} + */ + + editormd.lockScreen = function(lock) { + $("html,body").css("overflow", (lock) ? "hidden" : ""); + }; + + /** + * 动态创建对话框 + * Creating custom dialogs + * + * @param {Object} options 配置项键值对 Key/Value + * @returns {dialog} 返回创建的dialog的jQuery实例对象 + */ + + editormd.createDialog = function(options) { + var defaults = { + name : "", + width : 420, + height: 240, + title : "", + drag : true, + closed : true, + content : "", + mask : true, + maskStyle : { + backgroundColor : "#fff", + opacity : 0.1 + }, + lockScreen : true, + footer : true, + buttons : false + }; + + options = $.extend(true, defaults, options); + + var $this = this; + var editor = this.editor; + var classPrefix = editormd.classPrefix; + var guid = (new Date()).getTime(); + var dialogName = ( (options.name === "") ? classPrefix + "dialog-" + guid : options.name); + var mouseOrTouch = editormd.mouseOrTouch; + + var html = "
            "; + + if (options.title !== "") + { + html += "
            "; + html += "" + options.title + ""; + html += "
            "; + } + + if (options.closed) + { + html += ""; + } + + html += "
            " + options.content; + + if (options.footer || typeof options.footer === "string") + { + html += "
            " + ( (typeof options.footer === "boolean") ? "" : options.footer) + "
            "; + } + + html += "
            "; + + html += "
            "; + html += "
            "; + html += "
            "; + + editor.append(html); + + var dialog = editor.find("." + dialogName); + + dialog.lockScreen = function(lock) { + if (options.lockScreen) + { + $("html,body").css("overflow", (lock) ? "hidden" : ""); + $this.resize(); + } + + return dialog; + }; + + dialog.showMask = function() { + if (options.mask) + { + editor.find("." + classPrefix + "mask").css(options.maskStyle).css("z-index", editormd.dialogZindex - 1).show(); + } + return dialog; + }; + + dialog.hideMask = function() { + if (options.mask) + { + editor.find("." + classPrefix + "mask").hide(); + } + + return dialog; + }; + + dialog.loading = function(show) { + var loading = dialog.find("." + classPrefix + "dialog-mask"); + loading[(show) ? "show" : "hide"](); + + return dialog; + }; + + dialog.lockScreen(true).showMask(); + + dialog.show().css({ + zIndex : editormd.dialogZindex, + border : (editormd.isIE8) ? "1px solid #ddd" : "", + width : (typeof options.width === "number") ? options.width + "px" : options.width, + height : (typeof options.height === "number") ? options.height + "px" : options.height + }); + + var dialogPosition = function(){ + dialog.css({ + top : ($(window).height() - dialog.height()) / 2 + "px", + left : ($(window).width() - dialog.width()) / 2 + "px" + }); + }; + + dialogPosition(); + + $(window).resize(dialogPosition); + + dialog.children("." + classPrefix + "dialog-close").bind(mouseOrTouch("click", "touchend"), function() { + dialog.hide().lockScreen(false).hideMask(); + }); + + if (typeof options.buttons === "object") + { + var footer = dialog.footer = dialog.find("." + classPrefix + "dialog-footer"); + + for (var key in options.buttons) + { + var btn = options.buttons[key]; + var btnClassName = classPrefix + key + "-btn"; + + footer.append(""); + btn[1] = $.proxy(btn[1], dialog); + footer.children("." + btnClassName).bind(mouseOrTouch("click", "touchend"), btn[1]); + } + } + + if (options.title !== "" && options.drag) + { + var posX, posY; + var dialogHeader = dialog.children("." + classPrefix + "dialog-header"); + + if (!options.mask) { + dialogHeader.bind(mouseOrTouch("click", "touchend"), function(){ + editormd.dialogZindex += 2; + dialog.css("z-index", editormd.dialogZindex); + }); + } + + dialogHeader.mousedown(function(e) { + e = e || window.event; //IE + posX = e.clientX - parseInt(dialog[0].style.left); + posY = e.clientY - parseInt(dialog[0].style.top); + + document.onmousemove = moveAction; + }); + + var userCanSelect = function (obj) { + obj.removeClass(classPrefix + "user-unselect").off("selectstart"); + }; + + var userUnselect = function (obj) { + obj.addClass(classPrefix + "user-unselect").on("selectstart", function(event) { // selectstart for IE + return false; + }); + }; + + var moveAction = function (e) { + e = e || window.event; //IE + + var left, top, nowLeft = parseInt(dialog[0].style.left), nowTop = parseInt(dialog[0].style.top); + + if( nowLeft >= 0 ) { + if( nowLeft + dialog.width() <= $(window).width()) { + left = e.clientX - posX; + } else { + left = $(window).width() - dialog.width(); + document.onmousemove = null; + } + } else { + left = 0; + document.onmousemove = null; + } + + if( nowTop >= 0 ) { + top = e.clientY - posY; + } else { + top = 0; + document.onmousemove = null; + } + + + document.onselectstart = function() { + return false; + }; + + userUnselect($("body")); + userUnselect(dialog); + dialog[0].style.left = left + "px"; + dialog[0].style.top = top + "px"; + }; + + document.onmouseup = function() { + userCanSelect($("body")); + userCanSelect(dialog); + + document.onselectstart = null; + document.onmousemove = null; + }; + + dialogHeader.touchDraggable = function() { + var offset = null; + var start = function(e) { + var orig = e.originalEvent; + var pos = $(this).parent().position(); + + offset = { + x : orig.changedTouches[0].pageX - pos.left, + y : orig.changedTouches[0].pageY - pos.top + }; + }; + + var move = function(e) { + e.preventDefault(); + var orig = e.originalEvent; + + $(this).parent().css({ + top : orig.changedTouches[0].pageY - offset.y, + left : orig.changedTouches[0].pageX - offset.x + }); + }; + + this.bind("touchstart", start).bind("touchmove", move); + }; + + dialogHeader.touchDraggable(); + } + + editormd.dialogZindex += 2; + + return dialog; + }; + + /** + * 鼠标和触摸事件的判断/选择方法 + * MouseEvent or TouchEvent type switch + * + * @param {String} [mouseEventType="click"] 供选择的鼠标事件 + * @param {String} [touchEventType="touchend"] 供选择的触摸事件 + * @returns {String} EventType 返回事件类型名称 + */ + + editormd.mouseOrTouch = function(mouseEventType, touchEventType) { + mouseEventType = mouseEventType || "click"; + touchEventType = touchEventType || "touchend"; + + var eventType = mouseEventType; + + try { + document.createEvent("TouchEvent"); + eventType = touchEventType; + } catch(e) {} + + return eventType; + }; + + /** + * 日期时间的格式化方法 + * Datetime format method + * + * @param {String} [format=""] 日期时间的格式,类似PHP的格式 + * @returns {String} datefmt 返回格式化后的日期时间字符串 + */ + + editormd.dateFormat = function(format) { + format = format || ""; + + var addZero = function(d) { + return (d < 10) ? "0" + d : d; + }; + + var date = new Date(); + var year = date.getFullYear(); + var year2 = year.toString().slice(2, 4); + var month = addZero(date.getMonth() + 1); + var day = addZero(date.getDate()); + var weekDay = date.getDay(); + var hour = addZero(date.getHours()); + var min = addZero(date.getMinutes()); + var second = addZero(date.getSeconds()); + var ms = addZero(date.getMilliseconds()); + var datefmt = ""; + + var ymd = year2 + "-" + month + "-" + day; + var fymd = year + "-" + month + "-" + day; + var hms = hour + ":" + min + ":" + second; + + switch (format) + { + case "UNIX Time" : + datefmt = date.getTime(); + break; + + case "UTC" : + datefmt = date.toUTCString(); + break; + + case "yy" : + datefmt = year2; + break; + + case "year" : + case "yyyy" : + datefmt = year; + break; + + case "month" : + case "mm" : + datefmt = month; + break; + + case "cn-week-day" : + case "cn-wd" : + var cnWeekDays = ["日", "一", "二", "三", "四", "五", "六"]; + datefmt = "星期" + cnWeekDays[weekDay]; + break; + + case "week-day" : + case "wd" : + var weekDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + datefmt = weekDays[weekDay]; + break; + + case "day" : + case "dd" : + datefmt = day; + break; + + case "hour" : + case "hh" : + datefmt = hour; + break; + + case "min" : + case "ii" : + datefmt = min; + break; + + case "second" : + case "ss" : + datefmt = second; + break; + + case "ms" : + datefmt = ms; + break; + + case "yy-mm-dd" : + datefmt = ymd; + break; + + case "yyyy-mm-dd" : + datefmt = fymd; + break; + + case "yyyy-mm-dd h:i:s ms" : + case "full + ms" : + datefmt = fymd + " " + hms + " " + ms; + break; + + case "full" : + case "yyyy-mm-dd h:i:s" : + default: + datefmt = fymd + " " + hms; + break; + } + + return datefmt; + }; + + return editormd; + +})); diff --git a/public/editormd/editormd.amd.min.js b/public/editormd/editormd.amd.min.js new file mode 100644 index 000000000..31e2dc7f9 --- /dev/null +++ b/public/editormd/editormd.amd.min.js @@ -0,0 +1,4 @@ +/*! Editor.md v1.5.0 | editormd.amd.min.js | Open source online markdown editor. | MIT License | By: Pandao | https://github.com/pandao/editor.md | 2015-06-09 */ +!function(e){"use strict";if("function"==typeof require&&"object"==typeof exports&&"object"==typeof module)module.exports=e;else if("function"==typeof define)if(define.amd){var t="codemirror/mode/",i="codemirror/addon/",o=["jquery","marked","prettify","katex","raphael","underscore","flowchart","jqueryflowchart","sequenceDiagram","codemirror/lib/codemirror",t+"css/css",t+"sass/sass",t+"shell/shell",t+"sql/sql",t+"clike/clike",t+"php/php",t+"xml/xml",t+"markdown/markdown",t+"javascript/javascript",t+"htmlmixed/htmlmixed",t+"gfm/gfm",t+"http/http",t+"go/go",t+"dart/dart",t+"coffeescript/coffeescript",t+"nginx/nginx",t+"python/python",t+"perl/perl",t+"lua/lua",t+"r/r",t+"ruby/ruby",t+"rst/rst",t+"smartymixed/smartymixed",t+"vb/vb",t+"vbscript/vbscript",t+"velocity/velocity",t+"xquery/xquery",t+"yaml/yaml",t+"erlang/erlang",t+"jade/jade",i+"edit/trailingspace",i+"dialog/dialog",i+"search/searchcursor",i+"search/search",i+"scroll/annotatescrollbar",i+"search/matchesonscrollbar",i+"display/placeholder",i+"edit/closetag",i+"fold/foldcode",i+"fold/foldgutter",i+"fold/indent-fold",i+"fold/brace-fold",i+"fold/xml-fold",i+"fold/markdown-fold",i+"fold/comment-fold",i+"mode/overlay",i+"selection/active-line",i+"edit/closebrackets",i+"display/fullscreen",i+"search/match-highlighter"];define(o,e)}else define(["jquery"],e);else window.editormd=e()}(function(){"function"==typeof define&&define.amd&&(e=arguments[0],marked=arguments[1],prettify=arguments[2],katex=arguments[3],Raphael=arguments[4],_=arguments[5],flowchart=arguments[6],CodeMirror=arguments[9]);var e="undefined"!=typeof jQuery?jQuery:Zepto;if("undefined"!=typeof e){var t=function(e,i){return new t.fn.init(e,i)};t.title=t.$name="Editor.md",t.version="1.5.0",t.homePage="https://pandao.github.io/editor.md/",t.classPrefix="editormd-",t.toolbarModes={full:["undo","redo","|","bold","del","italic","quote","ucwords","uppercase","lowercase","|","h1","h2","h3","h4","h5","h6","|","list-ul","list-ol","hr","|","link","reference-link","image","code","preformatted-text","code-block","table","datetime","emoji","html-entities","pagebreak","|","goto-line","watch","preview","fullscreen","clear","search","|","help","info"],simple:["undo","redo","|","bold","del","italic","quote","uppercase","lowercase","|","h1","h2","h3","h4","h5","h6","|","list-ul","list-ol","hr","|","watch","preview","fullscreen","|","help","info"],mini:["undo","redo","|","watch","preview","|","help","info"]},t.defaults={mode:"gfm",name:"",value:"",theme:"",editorTheme:"default",previewTheme:"",markdown:"",appendMarkdown:"",width:"100%",height:"100%",path:"./lib/",pluginPath:"",delay:300,autoLoadModules:!0,watch:!0,placeholder:"Enjoy Markdown! coding now...",gotoLine:!0,codeFold:!1,autoHeight:!1,autoFocus:!0,autoCloseTags:!0,searchReplace:!0,syncScrolling:!0,readOnly:!1,tabSize:4,indentUnit:4,lineNumbers:!0,lineWrapping:!0,autoCloseBrackets:!0,showTrailingSpace:!0,matchBrackets:!0,indentWithTabs:!0,styleSelectedText:!0,matchWordHighlight:!0,styleActiveLine:!0,dialogLockScreen:!0,dialogShowMask:!0,dialogDraggable:!0,dialogMaskBgColor:"#fff",dialogMaskOpacity:.1,fontSize:"13px",saveHTMLToTextarea:!1,disabledKeyMaps:[],onload:function(){},onresize:function(){},onchange:function(){},onwatch:null,onunwatch:null,onpreviewing:function(){},onpreviewed:function(){},onfullscreen:function(){},onfullscreenExit:function(){},onscroll:function(){},onpreviewscroll:function(){},imageUpload:!1,imageFormats:["jpg","jpeg","gif","png","bmp","webp"],imageUploadURL:"",crossDomainUpload:!1,uploadCallbackURL:"",toc:!0,tocm:!1,tocTitle:"",tocDropdown:!1,tocContainer:"",tocStartLevel:1,htmlDecode:!1,pageBreak:!0,atLink:!0,emailLink:!0,taskList:!1,emoji:!1,tex:!1,flowChart:!1,sequenceDiagram:!1,previewCodeHighlight:!0,toolbar:!0,toolbarAutoFixed:!0,toolbarIcons:"full",toolbarTitles:{},toolbarHandlers:{ucwords:function(){return t.toolbarHandlers.ucwords},lowercase:function(){return t.toolbarHandlers.lowercase}},toolbarCustomIcons:{lowercase:'a',ucwords:'Aa'},toolbarIconsClass:{undo:"fa-undo",redo:"fa-repeat",bold:"fa-bold",del:"fa-strikethrough",italic:"fa-italic",quote:"fa-quote-left",uppercase:"fa-font",h1:t.classPrefix+"bold",h2:t.classPrefix+"bold",h3:t.classPrefix+"bold",h4:t.classPrefix+"bold",h5:t.classPrefix+"bold",h6:t.classPrefix+"bold","list-ul":"fa-list-ul","list-ol":"fa-list-ol",hr:"fa-minus",link:"fa-link","reference-link":"fa-anchor",image:"fa-picture-o",code:"fa-code","preformatted-text":"fa-file-code-o","code-block":"fa-file-code-o",table:"fa-table",datetime:"fa-clock-o",emoji:"fa-smile-o","html-entities":"fa-copyright",pagebreak:"fa-newspaper-o","goto-line":"fa-terminal",watch:"fa-eye-slash",unwatch:"fa-eye",preview:"fa-desktop",search:"fa-search",fullscreen:"fa-arrows-alt",clear:"fa-eraser",help:"fa-question-circle",info:"fa-info-circle"},toolbarIconTexts:{},lang:{name:"zh-cn",description:"开源在线Markdown编辑器
            Open source online Markdown editor.",tocTitle:"目录",toolbar:{undo:"撤销(Ctrl+Z)",redo:"重做(Ctrl+Y)",bold:"粗体",del:"删除线",italic:"斜体",quote:"引用",ucwords:"将每个单词首字母转成大写",uppercase:"将所选转换成大写",lowercase:"将所选转换成小写",h1:"标题1",h2:"标题2",h3:"标题3",h4:"标题4",h5:"标题5",h6:"标题6","list-ul":"无序列表","list-ol":"有序列表",hr:"横线",link:"链接","reference-link":"引用链接",image:"添加图片",code:"行内代码","preformatted-text":"预格式文本 / 代码块(缩进风格)","code-block":"代码块(多语言风格)",table:"添加表格",datetime:"日期时间",emoji:"Emoji表情","html-entities":"HTML实体字符",pagebreak:"插入分页符","goto-line":"跳转到行",watch:"关闭实时预览",unwatch:"开启实时预览",preview:"全窗口预览HTML(按 Shift + ESC还原)",fullscreen:"全屏(按ESC还原)",clear:"清空",search:"搜索",help:"使用帮助",info:"关于"+t.title},buttons:{enter:"确定",cancel:"取消",close:"关闭"},dialog:{link:{title:"添加链接",url:"链接地址",urlTitle:"链接标题",urlEmpty:"错误:请填写链接地址。"},referenceLink:{title:"添加引用链接",name:"引用名称",url:"链接地址",urlId:"链接ID",urlTitle:"链接标题",nameEmpty:"错误:引用链接的名称不能为空。",idEmpty:"错误:请填写引用链接的ID。",urlEmpty:"错误:请填写引用链接的URL地址。"},image:{title:"添加图片",url:"图片地址",link:"图片链接",alt:"图片描述",uploadButton:"本地上传",imageURLEmpty:"错误:图片地址不能为空。",uploadFileEmpty:"错误:上传的图片不能为空。",formatNotAllowed:"错误:只允许上传图片文件,允许上传的图片文件格式有:"},preformattedText:{title:"添加预格式文本或代码块",emptyAlert:"错误:请填写预格式文本或代码的内容。"},codeBlock:{title:"添加代码块",selectLabel:"代码语言:",selectDefaultText:"请选择代码语言",otherLanguage:"其他语言",unselectedLanguageAlert:"错误:请选择代码所属的语言类型。",codeEmptyAlert:"错误:请填写代码内容。"},htmlEntities:{title:"HTML 实体字符"},help:{title:"使用帮助"}}}},t.classNames={tex:t.classPrefix+"tex"},t.dialogZindex=99999,t.$katex=null,t.$marked=null,t.$CodeMirror=null,t.$prettyPrint=null;var i,o;t.prototype=t.fn={state:{watching:!1,loaded:!1,preview:!1,fullscreen:!1},init:function(i,o){o=o||{},"object"==typeof i&&(o=i);var r=this.classPrefix=t.classPrefix,n=this.settings=e.extend(!0,t.defaults,o);i="object"==typeof i?n.id:i;var a=this.editor=e("#"+i);this.id=i,this.lang=n.lang;var s=this.classNames={textarea:{html:r+"html-textarea",markdown:r+"markdown-textarea"}};n.pluginPath=""===n.pluginPath?n.path+"../plugins/":n.pluginPath,this.state.watching=n.watch?!0:!1,a.hasClass("editormd")||a.addClass("editormd"),a.css({width:"number"==typeof n.width?n.width+"px":n.width,height:"number"==typeof n.height?n.height+"px":n.height}),n.autoHeight&&a.css("height","auto");var l=this.markdownTextarea=a.children("textarea");l.length<1&&(a.append(""),l=this.markdownTextarea=a.children("textarea")),l.addClass(s.textarea.markdown).attr("placeholder",n.placeholder),("undefined"==typeof l.attr("name")||""===l.attr("name"))&&l.attr("name",""!==n.name?n.name:i+"-markdown-doc");var c=[n.readOnly?"":'',n.saveHTMLToTextarea?'':"",'
            ','
            ','
            '].join("\n");return a.append(c).addClass(r+"vertical"),""!==n.theme&&a.addClass(r+"theme-"+n.theme),this.mask=a.children("."+r+"mask"),this.containerMask=a.children("."+r+"container-mask"),""!==n.markdown&&l.val(n.markdown),""!==n.appendMarkdown&&l.val(l.val()+n.appendMarkdown),this.htmlTextarea=a.children("."+s.textarea.html),this.preview=a.children("."+r+"preview"),this.previewContainer=this.preview.children("."+r+"preview-container"),""!==n.previewTheme&&this.preview.addClass(r+"preview-theme-"+n.previewTheme),"function"==typeof define&&define.amd&&("undefined"!=typeof katex&&(t.$katex=katex),n.searchReplace&&!n.readOnly&&(t.loadCSS(n.path+"codemirror/addon/dialog/dialog"),t.loadCSS(n.path+"codemirror/addon/search/matchesonscrollbar"))),"function"==typeof define&&define.amd||!n.autoLoadModules?("undefined"!=typeof CodeMirror&&(t.$CodeMirror=CodeMirror),"undefined"!=typeof marked&&(t.$marked=marked),this.setCodeMirror().setToolbar().loadedDisplay()):this.loadQueues(),this},loadQueues:function(){var e=this,i=this.settings,o=i.path,r=function(){return t.isIE8?void e.loadedDisplay():void(i.flowChart||i.sequenceDiagram?t.loadScript(o+"raphael.min",function(){t.loadScript(o+"underscore.min",function(){!i.flowChart&&i.sequenceDiagram?t.loadScript(o+"sequence-diagram.min",function(){e.loadedDisplay()}):i.flowChart&&!i.sequenceDiagram?t.loadScript(o+"flowchart.min",function(){t.loadScript(o+"jquery.flowchart.min",function(){e.loadedDisplay()})}):i.flowChart&&i.sequenceDiagram&&t.loadScript(o+"flowchart.min",function(){t.loadScript(o+"jquery.flowchart.min",function(){t.loadScript(o+"sequence-diagram.min",function(){e.loadedDisplay()})})})})}):e.loadedDisplay())};return t.loadCSS(o+"codemirror/codemirror.min"),i.searchReplace&&!i.readOnly&&(t.loadCSS(o+"codemirror/addon/dialog/dialog"),t.loadCSS(o+"codemirror/addon/search/matchesonscrollbar")),i.codeFold&&t.loadCSS(o+"codemirror/addon/fold/foldgutter"),t.loadScript(o+"codemirror/codemirror.min",function(){t.$CodeMirror=CodeMirror,t.loadScript(o+"codemirror/modes.min",function(){t.loadScript(o+"codemirror/addons.min",function(){return e.setCodeMirror(),"gfm"!==i.mode&&"markdown"!==i.mode?(e.loadedDisplay(),!1):(e.setToolbar(),void t.loadScript(o+"marked.min",function(){t.$marked=marked,i.previewCodeHighlight?t.loadScript(o+"prettify.min",function(){r()}):r()}))})})}),this},setTheme:function(e){var t=this.editor,i=this.settings.theme,o=this.classPrefix+"theme-";return t.removeClass(o+i).addClass(o+e),this.settings.theme=e,this},setEditorTheme:function(e){var i=this.settings;return i.editorTheme=e,"default"!==e&&t.loadCSS(i.path+"codemirror/theme/"+i.editorTheme),this.cm.setOption("theme",e),this},setCodeMirrorTheme:function(e){return this.setEditorTheme(e),this},setPreviewTheme:function(e){var t=this.preview,i=this.settings.previewTheme,o=this.classPrefix+"preview-theme-";return t.removeClass(o+i).addClass(o+e),this.settings.previewTheme=e,this},setCodeMirror:function(){var e=this.settings,i=this.editor;"default"!==e.editorTheme&&t.loadCSS(e.path+"codemirror/theme/"+e.editorTheme);var o={mode:e.mode,theme:e.editorTheme,tabSize:e.tabSize,dragDrop:!1,autofocus:e.autoFocus,autoCloseTags:e.autoCloseTags,readOnly:e.readOnly?"nocursor":!1,indentUnit:e.indentUnit,lineNumbers:e.lineNumbers,lineWrapping:e.lineWrapping,extraKeys:{"Ctrl-Q":function(e){e.foldCode(e.getCursor())}},foldGutter:e.codeFold,gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],matchBrackets:e.matchBrackets,indentWithTabs:e.indentWithTabs,styleActiveLine:e.styleActiveLine,styleSelectedText:e.styleSelectedText,autoCloseBrackets:e.autoCloseBrackets,showTrailingSpace:e.showTrailingSpace,highlightSelectionMatches:e.matchWordHighlight?{showToken:"onselected"===e.matchWordHighlight?!1:/\w/}:!1};return this.codeEditor=this.cm=t.$CodeMirror.fromTextArea(this.markdownTextarea[0],o),this.codeMirror=this.cmElement=i.children(".CodeMirror"),""!==e.value&&this.cm.setValue(e.value),this.codeMirror.css({fontSize:e.fontSize,width:e.watch?"50%":"100%"}),e.autoHeight&&(this.codeMirror.css("height","auto"),this.cm.setOption("viewportMargin",1/0)),e.lineNumbers||this.codeMirror.find(".CodeMirror-gutters").css("border-right","none"),this},getCodeMirrorOption:function(e){return this.cm.getOption(e)},setCodeMirrorOption:function(e,t){return this.cm.setOption(e,t),this},addKeyMap:function(e,t){return this.cm.addKeyMap(e,t),this},removeKeyMap:function(e){return this.cm.removeKeyMap(e),this},gotoLine:function(t){var i=this.settings;if(!i.gotoLine)return this;var o=this.cm,r=(this.editor,o.lineCount()),n=this.preview;if("string"==typeof t&&("last"===t&&(t=r),"first"===t&&(t=1)),"number"!=typeof t)return alert("Error: The line number must be an integer."),this;if(t=parseInt(t)-1,t>r)return alert("Error: The line number range 1-"+r),this;o.setCursor({line:t,ch:0});var a=o.getScrollInfo(),s=a.clientHeight,l=o.charCoords({line:t,ch:0},"local");if(o.scrollTo(null,(l.top+l.bottom-s)/2),i.watch){var c=this.codeMirror.find(".CodeMirror-scroll")[0],h=e(c).height(),d=c.scrollTop,u=d/c.scrollHeight;n.scrollTop(0===d?0:d+h>=c.scrollHeight-16?n[0].scrollHeight:n[0].scrollHeight*u)}return o.focus(),this},extend:function(){return"undefined"!=typeof arguments[1]&&("function"==typeof arguments[1]&&(arguments[1]=e.proxy(arguments[1],this)),this[arguments[0]]=arguments[1]),"object"==typeof arguments[0]&&"undefined"==typeof arguments[0].length&&e.extend(!0,this,arguments[0]),this},set:function(t,i){return"undefined"!=typeof i&&"function"==typeof i&&(i=e.proxy(i,this)),this[t]=i,this},config:function(t,i){var o=this.settings;return"object"==typeof t&&(o=e.extend(!0,o,t)),"string"==typeof t&&(o[t]=i),this.settings=o,this.recreate(),this},on:function(t,i){var o=this.settings;return"undefined"!=typeof o["on"+t]&&(o["on"+t]=e.proxy(i,this)),this},off:function(e){var t=this.settings;return"undefined"!=typeof t["on"+e]&&(t["on"+e]=function(){}),this},showToolbar:function(t){var i=this.settings;return i.readOnly?this:(i.toolbar&&(this.toolbar.length<1||""===this.toolbar.find("."+this.classPrefix+"menu").html())&&this.setToolbar(),i.toolbar=!0,this.toolbar.show(),this.resize(),e.proxy(t||function(){},this)(),this)},hideToolbar:function(t){var i=this.settings;return i.toolbar=!1,this.toolbar.hide(),this.resize(),e.proxy(t||function(){},this)(),this},setToolbarAutoFixed:function(t){var i=this.state,o=this.editor,r=this.toolbar,n=this.settings;"undefined"!=typeof t&&(n.toolbarAutoFixed=t);var a=function(){var t=e(window),i=t.scrollTop();return n.toolbarAutoFixed?void r.css(i-o.offset().top>10&&i
              ';i.append(n),r=this.toolbar=i.children("."+o+"toolbar")}if(!e.toolbar)return r.hide(),this;r.show();for(var a="function"==typeof e.toolbarIcons?e.toolbarIcons():"string"==typeof e.toolbarIcons?t.toolbarModes[e.toolbarIcons]:e.toolbarIcons,s=r.find("."+this.classPrefix+"menu"),l="",c=!1,h=0,d=a.length;d>h;h++){var u=a[h];if("||"===u)c=!0;else if("|"===u)l+='
            • |
            • ';else{var f=/h(\d)/.test(u),g=u;"watch"!==u||e.watch||(g="unwatch");var p=e.lang.toolbar[g],m=e.toolbarIconTexts[g],w=e.toolbarIconsClass[g];p="undefined"==typeof p?"":p,m="undefined"==typeof m?"":m,w="undefined"==typeof w?"":w;var v=c?'
            • ':"
            • ";"undefined"!=typeof e.toolbarCustomIcons[u]&&"function"!=typeof e.toolbarCustomIcons[u]?v+=e.toolbarCustomIcons[u]:(v+='',v+=''+(f?u.toUpperCase():""===w?m:"")+"",v+=""),v+="
            • ",l=c?v+l:l+v}}return s.html(l),s.find('[title="Lowercase"]').attr("title",e.lang.toolbar.lowercase),s.find('[title="ucwords"]').attr("title",e.lang.toolbar.ucwords),this.setToolbarHandler(),this.setToolbarAutoFixed(),this},dialogLockScreen:function(){return e.proxy(t.dialogLockScreen,this)(),this},dialogShowMask:function(i){return e.proxy(t.dialogShowMask,this)(i),this},getToolbarHandles:function(e){var i=this.toolbarHandlers=t.toolbarHandlers;return e&&"undefined"!=typeof toolbarIconHandlers[e]?i[e]:i},setToolbarHandler:function(){var i=this,o=this.settings;if(!o.toolbar||o.readOnly)return this;var r=this.toolbar,n=this.cm,a=this.classPrefix,s=this.toolbarIcons=r.find("."+a+"menu > li > a"),l=this.getToolbarHandles();return s.bind(t.mouseOrTouch("click","touchend"),function(t){var r=e(this).children(".fa"),a=r.attr("name"),s=n.getCursor(),c=n.getSelection();return""!==a?(i.activeIcon=r,"undefined"!=typeof l[a]?e.proxy(l[a],i)(n):"undefined"!=typeof o.toolbarHandlers[a]&&e.proxy(o.toolbarHandlers[a],i)(n,r,s,c),"link"!==a&&"reference-link"!==a&&"image"!==a&&"code-block"!==a&&"preformatted-text"!==a&&"watch"!==a&&"preview"!==a&&"search"!==a&&"fullscreen"!==a&&"info"!==a&&n.focus(),!1):void 0}),this},createDialog:function(i){return e.proxy(t.createDialog,this)(i)},createInfoDialog:function(){var e=this,i=this.editor,o=this.classPrefix,r=['
              ','
              ','

              '+t.title+"v"+t.version+"

              ","

              "+this.lang.description+"

              ",'

              '+t.homePage+'

              ','

              Copyright © 2015 Pandao, The MIT License.

              ',"
              ",'',"
              "].join("\n");i.append(r);var n=this.infoDialog=i.children("."+o+"dialog-info");return n.find("."+o+"dialog-close").bind(t.mouseOrTouch("click","touchend"),function(){e.hideInfoDialog()}),n.css("border",t.isIE8?"1px solid #ddd":"").css("z-index",t.dialogZindex).show(),this.infoDialogPosition(),this},infoDialogPosition:function(){var t=this.infoDialog,i=function(){t.css({top:(e(window).height()-t.height())/2+"px",left:(e(window).width()-t.width())/2+"px"})};return i(),e(window).resize(i),this},showInfoDialog:function(){e("html,body").css("overflow-x","hidden");var i=this.editor,o=this.settings,r=this.infoDialog=i.children("."+this.classPrefix+"dialog-info");return r.length<1&&this.createInfoDialog(),this.lockScreen(!0),this.mask.css({opacity:o.dialogMaskOpacity,backgroundColor:o.dialogMaskBgColor}).show(),r.css("z-index",t.dialogZindex).show(),this.infoDialogPosition(),this},hideInfoDialog:function(){return e("html,body").css("overflow-x",""),this.infoDialog.hide(),this.mask.hide(),this.lockScreen(!1),this},lockScreen:function(e){return t.lockScreen(e),this.resize(),this},recreate:function(){var e=this.editor,t=this.settings;return this.codeMirror.remove(),this.setCodeMirror(),t.readOnly||(e.find(".editormd-dialog").length>0&&e.find(".editormd-dialog").remove(),t.toolbar&&(this.getToolbarHandles(),this.setToolbar())),this.loadedDisplay(!0),this},previewCodeHighlight:function(){var e=this.settings,t=this.previewContainer;return e.previewCodeHighlight&&(t.find("pre").addClass("prettyprint linenums"),"undefined"!=typeof prettyPrint&&prettyPrint()),this},katexRender:function(){return null===i?this:(this.previewContainer.find("."+t.classNames.tex).each(function(){var i=e(this);t.$katex.render(i.text(),i[0]),i.find(".katex").css("font-size","1.6em")}),this)},flowChartAndSequenceDiagramRender:function(){var i=this,r=this.settings,n=this.previewContainer;if(t.isIE8)return this;if(r.flowChart){if(null===o)return this;n.find(".flowchart").flowChart()}r.sequenceDiagram&&n.find(".sequence-diagram").sequenceDiagram({theme:"simple"});var a=i.preview,s=i.codeMirror,l=s.find(".CodeMirror-scroll"),c=l.height(),h=l.scrollTop(),d=h/l[0].scrollHeight,u=0;a.find(".markdown-toc-list").each(function(){u+=e(this).height()});var f=a.find(".editormd-toc-menu").height();return f=f?f:0,a.scrollTop(0===h?0:h+c>=l[0].scrollHeight-16?a[0].scrollHeight:(a[0].scrollHeight+u+f)*d),this},registerKeyMaps:function(i){var o=this,r=this.cm,n=this.settings,a=t.toolbarHandlers,s=n.disabledKeyMaps;if(i=i||null){for(var l in i)if(e.inArray(l,s)<0){var c={};c[l]=i[l],r.addKeyMap(i)}}else{for(var h in t.keyMaps){var d=t.keyMaps[h],u="string"==typeof d?e.proxy(a[d],o):e.proxy(d,o);if(e.inArray(h,["F9","F10","F11"])<0&&e.inArray(h,s)<0){var f={};f[h]=u,r.addKeyMap(f)}}e(window).keydown(function(t){var i={120:"F9",121:"F10",122:"F11"};if(e.inArray(i[t.keyCode],s)<0)switch(t.keyCode){case 120:return e.proxy(a.watch,o)(),!1;case 121:return e.proxy(a.preview,o)(),!1;case 122:return e.proxy(a.fullscreen,o)(),!1}})}return this},bindScrollEvent:function(){var i=this,o=this.preview,r=this.settings,n=this.codeMirror,a=t.mouseOrTouch;if(!r.syncScrolling)return this;var s=function(){n.find(".CodeMirror-scroll").bind(a("scroll","touchmove"),function(t){var n=e(this).height(),a=e(this).scrollTop(),s=a/e(this)[0].scrollHeight,l=0;o.find(".markdown-toc-list").each(function(){l+=e(this).height()});var c=o.find(".editormd-toc-menu").height();c=c?c:0,o.scrollTop(0===a?0:a+n>=e(this)[0].scrollHeight-16?o[0].scrollHeight:(o[0].scrollHeight+l+c)*s),e.proxy(r.onscroll,i)(t)})},l=function(){n.find(".CodeMirror-scroll").unbind(a("scroll","touchmove"))},c=function(){o.bind(a("scroll","touchmove"),function(t){var o=e(this).height(),a=e(this).scrollTop(),s=a/e(this)[0].scrollHeight,l=n.find(".CodeMirror-scroll");l.scrollTop(0===a?0:a+o>=e(this)[0].scrollHeight?l[0].scrollHeight:l[0].scrollHeight*s),e.proxy(r.onpreviewscroll,i)(t)})},h=function(){o.unbind(a("scroll","touchmove"))};return n.bind({mouseover:s,mouseout:l,touchstart:s,touchend:l}),"single"===r.syncScrolling?this:(o.bind({mouseover:c,mouseout:h,touchstart:c,touchend:h}),this)},bindChangeEvent:function(){var e=this,t=this.cm,o=this.settings;return o.syncScrolling?(t.on("change",function(t,r){o.watch&&e.previewContainer.css("padding",o.autoHeight?"20px 20px 50px 40px":"20px"),i=setTimeout(function(){clearTimeout(i),e.save(),i=null},o.delay)}),this):this},loadedDisplay:function(t){t=t||!1;var i=this,o=this.editor,r=this.preview,n=this.settings;return this.containerMask.hide(),this.save(),n.watch&&r.show(),o.data("oldWidth",o.width()).data("oldHeight",o.height()),this.resize(),this.registerKeyMaps(),e(window).resize(function(){i.resize()}),this.bindScrollEvent().bindChangeEvent(),t||e.proxy(n.onload,this)(),this.state.loaded=!0,this},width:function(e){return this.editor.css("width","number"==typeof e?e+"px":e),this.resize(),this},height:function(e){return this.editor.css("height","number"==typeof e?e+"px":e),this.resize(),this},resize:function(t,i){t=t||null,i=i||null;var o=this.state,r=this.editor,n=this.preview,a=this.toolbar,s=this.settings,l=this.codeMirror;if(t&&r.css("width","number"==typeof t?t+"px":t),!s.autoHeight||o.fullscreen||o.preview?(i&&r.css("height","number"==typeof i?i+"px":i),o.fullscreen&&r.height(e(window).height()),s.toolbar&&!s.readOnly?l.css("margin-top",a.height()+1).height(r.height()-a.height()):l.css("margin-top",0).height(r.height())):(r.css("height","auto"),l.css("height","auto")),s.watch)if(l.width(r.width()/2),n.width(o.preview?r.width():r.width()/2),this.previewContainer.css("padding",s.autoHeight?"20px 20px 50px 40px":"20px"),s.toolbar&&!s.readOnly?n.css("top",a.height()+1):n.css("top",0),!s.autoHeight||o.fullscreen||o.preview){var c=s.toolbar&&!s.readOnly?r.height()-a.height():r.height();n.height(c)}else n.height("");else l.width(r.width()),n.hide();return o.loaded&&e.proxy(s.onresize,this)(),this},save:function(){if(null===i)return this;var r=this,n=this.state,a=this.settings,s=this.cm,l=s.getValue(),c=this.previewContainer;if("gfm"!==a.mode&&"markdown"!==a.mode)return this.markdownTextarea.val(l),this;var h=t.$marked,d=this.markdownToC=[],u=this.markedRendererOptions={toc:a.toc,tocm:a.tocm,tocStartLevel:a.tocStartLevel,pageBreak:a.pageBreak,taskList:a.taskList,emoji:a.emoji,tex:a.tex,atLink:a.atLink,emailLink:a.emailLink,flowChart:a.flowChart,sequenceDiagram:a.sequenceDiagram,previewCodeHighlight:a.previewCodeHighlight},f=this.markedOptions={renderer:t.markedRenderer(d,u),gfm:!0,tables:!0,breaks:!0,pedantic:!1,sanitize:a.htmlDecode?!1:!0,smartLists:!0,smartypants:!0};h.setOptions(f);var g=t.$marked(l,f);if(g=t.filterHTMLTags(g,a.htmlDecode),this.markdownTextarea.text(l),s.save(),a.saveHTMLToTextarea&&this.htmlTextarea.text(g),a.watch||!a.watch&&n.preview){if(c.html(g),this.previewCodeHighlight(),a.toc){var p=""===a.tocContainer?c:e(a.tocContainer),m=p.find("."+this.classPrefix+"toc-menu");p.attr("previewContainer",""===a.tocContainer?"true":"false"),""!==a.tocContainer&&m.length>0&&m.remove(),t.markdownToCRenderer(d,p,a.tocDropdown,a.tocStartLevel),(a.tocDropdown||p.find("."+this.classPrefix+"toc-menu").length>0)&&t.tocDropdownMenu(p,""!==a.tocTitle?a.tocTitle:this.lang.tocTitle),""!==a.tocContainer&&c.find(".markdown-toc").css("border","none")}a.tex&&(!t.kaTeXLoaded&&a.autoLoadModules?t.loadKaTeX(function(){t.$katex=katex,t.kaTeXLoaded=!0,r.katexRender()}):(t.$katex=katex,this.katexRender())),(a.flowChart||a.sequenceDiagram)&&(o=setTimeout(function(){clearTimeout(o),r.flowChartAndSequenceDiagramRender(),o=null},10)),n.loaded&&e.proxy(a.onchange,this)()}return this},focus:function(){return this.cm.focus(),this},setCursor:function(e){return this.cm.setCursor(e),this},getCursor:function(){return this.cm.getCursor()},setSelection:function(e,t){return this.cm.setSelection(e,t),this},getSelection:function(){return this.cm.getSelection()},setSelections:function(e){return this.cm.setSelections(e),this},getSelections:function(){return this.cm.getSelections()},replaceSelection:function(e){return this.cm.replaceSelection(e),this},insertValue:function(e){return this.replaceSelection(e),this},appendMarkdown:function(e){var t=(this.settings,this.cm);return t.setValue(t.getValue()+e),this},setMarkdown:function(e){return this.cm.setValue(e||this.settings.markdown),this},getMarkdown:function(){return this.cm.getValue()},getValue:function(){return this.cm.getValue()},setValue:function(e){return this.cm.setValue(e),this},clear:function(){return this.cm.setValue(""),this},getHTML:function(){return this.settings.saveHTMLToTextarea?this.htmlTextarea.val():(alert("Error: settings.saveHTMLToTextarea == false"),!1)},getTextareaSavedHTML:function(){return this.getHTML()},getPreviewedHTML:function(){return this.settings.watch?this.previewContainer.html():(alert("Error: settings.watch == false"),!1)},watch:function(t){var o=this.settings;if(e.inArray(o.mode,["gfm","markdown"])<0)return this;if(this.state.watching=o.watch=!0,this.preview.show(),this.toolbar){var r=o.toolbarIconsClass.watch,n=o.toolbarIconsClass.unwatch,a=this.toolbar.find(".fa[name=watch]");a.parent().attr("title",o.lang.toolbar.watch),a.removeClass(n).addClass(r)}return this.codeMirror.css("border-right","1px solid #ddd").width(this.editor.width()/2),i=0,this.save().resize(),o.onwatch||(o.onwatch=t||function(){}),e.proxy(o.onwatch,this)(),this},unwatch:function(t){var i=this.settings;if(this.state.watching=i.watch=!1,this.preview.hide(),this.toolbar){var o=i.toolbarIconsClass.watch,r=i.toolbarIconsClass.unwatch,n=this.toolbar.find(".fa[name=watch]");n.parent().attr("title",i.lang.toolbar.unwatch),n.removeClass(o).addClass(r)}return this.codeMirror.css("border-right","none").width(this.editor.width()),this.resize(),i.onunwatch||(i.onunwatch=t||function(){}),e.proxy(i.onunwatch,this)(),this},show:function(t){t=t||function(){};var i=this;return this.editor.show(0,function(){e.proxy(t,i)()}),this},hide:function(t){t=t||function(){};var i=this;return this.editor.hide(0,function(){e.proxy(t,i)()}),this},previewing:function(){var i=this,o=this.editor,r=this.preview,n=this.toolbar,a=this.settings,s=this.codeMirror,l=this.previewContainer;if(e.inArray(a.mode,["gfm","markdown"])<0)return this;a.toolbar&&n&&(n.toggle(),n.find(".fa[name=preview]").toggleClass("active")),s.toggle();var c=function(e){e.shiftKey&&27===e.keyCode&&i.previewed()};"none"===s.css("display")?(this.state.preview=!0,this.state.fullscreen&&r.css("background","#fff"),o.find("."+this.classPrefix+"preview-close-btn").show().bind(t.mouseOrTouch("click","touchend"),function(){i.previewed()}),a.watch?l.css("padding",""):this.save(),l.addClass(this.classPrefix+"preview-active"),r.show().css({position:"",top:0,width:o.width(),height:a.autoHeight&&!this.state.fullscreen?"auto":o.height()}),this.state.loaded&&e.proxy(a.onpreviewing,this)(),e(window).bind("keyup",c)):(e(window).unbind("keyup",c),this.previewed())},previewed:function(){var i=this.editor,o=this.preview,r=this.toolbar,n=this.settings,a=this.previewContainer,s=i.find("."+this.classPrefix+"preview-close-btn");return this.state.preview=!1,this.codeMirror.show(),n.toolbar&&r.show(),o[n.watch?"show":"hide"](),s.hide().unbind(t.mouseOrTouch("click","touchend")),a.removeClass(this.classPrefix+"preview-active"),n.watch&&a.css("padding","20px"),o.css({background:null,position:"absolute",width:i.width()/2,height:n.autoHeight&&!this.state.fullscreen?"auto":i.height()-r.height(),top:n.toolbar?r.height():0}),this.state.loaded&&e.proxy(n.onpreviewed,this)(),this},fullscreen:function(){var t=this,i=this.state,o=this.editor,r=(this.preview,this.toolbar),n=this.settings,a=this.classPrefix+"fullscreen";r&&r.find(".fa[name=fullscreen]").parent().toggleClass("active");var s=function(e){e.shiftKey||27!==e.keyCode||i.fullscreen&&t.fullscreenExit()};return o.hasClass(a)?(e(window).unbind("keyup",s),this.fullscreenExit()):(i.fullscreen=!0,e("html,body").css("overflow","hidden"),o.css({width:e(window).width(),height:e(window).height()}).addClass(a),this.resize(),e.proxy(n.onfullscreen,this)(),e(window).bind("keyup",s)),this},fullscreenExit:function(){var t=this.editor,i=this.settings,o=this.toolbar,r=this.classPrefix+"fullscreen";return this.state.fullscreen=!1,o&&o.find(".fa[name=fullscreen]").parent().removeClass("active"),e("html,body").css("overflow",""),t.css({width:t.data("oldWidth"),height:t.data("oldHeight")}).removeClass(r),this.resize(),e.proxy(i.onfullscreenExit,this)(),this},executePlugin:function(i,o){var r=this,n=this.cm,a=this.settings;return o=a.pluginPath+o,"function"==typeof define?"undefined"==typeof this[i]?(alert("Error: "+i+" plugin is not found, you are not load this plugin."),this):(this[i](n),this):(e.inArray(o,t.loadFiles.plugin)<0?t.loadPlugin(o,function(){t.loadPlugins[i]=r[i],r[i](n)}):e.proxy(t.loadPlugins[i],this)(n),this)},search:function(e){var t=this.settings;return t.searchReplace?(t.readOnly||this.cm.execCommand(e||"find"),this):(alert("Error: settings.searchReplace == false"),this)},searchReplace:function(){return this.search("replace"),this},searchReplaceAll:function(){return this.search("replaceAll"),this}},t.fn.init.prototype=t.fn,t.dialogLockScreen=function(){var t=this.settings||{dialogLockScreen:!0};t.dialogLockScreen&&(e("html,body").css("overflow","hidden"),this.resize())},t.dialogShowMask=function(t){var i=this.editor,o=this.settings||{dialogShowMask:!0};t.css({top:(e(window).height()-t.height())/2+"px",left:(e(window).width()-t.width())/2+"px"}),o.dialogShowMask&&i.children("."+this.classPrefix+"mask").css("z-index",parseInt(t.css("z-index"))-1).show()},t.toolbarHandlers={undo:function(){this.cm.undo()},redo:function(){this.cm.redo()},bold:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection(); + +e.replaceSelection("**"+i+"**"),""===i&&e.setCursor(t.line,t.ch+2)},del:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("~~"+i+"~~"),""===i&&e.setCursor(t.line,t.ch+2)},italic:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("*"+i+"*"),""===i&&e.setCursor(t.line,t.ch+1)},quote:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("> "+i),e.setCursor(t.line,t.ch+2)):e.replaceSelection("> "+i)},ucfirst:function(){var e=this.cm,i=e.getSelection(),o=e.listSelections();e.replaceSelection(t.firstUpperCase(i)),e.setSelections(o)},ucwords:function(){var e=this.cm,i=e.getSelection(),o=e.listSelections();e.replaceSelection(t.wordsFirstUpperCase(i)),e.setSelections(o)},uppercase:function(){var e=this.cm,t=e.getSelection(),i=e.listSelections();e.replaceSelection(t.toUpperCase()),e.setSelections(i)},lowercase:function(){var e=this.cm,t=(e.getCursor(),e.getSelection()),i=e.listSelections();e.replaceSelection(t.toLowerCase()),e.setSelections(i)},h1:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("# "+i),e.setCursor(t.line,t.ch+2)):e.replaceSelection("# "+i)},h2:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("## "+i),e.setCursor(t.line,t.ch+3)):e.replaceSelection("## "+i)},h3:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("### "+i),e.setCursor(t.line,t.ch+4)):e.replaceSelection("### "+i)},h4:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("#### "+i),e.setCursor(t.line,t.ch+5)):e.replaceSelection("#### "+i)},h5:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("##### "+i),e.setCursor(t.line,t.ch+6)):e.replaceSelection("##### "+i)},h6:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("###### "+i),e.setCursor(t.line,t.ch+7)):e.replaceSelection("###### "+i)},"list-ul":function(){var e=this.cm,t=(e.getCursor(),e.getSelection());if(""===t)e.replaceSelection("- "+t);else{for(var i=t.split("\n"),o=0,r=i.length;r>o;o++)i[o]=""===i[o]?"":"- "+i[o];e.replaceSelection(i.join("\n"))}},"list-ol":function(){var e=this.cm,t=(e.getCursor(),e.getSelection());if(""===t)e.replaceSelection("1. "+t);else{for(var i=t.split("\n"),o=0,r=i.length;r>o;o++)i[o]=""===i[o]?"":o+1+". "+i[o];e.replaceSelection(i.join("\n"))}},hr:function(){{var e=this.cm,t=e.getCursor();e.getSelection()}e.replaceSelection((0!==t.ch?"\n\n":"\n")+"------------\n\n")},tex:function(){if(!this.settings.tex)return alert("settings.tex === false"),this;var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("$$"+i+"$$"),""===i&&e.setCursor(t.line,t.ch+2)},link:function(){this.executePlugin("linkDialog","link-dialog/link-dialog")},"reference-link":function(){this.executePlugin("referenceLinkDialog","reference-link-dialog/reference-link-dialog")},pagebreak:function(){if(!this.settings.pageBreak)return alert("settings.pageBreak === false"),this;{var e=this.cm;e.getSelection()}e.replaceSelection("\r\n[========]\r\n")},image:function(){this.executePlugin("imageDialog","image-dialog/image-dialog")},code:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("`"+i+"`"),""===i&&e.setCursor(t.line,t.ch+1)},"code-block":function(){this.executePlugin("codeBlockDialog","code-block-dialog/code-block-dialog")},"preformatted-text":function(){this.executePlugin("preformattedTextDialog","preformatted-text-dialog/preformatted-text-dialog")},table:function(){this.executePlugin("tableDialog","table-dialog/table-dialog")},datetime:function(){var e=this.cm,i=(e.getSelection(),new Date,this.settings.lang.name),o=t.dateFormat()+" "+t.dateFormat("zh-cn"===i||"zh-tw"===i?"cn-week-day":"week-day");e.replaceSelection(o)},emoji:function(){this.executePlugin("emojiDialog","emoji-dialog/emoji-dialog")},"html-entities":function(){this.executePlugin("htmlEntitiesDialog","html-entities-dialog/html-entities-dialog")},"goto-line":function(){this.executePlugin("gotoLineDialog","goto-line-dialog/goto-line-dialog")},watch:function(){this[this.settings.watch?"unwatch":"watch"]()},preview:function(){this.previewing()},fullscreen:function(){this.fullscreen()},clear:function(){this.clear()},search:function(){this.search()},help:function(){this.executePlugin("helpDialog","help-dialog/help-dialog")},info:function(){this.showInfoDialog()}},t.keyMaps={"Ctrl-1":"h1","Ctrl-2":"h2","Ctrl-3":"h3","Ctrl-4":"h4","Ctrl-5":"h5","Ctrl-6":"h6","Ctrl-B":"bold","Ctrl-D":"datetime","Ctrl-E":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();return this.settings.emoji?(e.replaceSelection(":"+i+":"),void(""===i&&e.setCursor(t.line,t.ch+1))):void alert("Error: settings.emoji == false")},"Ctrl-Alt-G":"goto-line","Ctrl-H":"hr","Ctrl-I":"italic","Ctrl-K":"code","Ctrl-L":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection(),o=""===i?"":' "'+i+'"';e.replaceSelection("["+i+"]("+o+")"),""===i&&e.setCursor(t.line,t.ch+1)},"Ctrl-U":"list-ul","Shift-Ctrl-A":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();return this.settings.atLink?(e.replaceSelection("@"+i),void(""===i&&e.setCursor(t.line,t.ch+1))):void alert("Error: settings.atLink == false")},"Shift-Ctrl-C":"code","Shift-Ctrl-Q":"quote","Shift-Ctrl-S":"del","Shift-Ctrl-K":"tex","Shift-Alt-C":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection(["```",i,"```"].join("\n")),""===i&&e.setCursor(t.line,t.ch+3)},"Shift-Ctrl-Alt-C":"code-block","Shift-Ctrl-H":"html-entities","Shift-Alt-H":"help","Shift-Ctrl-E":"emoji","Shift-Ctrl-U":"uppercase","Shift-Alt-U":"ucwords","Shift-Ctrl-Alt-U":"ucfirst","Shift-Alt-L":"lowercase","Shift-Ctrl-I":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection(),o=""===i?"":' "'+i+'"';e.replaceSelection("!["+i+"]("+o+")"),""===i&&e.setCursor(t.line,t.ch+4)},"Shift-Ctrl-Alt-I":"image","Shift-Ctrl-L":"link","Shift-Ctrl-O":"list-ol","Shift-Ctrl-P":"preformatted-text","Shift-Ctrl-T":"table","Shift-Alt-P":"pagebreak",F9:"watch",F10:"preview",F11:"fullscreen"};var r=function(e){return String.prototype.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")};t.trim=r;var n=function(e){return e.toLowerCase().replace(/\b(\w)|\s(\w)/g,function(e){return e.toUpperCase()})};t.ucwords=t.wordsFirstUpperCase=n;var a=function(e){return e.toLowerCase().replace(/\b(\w)/,function(e){return e.toUpperCase()})};return t.firstUpperCase=t.ucfirst=a,t.urls={atLinkBase:"https://github.com/"},t.regexs={atLink:/@(\w+)/g,email:/(\w+)@(\w+)\.(\w+)\.?(\w+)?/g,emailLink:/(mailto:)?([\w\.\_]+)@(\w+)\.(\w+)\.?(\w+)?/g,emoji:/:([\w\+-]+):/g,emojiDatetime:/(\d{2}:\d{2}:\d{2})/g,twemoji:/:(tw-([\w]+)-?(\w+)?):/g,fontAwesome:/:(fa-([\w]+)(-(\w+)){0,}):/g,editormdLogo:/:(editormd-logo-?(\w+)?):/g,pageBreak:/^\[[=]{8,}\]$/},t.emoji={path:"http://www.emoji-cheat-sheet.com/graphics/emojis/",ext:".png"},t.twemoji={path:"http://twemoji.maxcdn.com/36x36/",ext:".png"},t.markedRenderer=function(i,o){var n={toc:!0,tocm:!1,tocStartLevel:1,pageBreak:!0,atLink:!0,emailLink:!0,taskList:!1,emoji:!1,tex:!1,flowChart:!1,sequenceDiagram:!1},a=e.extend(n,o||{}),s=t.$marked,l=new s.Renderer;i=i||[];var c=t.regexs,h=c.atLink,d=c.emoji,u=c.email,f=c.emailLink,g=c.twemoji,p=c.fontAwesome,m=c.editormdLogo,w=c.pageBreak;return l.emoji=function(e){e=e.replace(t.regexs.emojiDatetime,function(e){return e.replace(/:/g,":")});var i=e.match(d);if(!i||!a.emoji)return e;for(var o=0,r=i.length;r>o;o++)":+1:"===i[o]&&(i[o]=":\\+1:"),e=e.replace(new RegExp(i[o]),function(e,i){var o=e.match(p),r=e.replace(/:/g,"");if(o)for(var n=0,a=o.length;a>n;n++){var s=o[n].replace(/:/g,"");return''}else{var l=e.match(m),c=e.match(g);if(l)for(var h=0,d=l.length;d>h;h++){var u=l[h].replace(/:/g,"");return''}else{if(!c){var f="+1"===r?"plus1":r;return f="black_large_square"===f?"black_square":f,f="moon"===f?"waxing_gibbous_moon":f,':'+r+':'}for(var w=0,v=c.length;v>w;w++){var k=c[w].replace(/:/g,"").replace("tw-","");return'twemoji-'+k+''}}}});return e},l.atLink=function(i){return h.test(i)?(a.atLink&&(i=i.replace(u,function(e,t,i,o){return e.replace(/@/g,"_#_@_#_")}),i=i.replace(h,function(e,i){return''+e+""}).replace(/_#_@_#_/g,"@")),a.emailLink&&(i=i.replace(f,function(t,i,o,r,n){return!i&&e.inArray(n,"jpg|jpeg|png|gif|webp|ico|icon|pdf".split("|"))<0?''+t+"":t})),i):i},l.link=function(e,t,i){if(this.options.sanitize){try{var o=decodeURIComponent(unescape(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(r){return""}if(0===o.indexOf("javascript:"))return""}var n=''+i.replace(/@/g,"@")+""):(t&&(n+=' title="'+t+'"'),n+=">"+i+"")},l.heading=function(e,t,o){var n=e,a=/\s*\]*)\>(.*)\<\/a\>\s*/;if(a.test(e)){var s=[];e=e.split(/\]+)\>([^\>]*)\<\/a\>/);for(var l=0,c=e.length;c>l;l++)s.push(e[l].replace(/\s*href\=\"(.*)\"\s*/g,""));e=s.join(" ")}e=r(e);var h=e.toLowerCase().replace(/[^\w]+/g,"-"),d={text:e,level:t,slug:h},u=/^[\u4e00-\u9fa5]+$/.test(e),f=u?escape(e).replace(/\%/g,""):e.toLowerCase().replace(/[^\w]+/g,"-");i.push(d);var g="';return g+='',g+='',g+=this.atLink(a?this.emoji(n):this.emoji(e)),g+=""},l.pageBreak=function(e){return w.test(e)&&a.pageBreak&&(e='
              '),e},l.paragraph=function(e){var i=/\$\$(.*)\$\$/g.test(e),o=/^\$\$(.*)\$\$$/.test(e),r=o?' class="'+t.classNames.tex+'"':"",n=a.tocm?/^(\[TOC\]|\[TOCM\])$/.test(e):/^\[TOC\]$/.test(e),s=/^\[TOCM\]$/.test(e);e=!o&&i?e.replace(/(\$\$([^\$]*)\$\$)+/g,function(e,i){return''+i.replace(/\$/g,"")+""}):o?e.replace(/\$/g,""):e;var l='
              '+e+"
              ";return n?s?'
              '+l+"

              ":l:w.test(e)?this.pageBreak(e):""+this.atLink(this.emoji(e))+"

              \n"},l.code=function(e,i,o){return"seq"===i||"sequence"===i?'
              '+e+"
              ":"flow"===i?'
              '+e+"
              ":"math"===i||"latex"===i||"katex"===i?'

              '+e+"

              ":s.Renderer.prototype.code.apply(this,arguments)},l.tablecell=function(e,t){var i=t.header?"th":"td",o=t.align?"<"+i+' style="text-align:'+t.align+'">':"<"+i+">";return o+this.atLink(this.emoji(e))+"\n"},l.listitem=function(e){return a.taskList&&/^\s*\[[x\s]\]\s*/.test(e)?(e=e.replace(/^\s*\[\s\]\s*/,' ').replace(/^\s*\[x\]\s*/,' '),'
            • '+this.atLink(this.emoji(e))+"
            • "):"
            • "+this.atLink(this.emoji(e))+"
            • "},l},t.markdownToCRenderer=function(e,t,i,o){var r="",n=0,a=this.classPrefix;o=o||1;for(var s=0,l=e.length;l>s;s++){var c=e[s].text,h=e[s].level;o>h||(r+=h>n?"":n>h?new Array(n-h+2).join("
          • "):"",r+='
          • '+c+"
              ",n=h)}var d=t.find(".markdown-toc");if(d.length<1&&"false"===t.attr("previewContainer")){var u='
              ';u=i?'
              '+u+"
              ":u,t.html(u),d=t.find(".markdown-toc")}return i&&d.wrap('

              '),d.html('
                ').children(".markdown-toc-list").html(r.replace(/\r?\n?\\<\/ul\>/g,"")),d},t.tocDropdownMenu=function(t,i){i=i||"Table of Contents";var o=400,r=t.find("."+this.classPrefix+"toc-menu");return r.each(function(){var t=e(this),r=t.children(".markdown-toc"),n='',a=''+n+i+"",s=r.children("ul"),l=s.find("li");r.append(a),l.first().before("
              • "+i+" "+n+"

              • "),t.mouseover(function(){s.show(),l.each(function(){var t=e(this),i=t.children("ul");if(""===i.html()&&i.remove(),i.length>0&&""!==i.html()){var r=t.children("a").first();r.children(".fa").length<1&&r.append(e(n).css({"float":"right",paddingTop:"4px"}))}t.mouseover(function(){i.css("z-index",o).show(),o+=1}).mouseleave(function(){i.hide()})})}).mouseleave(function(){s.hide()})}),r},t.filterHTMLTags=function(t,i){if("string"!=typeof t&&(t=new String(t)),"string"!=typeof i)return t;for(var o=i.split("|"),r=o[0].split(","),n=o[1],a=0,s=r.length;s>a;a++){var l=r[a];t=t.replace(new RegExp("]*)>([^>]*)","igm"),"")}if("undefined"!=typeof n){var c=/\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/gi;t="*"===n?t.replace(c,function(e,t,i,o,r){return"<"+t+">"+o+""}):"on*"===n?t.replace(c,function(t,i,o,r,n){var a=e("<"+i+">"+r+""),s=e(t)[0].attributes,l={};e.each(s,function(e,t){'"'!==t.nodeName&&(l[t.nodeName]=t.nodeValue)}),e.each(l,function(e){0===e.indexOf("on")&&delete l[e]}),a.attr(l);var c="undefined"!=typeof a[1]?e(a[1]).text():"";return a[0].outerHTML+c}):t.replace(c,function(t,i,o,r){var a=n.split(","),s=e(t);return s.html(r),e.each(a,function(e){s.attr(a[e],null)}),s[0].outerHTML})}return t},t.markdownToHTML=function(i,o){var r={gfm:!0,toc:!0,tocm:!1,tocStartLevel:1,tocTitle:"目录",tocDropdown:!1,tocContainer:"",markdown:"",markdownSourceCode:!1,htmlDecode:!1,autoLoadKaTeX:!0,pageBreak:!0,atLink:!0,emailLink:!0,tex:!1,taskList:!1,emoji:!1,flowChart:!1,sequenceDiagram:!1,previewCodeHighlight:!0};t.$marked=marked;var n=e("#"+i),a=n.settings=e.extend(!0,r,o||{}),s=n.find("textarea");s.length<1&&(n.append(""),s=n.find("textarea"));var l=""===a.markdown?s.val():a.markdown,c=[],h={toc:a.toc,tocm:a.tocm,tocStartLevel:a.tocStartLevel,taskList:a.taskList,emoji:a.emoji,tex:a.tex,pageBreak:a.pageBreak,atLink:a.atLink,emailLink:a.emailLink,flowChart:a.flowChart,sequenceDiagram:a.sequenceDiagram,previewCodeHighlight:a.previewCodeHighlight},d={renderer:t.markedRenderer(c,h),gfm:a.gfm,tables:!0,breaks:!0,pedantic:!1,sanitize:a.htmlDecode?!1:!0,smartLists:!0,smartypants:!0};l=new String(l);var u=marked(l,d);u=t.filterHTMLTags(u,a.htmlDecode),a.markdownSourceCode?s.text(l):s.remove(),n.addClass("markdown-body "+this.classPrefix+"html-preview").append(u);var f=""!==a.tocContainer?e(a.tocContainer):n;if(""!==a.tocContainer&&f.attr("previewContainer",!1),a.toc&&(n.tocContainer=this.markdownToCRenderer(c,f,a.tocDropdown,a.tocStartLevel),(a.tocDropdown||n.find("."+this.classPrefix+"toc-menu").length>0)&&this.tocDropdownMenu(n,a.tocTitle),""!==a.tocContainer&&n.find(".editormd-toc-menu, .editormd-markdown-toc").remove()),a.previewCodeHighlight&&(n.find("pre").addClass("prettyprint linenums"),prettyPrint()),t.isIE8||(a.flowChart&&n.find(".flowchart").flowChart(),a.sequenceDiagram&&n.find(".sequence-diagram").sequenceDiagram({theme:"simple"})),a.tex){var g=function(){n.find("."+t.classNames.tex).each(function(){var t=e(this);katex.render(t.html().replace(/</g,"<").replace(/>/g,">"),t[0]),t.find(".katex").css("font-size","1.6em")})};!a.autoLoadKaTeX||t.$katex||t.kaTeXLoaded?g():this.loadKaTeX(function(){t.$katex=katex,t.kaTeXLoaded=!0,g()})}return n.getMarkdown=function(){return s.val()},n},t.themes=["default","dark"],t.previewThemes=["default","dark"],t.editorThemes=["default","3024-day","3024-night","ambiance","ambiance-mobile","base16-dark","base16-light","blackboard","cobalt","eclipse","elegant","erlang-dark","lesser-dark","mbo","mdn-like","midnight","monokai","neat","neo","night","paraiso-dark","paraiso-light","pastel-on-dark","rubyblue","solarized","the-matrix","tomorrow-night-eighties","twilight","vibrant-ink","xq-dark","xq-light"],t.loadPlugins={},t.loadFiles={js:[],css:[],plugin:[]},t.loadPlugin=function(e,i,o){i=i||function(){},this.loadScript(e,function(){t.loadFiles.plugin.push(e),i()},o)},t.loadCSS=function(e,i,o){o=o||"head",i=i||function(){};var r=document.createElement("link");r.type="text/css",r.rel="stylesheet",r.onload=r.onreadystatechange=function(){t.loadFiles.css.push(e),i()},r.href=e+".css","head"===o?document.getElementsByTagName("head")[0].appendChild(r):document.body.appendChild(r)},t.isIE="Microsoft Internet Explorer"==navigator.appName,t.isIE8=t.isIE&&"8."==navigator.appVersion.match(/8./i),t.loadScript=function(e,i,o){o=o||"head",i=i||function(){};var r=null;r=document.createElement("script"),r.id=e.replace(/[\./]+/g,"-"),r.type="text/javascript",r.src=e+".js",t.isIE8?r.onreadystatechange=function(){r.readyState&&("loaded"===r.readyState||"complete"===r.readyState)&&(r.onreadystatechange=null,t.loadFiles.js.push(e),i())}:r.onload=function(){t.loadFiles.js.push(e),i()},"head"===o?document.getElementsByTagName("head")[0].appendChild(r):document.body.appendChild(r)},t.katexURL={css:"//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min",js:"//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min"},t.kaTeXLoaded=!1,t.loadKaTeX=function(e){t.loadCSS(t.katexURL.css,function(){t.loadScript(t.katexURL.js,e||function(){})})},t.lockScreen=function(t){e("html,body").css("overflow",t?"hidden":"")},t.createDialog=function(i){var o={name:"",width:420,height:240,title:"",drag:!0,closed:!0,content:"",mask:!0,maskStyle:{backgroundColor:"#fff",opacity:.1},lockScreen:!0,footer:!0,buttons:!1};i=e.extend(!0,o,i);var r=this,n=this.editor,a=t.classPrefix,s=(new Date).getTime(),l=""===i.name?a+"dialog-"+s:i.name,c=t.mouseOrTouch,h='
                ';""!==i.title&&(h+='
                ",h+=''+i.title+"",h+="
                "),i.closed&&(h+=''),h+='
                '+i.content,(i.footer||"string"==typeof i.footer)&&(h+='"),h+="
                ",h+='
                ',h+='
                ',h+="
                ",n.append(h);var d=n.find("."+l);d.lockScreen=function(t){return i.lockScreen&&(e("html,body").css("overflow",t?"hidden":""),r.resize()),d},d.showMask=function(){return i.mask&&n.find("."+a+"mask").css(i.maskStyle).css("z-index",t.dialogZindex-1).show(),d},d.hideMask=function(){return i.mask&&n.find("."+a+"mask").hide(),d},d.loading=function(e){var t=d.find("."+a+"dialog-mask");return t[e?"show":"hide"](),d},d.lockScreen(!0).showMask(),d.show().css({zIndex:t.dialogZindex,border:t.isIE8?"1px solid #ddd":"",width:"number"==typeof i.width?i.width+"px":i.width,height:"number"==typeof i.height?i.height+"px":i.height});var u=function(){d.css({top:(e(window).height()-d.height())/2+"px",left:(e(window).width()-d.width())/2+"px"})};if(u(),e(window).resize(u),d.children("."+a+"dialog-close").bind(c("click","touchend"),function(){d.hide().lockScreen(!1).hideMask()}),"object"==typeof i.buttons){var f=d.footer=d.find("."+a+"dialog-footer");for(var g in i.buttons){var p=i.buttons[g],m=a+g+"-btn";f.append('"),p[1]=e.proxy(p[1],d),f.children("."+m).bind(c("click","touchend"),p[1])}}if(""!==i.title&&i.drag){var w,v,k=d.children("."+a+"dialog-header");i.mask||k.bind(c("click","touchend"),function(){t.dialogZindex+=2,d.css("z-index",t.dialogZindex)}),k.mousedown(function(e){e=e||window.event,w=e.clientX-parseInt(d[0].style.left),v=e.clientY-parseInt(d[0].style.top),document.onmousemove=y});var b=function(e){e.removeClass(a+"user-unselect").off("selectstart")},x=function(e){e.addClass(a+"user-unselect").on("selectstart",function(e){return!1})},y=function(t){t=t||window.event;var i,o,r=parseInt(d[0].style.left),n=parseInt(d[0].style.top);r>=0?r+d.width()<=e(window).width()?i=t.clientX-w:(i=e(window).width()-d.width(),document.onmousemove=null):(i=0,document.onmousemove=null),n>=0?o=t.clientY-v:(o=0,document.onmousemove=null),document.onselectstart=function(){return!1},x(e("body")),x(d),d[0].style.left=i+"px",d[0].style.top=o+"px"};document.onmouseup=function(){b(e("body")),b(d),document.onselectstart=null,document.onmousemove=null},k.touchDraggable=function(){var t=null,i=function(i){var o=i.originalEvent,r=e(this).parent().position();t={x:o.changedTouches[0].pageX-r.left,y:o.changedTouches[0].pageY-r.top}},o=function(i){i.preventDefault();var o=i.originalEvent;e(this).parent().css({top:o.changedTouches[0].pageY-t.y,left:o.changedTouches[0].pageX-t.x})};this.bind("touchstart",i).bind("touchmove",o)},k.touchDraggable()}return t.dialogZindex+=2,d},t.mouseOrTouch=function(e,t){e=e||"click",t=t||"touchend";var i=e;try{document.createEvent("TouchEvent"),i=t}catch(o){}return i},t.dateFormat=function(e){e=e||"";var t=function(e){return 10>e?"0"+e:e},i=new Date,o=i.getFullYear(),r=o.toString().slice(2,4),n=t(i.getMonth()+1),a=t(i.getDate()),s=i.getDay(),l=t(i.getHours()),c=t(i.getMinutes()),h=t(i.getSeconds()),d=t(i.getMilliseconds()),u="",f=r+"-"+n+"-"+a,g=o+"-"+n+"-"+a,p=l+":"+c+":"+h;switch(e){case"UNIX Time":u=i.getTime();break;case"UTC":u=i.toUTCString();break;case"yy":u=r;break;case"year":case"yyyy":u=o;break;case"month":case"mm":u=n;break;case"cn-week-day":case"cn-wd":var m=["日","一","二","三","四","五","六"];u="星期"+m[s];break;case"week-day":case"wd":var w=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];u=w[s];break;case"day":case"dd":u=a;break;case"hour":case"hh":u=l;break;case"min":case"ii":u=c;break;case"second":case"ss":u=h;break;case"ms":u=d;break;case"yy-mm-dd":u=f;break;case"yyyy-mm-dd":u=g;break;case"yyyy-mm-dd h:i:s ms":case"full + ms":u=g+" "+p+" "+d;break;case"full":case"yyyy-mm-dd h:i:s":default:u=g+" "+p}return u},t}}); \ No newline at end of file diff --git a/public/editormd/editormd.js b/public/editormd/editormd.js new file mode 100644 index 000000000..f3eb80a70 --- /dev/null +++ b/public/editormd/editormd.js @@ -0,0 +1,4664 @@ +/* + * Editor.md + * + * @file editormd.js + * @version v1.5.0 + * @description Open source online markdown editor. + * @license MIT License + * @author Pandao + * {@link https://github.com/pandao/editor.md} + * @updateTime 2015-06-09 + */ + +;(function(factory) { + "use strict"; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) // for Require.js + { + /* Require.js define replace */ + } + else + { + define(["jquery"], factory); // for Sea.js + } + } + else + { + window.editormd = factory(); + } + +}(function() { + + /* Require.js assignment replace */ + + "use strict"; + + var $ = (typeof (jQuery) !== "undefined") ? jQuery : Zepto; + + if (typeof ($) === "undefined") { + return ; + } + + /** + * editormd + * + * @param {String} id 编辑器的ID + * @param {Object} options 配置选项 Key/Value + * @returns {Object} editormd 返回editormd对象 + */ + + var editormd = function (id, options) { + return new editormd.fn.init(id, options); + }; + + editormd.title = editormd.$name = "Editor.md"; + editormd.version = "1.5.0"; + editormd.homePage = "https://pandao.github.io/editor.md/"; + editormd.classPrefix = "editormd-"; + + editormd.toolbarModes = { + full : [ + "undo", "redo", "|", + "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|", + "h1", "h2", "h3", "h4", "h5", "h6", "|", + "list-ul", "list-ol", "hr", "|", + "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|", + "goto-line", "watch", "preview", "fullscreen", "clear", "search", "|", + "help", "info" + ], + simple : [ + "undo", "redo", "|", + "bold", "del", "italic", "quote", "uppercase", "lowercase", "|", + "h1", "h2", "h3", "h4", "h5", "h6", "|", + "list-ul", "list-ol", "hr", "|", + "watch", "preview", "fullscreen", "|", + "help", "info" + ], + mini : [ + "undo", "redo", "|", + "watch", "preview", "|", + "help", "info" + ] + }; + + editormd.defaults = { + mode : "gfm", //gfm or markdown + name : "", // Form element name + value : "", // value for CodeMirror, if mode not gfm/markdown + theme : "", // Editor.md self themes, before v1.5.0 is CodeMirror theme, default empty + editorTheme : "default", // Editor area, this is CodeMirror theme at v1.5.0 + previewTheme : "", // Preview area theme, default empty + markdown : "", // Markdown source code + appendMarkdown : "", // if in init textarea value not empty, append markdown to textarea + width : "100%", + height : "100%", + path : "./lib/", // Dependents module file directory + pluginPath : "", // If this empty, default use settings.path + "../plugins/" + delay : 300, // Delay parse markdown to html, Uint : ms + autoLoadModules : true, // Automatic load dependent module files + watch : true, + placeholder : "Enjoy Markdown! coding now...", + gotoLine : true, + codeFold : false, + autoHeight : false, + autoFocus : true, + autoCloseTags : true, + searchReplace : true, + syncScrolling : true, // true | false | "single", default true + readOnly : false, + tabSize : 4, + indentUnit : 4, + lineNumbers : true, + lineWrapping : true, + autoCloseBrackets : true, + showTrailingSpace : true, + matchBrackets : true, + indentWithTabs : true, + styleSelectedText : true, + matchWordHighlight : true, // options: true, false, "onselected" + styleActiveLine : true, // Highlight the current line + dialogLockScreen : true, // false, // true, + dialogShowMask : true, + dialogDraggable : true, + dialogMaskBgColor : "#fff", + dialogMaskOpacity : 0.1, + fontSize : "13px", + saveHTMLToTextarea : false, + disabledKeyMaps : [], + + onload : function() {}, + onresize : function() {}, + onchange : function() {}, + onwatch : null, + onunwatch : null, + onpreviewing : function() {}, + onpreviewed : function() {}, + onfullscreen : function() {}, + onfullscreenExit : function() {}, + onscroll : function() {}, + onpreviewscroll : function() {}, + + imageUpload : false, + imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"], + imageUploadURL : "", + crossDomainUpload : false, + uploadCallbackURL : "", + + toc : true, // Table of contents + tocm : false, // Using [TOCM], auto create ToC dropdown menu + tocTitle : "", // for ToC dropdown menu btn + tocDropdown : false, + tocContainer : "", + tocStartLevel : 1, // Said from H1 to create ToC + htmlDecode : "style,iframe|on*", // Open the HTML tag identification + pageBreak : true, // Enable parse page break [========] + atLink : true, // for @link + emailLink : true, // for email address auto link + taskList : false, // Enable Github Flavored Markdown task lists + emoji : false, // :emoji: , Support Github emoji, Twitter Emoji (Twemoji); + // Support FontAwesome icon emoji :fa-xxx: > Using fontAwesome icon web fonts; + // Support Editor.md logo icon emoji :editormd-logo: :editormd-logo-1x: > 1~8x; + tex : false, // TeX(LaTeX), based on KaTeX + flowChart : false, // flowChart.js only support IE9+ + sequenceDiagram : false, // sequenceDiagram.js only support IE9+ + previewCodeHighlight : true, + + toolbar : true, // show/hide toolbar + toolbarAutoFixed : true, // on window scroll auto fixed position + toolbarIcons : "full", + toolbarTitles : {}, + toolbarHandlers : { + ucwords : function() { + return editormd.toolbarHandlers.ucwords; + }, + lowercase : function() { + return editormd.toolbarHandlers.lowercase; + } + }, + toolbarCustomIcons : { // using html tag create toolbar icon, unused default tag. + lowercase : "a", + "ucwords" : "Aa" + }, + toolbarIconsClass : { + undo : "fa-undo", + redo : "fa-repeat", + bold : "fa-bold", + del : "fa-strikethrough", + italic : "fa-italic", + quote : "fa-quote-left", + uppercase : "fa-font", + h1 : editormd.classPrefix + "bold", + h2 : editormd.classPrefix + "bold", + h3 : editormd.classPrefix + "bold", + h4 : editormd.classPrefix + "bold", + h5 : editormd.classPrefix + "bold", + h6 : editormd.classPrefix + "bold", + "list-ul" : "fa-list-ul", + "list-ol" : "fa-list-ol", + hr : "fa-minus", + link : "fa-link", + "reference-link" : "fa-anchor", + image : "fa-picture-o", + code : "fa-code", + "preformatted-text" : "fa-file-code-o", + "code-block" : "fa-file-code-o", + table : "fa-table", + datetime : "fa-clock-o", + emoji : "fa-smile-o", + "html-entities" : "fa-copyright", + pagebreak : "fa-newspaper-o", + "goto-line" : "fa-terminal", // fa-crosshairs + watch : "fa-eye-slash", + unwatch : "fa-eye", + preview : "fa-desktop", + search : "fa-search", + fullscreen : "fa-arrows-alt", + clear : "fa-eraser", + help : "fa-question-circle", + info : "fa-info-circle" + }, + toolbarIconTexts : {}, + + lang : { + name : "zh-cn", + description : "开源在线Markdown编辑器
                Open source online Markdown editor.", + tocTitle : "目录", + toolbar : { + undo : "撤销(Ctrl+Z)", + redo : "重做(Ctrl+Y)", + bold : "粗体", + del : "删除线", + italic : "斜体", + quote : "引用", + ucwords : "将每个单词首字母转成大写", + uppercase : "将所选转换成大写", + lowercase : "将所选转换成小写", + h1 : "标题1", + h2 : "标题2", + h3 : "标题3", + h4 : "标题4", + h5 : "标题5", + h6 : "标题6", + "list-ul" : "无序列表", + "list-ol" : "有序列表", + hr : "横线", + link : "链接", + "reference-link" : "引用链接", + image : "添加图片", + code : "行内代码", + "preformatted-text" : "预格式文本 / 代码块(缩进风格)", + "code-block" : "代码块(多语言风格)", + table : "添加表格", + datetime : "日期时间", + emoji : "Emoji表情", + "html-entities" : "HTML实体字符", + pagebreak : "插入分页符", + "goto-line" : "跳转到行", + watch : "关闭实时预览", + unwatch : "开启实时预览", + preview : "全窗口预览HTML(按 Shift + ESC还原)", + fullscreen : "全屏(按ESC还原)", + clear : "清空", + search : "搜索", + help : "使用帮助", + info : "关于" + editormd.title + }, + buttons : { + enter : "确定", + cancel : "取消", + close : "关闭" + }, + dialog : { + link : { + title : "添加链接", + url : "链接地址", + urlTitle : "链接标题", + urlEmpty : "错误:请填写链接地址。" + }, + referenceLink : { + title : "添加引用链接", + name : "引用名称", + url : "链接地址", + urlId : "链接ID", + urlTitle : "链接标题", + nameEmpty: "错误:引用链接的名称不能为空。", + idEmpty : "错误:请填写引用链接的ID。", + urlEmpty : "错误:请填写引用链接的URL地址。" + }, + image : { + title : "添加图片", + url : "图片地址", + link : "图片链接", + alt : "图片描述", + uploadButton : "本地上传", + imageURLEmpty : "错误:图片地址不能为空。", + uploadFileEmpty : "错误:上传的图片不能为空。", + formatNotAllowed : "错误:只允许上传图片文件,允许上传的图片文件格式有:" + }, + preformattedText : { + title : "添加预格式文本或代码块", + emptyAlert : "错误:请填写预格式文本或代码的内容。" + }, + codeBlock : { + title : "添加代码块", + selectLabel : "代码语言:", + selectDefaultText : "请选择代码语言", + otherLanguage : "其他语言", + unselectedLanguageAlert : "错误:请选择代码所属的语言类型。", + codeEmptyAlert : "错误:请填写代码内容。" + }, + htmlEntities : { + title : "HTML 实体字符" + }, + help : { + title : "使用帮助" + } + } + } + }; + + editormd.classNames = { + tex : editormd.classPrefix + "tex" + }; + + editormd.dialogZindex = 99999; + + editormd.$katex = null; + editormd.$marked = null; + editormd.$CodeMirror = null; + editormd.$prettyPrint = null; + + var timer, flowchartTimer; + + editormd.prototype = editormd.fn = { + state : { + watching : false, + loaded : false, + preview : false, + fullscreen : false + }, + + /** + * 构造函数/实例初始化 + * Constructor / instance initialization + * + * @param {String} id 编辑器的ID + * @param {Object} [options={}] 配置选项 Key/Value + * @returns {editormd} 返回editormd的实例对象 + */ + + init : function (id, options) { + + options = options || {}; + + if (typeof id === "object") + { + options = id; + } + + var _this = this; + var classPrefix = this.classPrefix = editormd.classPrefix; + var settings = this.settings = $.extend(true, editormd.defaults, options); + + id = (typeof id === "object") ? settings.id : id; + + var editor = this.editor = $("#" + id); + + this.id = id; + this.lang = settings.lang; + + var classNames = this.classNames = { + textarea : { + html : classPrefix + "html-textarea", + markdown : classPrefix + "markdown-textarea" + } + }; + + settings.pluginPath = (settings.pluginPath === "") ? settings.path + "../plugins/" : settings.pluginPath; + + this.state.watching = (settings.watch) ? true : false; + + if ( !editor.hasClass("editormd") ) { + editor.addClass("editormd"); + } + + editor.css({ + width : (typeof settings.width === "number") ? settings.width + "px" : settings.width, + height : (typeof settings.height === "number") ? settings.height + "px" : settings.height + }); + + if (settings.autoHeight) + { + editor.css("height", "auto"); + } + + var markdownTextarea = this.markdownTextarea = editor.children("textarea"); + + if (markdownTextarea.length < 1) + { + editor.append(""); + markdownTextarea = this.markdownTextarea = editor.children("textarea"); + } + + markdownTextarea.addClass(classNames.textarea.markdown).attr("placeholder", settings.placeholder); + + if (typeof markdownTextarea.attr("name") === "undefined" || markdownTextarea.attr("name") === "") + { + markdownTextarea.attr("name", (settings.name !== "") ? settings.name : id + "-markdown-doc"); + } + + var appendElements = [ + (!settings.readOnly) ? "" : "", + ( (settings.saveHTMLToTextarea) ? "" : "" ), + "
                ", + "
                ", + "
                " + ].join("\n"); + + editor.append(appendElements).addClass(classPrefix + "vertical"); + + if (settings.theme !== "") + { + editor.addClass(classPrefix + "theme-" + settings.theme); + } + + this.mask = editor.children("." + classPrefix + "mask"); + this.containerMask = editor.children("." + classPrefix + "container-mask"); + + if (settings.markdown !== "") + { + markdownTextarea.val(settings.markdown); + } + + if (settings.appendMarkdown !== "") + { + markdownTextarea.val(markdownTextarea.val() + settings.appendMarkdown); + } + + this.htmlTextarea = editor.children("." + classNames.textarea.html); + this.preview = editor.children("." + classPrefix + "preview"); + this.previewContainer = this.preview.children("." + classPrefix + "preview-container"); + + if (settings.previewTheme !== "") + { + this.preview.addClass(classPrefix + "preview-theme-" + settings.previewTheme); + } + + if (typeof define === "function" && define.amd) + { + if (typeof katex !== "undefined") + { + editormd.$katex = katex; + } + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(settings.path + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(settings.path + "codemirror/addon/search/matchesonscrollbar"); + } + } + + if ((typeof define === "function" && define.amd) || !settings.autoLoadModules) + { + if (typeof CodeMirror !== "undefined") { + editormd.$CodeMirror = CodeMirror; + } + + if (typeof marked !== "undefined") { + editormd.$marked = marked; + } + + this.setCodeMirror().setToolbar().loadedDisplay(); + } + else + { + this.loadQueues(); + } + + + + return this; + }, + + /** + * 所需组件加载队列 + * Required components loading queue + * + * @returns {editormd} 返回editormd的实例对象 + */ + + loadQueues : function() { + var _this = this; + var settings = this.settings; + var loadPath = settings.path; + + var loadFlowChartOrSequenceDiagram = function() { + + if (editormd.isIE8) + { + _this.loadedDisplay(); + + return ; + } + + if (settings.flowChart || settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "raphael.min", function() { + + editormd.loadScript(loadPath + "underscore.min", function() { + + if (!settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + } + else if (settings.flowChart && !settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + _this.loadedDisplay(); + }); + }); + } + else if (settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + }); + }); + } + }); + + }); + } + else + { + _this.loadedDisplay(); + } + }; + + editormd.loadCSS(loadPath + "codemirror/codemirror.min"); + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(loadPath + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(loadPath + "codemirror/addon/search/matchesonscrollbar"); + } + + if (settings.codeFold) + { + editormd.loadCSS(loadPath + "codemirror/addon/fold/foldgutter"); + } + + editormd.loadScript(loadPath + "codemirror/codemirror.min", function() { + editormd.$CodeMirror = CodeMirror; + + editormd.loadScript(loadPath + "codemirror/modes.min", function() { + + editormd.loadScript(loadPath + "codemirror/addons.min", function() { + + _this.setCodeMirror(); + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + _this.loadedDisplay(); + + return false; + } + + _this.setToolbar(); + + editormd.loadScript(loadPath + "marked.min", function() { + + editormd.$marked = marked; + + if (settings.previewCodeHighlight) + { + editormd.loadScript(loadPath + "prettify.min", function() { + loadFlowChartOrSequenceDiagram(); + }); + } + else + { + loadFlowChartOrSequenceDiagram(); + } + }); + + }); + + }); + + }); + + return this; + }, + + /** + * 设置 Editor.md 的整体主题,主要是工具栏 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setTheme : function(theme) { + var editor = this.editor; + var oldTheme = this.settings.theme; + var themePrefix = this.classPrefix + "theme-"; + + editor.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + this.settings.theme = theme; + + return this; + }, + + /** + * 设置 CodeMirror(编辑区)的主题 + * Setting CodeMirror (Editor area) theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setEditorTheme : function(theme) { + var settings = this.settings; + settings.editorTheme = theme; + + if (theme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + this.cm.setOption("theme", theme); + + return this; + }, + + /** + * setEditorTheme() 的别名 + * setEditorTheme() alias + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorTheme : function (theme) { + this.setEditorTheme(theme); + + return this; + }, + + /** + * 设置 Editor.md 的主题 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setPreviewTheme : function(theme) { + var preview = this.preview; + var oldTheme = this.settings.previewTheme; + var themePrefix = this.classPrefix + "preview-theme-"; + + preview.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + this.settings.previewTheme = theme; + + return this; + }, + + /** + * 配置和初始化CodeMirror组件 + * CodeMirror initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirror : function() { + var settings = this.settings; + var editor = this.editor; + + if (settings.editorTheme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + var codeMirrorConfig = { + mode : settings.mode, + theme : settings.editorTheme, + tabSize : settings.tabSize, + dragDrop : false, + autofocus : settings.autoFocus, + autoCloseTags : settings.autoCloseTags, + readOnly : (settings.readOnly) ? "nocursor" : false, + indentUnit : settings.indentUnit, + lineNumbers : settings.lineNumbers, + lineWrapping : settings.lineWrapping, + extraKeys : { + "Ctrl-Q": function(cm) { + cm.foldCode(cm.getCursor()); + } + }, + foldGutter : settings.codeFold, + gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + matchBrackets : settings.matchBrackets, + indentWithTabs : settings.indentWithTabs, + styleActiveLine : settings.styleActiveLine, + styleSelectedText : settings.styleSelectedText, + autoCloseBrackets : settings.autoCloseBrackets, + showTrailingSpace : settings.showTrailingSpace, + highlightSelectionMatches : ( (!settings.matchWordHighlight) ? false : { showToken: (settings.matchWordHighlight === "onselected") ? false : /\w/ } ) + }; + + this.codeEditor = this.cm = editormd.$CodeMirror.fromTextArea(this.markdownTextarea[0], codeMirrorConfig); + this.codeMirror = this.cmElement = editor.children(".CodeMirror"); + + if (settings.value !== "") + { + this.cm.setValue(settings.value); + } + + this.codeMirror.css({ + fontSize : settings.fontSize, + width : (!settings.watch) ? "100%" : "50%" + }); + + if (settings.autoHeight) + { + this.codeMirror.css("height", "auto"); + this.cm.setOption("viewportMargin", Infinity); + } + + if (!settings.lineNumbers) + { + this.codeMirror.find(".CodeMirror-gutters").css("border-right", "none"); + } + + return this; + }, + + /** + * 获取CodeMirror的配置选项 + * Get CodeMirror setting options + * + * @returns {Mixed} return CodeMirror setting option value + */ + + getCodeMirrorOption : function(key) { + return this.cm.getOption(key); + }, + + /** + * 配置和重配置CodeMirror的选项 + * CodeMirror setting options / resettings + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorOption : function(key, value) { + + this.cm.setOption(key, value); + + return this; + }, + + /** + * 添加 CodeMirror 键盘快捷键 + * Add CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + addKeyMap : function(map, bottom) { + this.cm.addKeyMap(map, bottom); + + return this; + }, + + /** + * 移除 CodeMirror 键盘快捷键 + * Remove CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + removeKeyMap : function(map) { + this.cm.removeKeyMap(map); + + return this; + }, + + /** + * 跳转到指定的行 + * Goto CodeMirror line + * + * @param {String|Intiger} line line number or "first"|"last" + * @returns {editormd} 返回editormd的实例对象 + */ + + gotoLine : function (line) { + + var settings = this.settings; + + if (!settings.gotoLine) + { + return this; + } + + var cm = this.cm; + var editor = this.editor; + var count = cm.lineCount(); + var preview = this.preview; + + if (typeof line === "string") + { + if(line === "last") + { + line = count; + } + + if (line === "first") + { + line = 1; + } + } + + if (typeof line !== "number") + { + alert("Error: The line number must be an integer."); + return this; + } + + line = parseInt(line) - 1; + + if (line > count) + { + alert("Error: The line number range 1-" + count); + + return this; + } + + cm.setCursor( {line : line, ch : 0} ); + + var scrollInfo = cm.getScrollInfo(); + var clientHeight = scrollInfo.clientHeight; + var coords = cm.charCoords({line : line, ch : 0}, "local"); + + cm.scrollTo(null, (coords.top + coords.bottom - clientHeight) / 2); + + if (settings.watch) + { + var cmScroll = this.codeMirror.find(".CodeMirror-scroll")[0]; + var height = $(cmScroll).height(); + var scrollTop = cmScroll.scrollTop; + var percent = (scrollTop / cmScroll.scrollHeight); + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= cmScroll.scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop(preview[0].scrollHeight * percent); + } + } + + cm.focus(); + + return this; + }, + + /** + * 扩展当前实例对象,可同时设置多个或者只设置一个 + * Extend editormd instance object, can mutil setting. + * + * @returns {editormd} this(editormd instance object.) + */ + + extend : function() { + if (typeof arguments[1] !== "undefined") + { + if (typeof arguments[1] === "function") + { + arguments[1] = $.proxy(arguments[1], this); + } + + this[arguments[0]] = arguments[1]; + } + + if (typeof arguments[0] === "object" && typeof arguments[0].length === "undefined") + { + $.extend(true, this, arguments[0]); + } + + return this; + }, + + /** + * 设置或扩展当前实例对象,单个设置 + * Extend editormd instance object, one by one + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + set : function (key, value) { + + if (typeof value !== "undefined" && typeof value === "function") + { + value = $.proxy(value, this); + } + + this[key] = value; + + return this; + }, + + /** + * 重新配置 + * Resetting editor options + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + config : function(key, value) { + var settings = this.settings; + + if (typeof key === "object") + { + settings = $.extend(true, settings, key); + } + + if (typeof key === "string") + { + settings[key] = value; + } + + this.settings = settings; + this.recreate(); + + return this; + }, + + /** + * 注册事件处理方法 + * Bind editor event handle + * + * @param {String} eventType event type + * @param {Function} callback 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + on : function(eventType, callback) { + var settings = this.settings; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = $.proxy(callback, this); + } + + return this; + }, + + /** + * 解除事件处理方法 + * Unbind editor event handle + * + * @param {String} eventType event type + * @returns {editormd} this(editormd instance object.) + */ + + off : function(eventType) { + var settings = this.settings; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = function(){}; + } + + return this; + }, + + /** + * 显示工具栏 + * Display toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + showToolbar : function(callback) { + var settings = this.settings; + + if(settings.readOnly) { + return this; + } + + if (settings.toolbar && (this.toolbar.length < 1 || this.toolbar.find("." + this.classPrefix + "menu").html() === "") ) + { + this.setToolbar(); + } + + settings.toolbar = true; + + this.toolbar.show(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 隐藏工具栏 + * Hide toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + hideToolbar : function(callback) { + var settings = this.settings; + + settings.toolbar = false; + this.toolbar.hide(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 页面滚动时工具栏的固定定位 + * Set toolbar in window scroll auto fixed position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarAutoFixed : function(fixed) { + + var state = this.state; + var editor = this.editor; + var toolbar = this.toolbar; + var settings = this.settings; + + if (typeof fixed !== "undefined") + { + settings.toolbarAutoFixed = fixed; + } + + var autoFixedHandle = function(){ + var $window = $(window); + var top = $window.scrollTop(); + + if (!settings.toolbarAutoFixed) + { + return false; + } + + if (top - editor.offset().top > 10 && top < editor.height()) + { + toolbar.css({ + position : "fixed", + width : editor.width() + "px", + left : ($window.width() - editor.width()) / 2 + "px" + }); + } + else + { + toolbar.css({ + position : "absolute", + width : "100%", + left : 0 + }); + } + }; + + if (!state.fullscreen && !state.preview && settings.toolbar && settings.toolbarAutoFixed) + { + $(window).bind("scroll", autoFixedHandle); + } + + return this; + }, + + /** + * 配置和初始化工具栏 + * Set toolbar and Initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbar : function() { + var settings = this.settings; + + if(settings.readOnly) { + return this; + } + + var editor = this.editor; + var preview = this.preview; + var classPrefix = this.classPrefix; + + var toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + + if (settings.toolbar && toolbar.length < 1) + { + var toolbarHTML = "
                  "; + + editor.append(toolbarHTML); + toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + } + + if (!settings.toolbar) + { + toolbar.hide(); + + return this; + } + + toolbar.show(); + + var icons = (typeof settings.toolbarIcons === "function") ? settings.toolbarIcons() + : ((typeof settings.toolbarIcons === "string") ? editormd.toolbarModes[settings.toolbarIcons] : settings.toolbarIcons); + + var toolbarMenu = toolbar.find("." + this.classPrefix + "menu"), menu = ""; + var pullRight = false; + + for (var i = 0, len = icons.length; i < len; i++) + { + var name = icons[i]; + + if (name === "||") + { + pullRight = true; + } + else if (name === "|") + { + menu += "
                • |
                • "; + } + else + { + var isHeader = (/h(\d)/.test(name)); + var index = name; + + if (name === "watch" && !settings.watch) { + index = "unwatch"; + } + + var title = settings.lang.toolbar[index]; + var iconTexts = settings.toolbarIconTexts[index]; + var iconClass = settings.toolbarIconsClass[index]; + + title = (typeof title === "undefined") ? "" : title; + iconTexts = (typeof iconTexts === "undefined") ? "" : iconTexts; + iconClass = (typeof iconClass === "undefined") ? "" : iconClass; + + var menuItem = pullRight ? "
                • " : "
                • "; + + if (typeof settings.toolbarCustomIcons[name] !== "undefined" && typeof settings.toolbarCustomIcons[name] !== "function") + { + menuItem += settings.toolbarCustomIcons[name]; + } + else + { + menuItem += ""; + menuItem += ""+((isHeader) ? name.toUpperCase() : ( (iconClass === "") ? iconTexts : "") ) + ""; + menuItem += ""; + } + + menuItem += "
                • "; + + menu = pullRight ? menuItem + menu : menu + menuItem; + } + } + + toolbarMenu.html(menu); + + toolbarMenu.find("[title=\"Lowercase\"]").attr("title", settings.lang.toolbar.lowercase); + toolbarMenu.find("[title=\"ucwords\"]").attr("title", settings.lang.toolbar.ucwords); + + this.setToolbarHandler(); + this.setToolbarAutoFixed(); + + return this; + }, + + /** + * 工具栏图标事件处理对象序列 + * Get toolbar icons event handlers + * + * @param {Object} cm CodeMirror的实例对象 + * @param {String} name 要获取的事件处理器名称 + * @returns {Object} 返回处理对象序列 + */ + + dialogLockScreen : function() { + $.proxy(editormd.dialogLockScreen, this)(); + + return this; + }, + + dialogShowMask : function(dialog) { + $.proxy(editormd.dialogShowMask, this)(dialog); + + return this; + }, + + getToolbarHandles : function(name) { + var toolbarHandlers = this.toolbarHandlers = editormd.toolbarHandlers; + + return (name && typeof toolbarIconHandlers[name] !== "undefined") ? toolbarHandlers[name] : toolbarHandlers; + }, + + /** + * 工具栏图标事件处理器 + * Bind toolbar icons event handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarHandler : function() { + var _this = this; + var settings = this.settings; + + if (!settings.toolbar || settings.readOnly) { + return this; + } + + var toolbar = this.toolbar; + var cm = this.cm; + var classPrefix = this.classPrefix; + var toolbarIcons = this.toolbarIcons = toolbar.find("." + classPrefix + "menu > li > a"); + var toolbarIconHandlers = this.getToolbarHandles(); + + toolbarIcons.bind(editormd.mouseOrTouch("click", "touchend"), function(event) { + + var icon = $(this).children(".fa"); + var name = icon.attr("name"); + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (name === "") { + return ; + } + + _this.activeIcon = icon; + + if (typeof toolbarIconHandlers[name] !== "undefined") + { + $.proxy(toolbarIconHandlers[name], _this)(cm); + } + else + { + if (typeof settings.toolbarHandlers[name] !== "undefined") + { + $.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection); + } + } + + if (name !== "link" && name !== "reference-link" && name !== "image" && name !== "code-block" && + name !== "preformatted-text" && name !== "watch" && name !== "preview" && name !== "search" && name !== "fullscreen" && name !== "info") + { + cm.focus(); + } + + return false; + + }); + + return this; + }, + + /** + * 动态创建对话框 + * Creating custom dialogs + * + * @param {Object} options 配置项键值对 Key/Value + * @returns {dialog} 返回创建的dialog的jQuery实例对象 + */ + + createDialog : function(options) { + return $.proxy(editormd.createDialog, this)(options); + }, + + /** + * 创建关于Editor.md的对话框 + * Create about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + createInfoDialog : function() { + var _this = this; + var editor = this.editor; + var classPrefix = this.classPrefix; + + var infoDialogHTML = [ + "
                  ", + "
                  ", + "

                  " + editormd.title + "v" + editormd.version + "

                  ", + "

                  " + this.lang.description + "

                  ", + "

                  " + editormd.homePage + "

                  ", + "

                  Copyright © 2015 Pandao, The MIT License.

                  ", + "
                  ", + "", + "
                  " + ].join("\n"); + + editor.append(infoDialogHTML); + + var infoDialog = this.infoDialog = editor.children("." + classPrefix + "dialog-info"); + + infoDialog.find("." + classPrefix + "dialog-close").bind(editormd.mouseOrTouch("click", "touchend"), function() { + _this.hideInfoDialog(); + }); + + infoDialog.css("border", (editormd.isIE8) ? "1px solid #ddd" : "").css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 关于Editor.md对话居中定位 + * Editor.md dialog position handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + infoDialogPosition : function() { + var infoDialog = this.infoDialog; + + var _infoDialogPosition = function() { + infoDialog.css({ + top : ($(window).height() - infoDialog.height()) / 2 + "px", + left : ($(window).width() - infoDialog.width()) / 2 + "px" + }); + }; + + _infoDialogPosition(); + + $(window).resize(_infoDialogPosition); + + return this; + }, + + /** + * 显示关于Editor.md + * Display about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + showInfoDialog : function() { + + $("html,body").css("overflow-x", "hidden"); + + var _this = this; + var editor = this.editor; + var settings = this.settings; + var infoDialog = this.infoDialog = editor.children("." + this.classPrefix + "dialog-info"); + + if (infoDialog.length < 1) + { + this.createInfoDialog(); + } + + this.lockScreen(true); + + this.mask.css({ + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }).show(); + + infoDialog.css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 隐藏关于Editor.md + * Hide about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + hideInfoDialog : function() { + $("html,body").css("overflow-x", ""); + this.infoDialog.hide(); + this.mask.hide(); + this.lockScreen(false); + + return this; + }, + + /** + * 锁屏 + * lock screen + * + * @param {Boolean} lock Boolean 布尔值,是否锁屏 + * @returns {editormd} 返回editormd的实例对象 + */ + + lockScreen : function(lock) { + editormd.lockScreen(lock); + this.resize(); + + return this; + }, + + /** + * 编辑器界面重建,用于动态语言包或模块加载等 + * Recreate editor + * + * @returns {editormd} 返回editormd的实例对象 + */ + + recreate : function() { + var _this = this; + var editor = this.editor; + var settings = this.settings; + + this.codeMirror.remove(); + + this.setCodeMirror(); + + if (!settings.readOnly) + { + if (editor.find(".editormd-dialog").length > 0) { + editor.find(".editormd-dialog").remove(); + } + + if (settings.toolbar) + { + this.getToolbarHandles(); + this.setToolbar(); + } + } + + this.loadedDisplay(true); + + return this; + }, + + /** + * 高亮预览HTML的pre代码部分 + * highlight of preview codes + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewCodeHighlight : function() { + var settings = this.settings; + var previewContainer = this.previewContainer; + + if (settings.previewCodeHighlight) + { + previewContainer.find("pre").addClass("prettyprint linenums"); + + if (typeof prettyPrint !== "undefined") + { + prettyPrint(); + } + } + + return this; + }, + + /** + * 解析TeX(KaTeX)科学公式 + * TeX(KaTeX) Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + katexRender : function() { + + if (timer === null) + { + return this; + } + + this.previewContainer.find("." + editormd.classNames.tex).each(function(){ + var tex = $(this); + editormd.$katex.render(tex.text(), tex[0]); + + tex.find(".katex").css("font-size", "1.0em"); + }); + + return this; + }, + + /** + * 解析和渲染流程图及时序图 + * FlowChart and SequenceDiagram Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + flowChartAndSequenceDiagramRender : function() { + var $this = this; + var settings = this.settings; + var previewContainer = this.previewContainer; + + if (editormd.isIE8) { + return this; + } + + if (settings.flowChart) { + if (flowchartTimer === null) { + return this; + } + + previewContainer.find(".flowchart").flowChart(); + } + + if (settings.sequenceDiagram) { + previewContainer.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); + } + + var preview = $this.preview; + var codeMirror = $this.codeMirror; + var codeView = codeMirror.find(".CodeMirror-scroll"); + + var height = codeView.height(); + var scrollTop = codeView.scrollTop(); + var percent = (scrollTop / codeView[0].scrollHeight); + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= codeView[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + return this; + }, + + /** + * 注册键盘快捷键处理 + * Register CodeMirror keyMaps (keyboard shortcuts). + * + * @param {Object} keyMap KeyMap key/value {"(Ctrl/Shift/Alt)-Key" : function(){}} + * @returns {editormd} return this + */ + + registerKeyMaps : function(keyMap) { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + var toolbarHandlers = editormd.toolbarHandlers; + var disabledKeyMaps = settings.disabledKeyMaps; + + keyMap = keyMap || null; + + if (keyMap) + { + for (var i in keyMap) + { + if ($.inArray(i, disabledKeyMaps) < 0) + { + var map = {}; + map[i] = keyMap[i]; + + cm.addKeyMap(keyMap); + } + } + } + else + { + for (var k in editormd.keyMaps) + { + var _keyMap = editormd.keyMaps[k]; + var handle = (typeof _keyMap === "string") ? $.proxy(toolbarHandlers[_keyMap], _this) : $.proxy(_keyMap, _this); + + if ($.inArray(k, ["F9", "F10", "F11"]) < 0 && $.inArray(k, disabledKeyMaps) < 0) + { + var _map = {}; + _map[k] = handle; + + cm.addKeyMap(_map); + } + } + + $(window).keydown(function(event) { + + var keymaps = { + "120" : "F9", + "121" : "F10", + "122" : "F11" + }; + + if ( $.inArray(keymaps[event.keyCode], disabledKeyMaps) < 0 ) + { + switch (event.keyCode) + { + case 120: + $.proxy(toolbarHandlers["watch"], _this)(); + return false; + break; + + case 121: + $.proxy(toolbarHandlers["preview"], _this)(); + return false; + break; + + case 122: + $.proxy(toolbarHandlers["fullscreen"], _this)(); + return false; + break; + + default: + break; + } + } + }); + } + + return this; + }, + + /** + * 绑定同步滚动 + * + * @returns {editormd} return this + */ + + bindScrollEvent : function() { + + var _this = this; + var preview = this.preview; + var settings = this.settings; + var codeMirror = this.codeMirror; + var mouseOrTouch = editormd.mouseOrTouch; + + if (!settings.syncScrolling) { + return this; + } + + var cmBindScroll = function() { + codeMirror.find(".CodeMirror-scroll").bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + $.proxy(settings.onscroll, _this)(event); + }); + }; + + var cmUnbindScroll = function() { + codeMirror.find(".CodeMirror-scroll").unbind(mouseOrTouch("scroll", "touchmove")); + }; + + var previewBindScroll = function() { + + preview.bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + var codeView = codeMirror.find(".CodeMirror-scroll"); + + if(scrollTop === 0) + { + codeView.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight) + { + codeView.scrollTop(codeView[0].scrollHeight); + } + else + { + codeView.scrollTop(codeView[0].scrollHeight * percent); + } + + $.proxy(settings.onpreviewscroll, _this)(event); + }); + + }; + + var previewUnbindScroll = function() { + preview.unbind(mouseOrTouch("scroll", "touchmove")); + }; + + codeMirror.bind({ + mouseover : cmBindScroll, + mouseout : cmUnbindScroll, + touchstart : cmBindScroll, + touchend : cmUnbindScroll + }); + + if (settings.syncScrolling === "single") { + return this; + } + + preview.bind({ + mouseover : previewBindScroll, + mouseout : previewUnbindScroll, + touchstart : previewBindScroll, + touchend : previewUnbindScroll + }); + + return this; + }, + + bindChangeEvent : function() { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + + if (!settings.syncScrolling) { + return this; + } + + cm.on("change", function(_cm, changeObj) { + + if (settings.watch) + { + _this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + } + + timer = setTimeout(function() { + clearTimeout(timer); + _this.save(); + timer = null; + }, settings.delay); + }); + + return this; + }, + + /** + * 加载队列完成之后的显示处理 + * Display handle of the module queues loaded after. + * + * @param {Boolean} recreate 是否为重建编辑器 + * @returns {editormd} 返回editormd的实例对象 + */ + + loadedDisplay : function(recreate) { + + recreate = recreate || false; + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var settings = this.settings; + + this.containerMask.hide(); + + this.save(); + + if (settings.watch) { + preview.show(); + } + + editor.data("oldWidth", editor.width()).data("oldHeight", editor.height()); // 为了兼容Zepto + + this.resize(); + this.registerKeyMaps(); + + $(window).resize(function(){ + _this.resize(); + }); + + this.bindScrollEvent().bindChangeEvent(); + + if (!recreate) + { + // TODO url完善 + settings.imageUploadURL && initEditormdPasteUpload( this , settings.imageUploadURL) + $.proxy(settings.onload, this)(); + } + + this.state.loaded = true; + + return this; + }, + + /** + * 设置编辑器的宽度 + * Set editor width + * + * @param {Number|String} width 编辑器宽度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + width : function(width) { + + this.editor.css("width", (typeof width === "number") ? width + "px" : width); + this.resize(); + + return this; + }, + + /** + * 设置编辑器的高度 + * Set editor height + * + * @param {Number|String} height 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + height : function(height) { + + this.editor.css("height", (typeof height === "number") ? height + "px" : height); + this.resize(); + + return this; + }, + + /** + * 调整编辑器的尺寸和布局 + * Resize editor layout + * + * @param {Number|String} [width=null] 编辑器宽度值 + * @param {Number|String} [height=null] 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + resize : function(width, height) { + + width = width || null; + height = height || null; + + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var codeMirror = this.codeMirror; + + if (width) + { + editor.css("width", (typeof width === "number") ? width + "px" : width); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + editor.css("height", "auto"); + codeMirror.css("height", "auto"); + } + else + { + if (height) + { + editor.css("height", (typeof height === "number") ? height + "px" : height); + } + + if (state.fullscreen) + { + editor.height($(window).height()); + } + + if (settings.toolbar && !settings.readOnly) + { + codeMirror.css("margin-top", toolbar.height() + 1).height(editor.height() - toolbar.height()); + } + else + { + codeMirror.css("margin-top", 0).height(editor.height()); + } + } + + if(settings.watch) + { + codeMirror.width(editor.width() / 2); + preview.width((!state.preview) ? editor.width() / 2 : editor.width()); + + this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + + if (settings.toolbar && !settings.readOnly) + { + preview.css("top", toolbar.height() + 1); + } + else + { + preview.css("top", 0); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + preview.height(""); + } + else + { + var previewHeight = (settings.toolbar && !settings.readOnly) ? editor.height() - toolbar.height() : editor.height(); + + preview.height(previewHeight); + } + } + else + { + codeMirror.width(editor.width()); + preview.hide(); + } + + if (state.loaded) + { + $.proxy(settings.onresize, this)(); + } + + return this; + }, + + /** + * 解析和保存Markdown代码 + * Parse & Saving Markdown source code + * + * @returns {editormd} 返回editormd的实例对象 + */ + + save : function() { + + if (timer === null) + { + return this; + } + + var _this = this; + var state = this.state; + var settings = this.settings; + var cm = this.cm; + var cmValue = cm.getValue(); + var previewContainer = this.previewContainer; + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + this.markdownTextarea.val(cmValue); + + return this; + } + + var marked = editormd.$marked; + var markdownToC = this.markdownToC = []; + var rendererOptions = this.markedRendererOptions = { + toc : settings.toc, + tocm : settings.tocm, + tocStartLevel : settings.tocStartLevel, + pageBreak : settings.pageBreak, + taskList : settings.taskList, + emoji : settings.emoji, + tex : settings.tex, + atLink : settings.atLink, // for @link + emailLink : settings.emailLink, // for mail address auto link + flowChart : settings.flowChart, + sequenceDiagram : settings.sequenceDiagram, + previewCodeHighlight : settings.previewCodeHighlight, + }; + + var markedOptions = this.markedOptions = { + renderer : editormd.markedRenderer(markdownToC, rendererOptions), + gfm : true, + tables : true, + breaks : true, + pedantic : false, + sanitize : (settings.htmlDecode) ? false : true, // 关闭忽略HTML标签,即开启识别HTML标签,默认为false + smartLists : true, + smartypants : true + }; + + marked.setOptions(markedOptions); + + var newMarkdownDoc = editormd.$marked(cmValue, markedOptions); + + //console.info("cmValue", cmValue, newMarkdownDoc); + + newMarkdownDoc = editormd.filterHTMLTags(newMarkdownDoc, settings.htmlDecode); + + //console.error("cmValue", cmValue, newMarkdownDoc); + + this.markdownTextarea.text(cmValue); + + cm.save(); + + if (settings.saveHTMLToTextarea) + { + this.htmlTextarea.text(newMarkdownDoc); + } + + if(settings.watch || (!settings.watch && state.preview)) + { + previewContainer.html(newMarkdownDoc); + + this.previewCodeHighlight(); + + if (settings.toc) + { + var tocContainer = (settings.tocContainer === "") ? previewContainer : $(settings.tocContainer); + var tocMenu = tocContainer.find("." + this.classPrefix + "toc-menu"); + + tocContainer.attr("previewContainer", (settings.tocContainer === "") ? "true" : "false"); + + if (settings.tocContainer !== "" && tocMenu.length > 0) + { + tocMenu.remove(); + } + + editormd.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); + + if (settings.tocDropdown || tocContainer.find("." + this.classPrefix + "toc-menu").length > 0) + { + editormd.tocDropdownMenu(tocContainer, (settings.tocTitle !== "") ? settings.tocTitle : this.lang.tocTitle); + } + + if (settings.tocContainer !== "") + { + previewContainer.find(".markdown-toc").css("border", "none"); + } + } + + if (settings.tex) + { + if (!editormd.kaTeXLoaded && settings.autoLoadModules) + { + editormd.loadKaTeX(function() { + editormd.$katex = katex; + editormd.kaTeXLoaded = true; + _this.katexRender(); + }); + } + else + { + editormd.$katex = katex; + this.katexRender(); + } + } + + if (settings.flowChart || settings.sequenceDiagram) + { + flowchartTimer = setTimeout(function(){ + clearTimeout(flowchartTimer); + _this.flowChartAndSequenceDiagramRender(); + flowchartTimer = null; + }, 10); + } + + if (state.loaded) + { + $.proxy(settings.onchange, this)(); + } + } + + return this; + }, + + /** + * 聚焦光标位置 + * Focusing the cursor position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + focus : function() { + this.cm.focus(); + + return this; + }, + + /** + * 设置光标的位置 + * Set cursor position + * + * @param {Object} cursor 要设置的光标位置键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setCursor : function(cursor) { + this.cm.setCursor(cursor); + + return this; + }, + + /** + * 获取当前光标的位置 + * Get the current position of the cursor + * + * @returns {Cursor} 返回一个光标Cursor对象 + */ + + getCursor : function() { + return this.cm.getCursor(); + }, + + /** + * 设置光标选中的范围 + * Set cursor selected ranges + * + * @param {Object} from 开始位置的光标键值对象,例:{line:1, ch:0} + * @param {Object} to 结束位置的光标键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setSelection : function(from, to) { + + this.cm.setSelection(from, to); + + return this; + }, + + /** + * 获取光标选中的文本 + * Get the texts from cursor selected + * + * @returns {String} 返回选中文本的字符串形式 + */ + + getSelection : function() { + return this.cm.getSelection(); + }, + + /** + * 设置光标选中的文本范围 + * Set the cursor selection ranges + * + * @param {Array} ranges cursor selection ranges array + * @returns {Array} return this + */ + + setSelections : function(ranges) { + this.cm.setSelections(ranges); + + return this; + }, + + /** + * 获取光标选中的文本范围 + * Get the cursor selection ranges + * + * @returns {Array} return selection ranges array + */ + + getSelections : function() { + return this.cm.getSelections(); + }, + + /** + * 替换当前光标选中的文本或在当前光标处插入新字符 + * Replace the text at the current cursor selected or insert a new character at the current cursor position + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + replaceSelection : function(value) { + this.cm.replaceSelection(value); + + return this; + }, + + /** + * 在当前光标处插入新字符 + * Insert a new character at the current cursor position + * + * 同replaceSelection()方法 + * With the replaceSelection() method + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + insertValue : function(value) { + this.replaceSelection(value); + + return this; + }, + + /** + * 追加markdown + * append Markdown to editor + * + * @param {String} md 要追加的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + appendMarkdown : function(md) { + var settings = this.settings; + var cm = this.cm; + + cm.setValue(cm.getValue() + md); + + return this; + }, + + /** + * 设置和传入编辑器的markdown源文档 + * Set Markdown source document + * + * @param {String} md 要传入的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + setMarkdown : function(md) { + this.cm.setValue(md || this.settings.markdown); + + return this; + }, + + /** + * 获取编辑器的markdown源文档 + * Set Editor.md markdown/CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getMarkdown : function() { + return this.cm.getValue(); + }, + + /** + * 获取编辑器的源文档 + * Get CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getValue : function() { + return this.cm.getValue(); + }, + + /** + * 设置编辑器的源文档 + * Set CodeMirror value + * + * @param {String} value set code/value/string/text + * @returns {editormd} 返回editormd的实例对象 + */ + + setValue : function(value) { + this.cm.setValue(value); + + return this; + }, + + /** + * 清空编辑器 + * Empty CodeMirror editor container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + clear : function() { + this.cm.setValue(""); + + return this; + }, + + /** + * 获取解析后存放在Textarea的HTML源码 + * Get parsed html code from Textarea + * + * @returns {String} 返回HTML源码 + */ + + getHTML : function() { + if (!this.settings.saveHTMLToTextarea) + { + alert("Error: settings.saveHTMLToTextarea == false"); + + return false; + } + + return this.htmlTextarea.val(); + }, + + /** + * getHTML()的别名 + * getHTML (alias) + * + * @returns {String} Return html code 返回HTML源码 + */ + + getTextareaSavedHTML : function() { + return this.getHTML(); + }, + + /** + * 获取预览窗口的HTML源码 + * Get html from preview container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getPreviewedHTML : function() { + if (!this.settings.watch) + { + alert("Error: settings.watch == false"); + + return false; + } + + return this.previewContainer.html(); + }, + + /** + * 开启实时预览 + * Enable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + watch : function(callback) { + var settings = this.settings; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) + { + return this; + } + + this.state.watching = settings.watch = true; + this.preview.show(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.watch); + icon.removeClass(unWatchIcon).addClass(watchIcon); + } + + this.codeMirror.css("border-right", "1px solid #ddd").width(this.editor.width() / 2); + + timer = 0; + + this.save().resize(); + + if (!settings.onwatch) + { + settings.onwatch = callback || function() {}; + } + + $.proxy(settings.onwatch, this)(); + + return this; + }, + + /** + * 关闭实时预览 + * Disable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + unwatch : function(callback) { + var settings = this.settings; + this.state.watching = settings.watch = false; + this.preview.hide(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.unwatch); + icon.removeClass(watchIcon).addClass(unWatchIcon); + } + + this.codeMirror.css("border-right", "none").width(this.editor.width()); + + this.resize(); + + if (!settings.onunwatch) + { + settings.onunwatch = callback || function() {}; + } + + $.proxy(settings.onunwatch, this)(); + + return this; + }, + + /** + * 显示编辑器 + * Show editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + show : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.show(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器 + * Hide editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + hide : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.hide(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器部分,只预览HTML + * Enter preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewing : function() { + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var codeMirror = this.codeMirror; + var previewContainer = this.previewContainer; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) { + return this; + } + + if (settings.toolbar && toolbar) { + toolbar.toggle(); + toolbar.find(".fa[name=preview]").toggleClass("active"); + } + + codeMirror.toggle(); + + var escHandle = function(event) { + if (event.shiftKey && event.keyCode === 27) { + _this.previewed(); + } + }; + + if (codeMirror.css("display") === "none") // 为了兼容Zepto,而不使用codeMirror.is(":hidden") + { + this.state.preview = true; + + if (this.state.fullscreen) { + preview.css("background", "#fff"); + } + + editor.find("." + this.classPrefix + "preview-close-btn").show().bind(editormd.mouseOrTouch("click", "touchend"), function(){ + _this.previewed(); + }); + + if (!settings.watch) + { + this.save(); + } + else + { + previewContainer.css("padding", ""); + } + + previewContainer.addClass(this.classPrefix + "preview-active"); + + preview.show().css({ + position : "", + top : 0, + width : editor.width(), + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewing, this)(); + } + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.previewed(); + } + }, + + /** + * 显示编辑器部分,退出只预览HTML + * Exit preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewed : function() { + + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var previewContainer = this.previewContainer; + var previewCloseBtn = editor.find("." + this.classPrefix + "preview-close-btn"); + + this.state.preview = false; + + this.codeMirror.show(); + + if (settings.toolbar) { + toolbar.show(); + } + + preview[(settings.watch) ? "show" : "hide"](); + + previewCloseBtn.hide().unbind(editormd.mouseOrTouch("click", "touchend")); + + previewContainer.removeClass(this.classPrefix + "preview-active"); + + if (settings.watch) + { + previewContainer.css("padding", "20px"); + } + + preview.css({ + background : null, + position : "absolute", + width : editor.width() / 2, + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() - toolbar.height(), + top : (settings.toolbar) ? toolbar.height() : 0 + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewed, this)(); + } + + return this; + }, + + /** + * 编辑器全屏显示 + * Fullscreen show + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreen : function() { + + var _this = this; + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var fullscreenClass = this.classPrefix + "fullscreen"; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().toggleClass("active"); + } + + var escHandle = function(event) { + if (!event.shiftKey && event.keyCode === 27) + { + if (state.fullscreen) + { + _this.fullscreenExit(); + } + } + }; + + if (!editor.hasClass(fullscreenClass)) + { + state.fullscreen = true; + + $("html,body").css("overflow", "hidden"); + + editor.css({ + width : $(window).width(), + height : $(window).height() + }).addClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreen, this)(); + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.fullscreenExit(); + } + + return this; + }, + + /** + * 编辑器退出全屏显示 + * Exit fullscreen state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreenExit : function() { + + var editor = this.editor; + var settings = this.settings; + var toolbar = this.toolbar; + var fullscreenClass = this.classPrefix + "fullscreen"; + + this.state.fullscreen = false; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().removeClass("active"); + } + + $("html,body").css("overflow", ""); + + editor.css({ + width : editor.data("oldWidth"), + height : editor.data("oldHeight") + }).removeClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreenExit, this)(); + + return this; + }, + + /** + * 加载并执行插件 + * Load and execute the plugin + * + * @param {String} name plugin name / function name + * @param {String} path plugin load path + * @returns {editormd} 返回editormd的实例对象 + */ + + executePlugin : function(name, path) { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + + path = settings.pluginPath + path; + + if (typeof define === "function") + { + if (typeof this[name] === "undefined") + { + alert("Error: " + name + " plugin is not found, you are not load this plugin."); + + return this; + } + + this[name](cm); + + return this; + } + + if ($.inArray(path, editormd.loadFiles.plugin) < 0) + { + editormd.loadPlugin(path, function() { + editormd.loadPlugins[name] = _this[name]; + _this[name](cm); + }); + } + else + { + $.proxy(editormd.loadPlugins[name], this)(cm); + } + + return this; + }, + + /** + * 搜索替换 + * Search & replace + * + * @param {String} command CodeMirror serach commands, "find, fintNext, fintPrev, clearSearch, replace, replaceAll" + * @returns {editormd} return this + */ + + search : function(command) { + var settings = this.settings; + + if (!settings.searchReplace) + { + alert("Error: settings.searchReplace == false"); + return this; + } + + if (!settings.readOnly) + { + this.cm.execCommand(command || "find"); + } + + return this; + }, + + searchReplace : function() { + this.search("replace"); + + return this; + }, + + searchReplaceAll : function() { + this.search("replaceAll"); + + return this; + } + }; + + editormd.fn.init.prototype = editormd.fn; + + /** + * 锁屏 + * lock screen when dialog opening + * + * @returns {void} + */ + + editormd.dialogLockScreen = function() { + var settings = this.settings || {dialogLockScreen : true}; + + if (settings.dialogLockScreen) + { + $("html,body").css("overflow", "hidden"); + this.resize(); + } + }; + + /** + * 显示透明背景层 + * Display mask layer when dialog opening + * + * @param {Object} dialog dialog jQuery object + * @returns {void} + */ + + editormd.dialogShowMask = function(dialog) { + var editor = this.editor; + var settings = this.settings || {dialogShowMask : true}; + + dialog.css({ + top : ($(window).height() - dialog.height()) / 2 + "px", + left : ($(window).width() - dialog.width()) / 2 + "px" + }); + + if (settings.dialogShowMask) { + editor.children("." + this.classPrefix + "mask").css("z-index", parseInt(dialog.css("z-index")) - 1).show(); + } + }; + + editormd.toolbarHandlers = { + undo : function() { + this.cm.undo(); + }, + + redo : function() { + this.cm.redo(); + }, + + bold : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("**" + selection + "**"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + del : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("~~" + selection + "~~"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + italic : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("*" + selection + "*"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + quote : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("> " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("> " + selection); + } + + //cm.replaceSelection("> " + selection); + //cm.setCursor(cursor.line, (selection === "") ? cursor.ch + 2 : cursor.ch + selection.length + 2); + }, + + ucfirst : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.firstUpperCase(selection)); + cm.setSelections(selections); + }, + + ucwords : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.wordsFirstUpperCase(selection)); + cm.setSelections(selections); + }, + + uppercase : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toUpperCase()); + cm.setSelections(selections); + }, + + lowercase : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toLowerCase()); + cm.setSelections(selections); + }, + + h1 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("# " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("# " + selection); + } + }, + + h2 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("## " + selection); + cm.setCursor(cursor.line, cursor.ch + 3); + } + else + { + cm.replaceSelection("## " + selection); + } + }, + + h3 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("### " + selection); + cm.setCursor(cursor.line, cursor.ch + 4); + } + else + { + cm.replaceSelection("### " + selection); + } + }, + + h4 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("#### " + selection); + cm.setCursor(cursor.line, cursor.ch + 5); + } + else + { + cm.replaceSelection("#### " + selection); + } + }, + + h5 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("##### " + selection); + cm.setCursor(cursor.line, cursor.ch + 6); + } + else + { + cm.replaceSelection("##### " + selection); + } + }, + + h6 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("###### " + selection); + cm.setCursor(cursor.line, cursor.ch + 7); + } + else + { + cm.replaceSelection("###### " + selection); + } + }, + + "list-ul" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (selection === "") + { + cm.replaceSelection("- " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : "- " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + "list-ol" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if(selection === "") + { + cm.replaceSelection("1. " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : (i+1) + ". " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + hr : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(((cursor.ch !== 0) ? "\n\n" : "\n") + "------------\n\n"); + }, + + tex : function() { + if (!this.settings.tex) + { + alert("settings.tex === false"); + return this; + } + + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("$$" + selection + "$$"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + link : function() { + this.executePlugin("linkDialog", "link-dialog/link-dialog"); + }, + + "reference-link" : function() { + this.executePlugin("referenceLinkDialog", "reference-link-dialog/reference-link-dialog"); + }, + + pagebreak : function() { + if (!this.settings.pageBreak) + { + alert("settings.pageBreak === false"); + return this; + } + + var cm = this.cm; + var selection = cm.getSelection(); + + cm.replaceSelection("\r\n[========]\r\n"); + }, + + image : function() { + this.executePlugin("imageDialog", "image-dialog/image-dialog"); + }, + + code : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("`" + selection + "`"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "code-block" : function() { + this.executePlugin("codeBlockDialog", "code-block-dialog/code-block-dialog"); + }, + + "preformatted-text" : function() { + this.executePlugin("preformattedTextDialog", "preformatted-text-dialog/preformatted-text-dialog"); + }, + + table : function() { + this.executePlugin("tableDialog", "table-dialog/table-dialog"); + }, + + datetime : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var date = new Date(); + var langName = this.settings.lang.name; + var datefmt = editormd.dateFormat() + " " + editormd.dateFormat((langName === "zh-cn" || langName === "zh-tw") ? "cn-week-day" : "week-day"); + + cm.replaceSelection(datefmt); + }, + + emoji : function() { + this.executePlugin("emojiDialog", "emoji-dialog/emoji-dialog"); + }, + + "html-entities" : function() { + this.executePlugin("htmlEntitiesDialog", "html-entities-dialog/html-entities-dialog"); + }, + + "goto-line" : function() { + this.executePlugin("gotoLineDialog", "goto-line-dialog/goto-line-dialog"); + }, + + watch : function() { + this[this.settings.watch ? "unwatch" : "watch"](); + }, + + preview : function() { + this.previewing(); + }, + + fullscreen : function() { + this.fullscreen(); + }, + + clear : function() { + this.clear(); + }, + + search : function() { + this.search(); + }, + + help : function() { + this.executePlugin("helpDialog", "help-dialog/help-dialog"); + }, + + info : function() { + this.showInfoDialog(); + } + }; + + editormd.keyMaps = { + "Ctrl-1" : "h1", + "Ctrl-2" : "h2", + "Ctrl-3" : "h3", + "Ctrl-4" : "h4", + "Ctrl-5" : "h5", + "Ctrl-6" : "h6", + "Ctrl-B" : "bold", // if this is string == editormd.toolbarHandlers.xxxx + "Ctrl-D" : "datetime", + + "Ctrl-E" : function() { // emoji + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!this.settings.emoji) + { + alert("Error: settings.emoji == false"); + return ; + } + + cm.replaceSelection(":" + selection + ":"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-Alt-G" : "goto-line", + "Ctrl-H" : "hr", + "Ctrl-I" : "italic", + "Ctrl-K" : "code", + + "Ctrl-L" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("[" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-U" : "list-ul", + + "Shift-Ctrl-A" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!this.settings.atLink) + { + alert("Error: settings.atLink == false"); + return ; + } + + cm.replaceSelection("@" + selection); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "Shift-Ctrl-C" : "code", + "Shift-Ctrl-Q" : "quote", + "Shift-Ctrl-S" : "del", + "Shift-Ctrl-K" : "tex", // KaTeX + + "Shift-Alt-C" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(["```", selection, "```"].join("\n")); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 3); + } + }, + + "Shift-Ctrl-Alt-C" : "code-block", + "Shift-Ctrl-H" : "html-entities", + "Shift-Alt-H" : "help", + "Shift-Ctrl-E" : "emoji", + "Shift-Ctrl-U" : "uppercase", + "Shift-Alt-U" : "ucwords", + "Shift-Ctrl-Alt-U" : "ucfirst", + "Shift-Alt-L" : "lowercase", + + "Shift-Ctrl-I" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("![" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 4); + } + }, + + "Shift-Ctrl-Alt-I" : "image", + "Shift-Ctrl-L" : "link", + "Shift-Ctrl-O" : "list-ol", + "Shift-Ctrl-P" : "preformatted-text", + "Shift-Ctrl-T" : "table", + "Shift-Alt-P" : "pagebreak", + "F9" : "watch", + "F10" : "preview", + "F11" : "fullscreen", + }; + + /** + * 清除字符串两边的空格 + * Clear the space of strings both sides. + * + * @param {String} str string + * @returns {String} trimed string + */ + + var trim = function(str) { + return (!String.prototype.trim) ? str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "") : str.trim(); + }; + + editormd.trim = trim; + + /** + * 所有单词首字母大写 + * Words first to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var ucwords = function (str) { + return str.toLowerCase().replace(/\b(\w)|\s(\w)/g, function($1) { + return $1.toUpperCase(); + }); + }; + + editormd.ucwords = editormd.wordsFirstUpperCase = ucwords; + + /** + * 字符串首字母大写 + * Only string first char to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var firstUpperCase = function(str) { + return str.toLowerCase().replace(/\b(\w)/, function($1){ + return $1.toUpperCase(); + }); + }; + + var ucfirst = firstUpperCase; + + editormd.firstUpperCase = editormd.ucfirst = firstUpperCase; + + editormd.urls = { + atLinkBase : "https://github.com/" + }; + + editormd.regexs = { + atLink : /@(\w+)/g, + email : /(\w+)@(\w+)\.(\w+)\.?(\w+)?/g, + emailLink : /(mailto:)?([\w\.\_]+)@(\w+)\.(\w+)\.?(\w+)?/g, + emoji : /:([\w\+-]+):/g, + emojiDatetime : /(\d{2}:\d{2}:\d{2})/g, + twemoji : /:(tw-([\w]+)-?(\w+)?):/g, + fontAwesome : /:(fa-([\w]+)(-(\w+)){0,}):/g, + editormdLogo : /:(editormd-logo-?(\w+)?):/g, + pageBreak : /^\[[=]{8,}\]$/ + }; + + // Emoji graphics files url path + editormd.emoji = { + path : "http://www.emoji-cheat-sheet.com/graphics/emojis/", + ext : ".png" + }; + + // Twitter Emoji (Twemoji) graphics files url path + editormd.twemoji = { + path : "http://twemoji.maxcdn.com/36x36/", + ext : ".png" + }; + + /** + * 自定义marked的解析器 + * Custom Marked renderer rules + * + * @param {Array} markdownToC 传入用于接收TOC的数组 + * @returns {Renderer} markedRenderer 返回marked的Renderer自定义对象 + */ + + editormd.markedRenderer = function(markdownToC, options) { + var defaults = { + toc : true, // Table of contents + tocm : false, + tocStartLevel : 1, // Said from H1 to create ToC + pageBreak : true, + atLink : true, // for @link + emailLink : true, // for mail address auto link + taskList : false, // Enable Github Flavored Markdown task lists + emoji : false, // :emoji: , Support Twemoji, fontAwesome, Editor.md logo emojis. + tex : false, // TeX(LaTeX), based on KaTeX + flowChart : false, // flowChart.js only support IE9+ + sequenceDiagram : false, // sequenceDiagram.js only support IE9+ + }; + + var settings = $.extend(defaults, options || {}); + var marked = editormd.$marked; + var markedRenderer = new marked.Renderer(); + markdownToC = markdownToC || []; + + var regexs = editormd.regexs; + var atLinkReg = regexs.atLink; + var emojiReg = regexs.emoji; + var emailReg = regexs.email; + var emailLinkReg = regexs.emailLink; + var twemojiReg = regexs.twemoji; + var faIconReg = regexs.fontAwesome; + var editormdLogoReg = regexs.editormdLogo; + var pageBreakReg = regexs.pageBreak; + + markedRenderer.emoji = function(text) { + + text = text.replace(editormd.regexs.emojiDatetime, function($1) { + return $1.replace(/:/g, ":"); + }); + + var matchs = text.match(emojiReg); + + if (!matchs || !settings.emoji) { + return text; + } + + for (var i = 0, len = matchs.length; i < len; i++) + { + if (matchs[i] === ":+1:") { + matchs[i] = ":\\+1:"; + } + + text = text.replace(new RegExp(matchs[i]), function($1, $2){ + var faMatchs = $1.match(faIconReg); + var name = $1.replace(/:/g, ""); + + if (faMatchs) + { + for (var fa = 0, len1 = faMatchs.length; fa < len1; fa++) + { + var faName = faMatchs[fa].replace(/:/g, ""); + + return ""; + } + } + else + { + var emdlogoMathcs = $1.match(editormdLogoReg); + var twemojiMatchs = $1.match(twemojiReg); + + if (emdlogoMathcs) + { + for (var x = 0, len2 = emdlogoMathcs.length; x < len2; x++) + { + var logoName = emdlogoMathcs[x].replace(/:/g, ""); + return ""; + } + } + else if (twemojiMatchs) + { + for (var t = 0, len3 = twemojiMatchs.length; t < len3; t++) + { + var twe = twemojiMatchs[t].replace(/:/g, "").replace("tw-", ""); + return "\"twemoji-""; + } + } + else + { + var src = (name === "+1") ? "plus1" : name; + src = (src === "black_large_square") ? "black_square" : src; + src = (src === "moon") ? "waxing_gibbous_moon" : src; + + return "\":""; + } + } + }); + } + + return text; + }; + + markedRenderer.atLink = function(text) { + + if (atLinkReg.test(text)) + { + if (settings.atLink) + { + text = text.replace(emailReg, function($1, $2, $3, $4) { + return $1.replace(/@/g, "_#_@_#_"); + }); + + text = text.replace(atLinkReg, function($1, $2) { + return "" + $1 + ""; + }).replace(/_#_@_#_/g, "@"); + } + + if (settings.emailLink) + { + text = text.replace(emailLinkReg, function($1, $2, $3, $4, $5) { + return (!$2 && $.inArray($5, "jpg|jpeg|png|gif|webp|ico|icon|pdf".split("|")) < 0) ? ""+$1+"" : $1; + }); + } + + return text; + } + + return text; + }; + + markedRenderer.link = function (href, title, text) { + + if (this.options.sanitize) { + try { + var prot = decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase(); + } catch(e) { + return ""; + } + + if (prot.indexOf("javascript:") === 0) { + return ""; + } + } + + var out = "" + text.replace(/@/g, "@") + ""; + } + + if (title) { + out += " title=\"" + title + "\""; + } + + out += ">" + text + ""; + + return out; + }; + + markedRenderer.heading = function(text, level, raw) { + + var linkText = text; + var hasLinkReg = /\s*\]*)\>(.*)\<\/a\>\s*/; + var getLinkTextReg = /\s*\]+)\>([^\>]*)\<\/a\>\s*/g; + + if (hasLinkReg.test(text)) + { + var tempText = []; + text = text.split(/\]+)\>([^\>]*)\<\/a\>/); + + for (var i = 0, len = text.length; i < len; i++) + { + tempText.push(text[i].replace(/\s*href\=\"(.*)\"\s*/g, "")); + } + + text = tempText.join(" "); + } + + text = trim(text); + + var escapedText = text.toLowerCase().replace(/[^\w]+/g, "-"); + var toc = { + text : text, + level : level, + slug : escapedText + }; + + var isChinese = /^[\u4e00-\u9fa5]+$/.test(text); + var id = (isChinese) ? escape(text).replace(/\%/g, "") : text.toLowerCase().replace(/[^\w]+/g, "-"); + + markdownToC.push(toc); + + var headingHTML = ""; + + headingHTML += ""; + headingHTML += ""; + headingHTML += (hasLinkReg) ? this.atLink(this.emoji(linkText)) : this.atLink(this.emoji(text)); + headingHTML += ""; + + return headingHTML; + }; + + markedRenderer.pageBreak = function(text) { + if (pageBreakReg.test(text) && settings.pageBreak) + { + text = "
                  "; + } + + return text; + }; + + markedRenderer.paragraph = function(text) { + var isTeXInline = /\$\$(.*)\$\$/g.test(text); + var isTeXLine = /^\$\$(.*)\$\$$/.test(text); + var isTeXAddClass = (isTeXLine) ? " class=\"" + editormd.classNames.tex + "\"" : ""; + var isToC = (settings.tocm) ? /^(\[TOC\]|\[TOCM\])$/.test(text) : /^\[TOC\]$/.test(text); + var isToCMenu = /^\[TOCM\]$/.test(text); + + if (!isTeXLine && isTeXInline) + { + text = text.replace(/(\$\$([^\$]*)\$\$)+/g, function($1, $2) { + return "" + $2.replace(/\$/g, "") + ""; + }); + } + else + { + text = (isTeXLine) ? text.replace(/\$/g, "") : text; + } + + var tocHTML = "
                  " + text + "
                  "; + + return (isToC) ? ( (isToCMenu) ? "
                  " + tocHTML + "

                  " : tocHTML ) + : ( (pageBreakReg.test(text)) ? this.pageBreak(text) : "" + this.atLink(this.emoji(text)) + "

                  \n" ); + }; + + markedRenderer.code = function (code, lang, escaped) { + + if (lang === "seq" || lang === "sequence") + { + return "
                  " + code + "
                  "; + } + else if ( lang === "flow") + { + return "
                  " + code + "
                  "; + } + else if ( lang === "math" || lang === "latex" || lang === "katex") + { + return "

                  " + code + "

                  "; + } + else + { + + return marked.Renderer.prototype.code.apply(this, arguments); + } + }; + + markedRenderer.tablecell = function(content, flags) { + var type = (flags.header) ? "th" : "td"; + var tag = (flags.align) ? "<" + type +" style=\"text-align:" + flags.align + "\">" : "<" + type + ">"; + + return tag + this.atLink(this.emoji(content)) + "\n"; + }; + + markedRenderer.listitem = function(text) { + if (settings.taskList && /^\s*\[[x\s]\]\s*/.test(text)) + { + text = text.replace(/^\s*\[\s\]\s*/, " ") + .replace(/^\s*\[x\]\s*/, " "); + + return "
                • " + this.atLink(this.emoji(text)) + "
                • "; + } + else + { + return "
                • " + this.atLink(this.emoji(text)) + "
                • "; + } + }; + + return markedRenderer; + }; + + /** + * + * 生成TOC(Table of Contents) + * Creating ToC (Table of Contents) + * + * @param {Array} toc 从marked获取的TOC数组列表 + * @param {Element} container 插入TOC的容器元素 + * @param {Integer} startLevel Hx 起始层级 + * @returns {Object} tocContainer 返回ToC列表容器层的jQuery对象元素 + */ + + editormd.markdownToCRenderer = function(toc, container, tocDropdown, startLevel) { + + var html = ""; + var lastLevel = 0; + var classPrefix = this.classPrefix; + + startLevel = startLevel || 1; + + for (var i = 0, len = toc.length; i < len; i++) + { + var text = toc[i].text; + var level = toc[i].level; + + if (level < startLevel) { + continue; + } + + if (level > lastLevel) + { + html += ""; + } + else if (level < lastLevel) + { + html += (new Array(lastLevel - level + 2)).join("
              • "); + } + else + { + html += ""; + } + + html += "
              • " + text + "
                  "; + lastLevel = level; + } + + var tocContainer = container.find(".markdown-toc"); + + if ((tocContainer.length < 1 && container.attr("previewContainer") === "false")) + { + var tocHTML = "
                  "; + + tocHTML = (tocDropdown) ? "
                  " + tocHTML + "
                  " : tocHTML; + + container.html(tocHTML); + + tocContainer = container.find(".markdown-toc"); + } + + if (tocDropdown) + { + tocContainer.wrap("

                  "); + } + + tocContainer.html("
                    ").children(".markdown-toc-list").html(html.replace(/\r?\n?\\<\/ul\>/g, "")); + + return tocContainer; + }; + + /** + * + * 生成TOC下拉菜单 + * Creating ToC dropdown menu + * + * @param {Object} container 插入TOC的容器jQuery对象元素 + * @param {String} tocTitle ToC title + * @returns {Object} return toc-menu object + */ + + editormd.tocDropdownMenu = function(container, tocTitle) { + + tocTitle = tocTitle || "Table of Contents"; + + var zindex = 400; + var tocMenus = container.find("." + this.classPrefix + "toc-menu"); + + tocMenus.each(function() { + var $this = $(this); + var toc = $this.children(".markdown-toc"); + var icon = ""; + var btn = "" + icon + tocTitle + ""; + var menu = toc.children("ul"); + var list = menu.find("li"); + + toc.append(btn); + + list.first().before("
                  • " + tocTitle + " " + icon + "

                  • "); + + $this.mouseover(function(){ + menu.show(); + + list.each(function(){ + var li = $(this); + var ul = li.children("ul"); + + if (ul.html() === "") + { + ul.remove(); + } + + if (ul.length > 0 && ul.html() !== "") + { + var firstA = li.children("a").first(); + + if (firstA.children(".fa").length < 1) + { + firstA.append( $(icon).css({ float:"right", paddingTop:"4px" }) ); + } + } + + li.mouseover(function(){ + ul.css("z-index", zindex).show(); + zindex += 1; + }).mouseleave(function(){ + ul.hide(); + }); + }); + }).mouseleave(function(){ + menu.hide(); + }); + }); + + return tocMenus; + }; + + /** + * 简单地过滤指定的HTML标签 + * Filter custom html tags + * + * @param {String} html 要过滤HTML + * @param {String} filters 要过滤的标签 + * @returns {String} html 返回过滤的HTML + */ + + editormd.filterHTMLTags = function(html, filters) { + + if (typeof html !== "string") { + html = new String(html); + } + + if (typeof filters !== "string") { + return html; + } + + var expression = filters.split("|"); + var filterTags = expression[0].split(","); + var attrs = expression[1]; + + for (var i = 0, len = filterTags.length; i < len; i++) + { + var tag = filterTags[i]; + + html = html.replace(new RegExp("\<\s*" + tag + "\s*([^\>]*)\>([^\>]*)\<\s*\/" + tag + "\s*\>", "igm"), ""); + } + + //return html; + + if (typeof attrs !== "undefined") + { + var htmlTagRegex = /\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/ig; + + if (attrs === "*") + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { + return "<" + $2 + ">" + $4 + ""; + }); + } + else if (attrs === "on*") + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { + var el = $("<" + $2 + ">" + $4 + ""); + var _attrs = $($1)[0].attributes; + var $attrs = {}; + + $.each(_attrs, function(i, e) { + if (e.nodeName !== '"') $attrs[e.nodeName] = e.nodeValue; + }); + + $.each($attrs, function(i) { + if (i.indexOf("on") === 0) { + delete $attrs[i]; + } + }); + + el.attr($attrs); + + var text = (typeof el[1] !== "undefined") ? $(el[1]).text() : ""; + + return el[0].outerHTML + text; + }); + } + else + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4) { + var filterAttrs = attrs.split(","); + var el = $($1); + el.html($4); + + $.each(filterAttrs, function(i) { + el.attr(filterAttrs[i], null); + }); + + return el[0].outerHTML; + }); + } + } + + return html; + }; + + /** + * 将Markdown文档解析为HTML用于前台显示 + * Parse Markdown to HTML for Font-end preview. + * + * @param {String} id 用于显示HTML的对象ID + * @param {Object} [options={}] 配置选项,可选 + * @returns {Object} div 返回jQuery对象元素 + */ + + editormd.markdownToHTML = function(id, options) { + var defaults = { + gfm : true, + toc : true, + tocm : false, + tocStartLevel : 1, + tocTitle : "目录", + tocDropdown : false, + tocContainer : "", + markdown : "", + markdownSourceCode : false, + htmlDecode : false, + autoLoadKaTeX : true, + pageBreak : true, + atLink : true, // for @link + emailLink : true, // for mail address auto link + tex : false, + taskList : false, // Github Flavored Markdown task lists + emoji : false, + flowChart : false, + sequenceDiagram : false, + previewCodeHighlight : true + }; + + editormd.$marked = marked; + + var div = $("#" + id); + var settings = div.settings = $.extend(true, defaults, options || {}); + var saveTo = div.find("textarea"); + + if (saveTo.length < 1) + { + div.append(""); + saveTo = div.find("textarea"); + } + + var markdownDoc = (settings.markdown === "") ? saveTo.val() : settings.markdown; + var markdownToC = []; + + var rendererOptions = { + toc : settings.toc, + tocm : settings.tocm, + tocStartLevel : settings.tocStartLevel, + taskList : settings.taskList, + emoji : settings.emoji, + tex : settings.tex, + pageBreak : settings.pageBreak, + atLink : settings.atLink, // for @link + emailLink : settings.emailLink, // for mail address auto link + flowChart : settings.flowChart, + sequenceDiagram : settings.sequenceDiagram, + previewCodeHighlight : settings.previewCodeHighlight, + }; + + var markedOptions = { + renderer : editormd.markedRenderer(markdownToC, rendererOptions), + gfm : settings.gfm, + tables : true, + breaks : true, + pedantic : false, + sanitize : (settings.htmlDecode) ? false : true, // 是否忽略HTML标签,即是否开启HTML标签解析,为了安全性,默认不开启 + smartLists : true, + smartypants : true + }; + + markdownDoc = new String(markdownDoc); + + var markdownParsed = marked(markdownDoc, markedOptions); + + markdownParsed = editormd.filterHTMLTags(markdownParsed, settings.htmlDecode); + + if (settings.markdownSourceCode) { + saveTo.text(markdownDoc); + } else { + saveTo.remove(); + } + + div.addClass("markdown-body " + this.classPrefix + "html-preview").append(markdownParsed); + + var tocContainer = (settings.tocContainer !== "") ? $(settings.tocContainer) : div; + + if (settings.tocContainer !== "") + { + tocContainer.attr("previewContainer", false); + } + + if (settings.toc) + { + div.tocContainer = this.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); + + if (settings.tocDropdown || div.find("." + this.classPrefix + "toc-menu").length > 0) + { + this.tocDropdownMenu(div, settings.tocTitle); + } + + if (settings.tocContainer !== "") + { + div.find(".editormd-toc-menu, .editormd-markdown-toc").remove(); + } + } + + if (settings.previewCodeHighlight) + { + div.find("pre").addClass("prettyprint linenums"); + prettyPrint(); + } + + if (!editormd.isIE8) + { + if (settings.flowChart) { + div.find(".flowchart").flowChart(); + } + + if (settings.sequenceDiagram) { + div.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); + } + } + + if (settings.tex) + { + var katexHandle = function() { + div.find("." + editormd.classNames.tex).each(function(){ + var tex = $(this); + katex.render(tex.text(), tex[0]); + tex.find(".katex").css("font-size", "1.0em"); + }); + }; + + if (settings.autoLoadKaTeX && !editormd.$katex && !editormd.kaTeXLoaded) + { + this.loadKaTeX(function() { + editormd.$katex = katex; + editormd.kaTeXLoaded = true; + katexHandle(); + }); + } + else + { + katexHandle(); + } + } + + div.getMarkdown = function() { + return saveTo.val(); + }; + + return div; + }; + + // Editor.md themes, change toolbar themes etc. + // added @1.5.0 + editormd.themes = ["default", "dark"]; + + // Preview area themes + // added @1.5.0 + editormd.previewThemes = ["default", "dark"]; + + // CodeMirror / editor area themes + // @1.5.0 rename -> editorThemes, old version -> themes + editormd.editorThemes = [ + "default", "3024-day", "3024-night", + "ambiance", "ambiance-mobile", + "base16-dark", "base16-light", "blackboard", + "cobalt", + "eclipse", "elegant", "erlang-dark", + "lesser-dark", + "mbo", "mdn-like", "midnight", "monokai", + "neat", "neo", "night", + "paraiso-dark", "paraiso-light", "pastel-on-dark", + "rubyblue", + "solarized", + "the-matrix", "tomorrow-night-eighties", "twilight", + "vibrant-ink", + "xq-dark", "xq-light" + ]; + + editormd.loadPlugins = {}; + + editormd.loadFiles = { + js : [], + css : [], + plugin : [] + }; + + /** + * 动态加载Editor.md插件,但不立即执行 + * Load editor.md plugins + * + * @param {String} fileName 插件文件路径 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadPlugin = function(fileName, callback, into) { + callback = callback || function() {}; + + this.loadScript(fileName, function() { + editormd.loadFiles.plugin.push(fileName); + callback(); + }, into); + }; + + /** + * 动态加载CSS文件的方法 + * Load css file method + * + * @param {String} fileName CSS文件名 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadCSS = function(fileName, callback, into) { + into = into || "head"; + callback = callback || function() {}; + + var css = document.createElement("link"); + css.type = "text/css"; + css.rel = "stylesheet"; + css.onload = css.onreadystatechange = function() { + editormd.loadFiles.css.push(fileName); + callback(); + }; + + css.href = fileName + ".css"; + + if(into === "head") { + document.getElementsByTagName("head")[0].appendChild(css); + } else { + document.body.appendChild(css); + } + }; + + editormd.isIE = (navigator.appName == "Microsoft Internet Explorer"); + editormd.isIE8 = (editormd.isIE && navigator.appVersion.match(/8./i) == "8."); + + /** + * 动态加载JS文件的方法 + * Load javascript file method + * + * @param {String} fileName JS文件名 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadScript = function(fileName, callback, into) { + + into = into || "head"; + callback = callback || function() {}; + + var script = null; + script = document.createElement("script"); + script.id = fileName.replace(/[\./]+/g, "-"); + script.type = "text/javascript"; + script.src = fileName + ".js"; + + if (editormd.isIE8) + { + script.onreadystatechange = function() { + if(script.readyState) + { + if (script.readyState === "loaded" || script.readyState === "complete") + { + script.onreadystatechange = null; + editormd.loadFiles.js.push(fileName); + callback(); + } + } + }; + } + else + { + script.onload = function() { + editormd.loadFiles.js.push(fileName); + callback(); + }; + } + + if (into === "head") { + document.getElementsByTagName("head")[0].appendChild(script); + } else { + document.body.appendChild(script); + } + }; + + // 使用国外的CDN,加载速度有时会很慢,或者自定义URL + // You can custom KaTeX load url. + editormd.katexURL = { + css : "/katex/katex.min", + js : "/katex/katex.min" + }; + + editormd.kaTeXLoaded = false; + + /** + * 加载KaTeX文件 + * load KaTeX files + * + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + */ + + editormd.loadKaTeX = function (callback) { + editormd.loadCSS(editormd.katexURL.css, function(){ + editormd.loadScript(editormd.katexURL.js, callback || function(){}); + }); + }; + + /** + * 锁屏 + * lock screen + * + * @param {Boolean} lock Boolean 布尔值,是否锁屏 + * @returns {void} + */ + + editormd.lockScreen = function(lock) { + $("html,body").css("overflow", (lock) ? "hidden" : ""); + }; + + /** + * 动态创建对话框 + * Creating custom dialogs + * + * @param {Object} options 配置项键值对 Key/Value + * @returns {dialog} 返回创建的dialog的jQuery实例对象 + */ + + editormd.createDialog = function(options) { + var defaults = { + name : "", + width : 420, + height: 240, + title : "", + drag : true, + closed : true, + content : "", + mask : true, + maskStyle : { + backgroundColor : "#fff", + opacity : 0.1 + }, + lockScreen : true, + footer : true, + buttons : false + }; + + options = $.extend(true, defaults, options); + + var $this = this; + var editor = this.editor; + var classPrefix = editormd.classPrefix; + var guid = (new Date()).getTime(); + var dialogName = ( (options.name === "") ? classPrefix + "dialog-" + guid : options.name); + var mouseOrTouch = editormd.mouseOrTouch; + + var html = "
                    "; + + if (options.title !== "") + { + html += "
                    "; + html += "" + options.title + ""; + html += "
                    "; + } + + if (options.closed) + { + html += ""; + } + + html += "
                    " + options.content; + + if (options.footer || typeof options.footer === "string") + { + html += "
                    " + ( (typeof options.footer === "boolean") ? "" : options.footer) + "
                    "; + } + + html += "
                    "; + + html += "
                    "; + html += "
                    "; + html += "
                    "; + + editor.append(html); + + var dialog = editor.find("." + dialogName); + + dialog.lockScreen = function(lock) { + if (options.lockScreen) + { + $("html,body").css("overflow", (lock) ? "hidden" : ""); + $this.resize(); + } + + return dialog; + }; + + dialog.showMask = function() { + if (options.mask) + { + editor.find("." + classPrefix + "mask").css(options.maskStyle).css("z-index", editormd.dialogZindex - 1).show(); + } + return dialog; + }; + + dialog.hideMask = function() { + if (options.mask) + { + editor.find("." + classPrefix + "mask").hide(); + } + + return dialog; + }; + + dialog.loading = function(show) { + var loading = dialog.find("." + classPrefix + "dialog-mask"); + loading[(show) ? "show" : "hide"](); + + return dialog; + }; + + dialog.lockScreen(true).showMask(); + + dialog.show().css({ + zIndex : editormd.dialogZindex, + border : (editormd.isIE8) ? "1px solid #ddd" : "", + width : (typeof options.width === "number") ? options.width + "px" : options.width, + height : (typeof options.height === "number") ? options.height + "px" : options.height + }); + + var dialogPosition = function(){ + dialog.css({ + top : ($(window).height() - dialog.height()) / 2 + "px", + left : ($(window).width() - dialog.width()) / 2 + "px" + }); + }; + + dialogPosition(); + + $(window).resize(dialogPosition); + + dialog.children("." + classPrefix + "dialog-close").bind(mouseOrTouch("click", "touchend"), function() { + dialog.hide().lockScreen(false).hideMask(); + }); + + if (typeof options.buttons === "object") + { + var footer = dialog.footer = dialog.find("." + classPrefix + "dialog-footer"); + + for (var key in options.buttons) + { + var btn = options.buttons[key]; + var btnClassName = classPrefix + key + "-btn"; + + footer.append(""); + btn[1] = $.proxy(btn[1], dialog); + footer.children("." + btnClassName).bind(mouseOrTouch("click", "touchend"), btn[1]); + } + } + + if (options.title !== "" && options.drag) + { + var posX, posY; + var dialogHeader = dialog.children("." + classPrefix + "dialog-header"); + + if (!options.mask) { + dialogHeader.bind(mouseOrTouch("click", "touchend"), function(){ + editormd.dialogZindex += 2; + dialog.css("z-index", editormd.dialogZindex); + }); + } + + dialogHeader.mousedown(function(e) { + e = e || window.event; //IE + posX = e.clientX - parseInt(dialog[0].style.left); + posY = e.clientY - parseInt(dialog[0].style.top); + + document.onmousemove = moveAction; + }); + + var userCanSelect = function (obj) { + obj.removeClass(classPrefix + "user-unselect").off("selectstart"); + }; + + var userUnselect = function (obj) { + obj.addClass(classPrefix + "user-unselect").on("selectstart", function(event) { // selectstart for IE + return false; + }); + }; + + var moveAction = function (e) { + e = e || window.event; //IE + + var left, top, nowLeft = parseInt(dialog[0].style.left), nowTop = parseInt(dialog[0].style.top); + + if( nowLeft >= 0 ) { + if( nowLeft + dialog.width() <= $(window).width()) { + left = e.clientX - posX; + } else { + left = $(window).width() - dialog.width(); + document.onmousemove = null; + } + } else { + left = 0; + document.onmousemove = null; + } + + if( nowTop >= 0 ) { + top = e.clientY - posY; + } else { + top = 0; + document.onmousemove = null; + } + + + document.onselectstart = function() { + return false; + }; + + userUnselect($("body")); + userUnselect(dialog); + dialog[0].style.left = left + "px"; + dialog[0].style.top = top + "px"; + }; + + document.onmouseup = function() { + userCanSelect($("body")); + userCanSelect(dialog); + + document.onselectstart = null; + document.onmousemove = null; + }; + + dialogHeader.touchDraggable = function() { + var offset = null; + var start = function(e) { + var orig = e.originalEvent; + var pos = $(this).parent().position(); + + offset = { + x : orig.changedTouches[0].pageX - pos.left, + y : orig.changedTouches[0].pageY - pos.top + }; + }; + + var move = function(e) { + e.preventDefault(); + var orig = e.originalEvent; + + $(this).parent().css({ + top : orig.changedTouches[0].pageY - offset.y, + left : orig.changedTouches[0].pageX - offset.x + }); + }; + + this.bind("touchstart", start).bind("touchmove", move); + }; + + dialogHeader.touchDraggable(); + } + + editormd.dialogZindex += 2; + $("body").removeAttr("style"); + return dialog; + }; + + /** + * 鼠标和触摸事件的判断/选择方法 + * MouseEvent or TouchEvent type switch + * + * @param {String} [mouseEventType="click"] 供选择的鼠标事件 + * @param {String} [touchEventType="touchend"] 供选择的触摸事件 + * @returns {String} EventType 返回事件类型名称 + */ + + editormd.mouseOrTouch = function(mouseEventType, touchEventType) { + mouseEventType = mouseEventType || "click"; + touchEventType = touchEventType || "touchend"; + + var eventType = mouseEventType; + + try { + document.createEvent("TouchEvent"); + eventType = touchEventType; + } catch(e) {} + + return eventType; + }; + + /** + * 日期时间的格式化方法 + * Datetime format method + * + * @param {String} [format=""] 日期时间的格式,类似PHP的格式 + * @returns {String} datefmt 返回格式化后的日期时间字符串 + */ + + editormd.dateFormat = function(format) { + format = format || ""; + + var addZero = function(d) { + return (d < 10) ? "0" + d : d; + }; + + var date = new Date(); + var year = date.getFullYear(); + var year2 = year.toString().slice(2, 4); + var month = addZero(date.getMonth() + 1); + var day = addZero(date.getDate()); + var weekDay = date.getDay(); + var hour = addZero(date.getHours()); + var min = addZero(date.getMinutes()); + var second = addZero(date.getSeconds()); + var ms = addZero(date.getMilliseconds()); + var datefmt = ""; + + var ymd = year2 + "-" + month + "-" + day; + var fymd = year + "-" + month + "-" + day; + var hms = hour + ":" + min + ":" + second; + + switch (format) + { + case "UNIX Time" : + datefmt = date.getTime(); + break; + + case "UTC" : + datefmt = date.toUTCString(); + break; + + case "yy" : + datefmt = year2; + break; + + case "year" : + case "yyyy" : + datefmt = year; + break; + + case "month" : + case "mm" : + datefmt = month; + break; + + case "cn-week-day" : + case "cn-wd" : + var cnWeekDays = ["日", "一", "二", "三", "四", "五", "六"]; + datefmt = "星期" + cnWeekDays[weekDay]; + break; + + case "week-day" : + case "wd" : + var weekDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + datefmt = weekDays[weekDay]; + break; + + case "day" : + case "dd" : + datefmt = day; + break; + + case "hour" : + case "hh" : + datefmt = hour; + break; + + case "min" : + case "ii" : + datefmt = min; + break; + + case "second" : + case "ss" : + datefmt = second; + break; + + case "ms" : + datefmt = ms; + break; + + case "yy-mm-dd" : + datefmt = ymd; + break; + + case "yyyy-mm-dd" : + datefmt = fymd; + break; + + case "yyyy-mm-dd h:i:s ms" : + case "full + ms" : + datefmt = fymd + " " + hms + " " + ms; + break; + + case "full" : + case "yyyy-mm-dd h:i:s" : + default: + datefmt = fymd + " " + hms; + break; + } + + return datefmt; + }; + + return editormd; + +})); + +/** + cm paste事件上传图片的封装 + event : paste事件的event + action: 图片上传url + callback: 图片上传xhr回调 + */ +window._whenPasterDoUpload = function(event, action, callback){ + var clipboardData = event.clipboardData, + i = 0, items, item, types; + if( clipboardData ){ + items = clipboardData.items; + if( !items ) + return; + item = items[0]; + // 保存在剪贴板中的数据类型 + types = clipboardData.types || []; + + for( ; i < types.length; i++ ){ + if( types[i] === 'Files' ){ + item = items[i]; + break; + } + } + // 判断是否为图片数据 + if( item && item.kind === 'file' && item.type.match(/^image\//i) ){ + // 读取该图片 + var file = item.getAsFile(); + var oMyForm = new FormData(); + oMyForm.append("editormd-image-file",file); + oMyForm.append("byxhr","true"); + var xhr = new window.XMLHttpRequest(); + xhr.addEventListener("load", + function(_xhr){ + var response=_xhr.target, json=JSON.parse(response.responseText); + + if (json.success === 1) { + callback && callback(json) + // input.value=json.url; + } + else + { + callback && callback(json) + console.log(json.message); + } + }, false); + xhr.addEventListener("error", function(){console.error("error");}, false); + xhr.open("POST", action); + xhr.send(oMyForm); + } + } +} + +function initEditormdPasteUpload(editormd, url, callback) { + editormd.cm.getInputField().addEventListener("paste", function(event) { + _whenPasterDoUpload(event, url, function(resJson) { + // TODO 插入图片url到cm + if (resJson.success === 1) { + editormd.cm.replaceSelection("![](" + resJson.url + ")") + } + }); + }) +} \ No newline at end of file diff --git a/public/editormd/editormd.min.js b/public/editormd/editormd.min.js new file mode 100644 index 000000000..f989b796f --- /dev/null +++ b/public/editormd/editormd.min.js @@ -0,0 +1,3 @@ +/*! Editor.md v1.5.0 | editormd.min.js | Open source online markdown editor. | MIT License | By: Pandao | https://github.com/pandao/editor.md | 2015-06-09 */ +!function(e){"use strict";"function"==typeof require&&"object"==typeof exports&&"object"==typeof module?module.exports=e:"function"==typeof define?define.amd||define(["jquery"],e):window.editormd=e()}(function(){"use strict";var e="undefined"!=typeof jQuery?jQuery:Zepto;if("undefined"!=typeof e){var t=function(e,i){return new t.fn.init(e,i)};t.title=t.$name="Editor.md",t.version="1.5.0",t.homePage="https://pandao.github.io/editor.md/",t.classPrefix="editormd-",t.toolbarModes={full:["undo","redo","|","bold","del","italic","quote","ucwords","uppercase","lowercase","|","h1","h2","h3","h4","h5","h6","|","list-ul","list-ol","hr","|","link","reference-link","image","code","preformatted-text","code-block","table","datetime","emoji","html-entities","pagebreak","|","goto-line","watch","preview","fullscreen","clear","search","|","help","info"],simple:["undo","redo","|","bold","del","italic","quote","uppercase","lowercase","|","h1","h2","h3","h4","h5","h6","|","list-ul","list-ol","hr","|","watch","preview","fullscreen","|","help","info"],mini:["undo","redo","|","watch","preview","|","help","info"]},t.defaults={mode:"gfm",name:"",value:"",theme:"",editorTheme:"default",previewTheme:"",markdown:"",appendMarkdown:"",width:"100%",height:"100%",path:"./lib/",pluginPath:"",delay:300,autoLoadModules:!0,watch:!0,placeholder:"Enjoy Markdown! coding now...",gotoLine:!0,codeFold:!1,autoHeight:!1,autoFocus:!0,autoCloseTags:!0,searchReplace:!0,syncScrolling:!0,readOnly:!1,tabSize:4,indentUnit:4,lineNumbers:!0,lineWrapping:!0,autoCloseBrackets:!0,showTrailingSpace:!0,matchBrackets:!0,indentWithTabs:!0,styleSelectedText:!0,matchWordHighlight:!0,styleActiveLine:!0,dialogLockScreen:!0,dialogShowMask:!0,dialogDraggable:!0,dialogMaskBgColor:"#fff",dialogMaskOpacity:.1,fontSize:"13px",saveHTMLToTextarea:!1,disabledKeyMaps:[],onload:function(){},onresize:function(){},onchange:function(){},onwatch:null,onunwatch:null,onpreviewing:function(){},onpreviewed:function(){},onfullscreen:function(){},onfullscreenExit:function(){},onscroll:function(){},onpreviewscroll:function(){},imageUpload:!1,imageFormats:["jpg","jpeg","gif","png","bmp","webp"],imageUploadURL:"",crossDomainUpload:!1,uploadCallbackURL:"",toc:!0,tocm:!1,tocTitle:"",tocDropdown:!1,tocContainer:"",tocStartLevel:1,htmlDecode:!1,pageBreak:!0,atLink:!0,emailLink:!0,taskList:!1,emoji:!1,tex:!1,flowChart:!1,sequenceDiagram:!1,previewCodeHighlight:!0,toolbar:!0,toolbarAutoFixed:!0,toolbarIcons:"full",toolbarTitles:{},toolbarHandlers:{ucwords:function(){return t.toolbarHandlers.ucwords},lowercase:function(){return t.toolbarHandlers.lowercase}},toolbarCustomIcons:{lowercase:'a',ucwords:'Aa'},toolbarIconsClass:{undo:"fa-undo",redo:"fa-repeat",bold:"fa-bold",del:"fa-strikethrough",italic:"fa-italic",quote:"fa-quote-left",uppercase:"fa-font",h1:t.classPrefix+"bold",h2:t.classPrefix+"bold",h3:t.classPrefix+"bold",h4:t.classPrefix+"bold",h5:t.classPrefix+"bold",h6:t.classPrefix+"bold","list-ul":"fa-list-ul","list-ol":"fa-list-ol",hr:"fa-minus",link:"fa-link","reference-link":"fa-anchor",image:"fa-picture-o",code:"fa-code","preformatted-text":"fa-file-code-o","code-block":"fa-file-code-o",table:"fa-table",datetime:"fa-clock-o",emoji:"fa-smile-o","html-entities":"fa-copyright",pagebreak:"fa-newspaper-o","goto-line":"fa-terminal",watch:"fa-eye-slash",unwatch:"fa-eye",preview:"fa-desktop",search:"fa-search",fullscreen:"fa-arrows-alt",clear:"fa-eraser",help:"fa-question-circle",info:"fa-info-circle"},toolbarIconTexts:{},lang:{name:"zh-cn",description:"开源在线Markdown编辑器
                    Open source online Markdown editor.",tocTitle:"目录",toolbar:{undo:"撤销(Ctrl+Z)",redo:"重做(Ctrl+Y)",bold:"粗体",del:"删除线",italic:"斜体",quote:"引用",ucwords:"将每个单词首字母转成大写",uppercase:"将所选转换成大写",lowercase:"将所选转换成小写",h1:"标题1",h2:"标题2",h3:"标题3",h4:"标题4",h5:"标题5",h6:"标题6","list-ul":"无序列表","list-ol":"有序列表",hr:"横线",link:"链接","reference-link":"引用链接",image:"添加图片",code:"行内代码","preformatted-text":"预格式文本 / 代码块(缩进风格)","code-block":"代码块(多语言风格)",table:"添加表格",datetime:"日期时间",emoji:"Emoji表情","html-entities":"HTML实体字符",pagebreak:"插入分页符","goto-line":"跳转到行",watch:"关闭实时预览",unwatch:"开启实时预览",preview:"全窗口预览HTML(按 Shift + ESC还原)",fullscreen:"全屏(按ESC还原)",clear:"清空",search:"搜索",help:"使用帮助",info:"关于"+t.title},buttons:{enter:"确定",cancel:"取消",close:"关闭"},dialog:{link:{title:"添加链接",url:"链接地址",urlTitle:"链接标题",urlEmpty:"错误:请填写链接地址。"},referenceLink:{title:"添加引用链接",name:"引用名称",url:"链接地址",urlId:"链接ID",urlTitle:"链接标题",nameEmpty:"错误:引用链接的名称不能为空。",idEmpty:"错误:请填写引用链接的ID。",urlEmpty:"错误:请填写引用链接的URL地址。"},image:{title:"添加图片",url:"图片地址",link:"图片链接",alt:"图片描述",uploadButton:"本地上传",imageURLEmpty:"错误:图片地址不能为空。",uploadFileEmpty:"错误:上传的图片不能为空。",formatNotAllowed:"错误:只允许上传图片文件,允许上传的图片文件格式有:"},preformattedText:{title:"添加预格式文本或代码块",emptyAlert:"错误:请填写预格式文本或代码的内容。"},codeBlock:{title:"添加代码块",selectLabel:"代码语言:",selectDefaultText:"请选择代码语言",otherLanguage:"其他语言",unselectedLanguageAlert:"错误:请选择代码所属的语言类型。",codeEmptyAlert:"错误:请填写代码内容。"},htmlEntities:{title:"HTML 实体字符"},help:{title:"使用帮助"}}}},t.classNames={tex:t.classPrefix+"tex"},t.dialogZindex=99999,t.$katex=null,t.$marked=null,t.$CodeMirror=null,t.$prettyPrint=null;var i,o;t.prototype=t.fn={state:{watching:!1,loaded:!1,preview:!1,fullscreen:!1},init:function(i,o){o=o||{},"object"==typeof i&&(o=i);var r=this.classPrefix=t.classPrefix,n=this.settings=e.extend(!0,t.defaults,o);i="object"==typeof i?n.id:i;var a=this.editor=e("#"+i);this.id=i,this.lang=n.lang;var s=this.classNames={textarea:{html:r+"html-textarea",markdown:r+"markdown-textarea"}};n.pluginPath=""===n.pluginPath?n.path+"../plugins/":n.pluginPath,this.state.watching=n.watch?!0:!1,a.hasClass("editormd")||a.addClass("editormd"),a.css({width:"number"==typeof n.width?n.width+"px":n.width,height:"number"==typeof n.height?n.height+"px":n.height}),n.autoHeight&&a.css("height","auto");var l=this.markdownTextarea=a.children("textarea");l.length<1&&(a.append(""),l=this.markdownTextarea=a.children("textarea")),l.addClass(s.textarea.markdown).attr("placeholder",n.placeholder),("undefined"==typeof l.attr("name")||""===l.attr("name"))&&l.attr("name",""!==n.name?n.name:i+"-markdown-doc");var c=[n.readOnly?"":'',n.saveHTMLToTextarea?'':"",'
                    ','
                    ','
                    '].join("\n");return a.append(c).addClass(r+"vertical"),""!==n.theme&&a.addClass(r+"theme-"+n.theme),this.mask=a.children("."+r+"mask"),this.containerMask=a.children("."+r+"container-mask"),""!==n.markdown&&l.val(n.markdown),""!==n.appendMarkdown&&l.val(l.val()+n.appendMarkdown),this.htmlTextarea=a.children("."+s.textarea.html),this.preview=a.children("."+r+"preview"),this.previewContainer=this.preview.children("."+r+"preview-container"),""!==n.previewTheme&&this.preview.addClass(r+"preview-theme-"+n.previewTheme),"function"==typeof define&&define.amd&&("undefined"!=typeof katex&&(t.$katex=katex),n.searchReplace&&!n.readOnly&&(t.loadCSS(n.path+"codemirror/addon/dialog/dialog"),t.loadCSS(n.path+"codemirror/addon/search/matchesonscrollbar"))),"function"==typeof define&&define.amd||!n.autoLoadModules?("undefined"!=typeof CodeMirror&&(t.$CodeMirror=CodeMirror),"undefined"!=typeof marked&&(t.$marked=marked),this.setCodeMirror().setToolbar().loadedDisplay()):this.loadQueues(),this},loadQueues:function(){var e=this,i=this.settings,o=i.path,r=function(){return t.isIE8?void e.loadedDisplay():void(i.flowChart||i.sequenceDiagram?t.loadScript(o+"raphael.min",function(){t.loadScript(o+"underscore.min",function(){!i.flowChart&&i.sequenceDiagram?t.loadScript(o+"sequence-diagram.min",function(){e.loadedDisplay()}):i.flowChart&&!i.sequenceDiagram?t.loadScript(o+"flowchart.min",function(){t.loadScript(o+"jquery.flowchart.min",function(){e.loadedDisplay()})}):i.flowChart&&i.sequenceDiagram&&t.loadScript(o+"flowchart.min",function(){t.loadScript(o+"jquery.flowchart.min",function(){t.loadScript(o+"sequence-diagram.min",function(){e.loadedDisplay()})})})})}):e.loadedDisplay())};return t.loadCSS(o+"codemirror/codemirror.min"),i.searchReplace&&!i.readOnly&&(t.loadCSS(o+"codemirror/addon/dialog/dialog"),t.loadCSS(o+"codemirror/addon/search/matchesonscrollbar")),i.codeFold&&t.loadCSS(o+"codemirror/addon/fold/foldgutter"),t.loadScript(o+"codemirror/codemirror.min",function(){t.$CodeMirror=CodeMirror,t.loadScript(o+"codemirror/modes.min",function(){t.loadScript(o+"codemirror/addons.min",function(){return e.setCodeMirror(),"gfm"!==i.mode&&"markdown"!==i.mode?(e.loadedDisplay(),!1):(e.setToolbar(),void t.loadScript(o+"marked.min",function(){t.$marked=marked,i.previewCodeHighlight?t.loadScript(o+"prettify.min",function(){r()}):r()}))})})}),this},setTheme:function(e){var t=this.editor,i=this.settings.theme,o=this.classPrefix+"theme-";return t.removeClass(o+i).addClass(o+e),this.settings.theme=e,this},setEditorTheme:function(e){var i=this.settings;return i.editorTheme=e,"default"!==e&&t.loadCSS(i.path+"codemirror/theme/"+i.editorTheme),this.cm.setOption("theme",e),this},setCodeMirrorTheme:function(e){return this.setEditorTheme(e),this},setPreviewTheme:function(e){var t=this.preview,i=this.settings.previewTheme,o=this.classPrefix+"preview-theme-";return t.removeClass(o+i).addClass(o+e),this.settings.previewTheme=e,this},setCodeMirror:function(){var e=this.settings,i=this.editor;"default"!==e.editorTheme&&t.loadCSS(e.path+"codemirror/theme/"+e.editorTheme);var o={mode:e.mode,theme:e.editorTheme,tabSize:e.tabSize,dragDrop:!1,autofocus:e.autoFocus,autoCloseTags:e.autoCloseTags,readOnly:e.readOnly?"nocursor":!1,indentUnit:e.indentUnit,lineNumbers:e.lineNumbers,lineWrapping:e.lineWrapping,extraKeys:{"Ctrl-Q":function(e){e.foldCode(e.getCursor())}},foldGutter:e.codeFold,gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],matchBrackets:e.matchBrackets,indentWithTabs:e.indentWithTabs,styleActiveLine:e.styleActiveLine,styleSelectedText:e.styleSelectedText,autoCloseBrackets:e.autoCloseBrackets,showTrailingSpace:e.showTrailingSpace,highlightSelectionMatches:e.matchWordHighlight?{showToken:"onselected"===e.matchWordHighlight?!1:/\w/}:!1};return this.codeEditor=this.cm=t.$CodeMirror.fromTextArea(this.markdownTextarea[0],o),this.codeMirror=this.cmElement=i.children(".CodeMirror"),""!==e.value&&this.cm.setValue(e.value),this.codeMirror.css({fontSize:e.fontSize,width:e.watch?"50%":"100%"}),e.autoHeight&&(this.codeMirror.css("height","auto"),this.cm.setOption("viewportMargin",1/0)),e.lineNumbers||this.codeMirror.find(".CodeMirror-gutters").css("border-right","none"),this},getCodeMirrorOption:function(e){return this.cm.getOption(e)},setCodeMirrorOption:function(e,t){return this.cm.setOption(e,t),this},addKeyMap:function(e,t){return this.cm.addKeyMap(e,t),this},removeKeyMap:function(e){return this.cm.removeKeyMap(e),this},gotoLine:function(t){var i=this.settings;if(!i.gotoLine)return this;var o=this.cm,r=(this.editor,o.lineCount()),n=this.preview;if("string"==typeof t&&("last"===t&&(t=r),"first"===t&&(t=1)),"number"!=typeof t)return alert("Error: The line number must be an integer."),this;if(t=parseInt(t)-1,t>r)return alert("Error: The line number range 1-"+r),this;o.setCursor({line:t,ch:0});var a=o.getScrollInfo(),s=a.clientHeight,l=o.charCoords({line:t,ch:0},"local");if(o.scrollTo(null,(l.top+l.bottom-s)/2),i.watch){var c=this.codeMirror.find(".CodeMirror-scroll")[0],h=e(c).height(),d=c.scrollTop,u=d/c.scrollHeight;n.scrollTop(0===d?0:d+h>=c.scrollHeight-16?n[0].scrollHeight:n[0].scrollHeight*u)}return o.focus(),this},extend:function(){return"undefined"!=typeof arguments[1]&&("function"==typeof arguments[1]&&(arguments[1]=e.proxy(arguments[1],this)),this[arguments[0]]=arguments[1]),"object"==typeof arguments[0]&&"undefined"==typeof arguments[0].length&&e.extend(!0,this,arguments[0]),this},set:function(t,i){return"undefined"!=typeof i&&"function"==typeof i&&(i=e.proxy(i,this)),this[t]=i,this},config:function(t,i){var o=this.settings;return"object"==typeof t&&(o=e.extend(!0,o,t)),"string"==typeof t&&(o[t]=i),this.settings=o,this.recreate(),this},on:function(t,i){var o=this.settings;return"undefined"!=typeof o["on"+t]&&(o["on"+t]=e.proxy(i,this)),this},off:function(e){var t=this.settings;return"undefined"!=typeof t["on"+e]&&(t["on"+e]=function(){}),this},showToolbar:function(t){var i=this.settings;return i.readOnly?this:(i.toolbar&&(this.toolbar.length<1||""===this.toolbar.find("."+this.classPrefix+"menu").html())&&this.setToolbar(),i.toolbar=!0,this.toolbar.show(),this.resize(),e.proxy(t||function(){},this)(),this)},hideToolbar:function(t){var i=this.settings;return i.toolbar=!1,this.toolbar.hide(),this.resize(),e.proxy(t||function(){},this)(),this},setToolbarAutoFixed:function(t){var i=this.state,o=this.editor,r=this.toolbar,n=this.settings;"undefined"!=typeof t&&(n.toolbarAutoFixed=t);var a=function(){var t=e(window),i=t.scrollTop();return n.toolbarAutoFixed?void r.css(i-o.offset().top>10&&i
                      ';i.append(n),r=this.toolbar=i.children("."+o+"toolbar")}if(!e.toolbar)return r.hide(),this;r.show();for(var a="function"==typeof e.toolbarIcons?e.toolbarIcons():"string"==typeof e.toolbarIcons?t.toolbarModes[e.toolbarIcons]:e.toolbarIcons,s=r.find("."+this.classPrefix+"menu"),l="",c=!1,h=0,d=a.length;d>h;h++){var u=a[h];if("||"===u)c=!0;else if("|"===u)l+='
                    • |
                    • ';else{var f=/h(\d)/.test(u),g=u;"watch"!==u||e.watch||(g="unwatch");var p=e.lang.toolbar[g],m=e.toolbarIconTexts[g],w=e.toolbarIconsClass[g];p="undefined"==typeof p?"":p,m="undefined"==typeof m?"":m,w="undefined"==typeof w?"":w;var v=c?'
                    • ':"
                    • ";"undefined"!=typeof e.toolbarCustomIcons[u]&&"function"!=typeof e.toolbarCustomIcons[u]?v+=e.toolbarCustomIcons[u]:(v+='',v+=''+(f?u.toUpperCase():""===w?m:"")+"",v+=""),v+="
                    • ",l=c?v+l:l+v}}return s.html(l),s.find('[title="Lowercase"]').attr("title",e.lang.toolbar.lowercase),s.find('[title="ucwords"]').attr("title",e.lang.toolbar.ucwords),this.setToolbarHandler(),this.setToolbarAutoFixed(),this},dialogLockScreen:function(){return e.proxy(t.dialogLockScreen,this)(),this},dialogShowMask:function(i){return e.proxy(t.dialogShowMask,this)(i),this},getToolbarHandles:function(e){var i=this.toolbarHandlers=t.toolbarHandlers;return e&&"undefined"!=typeof toolbarIconHandlers[e]?i[e]:i},setToolbarHandler:function(){var i=this,o=this.settings;if(!o.toolbar||o.readOnly)return this;var r=this.toolbar,n=this.cm,a=this.classPrefix,s=this.toolbarIcons=r.find("."+a+"menu > li > a"),l=this.getToolbarHandles();return s.bind(t.mouseOrTouch("click","touchend"),function(t){var r=e(this).children(".fa"),a=r.attr("name"),s=n.getCursor(),c=n.getSelection();return""!==a?(i.activeIcon=r,"undefined"!=typeof l[a]?e.proxy(l[a],i)(n):"undefined"!=typeof o.toolbarHandlers[a]&&e.proxy(o.toolbarHandlers[a],i)(n,r,s,c),"link"!==a&&"reference-link"!==a&&"image"!==a&&"code-block"!==a&&"preformatted-text"!==a&&"watch"!==a&&"preview"!==a&&"search"!==a&&"fullscreen"!==a&&"info"!==a&&n.focus(),!1):void 0}),this},createDialog:function(i){return e.proxy(t.createDialog,this)(i)},createInfoDialog:function(){var e=this,i=this.editor,o=this.classPrefix,r=['
                      ','
                      ','

                      '+t.title+"v"+t.version+"

                      ","

                      "+this.lang.description+"

                      ",'

                      '+t.homePage+'

                      ','

                      Copyright © 2015 Pandao, The MIT License.

                      ',"
                      ",'',"
                      "].join("\n");i.append(r);var n=this.infoDialog=i.children("."+o+"dialog-info");return n.find("."+o+"dialog-close").bind(t.mouseOrTouch("click","touchend"),function(){e.hideInfoDialog()}),n.css("border",t.isIE8?"1px solid #ddd":"").css("z-index",t.dialogZindex).show(),this.infoDialogPosition(),this},infoDialogPosition:function(){var t=this.infoDialog,i=function(){t.css({top:(e(window).height()-t.height())/2+"px",left:(e(window).width()-t.width())/2+"px"})};return i(),e(window).resize(i),this},showInfoDialog:function(){e("html,body").css("overflow-x","hidden");var i=this.editor,o=this.settings,r=this.infoDialog=i.children("."+this.classPrefix+"dialog-info");return r.length<1&&this.createInfoDialog(),this.lockScreen(!0),this.mask.css({opacity:o.dialogMaskOpacity,backgroundColor:o.dialogMaskBgColor}).show(),r.css("z-index",t.dialogZindex).show(),this.infoDialogPosition(),this},hideInfoDialog:function(){return e("html,body").css("overflow-x",""),this.infoDialog.hide(),this.mask.hide(),this.lockScreen(!1),this},lockScreen:function(e){return t.lockScreen(e),this.resize(),this},recreate:function(){var e=this.editor,t=this.settings;return this.codeMirror.remove(),this.setCodeMirror(),t.readOnly||(e.find(".editormd-dialog").length>0&&e.find(".editormd-dialog").remove(),t.toolbar&&(this.getToolbarHandles(),this.setToolbar())),this.loadedDisplay(!0),this},previewCodeHighlight:function(){var e=this.settings,t=this.previewContainer;return e.previewCodeHighlight&&(t.find("pre").addClass("prettyprint linenums"),"undefined"!=typeof prettyPrint&&prettyPrint()),this},katexRender:function(){return null===i?this:(this.previewContainer.find("."+t.classNames.tex).each(function(){var i=e(this);t.$katex.render(i.text(),i[0]),i.find(".katex").css("font-size","1.6em")}),this)},flowChartAndSequenceDiagramRender:function(){var i=this,r=this.settings,n=this.previewContainer;if(t.isIE8)return this;if(r.flowChart){if(null===o)return this;n.find(".flowchart").flowChart()}r.sequenceDiagram&&n.find(".sequence-diagram").sequenceDiagram({theme:"simple"});var a=i.preview,s=i.codeMirror,l=s.find(".CodeMirror-scroll"),c=l.height(),h=l.scrollTop(),d=h/l[0].scrollHeight,u=0;a.find(".markdown-toc-list").each(function(){u+=e(this).height()});var f=a.find(".editormd-toc-menu").height();return f=f?f:0,a.scrollTop(0===h?0:h+c>=l[0].scrollHeight-16?a[0].scrollHeight:(a[0].scrollHeight+u+f)*d),this},registerKeyMaps:function(i){var o=this,r=this.cm,n=this.settings,a=t.toolbarHandlers,s=n.disabledKeyMaps;if(i=i||null){for(var l in i)if(e.inArray(l,s)<0){var c={};c[l]=i[l],r.addKeyMap(i)}}else{for(var h in t.keyMaps){var d=t.keyMaps[h],u="string"==typeof d?e.proxy(a[d],o):e.proxy(d,o);if(e.inArray(h,["F9","F10","F11"])<0&&e.inArray(h,s)<0){var f={};f[h]=u,r.addKeyMap(f)}}e(window).keydown(function(t){var i={120:"F9",121:"F10",122:"F11"};if(e.inArray(i[t.keyCode],s)<0)switch(t.keyCode){case 120:return e.proxy(a.watch,o)(),!1;case 121:return e.proxy(a.preview,o)(),!1;case 122:return e.proxy(a.fullscreen,o)(),!1}})}return this},bindScrollEvent:function(){var i=this,o=this.preview,r=this.settings,n=this.codeMirror,a=t.mouseOrTouch;if(!r.syncScrolling)return this;var s=function(){n.find(".CodeMirror-scroll").bind(a("scroll","touchmove"),function(t){var n=e(this).height(),a=e(this).scrollTop(),s=a/e(this)[0].scrollHeight,l=0;o.find(".markdown-toc-list").each(function(){l+=e(this).height()});var c=o.find(".editormd-toc-menu").height();c=c?c:0,o.scrollTop(0===a?0:a+n>=e(this)[0].scrollHeight-16?o[0].scrollHeight:(o[0].scrollHeight+l+c)*s),e.proxy(r.onscroll,i)(t)})},l=function(){n.find(".CodeMirror-scroll").unbind(a("scroll","touchmove"))},c=function(){o.bind(a("scroll","touchmove"),function(t){var o=e(this).height(),a=e(this).scrollTop(),s=a/e(this)[0].scrollHeight,l=n.find(".CodeMirror-scroll");l.scrollTop(0===a?0:a+o>=e(this)[0].scrollHeight?l[0].scrollHeight:l[0].scrollHeight*s),e.proxy(r.onpreviewscroll,i)(t)})},h=function(){o.unbind(a("scroll","touchmove"))};return n.bind({mouseover:s,mouseout:l,touchstart:s,touchend:l}),"single"===r.syncScrolling?this:(o.bind({mouseover:c,mouseout:h,touchstart:c,touchend:h}),this)},bindChangeEvent:function(){var e=this,t=this.cm,o=this.settings;return o.syncScrolling?(t.on("change",function(t,r){o.watch&&e.previewContainer.css("padding",o.autoHeight?"20px 20px 50px 40px":"20px"),i=setTimeout(function(){clearTimeout(i),e.save(),i=null},o.delay)}),this):this},loadedDisplay:function(t){t=t||!1;var i=this,o=this.editor,r=this.preview,n=this.settings;return this.containerMask.hide(),this.save(),n.watch&&r.show(),o.data("oldWidth",o.width()).data("oldHeight",o.height()),this.resize(),this.registerKeyMaps(),e(window).resize(function(){i.resize()}),this.bindScrollEvent().bindChangeEvent(),t||e.proxy(n.onload,this)(),this.state.loaded=!0,this},width:function(e){return this.editor.css("width","number"==typeof e?e+"px":e),this.resize(),this},height:function(e){return this.editor.css("height","number"==typeof e?e+"px":e),this.resize(),this},resize:function(t,i){t=t||null,i=i||null;var o=this.state,r=this.editor,n=this.preview,a=this.toolbar,s=this.settings,l=this.codeMirror;if(t&&r.css("width","number"==typeof t?t+"px":t),!s.autoHeight||o.fullscreen||o.preview?(i&&r.css("height","number"==typeof i?i+"px":i),o.fullscreen&&r.height(e(window).height()),s.toolbar&&!s.readOnly?l.css("margin-top",a.height()+1).height(r.height()-a.height()):l.css("margin-top",0).height(r.height())):(r.css("height","auto"),l.css("height","auto")),s.watch)if(l.width(r.width()/2),n.width(o.preview?r.width():r.width()/2),this.previewContainer.css("padding",s.autoHeight?"20px 20px 50px 40px":"20px"),s.toolbar&&!s.readOnly?n.css("top",a.height()+1):n.css("top",0),!s.autoHeight||o.fullscreen||o.preview){var c=s.toolbar&&!s.readOnly?r.height()-a.height():r.height();n.height(c)}else n.height("");else l.width(r.width()),n.hide();return o.loaded&&e.proxy(s.onresize,this)(),this},save:function(){if(null===i)return this;var r=this,n=this.state,a=this.settings,s=this.cm,l=s.getValue(),c=this.previewContainer;if("gfm"!==a.mode&&"markdown"!==a.mode)return this.markdownTextarea.val(l),this;var h=t.$marked,d=this.markdownToC=[],u=this.markedRendererOptions={toc:a.toc,tocm:a.tocm,tocStartLevel:a.tocStartLevel,pageBreak:a.pageBreak,taskList:a.taskList,emoji:a.emoji,tex:a.tex,atLink:a.atLink,emailLink:a.emailLink,flowChart:a.flowChart,sequenceDiagram:a.sequenceDiagram,previewCodeHighlight:a.previewCodeHighlight},f=this.markedOptions={renderer:t.markedRenderer(d,u),gfm:!0,tables:!0,breaks:!0,pedantic:!1,sanitize:a.htmlDecode?!1:!0,smartLists:!0,smartypants:!0};h.setOptions(f);var g=t.$marked(l,f);if(g=t.filterHTMLTags(g,a.htmlDecode),this.markdownTextarea.text(l),s.save(),a.saveHTMLToTextarea&&this.htmlTextarea.text(g),a.watch||!a.watch&&n.preview){if(c.html(g),this.previewCodeHighlight(),a.toc){var p=""===a.tocContainer?c:e(a.tocContainer),m=p.find("."+this.classPrefix+"toc-menu");p.attr("previewContainer",""===a.tocContainer?"true":"false"),""!==a.tocContainer&&m.length>0&&m.remove(),t.markdownToCRenderer(d,p,a.tocDropdown,a.tocStartLevel),(a.tocDropdown||p.find("."+this.classPrefix+"toc-menu").length>0)&&t.tocDropdownMenu(p,""!==a.tocTitle?a.tocTitle:this.lang.tocTitle),""!==a.tocContainer&&c.find(".markdown-toc").css("border","none")}a.tex&&(!t.kaTeXLoaded&&a.autoLoadModules?t.loadKaTeX(function(){t.$katex=katex,t.kaTeXLoaded=!0,r.katexRender()}):(t.$katex=katex,this.katexRender())),(a.flowChart||a.sequenceDiagram)&&(o=setTimeout(function(){clearTimeout(o),r.flowChartAndSequenceDiagramRender(),o=null},10)),n.loaded&&e.proxy(a.onchange,this)()}return this},focus:function(){return this.cm.focus(),this},setCursor:function(e){return this.cm.setCursor(e),this},getCursor:function(){return this.cm.getCursor()},setSelection:function(e,t){return this.cm.setSelection(e,t),this},getSelection:function(){return this.cm.getSelection()},setSelections:function(e){return this.cm.setSelections(e),this},getSelections:function(){return this.cm.getSelections()},replaceSelection:function(e){return this.cm.replaceSelection(e),this},insertValue:function(e){return this.replaceSelection(e),this},appendMarkdown:function(e){var t=(this.settings,this.cm);return t.setValue(t.getValue()+e),this},setMarkdown:function(e){return this.cm.setValue(e||this.settings.markdown),this},getMarkdown:function(){return this.cm.getValue()},getValue:function(){return this.cm.getValue()},setValue:function(e){return this.cm.setValue(e),this},clear:function(){return this.cm.setValue(""),this},getHTML:function(){return this.settings.saveHTMLToTextarea?this.htmlTextarea.val():(alert("Error: settings.saveHTMLToTextarea == false"),!1)},getTextareaSavedHTML:function(){return this.getHTML()},getPreviewedHTML:function(){return this.settings.watch?this.previewContainer.html():(alert("Error: settings.watch == false"),!1)},watch:function(t){var o=this.settings;if(e.inArray(o.mode,["gfm","markdown"])<0)return this;if(this.state.watching=o.watch=!0,this.preview.show(),this.toolbar){var r=o.toolbarIconsClass.watch,n=o.toolbarIconsClass.unwatch,a=this.toolbar.find(".fa[name=watch]");a.parent().attr("title",o.lang.toolbar.watch),a.removeClass(n).addClass(r)}return this.codeMirror.css("border-right","1px solid #ddd").width(this.editor.width()/2),i=0,this.save().resize(),o.onwatch||(o.onwatch=t||function(){}),e.proxy(o.onwatch,this)(),this},unwatch:function(t){var i=this.settings;if(this.state.watching=i.watch=!1,this.preview.hide(),this.toolbar){var o=i.toolbarIconsClass.watch,r=i.toolbarIconsClass.unwatch,n=this.toolbar.find(".fa[name=watch]");n.parent().attr("title",i.lang.toolbar.unwatch),n.removeClass(o).addClass(r)}return this.codeMirror.css("border-right","none").width(this.editor.width()),this.resize(),i.onunwatch||(i.onunwatch=t||function(){}),e.proxy(i.onunwatch,this)(),this},show:function(t){t=t||function(){};var i=this;return this.editor.show(0,function(){e.proxy(t,i)()}),this},hide:function(t){t=t||function(){};var i=this;return this.editor.hide(0,function(){e.proxy(t,i)()}),this},previewing:function(){var i=this,o=this.editor,r=this.preview,n=this.toolbar,a=this.settings,s=this.codeMirror,l=this.previewContainer;if(e.inArray(a.mode,["gfm","markdown"])<0)return this;a.toolbar&&n&&(n.toggle(),n.find(".fa[name=preview]").toggleClass("active")),s.toggle();var c=function(e){e.shiftKey&&27===e.keyCode&&i.previewed()};"none"===s.css("display")?(this.state.preview=!0,this.state.fullscreen&&r.css("background","#fff"),o.find("."+this.classPrefix+"preview-close-btn").show().bind(t.mouseOrTouch("click","touchend"),function(){i.previewed()}),a.watch?l.css("padding",""):this.save(),l.addClass(this.classPrefix+"preview-active"),r.show().css({position:"",top:0,width:o.width(),height:a.autoHeight&&!this.state.fullscreen?"auto":o.height()}),this.state.loaded&&e.proxy(a.onpreviewing,this)(),e(window).bind("keyup",c)):(e(window).unbind("keyup",c),this.previewed())},previewed:function(){var i=this.editor,o=this.preview,r=this.toolbar,n=this.settings,a=this.previewContainer,s=i.find("."+this.classPrefix+"preview-close-btn");return this.state.preview=!1,this.codeMirror.show(),n.toolbar&&r.show(),o[n.watch?"show":"hide"](),s.hide().unbind(t.mouseOrTouch("click","touchend")),a.removeClass(this.classPrefix+"preview-active"),n.watch&&a.css("padding","20px"),o.css({background:null,position:"absolute",width:i.width()/2,height:n.autoHeight&&!this.state.fullscreen?"auto":i.height()-r.height(),top:n.toolbar?r.height():0}),this.state.loaded&&e.proxy(n.onpreviewed,this)(),this},fullscreen:function(){var t=this,i=this.state,o=this.editor,r=(this.preview,this.toolbar),n=this.settings,a=this.classPrefix+"fullscreen";r&&r.find(".fa[name=fullscreen]").parent().toggleClass("active");var s=function(e){e.shiftKey||27!==e.keyCode||i.fullscreen&&t.fullscreenExit()};return o.hasClass(a)?(e(window).unbind("keyup",s),this.fullscreenExit()):(i.fullscreen=!0,e("html,body").css("overflow","hidden"),o.css({width:e(window).width(),height:e(window).height()}).addClass(a),this.resize(),e.proxy(n.onfullscreen,this)(),e(window).bind("keyup",s)),this},fullscreenExit:function(){var t=this.editor,i=this.settings,o=this.toolbar,r=this.classPrefix+"fullscreen";return this.state.fullscreen=!1,o&&o.find(".fa[name=fullscreen]").parent().removeClass("active"),e("html,body").css("overflow",""),t.css({width:t.data("oldWidth"),height:t.data("oldHeight")}).removeClass(r),this.resize(),e.proxy(i.onfullscreenExit,this)(),this},executePlugin:function(i,o){var r=this,n=this.cm,a=this.settings;return o=a.pluginPath+o,"function"==typeof define?"undefined"==typeof this[i]?(alert("Error: "+i+" plugin is not found, you are not load this plugin."),this):(this[i](n),this):(e.inArray(o,t.loadFiles.plugin)<0?t.loadPlugin(o,function(){t.loadPlugins[i]=r[i],r[i](n)}):e.proxy(t.loadPlugins[i],this)(n),this)},search:function(e){var t=this.settings;return t.searchReplace?(t.readOnly||this.cm.execCommand(e||"find"),this):(alert("Error: settings.searchReplace == false"),this)},searchReplace:function(){return this.search("replace"),this},searchReplaceAll:function(){return this.search("replaceAll"),this}},t.fn.init.prototype=t.fn,t.dialogLockScreen=function(){var t=this.settings||{dialogLockScreen:!0};t.dialogLockScreen&&(e("html,body").css("overflow","hidden"),this.resize())},t.dialogShowMask=function(t){var i=this.editor,o=this.settings||{dialogShowMask:!0};t.css({top:(e(window).height()-t.height())/2+"px",left:(e(window).width()-t.width())/2+"px"}),o.dialogShowMask&&i.children("."+this.classPrefix+"mask").css("z-index",parseInt(t.css("z-index"))-1).show()},t.toolbarHandlers={undo:function(){this.cm.undo()},redo:function(){this.cm.redo()},bold:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("**"+i+"**"),""===i&&e.setCursor(t.line,t.ch+2)},del:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("~~"+i+"~~"),""===i&&e.setCursor(t.line,t.ch+2)},italic:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("*"+i+"*"),""===i&&e.setCursor(t.line,t.ch+1)},quote:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("> "+i),e.setCursor(t.line,t.ch+2)):e.replaceSelection("> "+i)},ucfirst:function(){var e=this.cm,i=e.getSelection(),o=e.listSelections();e.replaceSelection(t.firstUpperCase(i)),e.setSelections(o)},ucwords:function(){var e=this.cm,i=e.getSelection(),o=e.listSelections();e.replaceSelection(t.wordsFirstUpperCase(i)),e.setSelections(o)},uppercase:function(){var e=this.cm,t=e.getSelection(),i=e.listSelections();e.replaceSelection(t.toUpperCase()),e.setSelections(i)},lowercase:function(){var e=this.cm,t=(e.getCursor(),e.getSelection()),i=e.listSelections();e.replaceSelection(t.toLowerCase()),e.setSelections(i)},h1:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("# "+i),e.setCursor(t.line,t.ch+2)):e.replaceSelection("# "+i)},h2:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0), +e.replaceSelection("## "+i),e.setCursor(t.line,t.ch+3)):e.replaceSelection("## "+i)},h3:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("### "+i),e.setCursor(t.line,t.ch+4)):e.replaceSelection("### "+i)},h4:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("#### "+i),e.setCursor(t.line,t.ch+5)):e.replaceSelection("#### "+i)},h5:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("##### "+i),e.setCursor(t.line,t.ch+6)):e.replaceSelection("##### "+i)},h6:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("###### "+i),e.setCursor(t.line,t.ch+7)):e.replaceSelection("###### "+i)},"list-ul":function(){var e=this.cm,t=(e.getCursor(),e.getSelection());if(""===t)e.replaceSelection("- "+t);else{for(var i=t.split("\n"),o=0,r=i.length;r>o;o++)i[o]=""===i[o]?"":"- "+i[o];e.replaceSelection(i.join("\n"))}},"list-ol":function(){var e=this.cm,t=(e.getCursor(),e.getSelection());if(""===t)e.replaceSelection("1. "+t);else{for(var i=t.split("\n"),o=0,r=i.length;r>o;o++)i[o]=""===i[o]?"":o+1+". "+i[o];e.replaceSelection(i.join("\n"))}},hr:function(){{var e=this.cm,t=e.getCursor();e.getSelection()}e.replaceSelection((0!==t.ch?"\n\n":"\n")+"------------\n\n")},tex:function(){if(!this.settings.tex)return alert("settings.tex === false"),this;var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("$$"+i+"$$"),""===i&&e.setCursor(t.line,t.ch+2)},link:function(){this.executePlugin("linkDialog","link-dialog/link-dialog")},"reference-link":function(){this.executePlugin("referenceLinkDialog","reference-link-dialog/reference-link-dialog")},pagebreak:function(){if(!this.settings.pageBreak)return alert("settings.pageBreak === false"),this;{var e=this.cm;e.getSelection()}e.replaceSelection("\r\n[========]\r\n")},image:function(){this.executePlugin("imageDialog","image-dialog/image-dialog")},code:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("`"+i+"`"),""===i&&e.setCursor(t.line,t.ch+1)},"code-block":function(){this.executePlugin("codeBlockDialog","code-block-dialog/code-block-dialog")},"preformatted-text":function(){this.executePlugin("preformattedTextDialog","preformatted-text-dialog/preformatted-text-dialog")},table:function(){this.executePlugin("tableDialog","table-dialog/table-dialog")},datetime:function(){var e=this.cm,i=(e.getSelection(),new Date,this.settings.lang.name),o=t.dateFormat()+" "+t.dateFormat("zh-cn"===i||"zh-tw"===i?"cn-week-day":"week-day");e.replaceSelection(o)},emoji:function(){this.executePlugin("emojiDialog","emoji-dialog/emoji-dialog")},"html-entities":function(){this.executePlugin("htmlEntitiesDialog","html-entities-dialog/html-entities-dialog")},"goto-line":function(){this.executePlugin("gotoLineDialog","goto-line-dialog/goto-line-dialog")},watch:function(){this[this.settings.watch?"unwatch":"watch"]()},preview:function(){this.previewing()},fullscreen:function(){this.fullscreen()},clear:function(){this.clear()},search:function(){this.search()},help:function(){this.executePlugin("helpDialog","help-dialog/help-dialog")},info:function(){this.showInfoDialog()}},t.keyMaps={"Ctrl-1":"h1","Ctrl-2":"h2","Ctrl-3":"h3","Ctrl-4":"h4","Ctrl-5":"h5","Ctrl-6":"h6","Ctrl-B":"bold","Ctrl-D":"datetime","Ctrl-E":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();return this.settings.emoji?(e.replaceSelection(":"+i+":"),void(""===i&&e.setCursor(t.line,t.ch+1))):void alert("Error: settings.emoji == false")},"Ctrl-Alt-G":"goto-line","Ctrl-H":"hr","Ctrl-I":"italic","Ctrl-K":"code","Ctrl-L":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection(),o=""===i?"":' "'+i+'"';e.replaceSelection("["+i+"]("+o+")"),""===i&&e.setCursor(t.line,t.ch+1)},"Ctrl-U":"list-ul","Shift-Ctrl-A":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();return this.settings.atLink?(e.replaceSelection("@"+i),void(""===i&&e.setCursor(t.line,t.ch+1))):void alert("Error: settings.atLink == false")},"Shift-Ctrl-C":"code","Shift-Ctrl-Q":"quote","Shift-Ctrl-S":"del","Shift-Ctrl-K":"tex","Shift-Alt-C":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection(["```",i,"```"].join("\n")),""===i&&e.setCursor(t.line,t.ch+3)},"Shift-Ctrl-Alt-C":"code-block","Shift-Ctrl-H":"html-entities","Shift-Alt-H":"help","Shift-Ctrl-E":"emoji","Shift-Ctrl-U":"uppercase","Shift-Alt-U":"ucwords","Shift-Ctrl-Alt-U":"ucfirst","Shift-Alt-L":"lowercase","Shift-Ctrl-I":function(){var e=this.cm,t=e.getCursor(),i=e.getSelection(),o=""===i?"":' "'+i+'"';e.replaceSelection("!["+i+"]("+o+")"),""===i&&e.setCursor(t.line,t.ch+4)},"Shift-Ctrl-Alt-I":"image","Shift-Ctrl-L":"link","Shift-Ctrl-O":"list-ol","Shift-Ctrl-P":"preformatted-text","Shift-Ctrl-T":"table","Shift-Alt-P":"pagebreak",F9:"watch",F10:"preview",F11:"fullscreen"};var r=function(e){return String.prototype.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")};t.trim=r;var n=function(e){return e.toLowerCase().replace(/\b(\w)|\s(\w)/g,function(e){return e.toUpperCase()})};t.ucwords=t.wordsFirstUpperCase=n;var a=function(e){return e.toLowerCase().replace(/\b(\w)/,function(e){return e.toUpperCase()})};return t.firstUpperCase=t.ucfirst=a,t.urls={atLinkBase:"https://github.com/"},t.regexs={atLink:/@(\w+)/g,email:/(\w+)@(\w+)\.(\w+)\.?(\w+)?/g,emailLink:/(mailto:)?([\w\.\_]+)@(\w+)\.(\w+)\.?(\w+)?/g,emoji:/:([\w\+-]+):/g,emojiDatetime:/(\d{2}:\d{2}:\d{2})/g,twemoji:/:(tw-([\w]+)-?(\w+)?):/g,fontAwesome:/:(fa-([\w]+)(-(\w+)){0,}):/g,editormdLogo:/:(editormd-logo-?(\w+)?):/g,pageBreak:/^\[[=]{8,}\]$/},t.emoji={path:"http://www.emoji-cheat-sheet.com/graphics/emojis/",ext:".png"},t.twemoji={path:"http://twemoji.maxcdn.com/36x36/",ext:".png"},t.markedRenderer=function(i,o){var n={toc:!0,tocm:!1,tocStartLevel:1,pageBreak:!0,atLink:!0,emailLink:!0,taskList:!1,emoji:!1,tex:!1,flowChart:!1,sequenceDiagram:!1},a=e.extend(n,o||{}),s=t.$marked,l=new s.Renderer;i=i||[];var c=t.regexs,h=c.atLink,d=c.emoji,u=c.email,f=c.emailLink,g=c.twemoji,p=c.fontAwesome,m=c.editormdLogo,w=c.pageBreak;return l.emoji=function(e){e=e.replace(t.regexs.emojiDatetime,function(e){return e.replace(/:/g,":")});var i=e.match(d);if(!i||!a.emoji)return e;for(var o=0,r=i.length;r>o;o++)":+1:"===i[o]&&(i[o]=":\\+1:"),e=e.replace(new RegExp(i[o]),function(e,i){var o=e.match(p),r=e.replace(/:/g,"");if(o)for(var n=0,a=o.length;a>n;n++){var s=o[n].replace(/:/g,"");return''}else{var l=e.match(m),c=e.match(g);if(l)for(var h=0,d=l.length;d>h;h++){var u=l[h].replace(/:/g,"");return''}else{if(!c){var f="+1"===r?"plus1":r;return f="black_large_square"===f?"black_square":f,f="moon"===f?"waxing_gibbous_moon":f,':'+r+':'}for(var w=0,v=c.length;v>w;w++){var k=c[w].replace(/:/g,"").replace("tw-","");return'twemoji-'+k+''}}}});return e},l.atLink=function(i){return h.test(i)?(a.atLink&&(i=i.replace(u,function(e,t,i,o){return e.replace(/@/g,"_#_@_#_")}),i=i.replace(h,function(e,i){return''+e+""}).replace(/_#_@_#_/g,"@")),a.emailLink&&(i=i.replace(f,function(t,i,o,r,n){return!i&&e.inArray(n,"jpg|jpeg|png|gif|webp|ico|icon|pdf".split("|"))<0?''+t+"":t})),i):i},l.link=function(e,t,i){if(this.options.sanitize){try{var o=decodeURIComponent(unescape(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(r){return""}if(0===o.indexOf("javascript:"))return""}var n=''+i.replace(/@/g,"@")+""):(t&&(n+=' title="'+t+'"'),n+=">"+i+"")},l.heading=function(e,t,o){var n=e,a=/\s*\]*)\>(.*)\<\/a\>\s*/;if(a.test(e)){var s=[];e=e.split(/\]+)\>([^\>]*)\<\/a\>/);for(var l=0,c=e.length;c>l;l++)s.push(e[l].replace(/\s*href\=\"(.*)\"\s*/g,""));e=s.join(" ")}e=r(e);var h=e.toLowerCase().replace(/[^\w]+/g,"-"),d={text:e,level:t,slug:h},u=/^[\u4e00-\u9fa5]+$/.test(e),f=u?escape(e).replace(/\%/g,""):e.toLowerCase().replace(/[^\w]+/g,"-");i.push(d);var g="';return g+='',g+='',g+=this.atLink(a?this.emoji(n):this.emoji(e)),g+=""},l.pageBreak=function(e){return w.test(e)&&a.pageBreak&&(e='
                      '),e},l.paragraph=function(e){var i=/\$\$(.*)\$\$/g.test(e),o=/^\$\$(.*)\$\$$/.test(e),r=o?' class="'+t.classNames.tex+'"':"",n=a.tocm?/^(\[TOC\]|\[TOCM\])$/.test(e):/^\[TOC\]$/.test(e),s=/^\[TOCM\]$/.test(e);e=!o&&i?e.replace(/(\$\$([^\$]*)\$\$)+/g,function(e,i){return''+i.replace(/\$/g,"")+""}):o?e.replace(/\$/g,""):e;var l='
                      '+e+"
                      ";return n?s?'
                      '+l+"

                      ":l:w.test(e)?this.pageBreak(e):""+this.atLink(this.emoji(e))+"

                      \n"},l.code=function(e,i,o){return"seq"===i||"sequence"===i?'
                      '+e+"
                      ":"flow"===i?'
                      '+e+"
                      ":"math"===i||"latex"===i||"katex"===i?'

                      '+e+"

                      ":s.Renderer.prototype.code.apply(this,arguments)},l.tablecell=function(e,t){var i=t.header?"th":"td",o=t.align?"<"+i+' style="text-align:'+t.align+'">':"<"+i+">";return o+this.atLink(this.emoji(e))+"\n"},l.listitem=function(e){return a.taskList&&/^\s*\[[x\s]\]\s*/.test(e)?(e=e.replace(/^\s*\[\s\]\s*/,' ').replace(/^\s*\[x\]\s*/,' '),'
                    • '+this.atLink(this.emoji(e))+"
                    • "):"
                    • "+this.atLink(this.emoji(e))+"
                    • "},l},t.markdownToCRenderer=function(e,t,i,o){var r="",n=0,a=this.classPrefix;o=o||1;for(var s=0,l=e.length;l>s;s++){var c=e[s].text,h=e[s].level;o>h||(r+=h>n?"":n>h?new Array(n-h+2).join("
                  • "):"",r+='
                  • '+c+"
                      ",n=h)}var d=t.find(".markdown-toc");if(d.length<1&&"false"===t.attr("previewContainer")){var u='
                      ';u=i?'
                      '+u+"
                      ":u,t.html(u),d=t.find(".markdown-toc")}return i&&d.wrap('

                      '),d.html('
                        ').children(".markdown-toc-list").html(r.replace(/\r?\n?\\<\/ul\>/g,"")),d},t.tocDropdownMenu=function(t,i){i=i||"Table of Contents";var o=400,r=t.find("."+this.classPrefix+"toc-menu");return r.each(function(){var t=e(this),r=t.children(".markdown-toc"),n='',a=''+n+i+"",s=r.children("ul"),l=s.find("li");r.append(a),l.first().before("
                      • "+i+" "+n+"

                      • "),t.mouseover(function(){s.show(),l.each(function(){var t=e(this),i=t.children("ul");if(""===i.html()&&i.remove(),i.length>0&&""!==i.html()){var r=t.children("a").first();r.children(".fa").length<1&&r.append(e(n).css({"float":"right",paddingTop:"4px"}))}t.mouseover(function(){i.css("z-index",o).show(),o+=1}).mouseleave(function(){i.hide()})})}).mouseleave(function(){s.hide()})}),r},t.filterHTMLTags=function(t,i){if("string"!=typeof t&&(t=new String(t)),"string"!=typeof i)return t;for(var o=i.split("|"),r=o[0].split(","),n=o[1],a=0,s=r.length;s>a;a++){var l=r[a];t=t.replace(new RegExp("]*)>([^>]*)","igm"),"")}if("undefined"!=typeof n){var c=/\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/gi;t="*"===n?t.replace(c,function(e,t,i,o,r){return"<"+t+">"+o+""}):"on*"===n?t.replace(c,function(t,i,o,r,n){var a=e("<"+i+">"+r+""),s=e(t)[0].attributes,l={};e.each(s,function(e,t){'"'!==t.nodeName&&(l[t.nodeName]=t.nodeValue)}),e.each(l,function(e){0===e.indexOf("on")&&delete l[e]}),a.attr(l);var c="undefined"!=typeof a[1]?e(a[1]).text():"";return a[0].outerHTML+c}):t.replace(c,function(t,i,o,r){var a=n.split(","),s=e(t);return s.html(r),e.each(a,function(e){s.attr(a[e],null)}),s[0].outerHTML})}return t},t.markdownToHTML=function(i,o){var r={gfm:!0,toc:!0,tocm:!1,tocStartLevel:1,tocTitle:"目录",tocDropdown:!1,tocContainer:"",markdown:"",markdownSourceCode:!1,htmlDecode:!1,autoLoadKaTeX:!0,pageBreak:!0,atLink:!0,emailLink:!0,tex:!1,taskList:!1,emoji:!1,flowChart:!1,sequenceDiagram:!1,previewCodeHighlight:!0};t.$marked=marked;var n=e("#"+i),a=n.settings=e.extend(!0,r,o||{}),s=n.find("textarea");s.length<1&&(n.append(""),s=n.find("textarea"));var l=""===a.markdown?s.val():a.markdown,c=[],h={toc:a.toc,tocm:a.tocm,tocStartLevel:a.tocStartLevel,taskList:a.taskList,emoji:a.emoji,tex:a.tex,pageBreak:a.pageBreak,atLink:a.atLink,emailLink:a.emailLink,flowChart:a.flowChart,sequenceDiagram:a.sequenceDiagram,previewCodeHighlight:a.previewCodeHighlight},d={renderer:t.markedRenderer(c,h),gfm:a.gfm,tables:!0,breaks:!0,pedantic:!1,sanitize:a.htmlDecode?!1:!0,smartLists:!0,smartypants:!0};l=new String(l);var u=marked(l,d);u=t.filterHTMLTags(u,a.htmlDecode),a.markdownSourceCode?s.text(l):s.remove(),n.addClass("markdown-body "+this.classPrefix+"html-preview").append(u);var f=""!==a.tocContainer?e(a.tocContainer):n;if(""!==a.tocContainer&&f.attr("previewContainer",!1),a.toc&&(n.tocContainer=this.markdownToCRenderer(c,f,a.tocDropdown,a.tocStartLevel),(a.tocDropdown||n.find("."+this.classPrefix+"toc-menu").length>0)&&this.tocDropdownMenu(n,a.tocTitle),""!==a.tocContainer&&n.find(".editormd-toc-menu, .editormd-markdown-toc").remove()),a.previewCodeHighlight&&(n.find("pre").addClass("prettyprint linenums"),prettyPrint()),t.isIE8||(a.flowChart&&n.find(".flowchart").flowChart(),a.sequenceDiagram&&n.find(".sequence-diagram").sequenceDiagram({theme:"simple"})),a.tex){var g=function(){n.find("."+t.classNames.tex).each(function(){var t=e(this);katex.render(t.html().replace(/</g,"<").replace(/>/g,">"),t[0]),t.find(".katex").css("font-size","1.6em")})};!a.autoLoadKaTeX||t.$katex||t.kaTeXLoaded?g():this.loadKaTeX(function(){t.$katex=katex,t.kaTeXLoaded=!0,g()})}return n.getMarkdown=function(){return s.val()},n},t.themes=["default","dark"],t.previewThemes=["default","dark"],t.editorThemes=["default","3024-day","3024-night","ambiance","ambiance-mobile","base16-dark","base16-light","blackboard","cobalt","eclipse","elegant","erlang-dark","lesser-dark","mbo","mdn-like","midnight","monokai","neat","neo","night","paraiso-dark","paraiso-light","pastel-on-dark","rubyblue","solarized","the-matrix","tomorrow-night-eighties","twilight","vibrant-ink","xq-dark","xq-light"],t.loadPlugins={},t.loadFiles={js:[],css:[],plugin:[]},t.loadPlugin=function(e,i,o){i=i||function(){},this.loadScript(e,function(){t.loadFiles.plugin.push(e),i()},o)},t.loadCSS=function(e,i,o){o=o||"head",i=i||function(){};var r=document.createElement("link");r.type="text/css",r.rel="stylesheet",r.onload=r.onreadystatechange=function(){t.loadFiles.css.push(e),i()},r.href=e+".css","head"===o?document.getElementsByTagName("head")[0].appendChild(r):document.body.appendChild(r)},t.isIE="Microsoft Internet Explorer"==navigator.appName,t.isIE8=t.isIE&&"8."==navigator.appVersion.match(/8./i),t.loadScript=function(e,i,o){o=o||"head",i=i||function(){};var r=null;r=document.createElement("script"),r.id=e.replace(/[\./]+/g,"-"),r.type="text/javascript",r.src=e+".js",t.isIE8?r.onreadystatechange=function(){r.readyState&&("loaded"===r.readyState||"complete"===r.readyState)&&(r.onreadystatechange=null,t.loadFiles.js.push(e),i())}:r.onload=function(){t.loadFiles.js.push(e),i()},"head"===o?document.getElementsByTagName("head")[0].appendChild(r):document.body.appendChild(r)},t.katexURL={css:"/katex/katex.min",js:"/katex/katex.min"},t.kaTeXLoaded=!1,t.loadKaTeX=function(e){t.loadCSS(t.katexURL.css,function(){t.loadScript(t.katexURL.js,e||function(){})})},t.lockScreen=function(t){e("html,body").css("overflow",t?"hidden":"")},t.createDialog=function(i){var o={name:"",width:420,height:240,title:"",drag:!0,closed:!0,content:"",mask:!0,maskStyle:{backgroundColor:"#fff",opacity:.1},lockScreen:!0,footer:!0,buttons:!1};i=e.extend(!0,o,i);var r=this,n=this.editor,a=t.classPrefix,s=(new Date).getTime(),l=""===i.name?a+"dialog-"+s:i.name,c=t.mouseOrTouch,h='
                        ';""!==i.title&&(h+='
                        ",h+=''+i.title+"",h+="
                        "),i.closed&&(h+=''),h+='
                        '+i.content,(i.footer||"string"==typeof i.footer)&&(h+='"),h+="
                        ",h+='
                        ',h+='
                        ',h+="
                        ",n.append(h);var d=n.find("."+l);d.lockScreen=function(t){return i.lockScreen&&(e("html,body").css("overflow",t?"hidden":""),r.resize()),d},d.showMask=function(){return i.mask&&n.find("."+a+"mask").css(i.maskStyle).css("z-index",t.dialogZindex-1).show(),d},d.hideMask=function(){return i.mask&&n.find("."+a+"mask").hide(),d},d.loading=function(e){var t=d.find("."+a+"dialog-mask");return t[e?"show":"hide"](),d},d.lockScreen(!0).showMask(),d.show().css({zIndex:t.dialogZindex,border:t.isIE8?"1px solid #ddd":"",width:"number"==typeof i.width?i.width+"px":i.width,height:"number"==typeof i.height?i.height+"px":i.height});var u=function(){d.css({top:(e(window).height()-d.height())/2+"px",left:(e(window).width()-d.width())/2+"px"})};if(u(),e(window).resize(u),d.children("."+a+"dialog-close").bind(c("click","touchend"),function(){d.hide().lockScreen(!1).hideMask()}),"object"==typeof i.buttons){var f=d.footer=d.find("."+a+"dialog-footer");for(var g in i.buttons){var p=i.buttons[g],m=a+g+"-btn";f.append('"),p[1]=e.proxy(p[1],d),f.children("."+m).bind(c("click","touchend"),p[1])}}if(""!==i.title&&i.drag){var w,v,k=d.children("."+a+"dialog-header");i.mask||k.bind(c("click","touchend"),function(){t.dialogZindex+=2,d.css("z-index",t.dialogZindex)}),k.mousedown(function(e){e=e||window.event,w=e.clientX-parseInt(d[0].style.left),v=e.clientY-parseInt(d[0].style.top),document.onmousemove=y});var b=function(e){e.removeClass(a+"user-unselect").off("selectstart")},x=function(e){e.addClass(a+"user-unselect").on("selectstart",function(e){return!1})},y=function(t){t=t||window.event;var i,o,r=parseInt(d[0].style.left),n=parseInt(d[0].style.top);r>=0?r+d.width()<=e(window).width()?i=t.clientX-w:(i=e(window).width()-d.width(),document.onmousemove=null):(i=0,document.onmousemove=null),n>=0?o=t.clientY-v:(o=0,document.onmousemove=null),document.onselectstart=function(){return!1},x(e("body")),x(d),d[0].style.left=i+"px",d[0].style.top=o+"px"};document.onmouseup=function(){b(e("body")),b(d),document.onselectstart=null,document.onmousemove=null},k.touchDraggable=function(){var t=null,i=function(i){var o=i.originalEvent,r=e(this).parent().position();t={x:o.changedTouches[0].pageX-r.left,y:o.changedTouches[0].pageY-r.top}},o=function(i){i.preventDefault();var o=i.originalEvent;e(this).parent().css({top:o.changedTouches[0].pageY-t.y,left:o.changedTouches[0].pageX-t.x})};this.bind("touchstart",i).bind("touchmove",o)},k.touchDraggable()}return t.dialogZindex+=2,d},t.mouseOrTouch=function(e,t){e=e||"click",t=t||"touchend";var i=e;try{document.createEvent("TouchEvent"),i=t}catch(o){}return i},t.dateFormat=function(e){e=e||"";var t=function(e){return 10>e?"0"+e:e},i=new Date,o=i.getFullYear(),r=o.toString().slice(2,4),n=t(i.getMonth()+1),a=t(i.getDate()),s=i.getDay(),l=t(i.getHours()),c=t(i.getMinutes()),h=t(i.getSeconds()),d=t(i.getMilliseconds()),u="",f=r+"-"+n+"-"+a,g=o+"-"+n+"-"+a,p=l+":"+c+":"+h;switch(e){case"UNIX Time":u=i.getTime();break;case"UTC":u=i.toUTCString();break;case"yy":u=r;break;case"year":case"yyyy":u=o;break;case"month":case"mm":u=n;break;case"cn-week-day":case"cn-wd":var m=["日","一","二","三","四","五","六"];u="星期"+m[s];break;case"week-day":case"wd":var w=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];u=w[s];break;case"day":case"dd":u=a;break;case"hour":case"hh":u=l;break;case"min":case"ii":u=c;break;case"second":case"ss":u=h;break;case"ms":u=d;break;case"yy-mm-dd":u=f;break;case"yyyy-mm-dd":u=g;break;case"yyyy-mm-dd h:i:s ms":case"full + ms":u=g+" "+p+" "+d;break;case"full":case"yyyy-mm-dd h:i:s":default:u=g+" "+p}return u},t}}); \ No newline at end of file diff --git a/public/editormd/emoji/+1.png b/public/editormd/emoji/+1.png new file mode 100644 index 000000000..ec7af7f6c Binary files /dev/null and b/public/editormd/emoji/+1.png differ diff --git a/public/editormd/emoji/-1.png b/public/editormd/emoji/-1.png new file mode 100644 index 000000000..41c6b825d Binary files /dev/null and b/public/editormd/emoji/-1.png differ diff --git a/public/editormd/emoji/100.png b/public/editormd/emoji/100.png new file mode 100644 index 000000000..248641a28 Binary files /dev/null and b/public/editormd/emoji/100.png differ diff --git a/public/editormd/emoji/1234.png b/public/editormd/emoji/1234.png new file mode 100644 index 000000000..c47c2e1f9 Binary files /dev/null and b/public/editormd/emoji/1234.png differ diff --git a/public/editormd/emoji/8ball.png b/public/editormd/emoji/8ball.png new file mode 100644 index 000000000..c2c710d45 Binary files /dev/null and b/public/editormd/emoji/8ball.png differ diff --git a/public/editormd/emoji/a.png b/public/editormd/emoji/a.png new file mode 100644 index 000000000..6bebbfda9 Binary files /dev/null and b/public/editormd/emoji/a.png differ diff --git a/public/editormd/emoji/ab.png b/public/editormd/emoji/ab.png new file mode 100644 index 000000000..1b6d2aede Binary files /dev/null and b/public/editormd/emoji/ab.png differ diff --git a/public/editormd/emoji/abc.png b/public/editormd/emoji/abc.png new file mode 100644 index 000000000..505d40a15 Binary files /dev/null and b/public/editormd/emoji/abc.png differ diff --git a/public/editormd/emoji/abcd.png b/public/editormd/emoji/abcd.png new file mode 100644 index 000000000..5218470b6 Binary files /dev/null and b/public/editormd/emoji/abcd.png differ diff --git a/public/editormd/emoji/accept.png b/public/editormd/emoji/accept.png new file mode 100644 index 000000000..2d2009031 Binary files /dev/null and b/public/editormd/emoji/accept.png differ diff --git a/public/editormd/emoji/aerial_tramway.png b/public/editormd/emoji/aerial_tramway.png new file mode 100644 index 000000000..38f6dfe23 Binary files /dev/null and b/public/editormd/emoji/aerial_tramway.png differ diff --git a/public/editormd/emoji/airplane.png b/public/editormd/emoji/airplane.png new file mode 100644 index 000000000..8407cb675 Binary files /dev/null and b/public/editormd/emoji/airplane.png differ diff --git a/public/editormd/emoji/alarm_clock.png b/public/editormd/emoji/alarm_clock.png new file mode 100644 index 000000000..86ca8c8ed Binary files /dev/null and b/public/editormd/emoji/alarm_clock.png differ diff --git a/public/editormd/emoji/alien.png b/public/editormd/emoji/alien.png new file mode 100644 index 000000000..a06d31086 Binary files /dev/null and b/public/editormd/emoji/alien.png differ diff --git a/public/editormd/emoji/ambulance.png b/public/editormd/emoji/ambulance.png new file mode 100644 index 000000000..c3a8add20 Binary files /dev/null and b/public/editormd/emoji/ambulance.png differ diff --git a/public/editormd/emoji/anchor.png b/public/editormd/emoji/anchor.png new file mode 100644 index 000000000..eeeb3533e Binary files /dev/null and b/public/editormd/emoji/anchor.png differ diff --git a/public/editormd/emoji/angel.png b/public/editormd/emoji/angel.png new file mode 100644 index 000000000..bcf96cb18 Binary files /dev/null and b/public/editormd/emoji/angel.png differ diff --git a/public/editormd/emoji/anger.png b/public/editormd/emoji/anger.png new file mode 100644 index 000000000..6fb4dca18 Binary files /dev/null and b/public/editormd/emoji/anger.png differ diff --git a/public/editormd/emoji/angry.png b/public/editormd/emoji/angry.png new file mode 100644 index 000000000..9ea790656 Binary files /dev/null and b/public/editormd/emoji/angry.png differ diff --git a/public/editormd/emoji/anguished.png b/public/editormd/emoji/anguished.png new file mode 100644 index 000000000..18abde5c2 Binary files /dev/null and b/public/editormd/emoji/anguished.png differ diff --git a/public/editormd/emoji/ant.png b/public/editormd/emoji/ant.png new file mode 100644 index 000000000..b92d1cc14 Binary files /dev/null and b/public/editormd/emoji/ant.png differ diff --git a/public/editormd/emoji/apple.png b/public/editormd/emoji/apple.png new file mode 100644 index 000000000..08aa17b95 Binary files /dev/null and b/public/editormd/emoji/apple.png differ diff --git a/public/editormd/emoji/aquarius.png b/public/editormd/emoji/aquarius.png new file mode 100644 index 000000000..cbff66edc Binary files /dev/null and b/public/editormd/emoji/aquarius.png differ diff --git a/public/editormd/emoji/aries.png b/public/editormd/emoji/aries.png new file mode 100644 index 000000000..25d4c0372 Binary files /dev/null and b/public/editormd/emoji/aries.png differ diff --git a/public/editormd/emoji/arrow_backward.png b/public/editormd/emoji/arrow_backward.png new file mode 100644 index 000000000..088621834 Binary files /dev/null and b/public/editormd/emoji/arrow_backward.png differ diff --git a/public/editormd/emoji/arrow_double_down.png b/public/editormd/emoji/arrow_double_down.png new file mode 100644 index 000000000..2ecbebcda Binary files /dev/null and b/public/editormd/emoji/arrow_double_down.png differ diff --git a/public/editormd/emoji/arrow_double_up.png b/public/editormd/emoji/arrow_double_up.png new file mode 100644 index 000000000..2bd6659b1 Binary files /dev/null and b/public/editormd/emoji/arrow_double_up.png differ diff --git a/public/editormd/emoji/arrow_down.png b/public/editormd/emoji/arrow_down.png new file mode 100644 index 000000000..7d695bdc5 Binary files /dev/null and b/public/editormd/emoji/arrow_down.png differ diff --git a/public/editormd/emoji/arrow_down_small.png b/public/editormd/emoji/arrow_down_small.png new file mode 100644 index 000000000..32a52bd9b Binary files /dev/null and b/public/editormd/emoji/arrow_down_small.png differ diff --git a/public/editormd/emoji/arrow_forward.png b/public/editormd/emoji/arrow_forward.png new file mode 100644 index 000000000..fbfe711b6 Binary files /dev/null and b/public/editormd/emoji/arrow_forward.png differ diff --git a/public/editormd/emoji/arrow_heading_down.png b/public/editormd/emoji/arrow_heading_down.png new file mode 100644 index 000000000..daf2a00b9 Binary files /dev/null and b/public/editormd/emoji/arrow_heading_down.png differ diff --git a/public/editormd/emoji/arrow_heading_up.png b/public/editormd/emoji/arrow_heading_up.png new file mode 100644 index 000000000..c8f670a1e Binary files /dev/null and b/public/editormd/emoji/arrow_heading_up.png differ diff --git a/public/editormd/emoji/arrow_left.png b/public/editormd/emoji/arrow_left.png new file mode 100644 index 000000000..526fe7881 Binary files /dev/null and b/public/editormd/emoji/arrow_left.png differ diff --git a/public/editormd/emoji/arrow_lower_left.png b/public/editormd/emoji/arrow_lower_left.png new file mode 100644 index 000000000..ac8cc39a8 Binary files /dev/null and b/public/editormd/emoji/arrow_lower_left.png differ diff --git a/public/editormd/emoji/arrow_lower_right.png b/public/editormd/emoji/arrow_lower_right.png new file mode 100644 index 000000000..0c34773a5 Binary files /dev/null and b/public/editormd/emoji/arrow_lower_right.png differ diff --git a/public/editormd/emoji/arrow_right.png b/public/editormd/emoji/arrow_right.png new file mode 100644 index 000000000..1c9267b24 Binary files /dev/null and b/public/editormd/emoji/arrow_right.png differ diff --git a/public/editormd/emoji/arrow_right_hook.png b/public/editormd/emoji/arrow_right_hook.png new file mode 100644 index 000000000..8b4ea6e17 Binary files /dev/null and b/public/editormd/emoji/arrow_right_hook.png differ diff --git a/public/editormd/emoji/arrow_up.png b/public/editormd/emoji/arrow_up.png new file mode 100644 index 000000000..e1ecfa114 Binary files /dev/null and b/public/editormd/emoji/arrow_up.png differ diff --git a/public/editormd/emoji/arrow_up_down.png b/public/editormd/emoji/arrow_up_down.png new file mode 100644 index 000000000..be423de78 Binary files /dev/null and b/public/editormd/emoji/arrow_up_down.png differ diff --git a/public/editormd/emoji/arrow_up_small.png b/public/editormd/emoji/arrow_up_small.png new file mode 100644 index 000000000..995c62ff2 Binary files /dev/null and b/public/editormd/emoji/arrow_up_small.png differ diff --git a/public/editormd/emoji/arrow_upper_left.png b/public/editormd/emoji/arrow_upper_left.png new file mode 100644 index 000000000..c34a07f26 Binary files /dev/null and b/public/editormd/emoji/arrow_upper_left.png differ diff --git a/public/editormd/emoji/arrow_upper_right.png b/public/editormd/emoji/arrow_upper_right.png new file mode 100644 index 000000000..4ebb26c55 Binary files /dev/null and b/public/editormd/emoji/arrow_upper_right.png differ diff --git a/public/editormd/emoji/arrows_clockwise.png b/public/editormd/emoji/arrows_clockwise.png new file mode 100644 index 000000000..b08c09e2e Binary files /dev/null and b/public/editormd/emoji/arrows_clockwise.png differ diff --git a/public/editormd/emoji/arrows_counterclockwise.png b/public/editormd/emoji/arrows_counterclockwise.png new file mode 100644 index 000000000..3e06f5b3c Binary files /dev/null and b/public/editormd/emoji/arrows_counterclockwise.png differ diff --git a/public/editormd/emoji/art.png b/public/editormd/emoji/art.png new file mode 100644 index 000000000..d45212b03 Binary files /dev/null and b/public/editormd/emoji/art.png differ diff --git a/public/editormd/emoji/articulated_lorry.png b/public/editormd/emoji/articulated_lorry.png new file mode 100644 index 000000000..39774d75f Binary files /dev/null and b/public/editormd/emoji/articulated_lorry.png differ diff --git a/public/editormd/emoji/astonished.png b/public/editormd/emoji/astonished.png new file mode 100644 index 000000000..8e0a169f4 Binary files /dev/null and b/public/editormd/emoji/astonished.png differ diff --git a/public/editormd/emoji/atm.png b/public/editormd/emoji/atm.png new file mode 100644 index 000000000..c2846e792 Binary files /dev/null and b/public/editormd/emoji/atm.png differ diff --git a/public/editormd/emoji/b.png b/public/editormd/emoji/b.png new file mode 100644 index 000000000..ffada93dd Binary files /dev/null and b/public/editormd/emoji/b.png differ diff --git a/public/editormd/emoji/baby.png b/public/editormd/emoji/baby.png new file mode 100644 index 000000000..3b29da40b Binary files /dev/null and b/public/editormd/emoji/baby.png differ diff --git a/public/editormd/emoji/baby_bottle.png b/public/editormd/emoji/baby_bottle.png new file mode 100644 index 000000000..1b2cfe5e3 Binary files /dev/null and b/public/editormd/emoji/baby_bottle.png differ diff --git a/public/editormd/emoji/baby_chick.png b/public/editormd/emoji/baby_chick.png new file mode 100644 index 000000000..9be8d2930 Binary files /dev/null and b/public/editormd/emoji/baby_chick.png differ diff --git a/public/editormd/emoji/baby_symbol.png b/public/editormd/emoji/baby_symbol.png new file mode 100644 index 000000000..00861f02a Binary files /dev/null and b/public/editormd/emoji/baby_symbol.png differ diff --git a/public/editormd/emoji/back.png b/public/editormd/emoji/back.png new file mode 100644 index 000000000..6a5cac806 Binary files /dev/null and b/public/editormd/emoji/back.png differ diff --git a/public/editormd/emoji/baggage_claim.png b/public/editormd/emoji/baggage_claim.png new file mode 100644 index 000000000..e31c58c24 Binary files /dev/null and b/public/editormd/emoji/baggage_claim.png differ diff --git a/public/editormd/emoji/balloon.png b/public/editormd/emoji/balloon.png new file mode 100644 index 000000000..034489702 Binary files /dev/null and b/public/editormd/emoji/balloon.png differ diff --git a/public/editormd/emoji/ballot_box_with_check.png b/public/editormd/emoji/ballot_box_with_check.png new file mode 100644 index 000000000..f07a466c7 Binary files /dev/null and b/public/editormd/emoji/ballot_box_with_check.png differ diff --git a/public/editormd/emoji/bamboo.png b/public/editormd/emoji/bamboo.png new file mode 100644 index 000000000..fc858d0fc Binary files /dev/null and b/public/editormd/emoji/bamboo.png differ diff --git a/public/editormd/emoji/banana.png b/public/editormd/emoji/banana.png new file mode 100644 index 000000000..a0563afb9 Binary files /dev/null and b/public/editormd/emoji/banana.png differ diff --git a/public/editormd/emoji/bangbang.png b/public/editormd/emoji/bangbang.png new file mode 100644 index 000000000..7270f0afe Binary files /dev/null and b/public/editormd/emoji/bangbang.png differ diff --git a/public/editormd/emoji/bank.png b/public/editormd/emoji/bank.png new file mode 100644 index 000000000..1faa8777e Binary files /dev/null and b/public/editormd/emoji/bank.png differ diff --git a/public/editormd/emoji/bar_chart.png b/public/editormd/emoji/bar_chart.png new file mode 100644 index 000000000..8aac88cba Binary files /dev/null and b/public/editormd/emoji/bar_chart.png differ diff --git a/public/editormd/emoji/barber.png b/public/editormd/emoji/barber.png new file mode 100644 index 000000000..a10cb2322 Binary files /dev/null and b/public/editormd/emoji/barber.png differ diff --git a/public/editormd/emoji/baseball.png b/public/editormd/emoji/baseball.png new file mode 100644 index 000000000..da004e2ea Binary files /dev/null and b/public/editormd/emoji/baseball.png differ diff --git a/public/editormd/emoji/basketball.png b/public/editormd/emoji/basketball.png new file mode 100644 index 000000000..ef694bec4 Binary files /dev/null and b/public/editormd/emoji/basketball.png differ diff --git a/public/editormd/emoji/bath.png b/public/editormd/emoji/bath.png new file mode 100644 index 000000000..8f75d1d24 Binary files /dev/null and b/public/editormd/emoji/bath.png differ diff --git a/public/editormd/emoji/bathtub.png b/public/editormd/emoji/bathtub.png new file mode 100644 index 000000000..1c3f844ab Binary files /dev/null and b/public/editormd/emoji/bathtub.png differ diff --git a/public/editormd/emoji/battery.png b/public/editormd/emoji/battery.png new file mode 100644 index 000000000..aa7eedce4 Binary files /dev/null and b/public/editormd/emoji/battery.png differ diff --git a/public/editormd/emoji/bear.png b/public/editormd/emoji/bear.png new file mode 100644 index 000000000..f5afe920e Binary files /dev/null and b/public/editormd/emoji/bear.png differ diff --git a/public/editormd/emoji/bee.png b/public/editormd/emoji/bee.png new file mode 100644 index 000000000..f453bad59 Binary files /dev/null and b/public/editormd/emoji/bee.png differ diff --git a/public/editormd/emoji/beer.png b/public/editormd/emoji/beer.png new file mode 100644 index 000000000..cd78bed74 Binary files /dev/null and b/public/editormd/emoji/beer.png differ diff --git a/public/editormd/emoji/beers.png b/public/editormd/emoji/beers.png new file mode 100644 index 000000000..cc5e4ab5a Binary files /dev/null and b/public/editormd/emoji/beers.png differ diff --git a/public/editormd/emoji/beetle.png b/public/editormd/emoji/beetle.png new file mode 100644 index 000000000..222577ca7 Binary files /dev/null and b/public/editormd/emoji/beetle.png differ diff --git a/public/editormd/emoji/beginner.png b/public/editormd/emoji/beginner.png new file mode 100644 index 000000000..ad86de8f7 Binary files /dev/null and b/public/editormd/emoji/beginner.png differ diff --git a/public/editormd/emoji/bell.png b/public/editormd/emoji/bell.png new file mode 100644 index 000000000..69acceb28 Binary files /dev/null and b/public/editormd/emoji/bell.png differ diff --git a/public/editormd/emoji/bento.png b/public/editormd/emoji/bento.png new file mode 100644 index 000000000..99e75177e Binary files /dev/null and b/public/editormd/emoji/bento.png differ diff --git a/public/editormd/emoji/bicyclist.png b/public/editormd/emoji/bicyclist.png new file mode 100644 index 000000000..cbbd7c386 Binary files /dev/null and b/public/editormd/emoji/bicyclist.png differ diff --git a/public/editormd/emoji/bike.png b/public/editormd/emoji/bike.png new file mode 100644 index 000000000..657386027 Binary files /dev/null and b/public/editormd/emoji/bike.png differ diff --git a/public/editormd/emoji/bikini.png b/public/editormd/emoji/bikini.png new file mode 100644 index 000000000..4ff63b40f Binary files /dev/null and b/public/editormd/emoji/bikini.png differ diff --git a/public/editormd/emoji/bird.png b/public/editormd/emoji/bird.png new file mode 100644 index 000000000..e6be8c027 Binary files /dev/null and b/public/editormd/emoji/bird.png differ diff --git a/public/editormd/emoji/birthday.png b/public/editormd/emoji/birthday.png new file mode 100644 index 000000000..36e8edcbe Binary files /dev/null and b/public/editormd/emoji/birthday.png differ diff --git a/public/editormd/emoji/black_circle.png b/public/editormd/emoji/black_circle.png new file mode 100644 index 000000000..328e7cc30 Binary files /dev/null and b/public/editormd/emoji/black_circle.png differ diff --git a/public/editormd/emoji/black_joker.png b/public/editormd/emoji/black_joker.png new file mode 100644 index 000000000..a7d88ae74 Binary files /dev/null and b/public/editormd/emoji/black_joker.png differ diff --git a/public/editormd/emoji/black_medium_small_square.png b/public/editormd/emoji/black_medium_small_square.png new file mode 100644 index 000000000..2729e8af8 Binary files /dev/null and b/public/editormd/emoji/black_medium_small_square.png differ diff --git a/public/editormd/emoji/black_medium_square.png b/public/editormd/emoji/black_medium_square.png new file mode 100644 index 000000000..ed8e35dc5 Binary files /dev/null and b/public/editormd/emoji/black_medium_square.png differ diff --git a/public/editormd/emoji/black_nib.png b/public/editormd/emoji/black_nib.png new file mode 100644 index 000000000..f3c07fcc8 Binary files /dev/null and b/public/editormd/emoji/black_nib.png differ diff --git a/public/editormd/emoji/black_small_square.png b/public/editormd/emoji/black_small_square.png new file mode 100644 index 000000000..4a1436a6c Binary files /dev/null and b/public/editormd/emoji/black_small_square.png differ diff --git a/public/editormd/emoji/black_square.png b/public/editormd/emoji/black_square.png new file mode 100644 index 000000000..0bdbe17a2 Binary files /dev/null and b/public/editormd/emoji/black_square.png differ diff --git a/public/editormd/emoji/black_square_button.png b/public/editormd/emoji/black_square_button.png new file mode 100644 index 000000000..bb9fdc78e Binary files /dev/null and b/public/editormd/emoji/black_square_button.png differ diff --git a/public/editormd/emoji/blossom.png b/public/editormd/emoji/blossom.png new file mode 100644 index 000000000..55a97353b Binary files /dev/null and b/public/editormd/emoji/blossom.png differ diff --git a/public/editormd/emoji/blowfish.png b/public/editormd/emoji/blowfish.png new file mode 100644 index 000000000..d3ad46585 Binary files /dev/null and b/public/editormd/emoji/blowfish.png differ diff --git a/public/editormd/emoji/blue_book.png b/public/editormd/emoji/blue_book.png new file mode 100644 index 000000000..74c917769 Binary files /dev/null and b/public/editormd/emoji/blue_book.png differ diff --git a/public/editormd/emoji/blue_car.png b/public/editormd/emoji/blue_car.png new file mode 100644 index 000000000..ee2fc3ecf Binary files /dev/null and b/public/editormd/emoji/blue_car.png differ diff --git a/public/editormd/emoji/blue_heart.png b/public/editormd/emoji/blue_heart.png new file mode 100644 index 000000000..aae5a9eca Binary files /dev/null and b/public/editormd/emoji/blue_heart.png differ diff --git a/public/editormd/emoji/blush.png b/public/editormd/emoji/blush.png new file mode 100644 index 000000000..ec36f90c6 Binary files /dev/null and b/public/editormd/emoji/blush.png differ diff --git a/public/editormd/emoji/boar.png b/public/editormd/emoji/boar.png new file mode 100644 index 000000000..8196ad4a1 Binary files /dev/null and b/public/editormd/emoji/boar.png differ diff --git a/public/editormd/emoji/boat.png b/public/editormd/emoji/boat.png new file mode 100644 index 000000000..ff656dc62 Binary files /dev/null and b/public/editormd/emoji/boat.png differ diff --git a/public/editormd/emoji/bomb.png b/public/editormd/emoji/bomb.png new file mode 100644 index 000000000..e914b694c Binary files /dev/null and b/public/editormd/emoji/bomb.png differ diff --git a/public/editormd/emoji/book.png b/public/editormd/emoji/book.png new file mode 100644 index 000000000..07623f830 Binary files /dev/null and b/public/editormd/emoji/book.png differ diff --git a/public/editormd/emoji/bookmark.png b/public/editormd/emoji/bookmark.png new file mode 100644 index 000000000..6fc4ed902 Binary files /dev/null and b/public/editormd/emoji/bookmark.png differ diff --git a/public/editormd/emoji/bookmark_tabs.png b/public/editormd/emoji/bookmark_tabs.png new file mode 100644 index 000000000..60e71a786 Binary files /dev/null and b/public/editormd/emoji/bookmark_tabs.png differ diff --git a/public/editormd/emoji/books.png b/public/editormd/emoji/books.png new file mode 100644 index 000000000..2d5484363 Binary files /dev/null and b/public/editormd/emoji/books.png differ diff --git a/public/editormd/emoji/boom.png b/public/editormd/emoji/boom.png new file mode 100644 index 000000000..9d5bd0401 Binary files /dev/null and b/public/editormd/emoji/boom.png differ diff --git a/public/editormd/emoji/boot.png b/public/editormd/emoji/boot.png new file mode 100644 index 000000000..58d0fdbcd Binary files /dev/null and b/public/editormd/emoji/boot.png differ diff --git a/public/editormd/emoji/bouquet.png b/public/editormd/emoji/bouquet.png new file mode 100644 index 000000000..ce637832e Binary files /dev/null and b/public/editormd/emoji/bouquet.png differ diff --git a/public/editormd/emoji/bow.png b/public/editormd/emoji/bow.png new file mode 100644 index 000000000..5ba4ef3f4 Binary files /dev/null and b/public/editormd/emoji/bow.png differ diff --git a/public/editormd/emoji/bowling.png b/public/editormd/emoji/bowling.png new file mode 100644 index 000000000..13d8ece2e Binary files /dev/null and b/public/editormd/emoji/bowling.png differ diff --git a/public/editormd/emoji/bowtie.png b/public/editormd/emoji/bowtie.png new file mode 100644 index 000000000..38f85e020 Binary files /dev/null and b/public/editormd/emoji/bowtie.png differ diff --git a/public/editormd/emoji/boy.png b/public/editormd/emoji/boy.png new file mode 100644 index 000000000..f79f1f298 Binary files /dev/null and b/public/editormd/emoji/boy.png differ diff --git a/public/editormd/emoji/bread.png b/public/editormd/emoji/bread.png new file mode 100644 index 000000000..7e7c63753 Binary files /dev/null and b/public/editormd/emoji/bread.png differ diff --git a/public/editormd/emoji/bride_with_veil.png b/public/editormd/emoji/bride_with_veil.png new file mode 100644 index 000000000..dd0b0cfda Binary files /dev/null and b/public/editormd/emoji/bride_with_veil.png differ diff --git a/public/editormd/emoji/bridge_at_night.png b/public/editormd/emoji/bridge_at_night.png new file mode 100644 index 000000000..0f0b5c7cb Binary files /dev/null and b/public/editormd/emoji/bridge_at_night.png differ diff --git a/public/editormd/emoji/briefcase.png b/public/editormd/emoji/briefcase.png new file mode 100644 index 000000000..2eb791b51 Binary files /dev/null and b/public/editormd/emoji/briefcase.png differ diff --git a/public/editormd/emoji/broken_heart.png b/public/editormd/emoji/broken_heart.png new file mode 100644 index 000000000..de4e8a991 Binary files /dev/null and b/public/editormd/emoji/broken_heart.png differ diff --git a/public/editormd/emoji/bug.png b/public/editormd/emoji/bug.png new file mode 100644 index 000000000..63a7fb528 Binary files /dev/null and b/public/editormd/emoji/bug.png differ diff --git a/public/editormd/emoji/bulb.png b/public/editormd/emoji/bulb.png new file mode 100644 index 000000000..23afca1c7 Binary files /dev/null and b/public/editormd/emoji/bulb.png differ diff --git a/public/editormd/emoji/bullettrain_front.png b/public/editormd/emoji/bullettrain_front.png new file mode 100644 index 000000000..16651acff Binary files /dev/null and b/public/editormd/emoji/bullettrain_front.png differ diff --git a/public/editormd/emoji/bullettrain_side.png b/public/editormd/emoji/bullettrain_side.png new file mode 100644 index 000000000..8eca36845 Binary files /dev/null and b/public/editormd/emoji/bullettrain_side.png differ diff --git a/public/editormd/emoji/bus.png b/public/editormd/emoji/bus.png new file mode 100644 index 000000000..a4cba5641 Binary files /dev/null and b/public/editormd/emoji/bus.png differ diff --git a/public/editormd/emoji/busstop.png b/public/editormd/emoji/busstop.png new file mode 100644 index 000000000..94894847b Binary files /dev/null and b/public/editormd/emoji/busstop.png differ diff --git a/public/editormd/emoji/bust_in_silhouette.png b/public/editormd/emoji/bust_in_silhouette.png new file mode 100644 index 000000000..dd7defe28 Binary files /dev/null and b/public/editormd/emoji/bust_in_silhouette.png differ diff --git a/public/editormd/emoji/busts_in_silhouette.png b/public/editormd/emoji/busts_in_silhouette.png new file mode 100644 index 000000000..d3a62b39f Binary files /dev/null and b/public/editormd/emoji/busts_in_silhouette.png differ diff --git a/public/editormd/emoji/cactus.png b/public/editormd/emoji/cactus.png new file mode 100644 index 000000000..5a2c3cc72 Binary files /dev/null and b/public/editormd/emoji/cactus.png differ diff --git a/public/editormd/emoji/cake.png b/public/editormd/emoji/cake.png new file mode 100644 index 000000000..efeb9b4b2 Binary files /dev/null and b/public/editormd/emoji/cake.png differ diff --git a/public/editormd/emoji/calendar.png b/public/editormd/emoji/calendar.png new file mode 100644 index 000000000..9fbf0cb22 Binary files /dev/null and b/public/editormd/emoji/calendar.png differ diff --git a/public/editormd/emoji/calling.png b/public/editormd/emoji/calling.png new file mode 100644 index 000000000..29db4cd45 Binary files /dev/null and b/public/editormd/emoji/calling.png differ diff --git a/public/editormd/emoji/camel.png b/public/editormd/emoji/camel.png new file mode 100644 index 000000000..496c186ae Binary files /dev/null and b/public/editormd/emoji/camel.png differ diff --git a/public/editormd/emoji/camera.png b/public/editormd/emoji/camera.png new file mode 100644 index 000000000..afca2cdc1 Binary files /dev/null and b/public/editormd/emoji/camera.png differ diff --git a/public/editormd/emoji/cancer.png b/public/editormd/emoji/cancer.png new file mode 100644 index 000000000..7d8d59e41 Binary files /dev/null and b/public/editormd/emoji/cancer.png differ diff --git a/public/editormd/emoji/candy.png b/public/editormd/emoji/candy.png new file mode 100644 index 000000000..33722f236 Binary files /dev/null and b/public/editormd/emoji/candy.png differ diff --git a/public/editormd/emoji/capital_abcd.png b/public/editormd/emoji/capital_abcd.png new file mode 100644 index 000000000..ffc0cba4b Binary files /dev/null and b/public/editormd/emoji/capital_abcd.png differ diff --git a/public/editormd/emoji/capricorn.png b/public/editormd/emoji/capricorn.png new file mode 100644 index 000000000..59dda452f Binary files /dev/null and b/public/editormd/emoji/capricorn.png differ diff --git a/public/editormd/emoji/car.png b/public/editormd/emoji/car.png new file mode 100644 index 000000000..8896a8c1f Binary files /dev/null and b/public/editormd/emoji/car.png differ diff --git a/public/editormd/emoji/card_index.png b/public/editormd/emoji/card_index.png new file mode 100644 index 000000000..39cd045f4 Binary files /dev/null and b/public/editormd/emoji/card_index.png differ diff --git a/public/editormd/emoji/carousel_horse.png b/public/editormd/emoji/carousel_horse.png new file mode 100644 index 000000000..5bec060b4 Binary files /dev/null and b/public/editormd/emoji/carousel_horse.png differ diff --git a/public/editormd/emoji/cat.png b/public/editormd/emoji/cat.png new file mode 100644 index 000000000..09b9ef79a Binary files /dev/null and b/public/editormd/emoji/cat.png differ diff --git a/public/editormd/emoji/cat2.png b/public/editormd/emoji/cat2.png new file mode 100644 index 000000000..6dbc4c71e Binary files /dev/null and b/public/editormd/emoji/cat2.png differ diff --git a/public/editormd/emoji/cd.png b/public/editormd/emoji/cd.png new file mode 100644 index 000000000..bdccf6554 Binary files /dev/null and b/public/editormd/emoji/cd.png differ diff --git a/public/editormd/emoji/chart.png b/public/editormd/emoji/chart.png new file mode 100644 index 000000000..94a396ef0 Binary files /dev/null and b/public/editormd/emoji/chart.png differ diff --git a/public/editormd/emoji/chart_with_downwards_trend.png b/public/editormd/emoji/chart_with_downwards_trend.png new file mode 100644 index 000000000..0184b87c5 Binary files /dev/null and b/public/editormd/emoji/chart_with_downwards_trend.png differ diff --git a/public/editormd/emoji/chart_with_upwards_trend.png b/public/editormd/emoji/chart_with_upwards_trend.png new file mode 100644 index 000000000..22426316d Binary files /dev/null and b/public/editormd/emoji/chart_with_upwards_trend.png differ diff --git a/public/editormd/emoji/checkered_flag.png b/public/editormd/emoji/checkered_flag.png new file mode 100644 index 000000000..b12fbef54 Binary files /dev/null and b/public/editormd/emoji/checkered_flag.png differ diff --git a/public/editormd/emoji/cherries.png b/public/editormd/emoji/cherries.png new file mode 100644 index 000000000..2e3ebc9f2 Binary files /dev/null and b/public/editormd/emoji/cherries.png differ diff --git a/public/editormd/emoji/cherry_blossom.png b/public/editormd/emoji/cherry_blossom.png new file mode 100644 index 000000000..30368c0b7 Binary files /dev/null and b/public/editormd/emoji/cherry_blossom.png differ diff --git a/public/editormd/emoji/chestnut.png b/public/editormd/emoji/chestnut.png new file mode 100644 index 000000000..d83df9b36 Binary files /dev/null and b/public/editormd/emoji/chestnut.png differ diff --git a/public/editormd/emoji/chicken.png b/public/editormd/emoji/chicken.png new file mode 100644 index 000000000..6d25c0ef4 Binary files /dev/null and b/public/editormd/emoji/chicken.png differ diff --git a/public/editormd/emoji/children_crossing.png b/public/editormd/emoji/children_crossing.png new file mode 100644 index 000000000..00619f4c5 Binary files /dev/null and b/public/editormd/emoji/children_crossing.png differ diff --git a/public/editormd/emoji/chocolate_bar.png b/public/editormd/emoji/chocolate_bar.png new file mode 100644 index 000000000..c7ec19d07 Binary files /dev/null and b/public/editormd/emoji/chocolate_bar.png differ diff --git a/public/editormd/emoji/christmas_tree.png b/public/editormd/emoji/christmas_tree.png new file mode 100644 index 000000000..d813b9593 Binary files /dev/null and b/public/editormd/emoji/christmas_tree.png differ diff --git a/public/editormd/emoji/church.png b/public/editormd/emoji/church.png new file mode 100644 index 000000000..51bc95153 Binary files /dev/null and b/public/editormd/emoji/church.png differ diff --git a/public/editormd/emoji/cinema.png b/public/editormd/emoji/cinema.png new file mode 100644 index 000000000..855ff7ada Binary files /dev/null and b/public/editormd/emoji/cinema.png differ diff --git a/public/editormd/emoji/circus_tent.png b/public/editormd/emoji/circus_tent.png new file mode 100644 index 000000000..4af8719aa Binary files /dev/null and b/public/editormd/emoji/circus_tent.png differ diff --git a/public/editormd/emoji/city_sunrise.png b/public/editormd/emoji/city_sunrise.png new file mode 100644 index 000000000..9d6269797 Binary files /dev/null and b/public/editormd/emoji/city_sunrise.png differ diff --git a/public/editormd/emoji/city_sunset.png b/public/editormd/emoji/city_sunset.png new file mode 100644 index 000000000..8b7ce8540 Binary files /dev/null and b/public/editormd/emoji/city_sunset.png differ diff --git a/public/editormd/emoji/cl.png b/public/editormd/emoji/cl.png new file mode 100644 index 000000000..c3dc10d49 Binary files /dev/null and b/public/editormd/emoji/cl.png differ diff --git a/public/editormd/emoji/clap.png b/public/editormd/emoji/clap.png new file mode 100644 index 000000000..d01c982a7 Binary files /dev/null and b/public/editormd/emoji/clap.png differ diff --git a/public/editormd/emoji/clapper.png b/public/editormd/emoji/clapper.png new file mode 100644 index 000000000..20763f2dc Binary files /dev/null and b/public/editormd/emoji/clapper.png differ diff --git a/public/editormd/emoji/clipboard.png b/public/editormd/emoji/clipboard.png new file mode 100644 index 000000000..70be2210c Binary files /dev/null and b/public/editormd/emoji/clipboard.png differ diff --git a/public/editormd/emoji/clock1.png b/public/editormd/emoji/clock1.png new file mode 100644 index 000000000..9174d4e0b Binary files /dev/null and b/public/editormd/emoji/clock1.png differ diff --git a/public/editormd/emoji/clock10.png b/public/editormd/emoji/clock10.png new file mode 100644 index 000000000..39f590d69 Binary files /dev/null and b/public/editormd/emoji/clock10.png differ diff --git a/public/editormd/emoji/clock1030.png b/public/editormd/emoji/clock1030.png new file mode 100644 index 000000000..0483b3059 Binary files /dev/null and b/public/editormd/emoji/clock1030.png differ diff --git a/public/editormd/emoji/clock11.png b/public/editormd/emoji/clock11.png new file mode 100644 index 000000000..ddb53fada Binary files /dev/null and b/public/editormd/emoji/clock11.png differ diff --git a/public/editormd/emoji/clock1130.png b/public/editormd/emoji/clock1130.png new file mode 100644 index 000000000..415999ec8 Binary files /dev/null and b/public/editormd/emoji/clock1130.png differ diff --git a/public/editormd/emoji/clock12.png b/public/editormd/emoji/clock12.png new file mode 100644 index 000000000..87b132878 Binary files /dev/null and b/public/editormd/emoji/clock12.png differ diff --git a/public/editormd/emoji/clock1230.png b/public/editormd/emoji/clock1230.png new file mode 100644 index 000000000..a6527154d Binary files /dev/null and b/public/editormd/emoji/clock1230.png differ diff --git a/public/editormd/emoji/clock130.png b/public/editormd/emoji/clock130.png new file mode 100644 index 000000000..a5657b101 Binary files /dev/null and b/public/editormd/emoji/clock130.png differ diff --git a/public/editormd/emoji/clock2.png b/public/editormd/emoji/clock2.png new file mode 100644 index 000000000..65b3b3af0 Binary files /dev/null and b/public/editormd/emoji/clock2.png differ diff --git a/public/editormd/emoji/clock230.png b/public/editormd/emoji/clock230.png new file mode 100644 index 000000000..cb2db58e5 Binary files /dev/null and b/public/editormd/emoji/clock230.png differ diff --git a/public/editormd/emoji/clock3.png b/public/editormd/emoji/clock3.png new file mode 100644 index 000000000..3e44d64e2 Binary files /dev/null and b/public/editormd/emoji/clock3.png differ diff --git a/public/editormd/emoji/clock330.png b/public/editormd/emoji/clock330.png new file mode 100644 index 000000000..2c48e4fd3 Binary files /dev/null and b/public/editormd/emoji/clock330.png differ diff --git a/public/editormd/emoji/clock4.png b/public/editormd/emoji/clock4.png new file mode 100644 index 000000000..948ed1a38 Binary files /dev/null and b/public/editormd/emoji/clock4.png differ diff --git a/public/editormd/emoji/clock430.png b/public/editormd/emoji/clock430.png new file mode 100644 index 000000000..5d6b16a2d Binary files /dev/null and b/public/editormd/emoji/clock430.png differ diff --git a/public/editormd/emoji/clock5.png b/public/editormd/emoji/clock5.png new file mode 100644 index 000000000..b010b4f8a Binary files /dev/null and b/public/editormd/emoji/clock5.png differ diff --git a/public/editormd/emoji/clock530.png b/public/editormd/emoji/clock530.png new file mode 100644 index 000000000..fc6ba197d Binary files /dev/null and b/public/editormd/emoji/clock530.png differ diff --git a/public/editormd/emoji/clock6.png b/public/editormd/emoji/clock6.png new file mode 100644 index 000000000..76bf8cf18 Binary files /dev/null and b/public/editormd/emoji/clock6.png differ diff --git a/public/editormd/emoji/clock630.png b/public/editormd/emoji/clock630.png new file mode 100644 index 000000000..756f6a32b Binary files /dev/null and b/public/editormd/emoji/clock630.png differ diff --git a/public/editormd/emoji/clock7.png b/public/editormd/emoji/clock7.png new file mode 100644 index 000000000..d48f645d8 Binary files /dev/null and b/public/editormd/emoji/clock7.png differ diff --git a/public/editormd/emoji/clock730.png b/public/editormd/emoji/clock730.png new file mode 100644 index 000000000..f2807de2f Binary files /dev/null and b/public/editormd/emoji/clock730.png differ diff --git a/public/editormd/emoji/clock8.png b/public/editormd/emoji/clock8.png new file mode 100644 index 000000000..74c770d89 Binary files /dev/null and b/public/editormd/emoji/clock8.png differ diff --git a/public/editormd/emoji/clock830.png b/public/editormd/emoji/clock830.png new file mode 100644 index 000000000..f58f3dadd Binary files /dev/null and b/public/editormd/emoji/clock830.png differ diff --git a/public/editormd/emoji/clock9.png b/public/editormd/emoji/clock9.png new file mode 100644 index 000000000..f009d14ac Binary files /dev/null and b/public/editormd/emoji/clock9.png differ diff --git a/public/editormd/emoji/clock930.png b/public/editormd/emoji/clock930.png new file mode 100644 index 000000000..2709fec2f Binary files /dev/null and b/public/editormd/emoji/clock930.png differ diff --git a/public/editormd/emoji/closed_book.png b/public/editormd/emoji/closed_book.png new file mode 100644 index 000000000..9443210bb Binary files /dev/null and b/public/editormd/emoji/closed_book.png differ diff --git a/public/editormd/emoji/closed_lock_with_key.png b/public/editormd/emoji/closed_lock_with_key.png new file mode 100644 index 000000000..97a3c0ab5 Binary files /dev/null and b/public/editormd/emoji/closed_lock_with_key.png differ diff --git a/public/editormd/emoji/closed_umbrella.png b/public/editormd/emoji/closed_umbrella.png new file mode 100644 index 000000000..0b719f086 Binary files /dev/null and b/public/editormd/emoji/closed_umbrella.png differ diff --git a/public/editormd/emoji/cloud.png b/public/editormd/emoji/cloud.png new file mode 100644 index 000000000..05bb36872 Binary files /dev/null and b/public/editormd/emoji/cloud.png differ diff --git a/public/editormd/emoji/clubs.png b/public/editormd/emoji/clubs.png new file mode 100644 index 000000000..1471ffd4d Binary files /dev/null and b/public/editormd/emoji/clubs.png differ diff --git a/public/editormd/emoji/cn.png b/public/editormd/emoji/cn.png new file mode 100644 index 000000000..a0d597714 Binary files /dev/null and b/public/editormd/emoji/cn.png differ diff --git a/public/editormd/emoji/cocktail.png b/public/editormd/emoji/cocktail.png new file mode 100644 index 000000000..28b45ea51 Binary files /dev/null and b/public/editormd/emoji/cocktail.png differ diff --git a/public/editormd/emoji/coffee.png b/public/editormd/emoji/coffee.png new file mode 100644 index 000000000..f312bc530 Binary files /dev/null and b/public/editormd/emoji/coffee.png differ diff --git a/public/editormd/emoji/cold_sweat.png b/public/editormd/emoji/cold_sweat.png new file mode 100644 index 000000000..585a88d67 Binary files /dev/null and b/public/editormd/emoji/cold_sweat.png differ diff --git a/public/editormd/emoji/collision.png b/public/editormd/emoji/collision.png new file mode 100644 index 000000000..9d5bd0401 Binary files /dev/null and b/public/editormd/emoji/collision.png differ diff --git a/public/editormd/emoji/computer.png b/public/editormd/emoji/computer.png new file mode 100644 index 000000000..d4d268762 Binary files /dev/null and b/public/editormd/emoji/computer.png differ diff --git a/public/editormd/emoji/confetti_ball.png b/public/editormd/emoji/confetti_ball.png new file mode 100644 index 000000000..06273250c Binary files /dev/null and b/public/editormd/emoji/confetti_ball.png differ diff --git a/public/editormd/emoji/confounded.png b/public/editormd/emoji/confounded.png new file mode 100644 index 000000000..71959ad24 Binary files /dev/null and b/public/editormd/emoji/confounded.png differ diff --git a/public/editormd/emoji/confused.png b/public/editormd/emoji/confused.png new file mode 100644 index 000000000..9b51470c8 Binary files /dev/null and b/public/editormd/emoji/confused.png differ diff --git a/public/editormd/emoji/congratulations.png b/public/editormd/emoji/congratulations.png new file mode 100644 index 000000000..a5a05dd50 Binary files /dev/null and b/public/editormd/emoji/congratulations.png differ diff --git a/public/editormd/emoji/construction.png b/public/editormd/emoji/construction.png new file mode 100644 index 000000000..523e9f10b Binary files /dev/null and b/public/editormd/emoji/construction.png differ diff --git a/public/editormd/emoji/construction_worker.png b/public/editormd/emoji/construction_worker.png new file mode 100644 index 000000000..a9170a51e Binary files /dev/null and b/public/editormd/emoji/construction_worker.png differ diff --git a/public/editormd/emoji/convenience_store.png b/public/editormd/emoji/convenience_store.png new file mode 100644 index 000000000..671696c2d Binary files /dev/null and b/public/editormd/emoji/convenience_store.png differ diff --git a/public/editormd/emoji/cookie.png b/public/editormd/emoji/cookie.png new file mode 100644 index 000000000..1a3b219f5 Binary files /dev/null and b/public/editormd/emoji/cookie.png differ diff --git a/public/editormd/emoji/cool.png b/public/editormd/emoji/cool.png new file mode 100644 index 000000000..937dcd792 Binary files /dev/null and b/public/editormd/emoji/cool.png differ diff --git a/public/editormd/emoji/cop.png b/public/editormd/emoji/cop.png new file mode 100644 index 000000000..43a5a84f8 Binary files /dev/null and b/public/editormd/emoji/cop.png differ diff --git a/public/editormd/emoji/copyright.png b/public/editormd/emoji/copyright.png new file mode 100644 index 000000000..38493c33f Binary files /dev/null and b/public/editormd/emoji/copyright.png differ diff --git a/public/editormd/emoji/corn.png b/public/editormd/emoji/corn.png new file mode 100644 index 000000000..fe5d8b128 Binary files /dev/null and b/public/editormd/emoji/corn.png differ diff --git a/public/editormd/emoji/couple.png b/public/editormd/emoji/couple.png new file mode 100644 index 000000000..9e51f40e1 Binary files /dev/null and b/public/editormd/emoji/couple.png differ diff --git a/public/editormd/emoji/couple_with_heart.png b/public/editormd/emoji/couple_with_heart.png new file mode 100644 index 000000000..e86581ccd Binary files /dev/null and b/public/editormd/emoji/couple_with_heart.png differ diff --git a/public/editormd/emoji/couplekiss.png b/public/editormd/emoji/couplekiss.png new file mode 100644 index 000000000..af8200045 Binary files /dev/null and b/public/editormd/emoji/couplekiss.png differ diff --git a/public/editormd/emoji/cow.png b/public/editormd/emoji/cow.png new file mode 100644 index 000000000..12e1ab6c0 Binary files /dev/null and b/public/editormd/emoji/cow.png differ diff --git a/public/editormd/emoji/cow2.png b/public/editormd/emoji/cow2.png new file mode 100644 index 000000000..594c92155 Binary files /dev/null and b/public/editormd/emoji/cow2.png differ diff --git a/public/editormd/emoji/credit_card.png b/public/editormd/emoji/credit_card.png new file mode 100644 index 000000000..5e161b807 Binary files /dev/null and b/public/editormd/emoji/credit_card.png differ diff --git a/public/editormd/emoji/crescent_moon.png b/public/editormd/emoji/crescent_moon.png new file mode 100644 index 000000000..afdb450d1 Binary files /dev/null and b/public/editormd/emoji/crescent_moon.png differ diff --git a/public/editormd/emoji/crocodile.png b/public/editormd/emoji/crocodile.png new file mode 100644 index 000000000..7435d5ab3 Binary files /dev/null and b/public/editormd/emoji/crocodile.png differ diff --git a/public/editormd/emoji/crossed_flags.png b/public/editormd/emoji/crossed_flags.png new file mode 100644 index 000000000..2397bcd0f Binary files /dev/null and b/public/editormd/emoji/crossed_flags.png differ diff --git a/public/editormd/emoji/crown.png b/public/editormd/emoji/crown.png new file mode 100644 index 000000000..39da1d528 Binary files /dev/null and b/public/editormd/emoji/crown.png differ diff --git a/public/editormd/emoji/cry.png b/public/editormd/emoji/cry.png new file mode 100644 index 000000000..7eff46c16 Binary files /dev/null and b/public/editormd/emoji/cry.png differ diff --git a/public/editormd/emoji/crying_cat_face.png b/public/editormd/emoji/crying_cat_face.png new file mode 100644 index 000000000..42d4c27ca Binary files /dev/null and b/public/editormd/emoji/crying_cat_face.png differ diff --git a/public/editormd/emoji/crystal_ball.png b/public/editormd/emoji/crystal_ball.png new file mode 100644 index 000000000..23d53c4db Binary files /dev/null and b/public/editormd/emoji/crystal_ball.png differ diff --git a/public/editormd/emoji/cupid.png b/public/editormd/emoji/cupid.png new file mode 100644 index 000000000..498728476 Binary files /dev/null and b/public/editormd/emoji/cupid.png differ diff --git a/public/editormd/emoji/curly_loop.png b/public/editormd/emoji/curly_loop.png new file mode 100644 index 000000000..7dd841d00 Binary files /dev/null and b/public/editormd/emoji/curly_loop.png differ diff --git a/public/editormd/emoji/currency_exchange.png b/public/editormd/emoji/currency_exchange.png new file mode 100644 index 000000000..6ebebe70a Binary files /dev/null and b/public/editormd/emoji/currency_exchange.png differ diff --git a/public/editormd/emoji/curry.png b/public/editormd/emoji/curry.png new file mode 100644 index 000000000..090e2f416 Binary files /dev/null and b/public/editormd/emoji/curry.png differ diff --git a/public/editormd/emoji/custard.png b/public/editormd/emoji/custard.png new file mode 100644 index 000000000..9e5076733 Binary files /dev/null and b/public/editormd/emoji/custard.png differ diff --git a/public/editormd/emoji/customs.png b/public/editormd/emoji/customs.png new file mode 100644 index 000000000..92691e311 Binary files /dev/null and b/public/editormd/emoji/customs.png differ diff --git a/public/editormd/emoji/cyclone.png b/public/editormd/emoji/cyclone.png new file mode 100644 index 000000000..5fd2e4512 Binary files /dev/null and b/public/editormd/emoji/cyclone.png differ diff --git a/public/editormd/emoji/dancer.png b/public/editormd/emoji/dancer.png new file mode 100644 index 000000000..0f7ac4b2d Binary files /dev/null and b/public/editormd/emoji/dancer.png differ diff --git a/public/editormd/emoji/dancers.png b/public/editormd/emoji/dancers.png new file mode 100644 index 000000000..2dfb451a7 Binary files /dev/null and b/public/editormd/emoji/dancers.png differ diff --git a/public/editormd/emoji/dango.png b/public/editormd/emoji/dango.png new file mode 100644 index 000000000..2d042aebe Binary files /dev/null and b/public/editormd/emoji/dango.png differ diff --git a/public/editormd/emoji/dart.png b/public/editormd/emoji/dart.png new file mode 100644 index 000000000..5f16864cb Binary files /dev/null and b/public/editormd/emoji/dart.png differ diff --git a/public/editormd/emoji/dash.png b/public/editormd/emoji/dash.png new file mode 100644 index 000000000..9ff72ab7f Binary files /dev/null and b/public/editormd/emoji/dash.png differ diff --git a/public/editormd/emoji/date.png b/public/editormd/emoji/date.png new file mode 100644 index 000000000..9e06df562 Binary files /dev/null and b/public/editormd/emoji/date.png differ diff --git a/public/editormd/emoji/de.png b/public/editormd/emoji/de.png new file mode 100644 index 000000000..920bc8e72 Binary files /dev/null and b/public/editormd/emoji/de.png differ diff --git a/public/editormd/emoji/deciduous_tree.png b/public/editormd/emoji/deciduous_tree.png new file mode 100644 index 000000000..48a8907a7 Binary files /dev/null and b/public/editormd/emoji/deciduous_tree.png differ diff --git a/public/editormd/emoji/department_store.png b/public/editormd/emoji/department_store.png new file mode 100644 index 000000000..68d959c50 Binary files /dev/null and b/public/editormd/emoji/department_store.png differ diff --git a/public/editormd/emoji/diamond_shape_with_a_dot_inside.png b/public/editormd/emoji/diamond_shape_with_a_dot_inside.png new file mode 100644 index 000000000..717037a52 Binary files /dev/null and b/public/editormd/emoji/diamond_shape_with_a_dot_inside.png differ diff --git a/public/editormd/emoji/diamonds.png b/public/editormd/emoji/diamonds.png new file mode 100644 index 000000000..17ed99144 Binary files /dev/null and b/public/editormd/emoji/diamonds.png differ diff --git a/public/editormd/emoji/disappointed.png b/public/editormd/emoji/disappointed.png new file mode 100644 index 000000000..7aa2b7422 Binary files /dev/null and b/public/editormd/emoji/disappointed.png differ diff --git a/public/editormd/emoji/disappointed_relieved.png b/public/editormd/emoji/disappointed_relieved.png new file mode 100644 index 000000000..2301d9d8f Binary files /dev/null and b/public/editormd/emoji/disappointed_relieved.png differ diff --git a/public/editormd/emoji/dizzy.png b/public/editormd/emoji/dizzy.png new file mode 100644 index 000000000..3702b6131 Binary files /dev/null and b/public/editormd/emoji/dizzy.png differ diff --git a/public/editormd/emoji/dizzy_face.png b/public/editormd/emoji/dizzy_face.png new file mode 100644 index 000000000..7f7452c3b Binary files /dev/null and b/public/editormd/emoji/dizzy_face.png differ diff --git a/public/editormd/emoji/do_not_litter.png b/public/editormd/emoji/do_not_litter.png new file mode 100644 index 000000000..38c7ae7af Binary files /dev/null and b/public/editormd/emoji/do_not_litter.png differ diff --git a/public/editormd/emoji/dog.png b/public/editormd/emoji/dog.png new file mode 100644 index 000000000..389a02bf2 Binary files /dev/null and b/public/editormd/emoji/dog.png differ diff --git a/public/editormd/emoji/dog2.png b/public/editormd/emoji/dog2.png new file mode 100644 index 000000000..c7f6a24ac Binary files /dev/null and b/public/editormd/emoji/dog2.png differ diff --git a/public/editormd/emoji/dollar.png b/public/editormd/emoji/dollar.png new file mode 100644 index 000000000..e867b1813 Binary files /dev/null and b/public/editormd/emoji/dollar.png differ diff --git a/public/editormd/emoji/dolls.png b/public/editormd/emoji/dolls.png new file mode 100644 index 000000000..ec95a6414 Binary files /dev/null and b/public/editormd/emoji/dolls.png differ diff --git a/public/editormd/emoji/dolphin.png b/public/editormd/emoji/dolphin.png new file mode 100644 index 000000000..9326077a9 Binary files /dev/null and b/public/editormd/emoji/dolphin.png differ diff --git a/public/editormd/emoji/donut.png b/public/editormd/emoji/donut.png new file mode 100644 index 000000000..858754254 Binary files /dev/null and b/public/editormd/emoji/donut.png differ diff --git a/public/editormd/emoji/door.png b/public/editormd/emoji/door.png new file mode 100644 index 000000000..83c819ae4 Binary files /dev/null and b/public/editormd/emoji/door.png differ diff --git a/public/editormd/emoji/doughnut.png b/public/editormd/emoji/doughnut.png new file mode 100644 index 000000000..858754254 Binary files /dev/null and b/public/editormd/emoji/doughnut.png differ diff --git a/public/editormd/emoji/dragon.png b/public/editormd/emoji/dragon.png new file mode 100644 index 000000000..88d4784b8 Binary files /dev/null and b/public/editormd/emoji/dragon.png differ diff --git a/public/editormd/emoji/dragon_face.png b/public/editormd/emoji/dragon_face.png new file mode 100644 index 000000000..e5e556bd1 Binary files /dev/null and b/public/editormd/emoji/dragon_face.png differ diff --git a/public/editormd/emoji/dress.png b/public/editormd/emoji/dress.png new file mode 100644 index 000000000..6434e2e2f Binary files /dev/null and b/public/editormd/emoji/dress.png differ diff --git a/public/editormd/emoji/dromedary_camel.png b/public/editormd/emoji/dromedary_camel.png new file mode 100644 index 000000000..c8c7b9ffa Binary files /dev/null and b/public/editormd/emoji/dromedary_camel.png differ diff --git a/public/editormd/emoji/droplet.png b/public/editormd/emoji/droplet.png new file mode 100644 index 000000000..cae7f4951 Binary files /dev/null and b/public/editormd/emoji/droplet.png differ diff --git a/public/editormd/emoji/dvd.png b/public/editormd/emoji/dvd.png new file mode 100644 index 000000000..730874cc0 Binary files /dev/null and b/public/editormd/emoji/dvd.png differ diff --git a/public/editormd/emoji/e-mail.png b/public/editormd/emoji/e-mail.png new file mode 100644 index 000000000..a7a1ee5db Binary files /dev/null and b/public/editormd/emoji/e-mail.png differ diff --git a/public/editormd/emoji/ear.png b/public/editormd/emoji/ear.png new file mode 100644 index 000000000..2bbbf10c9 Binary files /dev/null and b/public/editormd/emoji/ear.png differ diff --git a/public/editormd/emoji/ear_of_rice.png b/public/editormd/emoji/ear_of_rice.png new file mode 100644 index 000000000..a9bba5c2c Binary files /dev/null and b/public/editormd/emoji/ear_of_rice.png differ diff --git a/public/editormd/emoji/earth_africa.png b/public/editormd/emoji/earth_africa.png new file mode 100644 index 000000000..44ce5ecb6 Binary files /dev/null and b/public/editormd/emoji/earth_africa.png differ diff --git a/public/editormd/emoji/earth_americas.png b/public/editormd/emoji/earth_americas.png new file mode 100644 index 000000000..97d717671 Binary files /dev/null and b/public/editormd/emoji/earth_americas.png differ diff --git a/public/editormd/emoji/earth_asia.png b/public/editormd/emoji/earth_asia.png new file mode 100644 index 000000000..95ec357ca Binary files /dev/null and b/public/editormd/emoji/earth_asia.png differ diff --git a/public/editormd/emoji/egg.png b/public/editormd/emoji/egg.png new file mode 100644 index 000000000..c3de6ae4e Binary files /dev/null and b/public/editormd/emoji/egg.png differ diff --git a/public/editormd/emoji/eggplant.png b/public/editormd/emoji/eggplant.png new file mode 100644 index 000000000..66f25fce4 Binary files /dev/null and b/public/editormd/emoji/eggplant.png differ diff --git a/public/editormd/emoji/eight.png b/public/editormd/emoji/eight.png new file mode 100644 index 000000000..aeda5d596 Binary files /dev/null and b/public/editormd/emoji/eight.png differ diff --git a/public/editormd/emoji/eight_pointed_black_star.png b/public/editormd/emoji/eight_pointed_black_star.png new file mode 100644 index 000000000..ce75737b4 Binary files /dev/null and b/public/editormd/emoji/eight_pointed_black_star.png differ diff --git a/public/editormd/emoji/eight_spoked_asterisk.png b/public/editormd/emoji/eight_spoked_asterisk.png new file mode 100644 index 000000000..946a20333 Binary files /dev/null and b/public/editormd/emoji/eight_spoked_asterisk.png differ diff --git a/public/editormd/emoji/electric_plug.png b/public/editormd/emoji/electric_plug.png new file mode 100644 index 000000000..2837bab4f Binary files /dev/null and b/public/editormd/emoji/electric_plug.png differ diff --git a/public/editormd/emoji/elephant.png b/public/editormd/emoji/elephant.png new file mode 100644 index 000000000..5ca04570e Binary files /dev/null and b/public/editormd/emoji/elephant.png differ diff --git a/public/editormd/emoji/email.png b/public/editormd/emoji/email.png new file mode 100644 index 000000000..7a82c28e6 Binary files /dev/null and b/public/editormd/emoji/email.png differ diff --git a/public/editormd/emoji/end.png b/public/editormd/emoji/end.png new file mode 100644 index 000000000..a4ee6c3aa Binary files /dev/null and b/public/editormd/emoji/end.png differ diff --git a/public/editormd/emoji/envelope.png b/public/editormd/emoji/envelope.png new file mode 100644 index 000000000..b00b62a12 Binary files /dev/null and b/public/editormd/emoji/envelope.png differ diff --git a/public/editormd/emoji/es.png b/public/editormd/emoji/es.png new file mode 100644 index 000000000..f3f748559 Binary files /dev/null and b/public/editormd/emoji/es.png differ diff --git a/public/editormd/emoji/euro.png b/public/editormd/emoji/euro.png new file mode 100644 index 000000000..7fc200c33 Binary files /dev/null and b/public/editormd/emoji/euro.png differ diff --git a/public/editormd/emoji/european_castle.png b/public/editormd/emoji/european_castle.png new file mode 100644 index 000000000..8036ab6bf Binary files /dev/null and b/public/editormd/emoji/european_castle.png differ diff --git a/public/editormd/emoji/european_post_office.png b/public/editormd/emoji/european_post_office.png new file mode 100644 index 000000000..0f65b1453 Binary files /dev/null and b/public/editormd/emoji/european_post_office.png differ diff --git a/public/editormd/emoji/evergreen_tree.png b/public/editormd/emoji/evergreen_tree.png new file mode 100644 index 000000000..ae8ad1037 Binary files /dev/null and b/public/editormd/emoji/evergreen_tree.png differ diff --git a/public/editormd/emoji/exclamation.png b/public/editormd/emoji/exclamation.png new file mode 100644 index 000000000..cac59b38d Binary files /dev/null and b/public/editormd/emoji/exclamation.png differ diff --git a/public/editormd/emoji/expressionless.png b/public/editormd/emoji/expressionless.png new file mode 100644 index 000000000..ff445361a Binary files /dev/null and b/public/editormd/emoji/expressionless.png differ diff --git a/public/editormd/emoji/eyeglasses.png b/public/editormd/emoji/eyeglasses.png new file mode 100644 index 000000000..a3cf75a27 Binary files /dev/null and b/public/editormd/emoji/eyeglasses.png differ diff --git a/public/editormd/emoji/eyes.png b/public/editormd/emoji/eyes.png new file mode 100644 index 000000000..11a68a2a8 Binary files /dev/null and b/public/editormd/emoji/eyes.png differ diff --git a/public/editormd/emoji/facepunch.png b/public/editormd/emoji/facepunch.png new file mode 100644 index 000000000..277047b7c Binary files /dev/null and b/public/editormd/emoji/facepunch.png differ diff --git a/public/editormd/emoji/factory.png b/public/editormd/emoji/factory.png new file mode 100644 index 000000000..3b7b58b9d Binary files /dev/null and b/public/editormd/emoji/factory.png differ diff --git a/public/editormd/emoji/fallen_leaf.png b/public/editormd/emoji/fallen_leaf.png new file mode 100644 index 000000000..d49f9c175 Binary files /dev/null and b/public/editormd/emoji/fallen_leaf.png differ diff --git a/public/editormd/emoji/family.png b/public/editormd/emoji/family.png new file mode 100644 index 000000000..c1f343334 Binary files /dev/null and b/public/editormd/emoji/family.png differ diff --git a/public/editormd/emoji/fast_forward.png b/public/editormd/emoji/fast_forward.png new file mode 100644 index 000000000..b23beaf11 Binary files /dev/null and b/public/editormd/emoji/fast_forward.png differ diff --git a/public/editormd/emoji/fax.png b/public/editormd/emoji/fax.png new file mode 100644 index 000000000..62be2c958 Binary files /dev/null and b/public/editormd/emoji/fax.png differ diff --git a/public/editormd/emoji/fearful.png b/public/editormd/emoji/fearful.png new file mode 100644 index 000000000..74131e0e3 Binary files /dev/null and b/public/editormd/emoji/fearful.png differ diff --git a/public/editormd/emoji/feelsgood.png b/public/editormd/emoji/feelsgood.png new file mode 100644 index 000000000..4fe16cf7e Binary files /dev/null and b/public/editormd/emoji/feelsgood.png differ diff --git a/public/editormd/emoji/feet.png b/public/editormd/emoji/feet.png new file mode 100644 index 000000000..1b0147b1d Binary files /dev/null and b/public/editormd/emoji/feet.png differ diff --git a/public/editormd/emoji/ferris_wheel.png b/public/editormd/emoji/ferris_wheel.png new file mode 100644 index 000000000..c958cda64 Binary files /dev/null and b/public/editormd/emoji/ferris_wheel.png differ diff --git a/public/editormd/emoji/file_folder.png b/public/editormd/emoji/file_folder.png new file mode 100644 index 000000000..4d8bebf8a Binary files /dev/null and b/public/editormd/emoji/file_folder.png differ diff --git a/public/editormd/emoji/finnadie.png b/public/editormd/emoji/finnadie.png new file mode 100644 index 000000000..43f88fe8c Binary files /dev/null and b/public/editormd/emoji/finnadie.png differ diff --git a/public/editormd/emoji/fire.png b/public/editormd/emoji/fire.png new file mode 100644 index 000000000..f2a3149bb Binary files /dev/null and b/public/editormd/emoji/fire.png differ diff --git a/public/editormd/emoji/fire_engine.png b/public/editormd/emoji/fire_engine.png new file mode 100644 index 000000000..77b0a3dea Binary files /dev/null and b/public/editormd/emoji/fire_engine.png differ diff --git a/public/editormd/emoji/fireworks.png b/public/editormd/emoji/fireworks.png new file mode 100644 index 000000000..da9971a86 Binary files /dev/null and b/public/editormd/emoji/fireworks.png differ diff --git a/public/editormd/emoji/first_quarter_moon.png b/public/editormd/emoji/first_quarter_moon.png new file mode 100644 index 000000000..f38c23693 Binary files /dev/null and b/public/editormd/emoji/first_quarter_moon.png differ diff --git a/public/editormd/emoji/first_quarter_moon_with_face.png b/public/editormd/emoji/first_quarter_moon_with_face.png new file mode 100644 index 000000000..85ae2ce72 Binary files /dev/null and b/public/editormd/emoji/first_quarter_moon_with_face.png differ diff --git a/public/editormd/emoji/fish.png b/public/editormd/emoji/fish.png new file mode 100644 index 000000000..b88fc9b7f Binary files /dev/null and b/public/editormd/emoji/fish.png differ diff --git a/public/editormd/emoji/fish_cake.png b/public/editormd/emoji/fish_cake.png new file mode 100644 index 000000000..a8f22614d Binary files /dev/null and b/public/editormd/emoji/fish_cake.png differ diff --git a/public/editormd/emoji/fishing_pole_and_fish.png b/public/editormd/emoji/fishing_pole_and_fish.png new file mode 100644 index 000000000..d84609c3b Binary files /dev/null and b/public/editormd/emoji/fishing_pole_and_fish.png differ diff --git a/public/editormd/emoji/fist.png b/public/editormd/emoji/fist.png new file mode 100644 index 000000000..34937fa3c Binary files /dev/null and b/public/editormd/emoji/fist.png differ diff --git a/public/editormd/emoji/five.png b/public/editormd/emoji/five.png new file mode 100644 index 000000000..794321aa2 Binary files /dev/null and b/public/editormd/emoji/five.png differ diff --git a/public/editormd/emoji/flags.png b/public/editormd/emoji/flags.png new file mode 100644 index 000000000..540164e84 Binary files /dev/null and b/public/editormd/emoji/flags.png differ diff --git a/public/editormd/emoji/flashlight.png b/public/editormd/emoji/flashlight.png new file mode 100644 index 000000000..56c79ead3 Binary files /dev/null and b/public/editormd/emoji/flashlight.png differ diff --git a/public/editormd/emoji/floppy_disk.png b/public/editormd/emoji/floppy_disk.png new file mode 100644 index 000000000..3cfd25ce9 Binary files /dev/null and b/public/editormd/emoji/floppy_disk.png differ diff --git a/public/editormd/emoji/flower_playing_cards.png b/public/editormd/emoji/flower_playing_cards.png new file mode 100644 index 000000000..559b57858 Binary files /dev/null and b/public/editormd/emoji/flower_playing_cards.png differ diff --git a/public/editormd/emoji/flushed.png b/public/editormd/emoji/flushed.png new file mode 100644 index 000000000..28cb2e98b Binary files /dev/null and b/public/editormd/emoji/flushed.png differ diff --git a/public/editormd/emoji/foggy.png b/public/editormd/emoji/foggy.png new file mode 100644 index 000000000..5bc3d5a88 Binary files /dev/null and b/public/editormd/emoji/foggy.png differ diff --git a/public/editormd/emoji/football.png b/public/editormd/emoji/football.png new file mode 100644 index 000000000..0e4e168fa Binary files /dev/null and b/public/editormd/emoji/football.png differ diff --git a/public/editormd/emoji/fork_and_knife.png b/public/editormd/emoji/fork_and_knife.png new file mode 100644 index 000000000..8ba4bc653 Binary files /dev/null and b/public/editormd/emoji/fork_and_knife.png differ diff --git a/public/editormd/emoji/fountain.png b/public/editormd/emoji/fountain.png new file mode 100644 index 000000000..34ca0de77 Binary files /dev/null and b/public/editormd/emoji/fountain.png differ diff --git a/public/editormd/emoji/four.png b/public/editormd/emoji/four.png new file mode 100644 index 000000000..b5736be34 Binary files /dev/null and b/public/editormd/emoji/four.png differ diff --git a/public/editormd/emoji/four_leaf_clover.png b/public/editormd/emoji/four_leaf_clover.png new file mode 100644 index 000000000..f2014bea4 Binary files /dev/null and b/public/editormd/emoji/four_leaf_clover.png differ diff --git a/public/editormd/emoji/fr.png b/public/editormd/emoji/fr.png new file mode 100644 index 000000000..806787475 Binary files /dev/null and b/public/editormd/emoji/fr.png differ diff --git a/public/editormd/emoji/free.png b/public/editormd/emoji/free.png new file mode 100644 index 000000000..c886cf249 Binary files /dev/null and b/public/editormd/emoji/free.png differ diff --git a/public/editormd/emoji/fried_shrimp.png b/public/editormd/emoji/fried_shrimp.png new file mode 100644 index 000000000..c8c284bf1 Binary files /dev/null and b/public/editormd/emoji/fried_shrimp.png differ diff --git a/public/editormd/emoji/fries.png b/public/editormd/emoji/fries.png new file mode 100644 index 000000000..cfef66966 Binary files /dev/null and b/public/editormd/emoji/fries.png differ diff --git a/public/editormd/emoji/frog.png b/public/editormd/emoji/frog.png new file mode 100644 index 000000000..cfe11b18f Binary files /dev/null and b/public/editormd/emoji/frog.png differ diff --git a/public/editormd/emoji/frowning.png b/public/editormd/emoji/frowning.png new file mode 100644 index 000000000..b5616bb16 Binary files /dev/null and b/public/editormd/emoji/frowning.png differ diff --git a/public/editormd/emoji/fu.png b/public/editormd/emoji/fu.png new file mode 100644 index 000000000..c35054ecc Binary files /dev/null and b/public/editormd/emoji/fu.png differ diff --git a/public/editormd/emoji/fuelpump.png b/public/editormd/emoji/fuelpump.png new file mode 100644 index 000000000..54c29aeb1 Binary files /dev/null and b/public/editormd/emoji/fuelpump.png differ diff --git a/public/editormd/emoji/full_moon.png b/public/editormd/emoji/full_moon.png new file mode 100644 index 000000000..8ff657a25 Binary files /dev/null and b/public/editormd/emoji/full_moon.png differ diff --git a/public/editormd/emoji/full_moon_with_face.png b/public/editormd/emoji/full_moon_with_face.png new file mode 100644 index 000000000..d42b3f0fb Binary files /dev/null and b/public/editormd/emoji/full_moon_with_face.png differ diff --git a/public/editormd/emoji/game_die.png b/public/editormd/emoji/game_die.png new file mode 100644 index 000000000..cff2bd8b7 Binary files /dev/null and b/public/editormd/emoji/game_die.png differ diff --git a/public/editormd/emoji/gb.png b/public/editormd/emoji/gb.png new file mode 100644 index 000000000..b6ef6c199 Binary files /dev/null and b/public/editormd/emoji/gb.png differ diff --git a/public/editormd/emoji/gem.png b/public/editormd/emoji/gem.png new file mode 100644 index 000000000..5b067bae1 Binary files /dev/null and b/public/editormd/emoji/gem.png differ diff --git a/public/editormd/emoji/gemini.png b/public/editormd/emoji/gemini.png new file mode 100644 index 000000000..d926f6e88 Binary files /dev/null and b/public/editormd/emoji/gemini.png differ diff --git a/public/editormd/emoji/ghost.png b/public/editormd/emoji/ghost.png new file mode 100644 index 000000000..671dd0c9e Binary files /dev/null and b/public/editormd/emoji/ghost.png differ diff --git a/public/editormd/emoji/gift.png b/public/editormd/emoji/gift.png new file mode 100644 index 000000000..552cfdc2b Binary files /dev/null and b/public/editormd/emoji/gift.png differ diff --git a/public/editormd/emoji/gift_heart.png b/public/editormd/emoji/gift_heart.png new file mode 100644 index 000000000..f31c26a3f Binary files /dev/null and b/public/editormd/emoji/gift_heart.png differ diff --git a/public/editormd/emoji/girl.png b/public/editormd/emoji/girl.png new file mode 100644 index 000000000..38ceb6e36 Binary files /dev/null and b/public/editormd/emoji/girl.png differ diff --git a/public/editormd/emoji/globe_with_meridians.png b/public/editormd/emoji/globe_with_meridians.png new file mode 100644 index 000000000..b19864667 Binary files /dev/null and b/public/editormd/emoji/globe_with_meridians.png differ diff --git a/public/editormd/emoji/goat.png b/public/editormd/emoji/goat.png new file mode 100644 index 000000000..4be9cf304 Binary files /dev/null and b/public/editormd/emoji/goat.png differ diff --git a/public/editormd/emoji/goberserk.png b/public/editormd/emoji/goberserk.png new file mode 100644 index 000000000..3742ada00 Binary files /dev/null and b/public/editormd/emoji/goberserk.png differ diff --git a/public/editormd/emoji/godmode.png b/public/editormd/emoji/godmode.png new file mode 100644 index 000000000..884b99651 Binary files /dev/null and b/public/editormd/emoji/godmode.png differ diff --git a/public/editormd/emoji/golf.png b/public/editormd/emoji/golf.png new file mode 100644 index 000000000..cba2116a7 Binary files /dev/null and b/public/editormd/emoji/golf.png differ diff --git a/public/editormd/emoji/grapes.png b/public/editormd/emoji/grapes.png new file mode 100644 index 000000000..0f9f007a1 Binary files /dev/null and b/public/editormd/emoji/grapes.png differ diff --git a/public/editormd/emoji/green_apple.png b/public/editormd/emoji/green_apple.png new file mode 100644 index 000000000..2996b7d2a Binary files /dev/null and b/public/editormd/emoji/green_apple.png differ diff --git a/public/editormd/emoji/green_book.png b/public/editormd/emoji/green_book.png new file mode 100644 index 000000000..6e9257d05 Binary files /dev/null and b/public/editormd/emoji/green_book.png differ diff --git a/public/editormd/emoji/green_heart.png b/public/editormd/emoji/green_heart.png new file mode 100644 index 000000000..2a452d329 Binary files /dev/null and b/public/editormd/emoji/green_heart.png differ diff --git a/public/editormd/emoji/grey_exclamation.png b/public/editormd/emoji/grey_exclamation.png new file mode 100644 index 000000000..971c47be1 Binary files /dev/null and b/public/editormd/emoji/grey_exclamation.png differ diff --git a/public/editormd/emoji/grey_question.png b/public/editormd/emoji/grey_question.png new file mode 100644 index 000000000..fb97ba752 Binary files /dev/null and b/public/editormd/emoji/grey_question.png differ diff --git a/public/editormd/emoji/grimacing.png b/public/editormd/emoji/grimacing.png new file mode 100644 index 000000000..e43af7e43 Binary files /dev/null and b/public/editormd/emoji/grimacing.png differ diff --git a/public/editormd/emoji/grin.png b/public/editormd/emoji/grin.png new file mode 100644 index 000000000..5e5cb8459 Binary files /dev/null and b/public/editormd/emoji/grin.png differ diff --git a/public/editormd/emoji/grinning.png b/public/editormd/emoji/grinning.png new file mode 100644 index 000000000..f8a5531ec Binary files /dev/null and b/public/editormd/emoji/grinning.png differ diff --git a/public/editormd/emoji/guardsman.png b/public/editormd/emoji/guardsman.png new file mode 100644 index 000000000..45fb728e8 Binary files /dev/null and b/public/editormd/emoji/guardsman.png differ diff --git a/public/editormd/emoji/guitar.png b/public/editormd/emoji/guitar.png new file mode 100644 index 000000000..d7d2e40fc Binary files /dev/null and b/public/editormd/emoji/guitar.png differ diff --git a/public/editormd/emoji/gun.png b/public/editormd/emoji/gun.png new file mode 100644 index 000000000..3d0a7dd66 Binary files /dev/null and b/public/editormd/emoji/gun.png differ diff --git a/public/editormd/emoji/haircut.png b/public/editormd/emoji/haircut.png new file mode 100644 index 000000000..152696fc6 Binary files /dev/null and b/public/editormd/emoji/haircut.png differ diff --git a/public/editormd/emoji/hamburger.png b/public/editormd/emoji/hamburger.png new file mode 100644 index 000000000..341dc60c2 Binary files /dev/null and b/public/editormd/emoji/hamburger.png differ diff --git a/public/editormd/emoji/hammer.png b/public/editormd/emoji/hammer.png new file mode 100644 index 000000000..482b1c747 Binary files /dev/null and b/public/editormd/emoji/hammer.png differ diff --git a/public/editormd/emoji/hamster.png b/public/editormd/emoji/hamster.png new file mode 100644 index 000000000..addfd2e6b Binary files /dev/null and b/public/editormd/emoji/hamster.png differ diff --git a/public/editormd/emoji/hand.png b/public/editormd/emoji/hand.png new file mode 100644 index 000000000..a289dca1d Binary files /dev/null and b/public/editormd/emoji/hand.png differ diff --git a/public/editormd/emoji/handbag.png b/public/editormd/emoji/handbag.png new file mode 100644 index 000000000..d7adf04dd Binary files /dev/null and b/public/editormd/emoji/handbag.png differ diff --git a/public/editormd/emoji/hankey.png b/public/editormd/emoji/hankey.png new file mode 100644 index 000000000..73a4dc840 Binary files /dev/null and b/public/editormd/emoji/hankey.png differ diff --git a/public/editormd/emoji/hash.png b/public/editormd/emoji/hash.png new file mode 100644 index 000000000..6765d7d3c Binary files /dev/null and b/public/editormd/emoji/hash.png differ diff --git a/public/editormd/emoji/hatched_chick.png b/public/editormd/emoji/hatched_chick.png new file mode 100644 index 000000000..39c25bc7c Binary files /dev/null and b/public/editormd/emoji/hatched_chick.png differ diff --git a/public/editormd/emoji/hatching_chick.png b/public/editormd/emoji/hatching_chick.png new file mode 100644 index 000000000..3c60526b2 Binary files /dev/null and b/public/editormd/emoji/hatching_chick.png differ diff --git a/public/editormd/emoji/headphones.png b/public/editormd/emoji/headphones.png new file mode 100644 index 000000000..055a2599f Binary files /dev/null and b/public/editormd/emoji/headphones.png differ diff --git a/public/editormd/emoji/hear_no_evil.png b/public/editormd/emoji/hear_no_evil.png new file mode 100644 index 000000000..f97a1f9a0 Binary files /dev/null and b/public/editormd/emoji/hear_no_evil.png differ diff --git a/public/editormd/emoji/heart.png b/public/editormd/emoji/heart.png new file mode 100644 index 000000000..33c6c8c66 Binary files /dev/null and b/public/editormd/emoji/heart.png differ diff --git a/public/editormd/emoji/heart_decoration.png b/public/editormd/emoji/heart_decoration.png new file mode 100644 index 000000000..b8be44db3 Binary files /dev/null and b/public/editormd/emoji/heart_decoration.png differ diff --git a/public/editormd/emoji/heart_eyes.png b/public/editormd/emoji/heart_eyes.png new file mode 100644 index 000000000..3712f383a Binary files /dev/null and b/public/editormd/emoji/heart_eyes.png differ diff --git a/public/editormd/emoji/heart_eyes_cat.png b/public/editormd/emoji/heart_eyes_cat.png new file mode 100644 index 000000000..eeba240e5 Binary files /dev/null and b/public/editormd/emoji/heart_eyes_cat.png differ diff --git a/public/editormd/emoji/heartbeat.png b/public/editormd/emoji/heartbeat.png new file mode 100644 index 000000000..9ebf668f4 Binary files /dev/null and b/public/editormd/emoji/heartbeat.png differ diff --git a/public/editormd/emoji/heartpulse.png b/public/editormd/emoji/heartpulse.png new file mode 100644 index 000000000..256135140 Binary files /dev/null and b/public/editormd/emoji/heartpulse.png differ diff --git a/public/editormd/emoji/hearts.png b/public/editormd/emoji/hearts.png new file mode 100644 index 000000000..85c2dc1bc Binary files /dev/null and b/public/editormd/emoji/hearts.png differ diff --git a/public/editormd/emoji/heavy_check_mark.png b/public/editormd/emoji/heavy_check_mark.png new file mode 100644 index 000000000..d0f010b4a Binary files /dev/null and b/public/editormd/emoji/heavy_check_mark.png differ diff --git a/public/editormd/emoji/heavy_division_sign.png b/public/editormd/emoji/heavy_division_sign.png new file mode 100644 index 000000000..658c6df8f Binary files /dev/null and b/public/editormd/emoji/heavy_division_sign.png differ diff --git a/public/editormd/emoji/heavy_dollar_sign.png b/public/editormd/emoji/heavy_dollar_sign.png new file mode 100644 index 000000000..4f435da7f Binary files /dev/null and b/public/editormd/emoji/heavy_dollar_sign.png differ diff --git a/public/editormd/emoji/heavy_exclamation_mark.png b/public/editormd/emoji/heavy_exclamation_mark.png new file mode 100644 index 000000000..4c560f5e3 Binary files /dev/null and b/public/editormd/emoji/heavy_exclamation_mark.png differ diff --git a/public/editormd/emoji/heavy_minus_sign.png b/public/editormd/emoji/heavy_minus_sign.png new file mode 100644 index 000000000..b666d2103 Binary files /dev/null and b/public/editormd/emoji/heavy_minus_sign.png differ diff --git a/public/editormd/emoji/heavy_multiplication_x.png b/public/editormd/emoji/heavy_multiplication_x.png new file mode 100644 index 000000000..fdea75a47 Binary files /dev/null and b/public/editormd/emoji/heavy_multiplication_x.png differ diff --git a/public/editormd/emoji/heavy_plus_sign.png b/public/editormd/emoji/heavy_plus_sign.png new file mode 100644 index 000000000..16ec5c3fb Binary files /dev/null and b/public/editormd/emoji/heavy_plus_sign.png differ diff --git a/public/editormd/emoji/helicopter.png b/public/editormd/emoji/helicopter.png new file mode 100644 index 000000000..94183cd2a Binary files /dev/null and b/public/editormd/emoji/helicopter.png differ diff --git a/public/editormd/emoji/herb.png b/public/editormd/emoji/herb.png new file mode 100644 index 000000000..de1ff1b73 Binary files /dev/null and b/public/editormd/emoji/herb.png differ diff --git a/public/editormd/emoji/hibiscus.png b/public/editormd/emoji/hibiscus.png new file mode 100644 index 000000000..9365ae216 Binary files /dev/null and b/public/editormd/emoji/hibiscus.png differ diff --git a/public/editormd/emoji/high_brightness.png b/public/editormd/emoji/high_brightness.png new file mode 100644 index 000000000..ba9de7d40 Binary files /dev/null and b/public/editormd/emoji/high_brightness.png differ diff --git a/public/editormd/emoji/high_heel.png b/public/editormd/emoji/high_heel.png new file mode 100644 index 000000000..5d3b0a5bd Binary files /dev/null and b/public/editormd/emoji/high_heel.png differ diff --git a/public/editormd/emoji/hocho.png b/public/editormd/emoji/hocho.png new file mode 100644 index 000000000..3f05193c7 Binary files /dev/null and b/public/editormd/emoji/hocho.png differ diff --git a/public/editormd/emoji/honey_pot.png b/public/editormd/emoji/honey_pot.png new file mode 100644 index 000000000..73278898a Binary files /dev/null and b/public/editormd/emoji/honey_pot.png differ diff --git a/public/editormd/emoji/honeybee.png b/public/editormd/emoji/honeybee.png new file mode 100644 index 000000000..f453bad59 Binary files /dev/null and b/public/editormd/emoji/honeybee.png differ diff --git a/public/editormd/emoji/horse.png b/public/editormd/emoji/horse.png new file mode 100644 index 000000000..78d580ad3 Binary files /dev/null and b/public/editormd/emoji/horse.png differ diff --git a/public/editormd/emoji/horse_racing.png b/public/editormd/emoji/horse_racing.png new file mode 100644 index 000000000..e3bbaec1d Binary files /dev/null and b/public/editormd/emoji/horse_racing.png differ diff --git a/public/editormd/emoji/hospital.png b/public/editormd/emoji/hospital.png new file mode 100644 index 000000000..c05c49377 Binary files /dev/null and b/public/editormd/emoji/hospital.png differ diff --git a/public/editormd/emoji/hotel.png b/public/editormd/emoji/hotel.png new file mode 100644 index 000000000..d29f276a1 Binary files /dev/null and b/public/editormd/emoji/hotel.png differ diff --git a/public/editormd/emoji/hotsprings.png b/public/editormd/emoji/hotsprings.png new file mode 100644 index 000000000..a0bc9d75f Binary files /dev/null and b/public/editormd/emoji/hotsprings.png differ diff --git a/public/editormd/emoji/hourglass.png b/public/editormd/emoji/hourglass.png new file mode 100644 index 000000000..405aab41b Binary files /dev/null and b/public/editormd/emoji/hourglass.png differ diff --git a/public/editormd/emoji/hourglass_flowing_sand.png b/public/editormd/emoji/hourglass_flowing_sand.png new file mode 100644 index 000000000..b68eb6957 Binary files /dev/null and b/public/editormd/emoji/hourglass_flowing_sand.png differ diff --git a/public/editormd/emoji/house.png b/public/editormd/emoji/house.png new file mode 100644 index 000000000..95b9ee094 Binary files /dev/null and b/public/editormd/emoji/house.png differ diff --git a/public/editormd/emoji/house_with_garden.png b/public/editormd/emoji/house_with_garden.png new file mode 100644 index 000000000..3338fb717 Binary files /dev/null and b/public/editormd/emoji/house_with_garden.png differ diff --git a/public/editormd/emoji/hurtrealbad.png b/public/editormd/emoji/hurtrealbad.png new file mode 100644 index 000000000..6cc43377c Binary files /dev/null and b/public/editormd/emoji/hurtrealbad.png differ diff --git a/public/editormd/emoji/hushed.png b/public/editormd/emoji/hushed.png new file mode 100644 index 000000000..abe5908dd Binary files /dev/null and b/public/editormd/emoji/hushed.png differ diff --git a/public/editormd/emoji/ice_cream.png b/public/editormd/emoji/ice_cream.png new file mode 100644 index 000000000..c0f08b9c2 Binary files /dev/null and b/public/editormd/emoji/ice_cream.png differ diff --git a/public/editormd/emoji/icecream.png b/public/editormd/emoji/icecream.png new file mode 100644 index 000000000..871ce0976 Binary files /dev/null and b/public/editormd/emoji/icecream.png differ diff --git a/public/editormd/emoji/id.png b/public/editormd/emoji/id.png new file mode 100644 index 000000000..47437a76d Binary files /dev/null and b/public/editormd/emoji/id.png differ diff --git a/public/editormd/emoji/ideograph_advantage.png b/public/editormd/emoji/ideograph_advantage.png new file mode 100644 index 000000000..3c1334d16 Binary files /dev/null and b/public/editormd/emoji/ideograph_advantage.png differ diff --git a/public/editormd/emoji/imp.png b/public/editormd/emoji/imp.png new file mode 100644 index 000000000..f805b3176 Binary files /dev/null and b/public/editormd/emoji/imp.png differ diff --git a/public/editormd/emoji/inbox_tray.png b/public/editormd/emoji/inbox_tray.png new file mode 100644 index 000000000..6c7c7c936 Binary files /dev/null and b/public/editormd/emoji/inbox_tray.png differ diff --git a/public/editormd/emoji/incoming_envelope.png b/public/editormd/emoji/incoming_envelope.png new file mode 100644 index 000000000..d90b54003 Binary files /dev/null and b/public/editormd/emoji/incoming_envelope.png differ diff --git a/public/editormd/emoji/information_desk_person.png b/public/editormd/emoji/information_desk_person.png new file mode 100644 index 000000000..52c0a50a3 Binary files /dev/null and b/public/editormd/emoji/information_desk_person.png differ diff --git a/public/editormd/emoji/information_source.png b/public/editormd/emoji/information_source.png new file mode 100644 index 000000000..9cb8b09b2 Binary files /dev/null and b/public/editormd/emoji/information_source.png differ diff --git a/public/editormd/emoji/innocent.png b/public/editormd/emoji/innocent.png new file mode 100644 index 000000000..45df61096 Binary files /dev/null and b/public/editormd/emoji/innocent.png differ diff --git a/public/editormd/emoji/interrobang.png b/public/editormd/emoji/interrobang.png new file mode 100644 index 000000000..64304b9f5 Binary files /dev/null and b/public/editormd/emoji/interrobang.png differ diff --git a/public/editormd/emoji/iphone.png b/public/editormd/emoji/iphone.png new file mode 100644 index 000000000..e848631ad Binary files /dev/null and b/public/editormd/emoji/iphone.png differ diff --git a/public/editormd/emoji/it.png b/public/editormd/emoji/it.png new file mode 100644 index 000000000..1b8aab382 Binary files /dev/null and b/public/editormd/emoji/it.png differ diff --git a/public/editormd/emoji/izakaya_lantern.png b/public/editormd/emoji/izakaya_lantern.png new file mode 100644 index 000000000..18730ad55 Binary files /dev/null and b/public/editormd/emoji/izakaya_lantern.png differ diff --git a/public/editormd/emoji/jack_o_lantern.png b/public/editormd/emoji/jack_o_lantern.png new file mode 100644 index 000000000..1f7667ea4 Binary files /dev/null and b/public/editormd/emoji/jack_o_lantern.png differ diff --git a/public/editormd/emoji/japan.png b/public/editormd/emoji/japan.png new file mode 100644 index 000000000..c314fa3dc Binary files /dev/null and b/public/editormd/emoji/japan.png differ diff --git a/public/editormd/emoji/japanese_castle.png b/public/editormd/emoji/japanese_castle.png new file mode 100644 index 000000000..ebd811d5d Binary files /dev/null and b/public/editormd/emoji/japanese_castle.png differ diff --git a/public/editormd/emoji/japanese_goblin.png b/public/editormd/emoji/japanese_goblin.png new file mode 100644 index 000000000..bd21b1875 Binary files /dev/null and b/public/editormd/emoji/japanese_goblin.png differ diff --git a/public/editormd/emoji/japanese_ogre.png b/public/editormd/emoji/japanese_ogre.png new file mode 100644 index 000000000..e9f5471c9 Binary files /dev/null and b/public/editormd/emoji/japanese_ogre.png differ diff --git a/public/editormd/emoji/jeans.png b/public/editormd/emoji/jeans.png new file mode 100644 index 000000000..d721cea54 Binary files /dev/null and b/public/editormd/emoji/jeans.png differ diff --git a/public/editormd/emoji/joy.png b/public/editormd/emoji/joy.png new file mode 100644 index 000000000..51e584fce Binary files /dev/null and b/public/editormd/emoji/joy.png differ diff --git a/public/editormd/emoji/joy_cat.png b/public/editormd/emoji/joy_cat.png new file mode 100644 index 000000000..6c60cb0ef Binary files /dev/null and b/public/editormd/emoji/joy_cat.png differ diff --git a/public/editormd/emoji/jp.png b/public/editormd/emoji/jp.png new file mode 100644 index 000000000..5f480164f Binary files /dev/null and b/public/editormd/emoji/jp.png differ diff --git a/public/editormd/emoji/key.png b/public/editormd/emoji/key.png new file mode 100644 index 000000000..34673213f Binary files /dev/null and b/public/editormd/emoji/key.png differ diff --git a/public/editormd/emoji/keycap_ten.png b/public/editormd/emoji/keycap_ten.png new file mode 100644 index 000000000..32f7e7259 Binary files /dev/null and b/public/editormd/emoji/keycap_ten.png differ diff --git a/public/editormd/emoji/kimono.png b/public/editormd/emoji/kimono.png new file mode 100644 index 000000000..34ffe137d Binary files /dev/null and b/public/editormd/emoji/kimono.png differ diff --git a/public/editormd/emoji/kiss.png b/public/editormd/emoji/kiss.png new file mode 100644 index 000000000..14fd9918d Binary files /dev/null and b/public/editormd/emoji/kiss.png differ diff --git a/public/editormd/emoji/kissing.png b/public/editormd/emoji/kissing.png new file mode 100644 index 000000000..02bcbf12c Binary files /dev/null and b/public/editormd/emoji/kissing.png differ diff --git a/public/editormd/emoji/kissing_cat.png b/public/editormd/emoji/kissing_cat.png new file mode 100644 index 000000000..adc62fbe3 Binary files /dev/null and b/public/editormd/emoji/kissing_cat.png differ diff --git a/public/editormd/emoji/kissing_closed_eyes.png b/public/editormd/emoji/kissing_closed_eyes.png new file mode 100644 index 000000000..a41bac169 Binary files /dev/null and b/public/editormd/emoji/kissing_closed_eyes.png differ diff --git a/public/editormd/emoji/kissing_face.png b/public/editormd/emoji/kissing_face.png new file mode 100644 index 000000000..a41bac169 Binary files /dev/null and b/public/editormd/emoji/kissing_face.png differ diff --git a/public/editormd/emoji/kissing_heart.png b/public/editormd/emoji/kissing_heart.png new file mode 100644 index 000000000..528a0c396 Binary files /dev/null and b/public/editormd/emoji/kissing_heart.png differ diff --git a/public/editormd/emoji/kissing_smiling_eyes.png b/public/editormd/emoji/kissing_smiling_eyes.png new file mode 100644 index 000000000..589c3233b Binary files /dev/null and b/public/editormd/emoji/kissing_smiling_eyes.png differ diff --git a/public/editormd/emoji/koala.png b/public/editormd/emoji/koala.png new file mode 100644 index 000000000..e17bd3cf5 Binary files /dev/null and b/public/editormd/emoji/koala.png differ diff --git a/public/editormd/emoji/koko.png b/public/editormd/emoji/koko.png new file mode 100644 index 000000000..3bef28c9f Binary files /dev/null and b/public/editormd/emoji/koko.png differ diff --git a/public/editormd/emoji/kr.png b/public/editormd/emoji/kr.png new file mode 100644 index 000000000..68ba07285 Binary files /dev/null and b/public/editormd/emoji/kr.png differ diff --git a/public/editormd/emoji/large_blue_circle.png b/public/editormd/emoji/large_blue_circle.png new file mode 100644 index 000000000..a5b4ad4aa Binary files /dev/null and b/public/editormd/emoji/large_blue_circle.png differ diff --git a/public/editormd/emoji/large_blue_diamond.png b/public/editormd/emoji/large_blue_diamond.png new file mode 100644 index 000000000..ee60b2ced Binary files /dev/null and b/public/editormd/emoji/large_blue_diamond.png differ diff --git a/public/editormd/emoji/large_orange_diamond.png b/public/editormd/emoji/large_orange_diamond.png new file mode 100644 index 000000000..88ffae017 Binary files /dev/null and b/public/editormd/emoji/large_orange_diamond.png differ diff --git a/public/editormd/emoji/last_quarter_moon.png b/public/editormd/emoji/last_quarter_moon.png new file mode 100644 index 000000000..6ae30d6c2 Binary files /dev/null and b/public/editormd/emoji/last_quarter_moon.png differ diff --git a/public/editormd/emoji/last_quarter_moon_with_face.png b/public/editormd/emoji/last_quarter_moon_with_face.png new file mode 100644 index 000000000..9ece82dfe Binary files /dev/null and b/public/editormd/emoji/last_quarter_moon_with_face.png differ diff --git a/public/editormd/emoji/laughing.png b/public/editormd/emoji/laughing.png new file mode 100644 index 000000000..87c2f0334 Binary files /dev/null and b/public/editormd/emoji/laughing.png differ diff --git a/public/editormd/emoji/leaves.png b/public/editormd/emoji/leaves.png new file mode 100644 index 000000000..5229e06bd Binary files /dev/null and b/public/editormd/emoji/leaves.png differ diff --git a/public/editormd/emoji/ledger.png b/public/editormd/emoji/ledger.png new file mode 100644 index 000000000..e4f72acea Binary files /dev/null and b/public/editormd/emoji/ledger.png differ diff --git a/public/editormd/emoji/left_luggage.png b/public/editormd/emoji/left_luggage.png new file mode 100644 index 000000000..1c08b464d Binary files /dev/null and b/public/editormd/emoji/left_luggage.png differ diff --git a/public/editormd/emoji/left_right_arrow.png b/public/editormd/emoji/left_right_arrow.png new file mode 100644 index 000000000..b9fd11c51 Binary files /dev/null and b/public/editormd/emoji/left_right_arrow.png differ diff --git a/public/editormd/emoji/leftwards_arrow_with_hook.png b/public/editormd/emoji/leftwards_arrow_with_hook.png new file mode 100644 index 000000000..bc45dfefd Binary files /dev/null and b/public/editormd/emoji/leftwards_arrow_with_hook.png differ diff --git a/public/editormd/emoji/lemon.png b/public/editormd/emoji/lemon.png new file mode 100644 index 000000000..9814dc959 Binary files /dev/null and b/public/editormd/emoji/lemon.png differ diff --git a/public/editormd/emoji/leo.png b/public/editormd/emoji/leo.png new file mode 100644 index 000000000..6ecc3e665 Binary files /dev/null and b/public/editormd/emoji/leo.png differ diff --git a/public/editormd/emoji/leopard.png b/public/editormd/emoji/leopard.png new file mode 100644 index 000000000..3e738d2d3 Binary files /dev/null and b/public/editormd/emoji/leopard.png differ diff --git a/public/editormd/emoji/libra.png b/public/editormd/emoji/libra.png new file mode 100644 index 000000000..e989b9ccd Binary files /dev/null and b/public/editormd/emoji/libra.png differ diff --git a/public/editormd/emoji/light_rail.png b/public/editormd/emoji/light_rail.png new file mode 100644 index 000000000..bcfe801ee Binary files /dev/null and b/public/editormd/emoji/light_rail.png differ diff --git a/public/editormd/emoji/link.png b/public/editormd/emoji/link.png new file mode 100644 index 000000000..0239e48e4 Binary files /dev/null and b/public/editormd/emoji/link.png differ diff --git a/public/editormd/emoji/lips.png b/public/editormd/emoji/lips.png new file mode 100644 index 000000000..27e2ddacd Binary files /dev/null and b/public/editormd/emoji/lips.png differ diff --git a/public/editormd/emoji/lipstick.png b/public/editormd/emoji/lipstick.png new file mode 100644 index 000000000..82f990c56 Binary files /dev/null and b/public/editormd/emoji/lipstick.png differ diff --git a/public/editormd/emoji/lock.png b/public/editormd/emoji/lock.png new file mode 100644 index 000000000..4892b0235 Binary files /dev/null and b/public/editormd/emoji/lock.png differ diff --git a/public/editormd/emoji/lock_with_ink_pen.png b/public/editormd/emoji/lock_with_ink_pen.png new file mode 100644 index 000000000..375e67e82 Binary files /dev/null and b/public/editormd/emoji/lock_with_ink_pen.png differ diff --git a/public/editormd/emoji/lollipop.png b/public/editormd/emoji/lollipop.png new file mode 100644 index 000000000..255976f70 Binary files /dev/null and b/public/editormd/emoji/lollipop.png differ diff --git a/public/editormd/emoji/loop.png b/public/editormd/emoji/loop.png new file mode 100644 index 000000000..ef34df3a4 Binary files /dev/null and b/public/editormd/emoji/loop.png differ diff --git a/public/editormd/emoji/loudspeaker.png b/public/editormd/emoji/loudspeaker.png new file mode 100644 index 000000000..752385e52 Binary files /dev/null and b/public/editormd/emoji/loudspeaker.png differ diff --git a/public/editormd/emoji/love_hotel.png b/public/editormd/emoji/love_hotel.png new file mode 100644 index 000000000..44d7db828 Binary files /dev/null and b/public/editormd/emoji/love_hotel.png differ diff --git a/public/editormd/emoji/love_letter.png b/public/editormd/emoji/love_letter.png new file mode 100644 index 000000000..193c1b5ca Binary files /dev/null and b/public/editormd/emoji/love_letter.png differ diff --git a/public/editormd/emoji/low_brightness.png b/public/editormd/emoji/low_brightness.png new file mode 100644 index 000000000..ea15bde4f Binary files /dev/null and b/public/editormd/emoji/low_brightness.png differ diff --git a/public/editormd/emoji/m.png b/public/editormd/emoji/m.png new file mode 100644 index 000000000..7e3a3bffb Binary files /dev/null and b/public/editormd/emoji/m.png differ diff --git a/public/editormd/emoji/mag.png b/public/editormd/emoji/mag.png new file mode 100644 index 000000000..da2273059 Binary files /dev/null and b/public/editormd/emoji/mag.png differ diff --git a/public/editormd/emoji/mag_right.png b/public/editormd/emoji/mag_right.png new file mode 100644 index 000000000..6e6cf11e6 Binary files /dev/null and b/public/editormd/emoji/mag_right.png differ diff --git a/public/editormd/emoji/mahjong.png b/public/editormd/emoji/mahjong.png new file mode 100644 index 000000000..a4e3aedc2 Binary files /dev/null and b/public/editormd/emoji/mahjong.png differ diff --git a/public/editormd/emoji/mailbox.png b/public/editormd/emoji/mailbox.png new file mode 100644 index 000000000..8351e7076 Binary files /dev/null and b/public/editormd/emoji/mailbox.png differ diff --git a/public/editormd/emoji/mailbox_closed.png b/public/editormd/emoji/mailbox_closed.png new file mode 100644 index 000000000..bfc90904a Binary files /dev/null and b/public/editormd/emoji/mailbox_closed.png differ diff --git a/public/editormd/emoji/mailbox_with_mail.png b/public/editormd/emoji/mailbox_with_mail.png new file mode 100644 index 000000000..dae345943 Binary files /dev/null and b/public/editormd/emoji/mailbox_with_mail.png differ diff --git a/public/editormd/emoji/mailbox_with_no_mail.png b/public/editormd/emoji/mailbox_with_no_mail.png new file mode 100644 index 000000000..59f15c5d7 Binary files /dev/null and b/public/editormd/emoji/mailbox_with_no_mail.png differ diff --git a/public/editormd/emoji/man.png b/public/editormd/emoji/man.png new file mode 100644 index 000000000..4f7f1334d Binary files /dev/null and b/public/editormd/emoji/man.png differ diff --git a/public/editormd/emoji/man_with_gua_pi_mao.png b/public/editormd/emoji/man_with_gua_pi_mao.png new file mode 100644 index 000000000..7aad74b55 Binary files /dev/null and b/public/editormd/emoji/man_with_gua_pi_mao.png differ diff --git a/public/editormd/emoji/man_with_turban.png b/public/editormd/emoji/man_with_turban.png new file mode 100644 index 000000000..43662faf1 Binary files /dev/null and b/public/editormd/emoji/man_with_turban.png differ diff --git a/public/editormd/emoji/mans_shoe.png b/public/editormd/emoji/mans_shoe.png new file mode 100644 index 000000000..ecba9ba7d Binary files /dev/null and b/public/editormd/emoji/mans_shoe.png differ diff --git a/public/editormd/emoji/maple_leaf.png b/public/editormd/emoji/maple_leaf.png new file mode 100644 index 000000000..4e9b47207 Binary files /dev/null and b/public/editormd/emoji/maple_leaf.png differ diff --git a/public/editormd/emoji/mask.png b/public/editormd/emoji/mask.png new file mode 100644 index 000000000..6e625744c Binary files /dev/null and b/public/editormd/emoji/mask.png differ diff --git a/public/editormd/emoji/massage.png b/public/editormd/emoji/massage.png new file mode 100644 index 000000000..dd30d1597 Binary files /dev/null and b/public/editormd/emoji/massage.png differ diff --git a/public/editormd/emoji/meat_on_bone.png b/public/editormd/emoji/meat_on_bone.png new file mode 100644 index 000000000..5b79a660c Binary files /dev/null and b/public/editormd/emoji/meat_on_bone.png differ diff --git a/public/editormd/emoji/mega.png b/public/editormd/emoji/mega.png new file mode 100644 index 000000000..022df2f8d Binary files /dev/null and b/public/editormd/emoji/mega.png differ diff --git a/public/editormd/emoji/melon.png b/public/editormd/emoji/melon.png new file mode 100644 index 000000000..11c13cbbd Binary files /dev/null and b/public/editormd/emoji/melon.png differ diff --git a/public/editormd/emoji/memo.png b/public/editormd/emoji/memo.png new file mode 100644 index 000000000..fc97ddbc9 Binary files /dev/null and b/public/editormd/emoji/memo.png differ diff --git a/public/editormd/emoji/mens.png b/public/editormd/emoji/mens.png new file mode 100644 index 000000000..2f4b0370c Binary files /dev/null and b/public/editormd/emoji/mens.png differ diff --git a/public/editormd/emoji/metal.png b/public/editormd/emoji/metal.png new file mode 100644 index 000000000..94f1fda22 Binary files /dev/null and b/public/editormd/emoji/metal.png differ diff --git a/public/editormd/emoji/metro.png b/public/editormd/emoji/metro.png new file mode 100644 index 000000000..6f82858da Binary files /dev/null and b/public/editormd/emoji/metro.png differ diff --git a/public/editormd/emoji/microphone.png b/public/editormd/emoji/microphone.png new file mode 100644 index 000000000..68c74adad Binary files /dev/null and b/public/editormd/emoji/microphone.png differ diff --git a/public/editormd/emoji/microscope.png b/public/editormd/emoji/microscope.png new file mode 100644 index 000000000..8b7a5e4e6 Binary files /dev/null and b/public/editormd/emoji/microscope.png differ diff --git a/public/editormd/emoji/milky_way.png b/public/editormd/emoji/milky_way.png new file mode 100644 index 000000000..91936f056 Binary files /dev/null and b/public/editormd/emoji/milky_way.png differ diff --git a/public/editormd/emoji/minibus.png b/public/editormd/emoji/minibus.png new file mode 100644 index 000000000..468bc014c Binary files /dev/null and b/public/editormd/emoji/minibus.png differ diff --git a/public/editormd/emoji/minidisc.png b/public/editormd/emoji/minidisc.png new file mode 100644 index 000000000..e19cc5d01 Binary files /dev/null and b/public/editormd/emoji/minidisc.png differ diff --git a/public/editormd/emoji/mobile_phone_off.png b/public/editormd/emoji/mobile_phone_off.png new file mode 100644 index 000000000..46838009c Binary files /dev/null and b/public/editormd/emoji/mobile_phone_off.png differ diff --git a/public/editormd/emoji/money_with_wings.png b/public/editormd/emoji/money_with_wings.png new file mode 100644 index 000000000..581a82449 Binary files /dev/null and b/public/editormd/emoji/money_with_wings.png differ diff --git a/public/editormd/emoji/moneybag.png b/public/editormd/emoji/moneybag.png new file mode 100644 index 000000000..5546c04ba Binary files /dev/null and b/public/editormd/emoji/moneybag.png differ diff --git a/public/editormd/emoji/monkey.png b/public/editormd/emoji/monkey.png new file mode 100644 index 000000000..640703597 Binary files /dev/null and b/public/editormd/emoji/monkey.png differ diff --git a/public/editormd/emoji/monkey_face.png b/public/editormd/emoji/monkey_face.png new file mode 100644 index 000000000..6964cf4d5 Binary files /dev/null and b/public/editormd/emoji/monkey_face.png differ diff --git a/public/editormd/emoji/monorail.png b/public/editormd/emoji/monorail.png new file mode 100644 index 000000000..913d30024 Binary files /dev/null and b/public/editormd/emoji/monorail.png differ diff --git a/public/editormd/emoji/mortar_board.png b/public/editormd/emoji/mortar_board.png new file mode 100644 index 000000000..84513f6ba Binary files /dev/null and b/public/editormd/emoji/mortar_board.png differ diff --git a/public/editormd/emoji/mount_fuji.png b/public/editormd/emoji/mount_fuji.png new file mode 100644 index 000000000..f71274d96 Binary files /dev/null and b/public/editormd/emoji/mount_fuji.png differ diff --git a/public/editormd/emoji/mountain_bicyclist.png b/public/editormd/emoji/mountain_bicyclist.png new file mode 100644 index 000000000..2d9b232fc Binary files /dev/null and b/public/editormd/emoji/mountain_bicyclist.png differ diff --git a/public/editormd/emoji/mountain_cableway.png b/public/editormd/emoji/mountain_cableway.png new file mode 100644 index 000000000..09ade89f3 Binary files /dev/null and b/public/editormd/emoji/mountain_cableway.png differ diff --git a/public/editormd/emoji/mountain_railway.png b/public/editormd/emoji/mountain_railway.png new file mode 100644 index 000000000..60bcb03f9 Binary files /dev/null and b/public/editormd/emoji/mountain_railway.png differ diff --git a/public/editormd/emoji/mouse.png b/public/editormd/emoji/mouse.png new file mode 100644 index 000000000..0d9b11459 Binary files /dev/null and b/public/editormd/emoji/mouse.png differ diff --git a/public/editormd/emoji/mouse2.png b/public/editormd/emoji/mouse2.png new file mode 100644 index 000000000..a3d168907 Binary files /dev/null and b/public/editormd/emoji/mouse2.png differ diff --git a/public/editormd/emoji/movie_camera.png b/public/editormd/emoji/movie_camera.png new file mode 100644 index 000000000..f3ef06312 Binary files /dev/null and b/public/editormd/emoji/movie_camera.png differ diff --git a/public/editormd/emoji/moyai.png b/public/editormd/emoji/moyai.png new file mode 100644 index 000000000..61a1a9c21 Binary files /dev/null and b/public/editormd/emoji/moyai.png differ diff --git a/public/editormd/emoji/muscle.png b/public/editormd/emoji/muscle.png new file mode 100644 index 000000000..8e4dd9c8a Binary files /dev/null and b/public/editormd/emoji/muscle.png differ diff --git a/public/editormd/emoji/mushroom.png b/public/editormd/emoji/mushroom.png new file mode 100644 index 000000000..5eeed8e79 Binary files /dev/null and b/public/editormd/emoji/mushroom.png differ diff --git a/public/editormd/emoji/musical_keyboard.png b/public/editormd/emoji/musical_keyboard.png new file mode 100644 index 000000000..b3360b18c Binary files /dev/null and b/public/editormd/emoji/musical_keyboard.png differ diff --git a/public/editormd/emoji/musical_note.png b/public/editormd/emoji/musical_note.png new file mode 100644 index 000000000..3a5b11db3 Binary files /dev/null and b/public/editormd/emoji/musical_note.png differ diff --git a/public/editormd/emoji/musical_score.png b/public/editormd/emoji/musical_score.png new file mode 100644 index 000000000..92efedf34 Binary files /dev/null and b/public/editormd/emoji/musical_score.png differ diff --git a/public/editormd/emoji/mute.png b/public/editormd/emoji/mute.png new file mode 100644 index 000000000..4cf67c367 Binary files /dev/null and b/public/editormd/emoji/mute.png differ diff --git a/public/editormd/emoji/nail_care.png b/public/editormd/emoji/nail_care.png new file mode 100644 index 000000000..50975aa82 Binary files /dev/null and b/public/editormd/emoji/nail_care.png differ diff --git a/public/editormd/emoji/name_badge.png b/public/editormd/emoji/name_badge.png new file mode 100644 index 000000000..2b712dcd5 Binary files /dev/null and b/public/editormd/emoji/name_badge.png differ diff --git a/public/editormd/emoji/neckbeard.png b/public/editormd/emoji/neckbeard.png new file mode 100644 index 000000000..cc9e5722d Binary files /dev/null and b/public/editormd/emoji/neckbeard.png differ diff --git a/public/editormd/emoji/necktie.png b/public/editormd/emoji/necktie.png new file mode 100644 index 000000000..80461c66f Binary files /dev/null and b/public/editormd/emoji/necktie.png differ diff --git a/public/editormd/emoji/negative_squared_cross_mark.png b/public/editormd/emoji/negative_squared_cross_mark.png new file mode 100644 index 000000000..b47a0cece Binary files /dev/null and b/public/editormd/emoji/negative_squared_cross_mark.png differ diff --git a/public/editormd/emoji/neutral_face.png b/public/editormd/emoji/neutral_face.png new file mode 100644 index 000000000..eafcdc674 Binary files /dev/null and b/public/editormd/emoji/neutral_face.png differ diff --git a/public/editormd/emoji/new.png b/public/editormd/emoji/new.png new file mode 100644 index 000000000..28d1570e0 Binary files /dev/null and b/public/editormd/emoji/new.png differ diff --git a/public/editormd/emoji/new_moon.png b/public/editormd/emoji/new_moon.png new file mode 100644 index 000000000..72492cb90 Binary files /dev/null and b/public/editormd/emoji/new_moon.png differ diff --git a/public/editormd/emoji/new_moon_with_face.png b/public/editormd/emoji/new_moon_with_face.png new file mode 100644 index 000000000..21a696eb9 Binary files /dev/null and b/public/editormd/emoji/new_moon_with_face.png differ diff --git a/public/editormd/emoji/newspaper.png b/public/editormd/emoji/newspaper.png new file mode 100644 index 000000000..b9b374a72 Binary files /dev/null and b/public/editormd/emoji/newspaper.png differ diff --git a/public/editormd/emoji/ng.png b/public/editormd/emoji/ng.png new file mode 100644 index 000000000..2ca180ae3 Binary files /dev/null and b/public/editormd/emoji/ng.png differ diff --git a/public/editormd/emoji/nine.png b/public/editormd/emoji/nine.png new file mode 100644 index 000000000..32d7715bb Binary files /dev/null and b/public/editormd/emoji/nine.png differ diff --git a/public/editormd/emoji/no_bell.png b/public/editormd/emoji/no_bell.png new file mode 100644 index 000000000..613b81cd2 Binary files /dev/null and b/public/editormd/emoji/no_bell.png differ diff --git a/public/editormd/emoji/no_bicycles.png b/public/editormd/emoji/no_bicycles.png new file mode 100644 index 000000000..4b2621664 Binary files /dev/null and b/public/editormd/emoji/no_bicycles.png differ diff --git a/public/editormd/emoji/no_entry.png b/public/editormd/emoji/no_entry.png new file mode 100644 index 000000000..7f4f92f9f Binary files /dev/null and b/public/editormd/emoji/no_entry.png differ diff --git a/public/editormd/emoji/no_entry_sign.png b/public/editormd/emoji/no_entry_sign.png new file mode 100644 index 000000000..b3231f66d Binary files /dev/null and b/public/editormd/emoji/no_entry_sign.png differ diff --git a/public/editormd/emoji/no_good.png b/public/editormd/emoji/no_good.png new file mode 100644 index 000000000..d459a35bc Binary files /dev/null and b/public/editormd/emoji/no_good.png differ diff --git a/public/editormd/emoji/no_mobile_phones.png b/public/editormd/emoji/no_mobile_phones.png new file mode 100644 index 000000000..41df57cf8 Binary files /dev/null and b/public/editormd/emoji/no_mobile_phones.png differ diff --git a/public/editormd/emoji/no_mouth.png b/public/editormd/emoji/no_mouth.png new file mode 100644 index 000000000..272aad36f Binary files /dev/null and b/public/editormd/emoji/no_mouth.png differ diff --git a/public/editormd/emoji/no_pedestrians.png b/public/editormd/emoji/no_pedestrians.png new file mode 100644 index 000000000..53ee0f927 Binary files /dev/null and b/public/editormd/emoji/no_pedestrians.png differ diff --git a/public/editormd/emoji/no_smoking.png b/public/editormd/emoji/no_smoking.png new file mode 100644 index 000000000..8696a2691 Binary files /dev/null and b/public/editormd/emoji/no_smoking.png differ diff --git a/public/editormd/emoji/non-potable_water.png b/public/editormd/emoji/non-potable_water.png new file mode 100644 index 000000000..1b29d35b9 Binary files /dev/null and b/public/editormd/emoji/non-potable_water.png differ diff --git a/public/editormd/emoji/nose.png b/public/editormd/emoji/nose.png new file mode 100644 index 000000000..169a4b426 Binary files /dev/null and b/public/editormd/emoji/nose.png differ diff --git a/public/editormd/emoji/notebook.png b/public/editormd/emoji/notebook.png new file mode 100644 index 000000000..5f0a5f6a2 Binary files /dev/null and b/public/editormd/emoji/notebook.png differ diff --git a/public/editormd/emoji/notebook_with_decorative_cover.png b/public/editormd/emoji/notebook_with_decorative_cover.png new file mode 100644 index 000000000..95891940e Binary files /dev/null and b/public/editormd/emoji/notebook_with_decorative_cover.png differ diff --git a/public/editormd/emoji/notes.png b/public/editormd/emoji/notes.png new file mode 100644 index 000000000..f94a083af Binary files /dev/null and b/public/editormd/emoji/notes.png differ diff --git a/public/editormd/emoji/nut_and_bolt.png b/public/editormd/emoji/nut_and_bolt.png new file mode 100644 index 000000000..bddfa72a7 Binary files /dev/null and b/public/editormd/emoji/nut_and_bolt.png differ diff --git a/public/editormd/emoji/o.png b/public/editormd/emoji/o.png new file mode 100644 index 000000000..1ff846c19 Binary files /dev/null and b/public/editormd/emoji/o.png differ diff --git a/public/editormd/emoji/o2.png b/public/editormd/emoji/o2.png new file mode 100644 index 000000000..d85f9fb98 Binary files /dev/null and b/public/editormd/emoji/o2.png differ diff --git a/public/editormd/emoji/ocean.png b/public/editormd/emoji/ocean.png new file mode 100644 index 000000000..f8d520cd4 Binary files /dev/null and b/public/editormd/emoji/ocean.png differ diff --git a/public/editormd/emoji/octocat.png b/public/editormd/emoji/octocat.png new file mode 100644 index 000000000..0472bf85d Binary files /dev/null and b/public/editormd/emoji/octocat.png differ diff --git a/public/editormd/emoji/octopus.png b/public/editormd/emoji/octopus.png new file mode 100644 index 000000000..52ce64b46 Binary files /dev/null and b/public/editormd/emoji/octopus.png differ diff --git a/public/editormd/emoji/oden.png b/public/editormd/emoji/oden.png new file mode 100644 index 000000000..73add1c73 Binary files /dev/null and b/public/editormd/emoji/oden.png differ diff --git a/public/editormd/emoji/office.png b/public/editormd/emoji/office.png new file mode 100644 index 000000000..53c3ef8d1 Binary files /dev/null and b/public/editormd/emoji/office.png differ diff --git a/public/editormd/emoji/ok.png b/public/editormd/emoji/ok.png new file mode 100644 index 000000000..570f1c5bc Binary files /dev/null and b/public/editormd/emoji/ok.png differ diff --git a/public/editormd/emoji/ok_hand.png b/public/editormd/emoji/ok_hand.png new file mode 100644 index 000000000..80c5aebb6 Binary files /dev/null and b/public/editormd/emoji/ok_hand.png differ diff --git a/public/editormd/emoji/ok_woman.png b/public/editormd/emoji/ok_woman.png new file mode 100644 index 000000000..e8b98194e Binary files /dev/null and b/public/editormd/emoji/ok_woman.png differ diff --git a/public/editormd/emoji/older_man.png b/public/editormd/emoji/older_man.png new file mode 100644 index 000000000..fc5d82cb8 Binary files /dev/null and b/public/editormd/emoji/older_man.png differ diff --git a/public/editormd/emoji/older_woman.png b/public/editormd/emoji/older_woman.png new file mode 100644 index 000000000..f839565f4 Binary files /dev/null and b/public/editormd/emoji/older_woman.png differ diff --git a/public/editormd/emoji/on.png b/public/editormd/emoji/on.png new file mode 100644 index 000000000..a4a66a46a Binary files /dev/null and b/public/editormd/emoji/on.png differ diff --git a/public/editormd/emoji/oncoming_automobile.png b/public/editormd/emoji/oncoming_automobile.png new file mode 100644 index 000000000..cb46de22c Binary files /dev/null and b/public/editormd/emoji/oncoming_automobile.png differ diff --git a/public/editormd/emoji/oncoming_bus.png b/public/editormd/emoji/oncoming_bus.png new file mode 100644 index 000000000..ecf05bb8f Binary files /dev/null and b/public/editormd/emoji/oncoming_bus.png differ diff --git a/public/editormd/emoji/oncoming_police_car.png b/public/editormd/emoji/oncoming_police_car.png new file mode 100644 index 000000000..af20e7eff Binary files /dev/null and b/public/editormd/emoji/oncoming_police_car.png differ diff --git a/public/editormd/emoji/oncoming_taxi.png b/public/editormd/emoji/oncoming_taxi.png new file mode 100644 index 000000000..f78cf3103 Binary files /dev/null and b/public/editormd/emoji/oncoming_taxi.png differ diff --git a/public/editormd/emoji/one.png b/public/editormd/emoji/one.png new file mode 100644 index 000000000..2d1f9f8c4 Binary files /dev/null and b/public/editormd/emoji/one.png differ diff --git a/public/editormd/emoji/open_file_folder.png b/public/editormd/emoji/open_file_folder.png new file mode 100644 index 000000000..2bbbbf5e7 Binary files /dev/null and b/public/editormd/emoji/open_file_folder.png differ diff --git a/public/editormd/emoji/open_hands.png b/public/editormd/emoji/open_hands.png new file mode 100644 index 000000000..34f7e06b8 Binary files /dev/null and b/public/editormd/emoji/open_hands.png differ diff --git a/public/editormd/emoji/open_mouth.png b/public/editormd/emoji/open_mouth.png new file mode 100644 index 000000000..0f78380eb Binary files /dev/null and b/public/editormd/emoji/open_mouth.png differ diff --git a/public/editormd/emoji/ophiuchus.png b/public/editormd/emoji/ophiuchus.png new file mode 100644 index 000000000..4eef715bc Binary files /dev/null and b/public/editormd/emoji/ophiuchus.png differ diff --git a/public/editormd/emoji/orange_book.png b/public/editormd/emoji/orange_book.png new file mode 100644 index 000000000..dba6bfdc0 Binary files /dev/null and b/public/editormd/emoji/orange_book.png differ diff --git a/public/editormd/emoji/outbox_tray.png b/public/editormd/emoji/outbox_tray.png new file mode 100644 index 000000000..adda58909 Binary files /dev/null and b/public/editormd/emoji/outbox_tray.png differ diff --git a/public/editormd/emoji/ox.png b/public/editormd/emoji/ox.png new file mode 100644 index 000000000..8d9819462 Binary files /dev/null and b/public/editormd/emoji/ox.png differ diff --git a/public/editormd/emoji/package.png b/public/editormd/emoji/package.png new file mode 100644 index 000000000..bcf6780ed Binary files /dev/null and b/public/editormd/emoji/package.png differ diff --git a/public/editormd/emoji/page_facing_up.png b/public/editormd/emoji/page_facing_up.png new file mode 100644 index 000000000..a4f9c9c56 Binary files /dev/null and b/public/editormd/emoji/page_facing_up.png differ diff --git a/public/editormd/emoji/page_with_curl.png b/public/editormd/emoji/page_with_curl.png new file mode 100644 index 000000000..37cb4de50 Binary files /dev/null and b/public/editormd/emoji/page_with_curl.png differ diff --git a/public/editormd/emoji/pager.png b/public/editormd/emoji/pager.png new file mode 100644 index 000000000..2a569a20b Binary files /dev/null and b/public/editormd/emoji/pager.png differ diff --git a/public/editormd/emoji/palm_tree.png b/public/editormd/emoji/palm_tree.png new file mode 100644 index 000000000..cc422e0b1 Binary files /dev/null and b/public/editormd/emoji/palm_tree.png differ diff --git a/public/editormd/emoji/panda_face.png b/public/editormd/emoji/panda_face.png new file mode 100644 index 000000000..a794fb17f Binary files /dev/null and b/public/editormd/emoji/panda_face.png differ diff --git a/public/editormd/emoji/paperclip.png b/public/editormd/emoji/paperclip.png new file mode 100644 index 000000000..677669a83 Binary files /dev/null and b/public/editormd/emoji/paperclip.png differ diff --git a/public/editormd/emoji/parking.png b/public/editormd/emoji/parking.png new file mode 100644 index 000000000..c24af81cc Binary files /dev/null and b/public/editormd/emoji/parking.png differ diff --git a/public/editormd/emoji/part_alternation_mark.png b/public/editormd/emoji/part_alternation_mark.png new file mode 100644 index 000000000..1e5855f8d Binary files /dev/null and b/public/editormd/emoji/part_alternation_mark.png differ diff --git a/public/editormd/emoji/partly_sunny.png b/public/editormd/emoji/partly_sunny.png new file mode 100644 index 000000000..b3f5bcfdd Binary files /dev/null and b/public/editormd/emoji/partly_sunny.png differ diff --git a/public/editormd/emoji/passport_control.png b/public/editormd/emoji/passport_control.png new file mode 100644 index 000000000..675b76d37 Binary files /dev/null and b/public/editormd/emoji/passport_control.png differ diff --git a/public/editormd/emoji/paw_prints.png b/public/editormd/emoji/paw_prints.png new file mode 100644 index 000000000..21e6a238b Binary files /dev/null and b/public/editormd/emoji/paw_prints.png differ diff --git a/public/editormd/emoji/peach.png b/public/editormd/emoji/peach.png new file mode 100644 index 000000000..865d5fe55 Binary files /dev/null and b/public/editormd/emoji/peach.png differ diff --git a/public/editormd/emoji/pear.png b/public/editormd/emoji/pear.png new file mode 100644 index 000000000..271b7f1bf Binary files /dev/null and b/public/editormd/emoji/pear.png differ diff --git a/public/editormd/emoji/pencil.png b/public/editormd/emoji/pencil.png new file mode 100644 index 000000000..fc97ddbc9 Binary files /dev/null and b/public/editormd/emoji/pencil.png differ diff --git a/public/editormd/emoji/pencil2.png b/public/editormd/emoji/pencil2.png new file mode 100644 index 000000000..64c2d9b79 Binary files /dev/null and b/public/editormd/emoji/pencil2.png differ diff --git a/public/editormd/emoji/penguin.png b/public/editormd/emoji/penguin.png new file mode 100644 index 000000000..847fe005a Binary files /dev/null and b/public/editormd/emoji/penguin.png differ diff --git a/public/editormd/emoji/pensive.png b/public/editormd/emoji/pensive.png new file mode 100644 index 000000000..3c7fd124f Binary files /dev/null and b/public/editormd/emoji/pensive.png differ diff --git a/public/editormd/emoji/performing_arts.png b/public/editormd/emoji/performing_arts.png new file mode 100644 index 000000000..899fbe5a7 Binary files /dev/null and b/public/editormd/emoji/performing_arts.png differ diff --git a/public/editormd/emoji/persevere.png b/public/editormd/emoji/persevere.png new file mode 100644 index 000000000..5338c77ab Binary files /dev/null and b/public/editormd/emoji/persevere.png differ diff --git a/public/editormd/emoji/person_frowning.png b/public/editormd/emoji/person_frowning.png new file mode 100644 index 000000000..6f34d5e15 Binary files /dev/null and b/public/editormd/emoji/person_frowning.png differ diff --git a/public/editormd/emoji/person_with_blond_hair.png b/public/editormd/emoji/person_with_blond_hair.png new file mode 100644 index 000000000..9b5e7f6a0 Binary files /dev/null and b/public/editormd/emoji/person_with_blond_hair.png differ diff --git a/public/editormd/emoji/person_with_pouting_face.png b/public/editormd/emoji/person_with_pouting_face.png new file mode 100644 index 000000000..c4a95c3b2 Binary files /dev/null and b/public/editormd/emoji/person_with_pouting_face.png differ diff --git a/public/editormd/emoji/phone.png b/public/editormd/emoji/phone.png new file mode 100644 index 000000000..87d2559b5 Binary files /dev/null and b/public/editormd/emoji/phone.png differ diff --git a/public/editormd/emoji/pig.png b/public/editormd/emoji/pig.png new file mode 100644 index 000000000..f7f273c73 Binary files /dev/null and b/public/editormd/emoji/pig.png differ diff --git a/public/editormd/emoji/pig2.png b/public/editormd/emoji/pig2.png new file mode 100644 index 000000000..44fe57f16 Binary files /dev/null and b/public/editormd/emoji/pig2.png differ diff --git a/public/editormd/emoji/pig_nose.png b/public/editormd/emoji/pig_nose.png new file mode 100644 index 000000000..1214dab17 Binary files /dev/null and b/public/editormd/emoji/pig_nose.png differ diff --git a/public/editormd/emoji/pill.png b/public/editormd/emoji/pill.png new file mode 100644 index 000000000..cd84a78ff Binary files /dev/null and b/public/editormd/emoji/pill.png differ diff --git a/public/editormd/emoji/pineapple.png b/public/editormd/emoji/pineapple.png new file mode 100644 index 000000000..d6f8e2876 Binary files /dev/null and b/public/editormd/emoji/pineapple.png differ diff --git a/public/editormd/emoji/pisces.png b/public/editormd/emoji/pisces.png new file mode 100644 index 000000000..f94e1fb5f Binary files /dev/null and b/public/editormd/emoji/pisces.png differ diff --git a/public/editormd/emoji/pizza.png b/public/editormd/emoji/pizza.png new file mode 100644 index 000000000..460367d02 Binary files /dev/null and b/public/editormd/emoji/pizza.png differ diff --git a/public/editormd/emoji/plus1.png b/public/editormd/emoji/plus1.png new file mode 100644 index 000000000..ec7af7f6c Binary files /dev/null and b/public/editormd/emoji/plus1.png differ diff --git a/public/editormd/emoji/point_down.png b/public/editormd/emoji/point_down.png new file mode 100644 index 000000000..658c6d918 Binary files /dev/null and b/public/editormd/emoji/point_down.png differ diff --git a/public/editormd/emoji/point_left.png b/public/editormd/emoji/point_left.png new file mode 100644 index 000000000..6322bfbf9 Binary files /dev/null and b/public/editormd/emoji/point_left.png differ diff --git a/public/editormd/emoji/point_right.png b/public/editormd/emoji/point_right.png new file mode 100644 index 000000000..4e07a0069 Binary files /dev/null and b/public/editormd/emoji/point_right.png differ diff --git a/public/editormd/emoji/point_up.png b/public/editormd/emoji/point_up.png new file mode 100644 index 000000000..01896e214 Binary files /dev/null and b/public/editormd/emoji/point_up.png differ diff --git a/public/editormd/emoji/point_up_2.png b/public/editormd/emoji/point_up_2.png new file mode 100644 index 000000000..1cfe73672 Binary files /dev/null and b/public/editormd/emoji/point_up_2.png differ diff --git a/public/editormd/emoji/police_car.png b/public/editormd/emoji/police_car.png new file mode 100644 index 000000000..b8f17275e Binary files /dev/null and b/public/editormd/emoji/police_car.png differ diff --git a/public/editormd/emoji/poodle.png b/public/editormd/emoji/poodle.png new file mode 100644 index 000000000..adac80bd9 Binary files /dev/null and b/public/editormd/emoji/poodle.png differ diff --git a/public/editormd/emoji/poop.png b/public/editormd/emoji/poop.png new file mode 100644 index 000000000..73a4dc840 Binary files /dev/null and b/public/editormd/emoji/poop.png differ diff --git a/public/editormd/emoji/post_office.png b/public/editormd/emoji/post_office.png new file mode 100644 index 000000000..43b59e30e Binary files /dev/null and b/public/editormd/emoji/post_office.png differ diff --git a/public/editormd/emoji/postal_horn.png b/public/editormd/emoji/postal_horn.png new file mode 100644 index 000000000..13a151418 Binary files /dev/null and b/public/editormd/emoji/postal_horn.png differ diff --git a/public/editormd/emoji/postbox.png b/public/editormd/emoji/postbox.png new file mode 100644 index 000000000..ce04b7008 Binary files /dev/null and b/public/editormd/emoji/postbox.png differ diff --git a/public/editormd/emoji/potable_water.png b/public/editormd/emoji/potable_water.png new file mode 100644 index 000000000..e9fd56079 Binary files /dev/null and b/public/editormd/emoji/potable_water.png differ diff --git a/public/editormd/emoji/pouch.png b/public/editormd/emoji/pouch.png new file mode 100644 index 000000000..dc35ae8e5 Binary files /dev/null and b/public/editormd/emoji/pouch.png differ diff --git a/public/editormd/emoji/poultry_leg.png b/public/editormd/emoji/poultry_leg.png new file mode 100644 index 000000000..43ad85965 Binary files /dev/null and b/public/editormd/emoji/poultry_leg.png differ diff --git a/public/editormd/emoji/pound.png b/public/editormd/emoji/pound.png new file mode 100644 index 000000000..38065c65d Binary files /dev/null and b/public/editormd/emoji/pound.png differ diff --git a/public/editormd/emoji/pouting_cat.png b/public/editormd/emoji/pouting_cat.png new file mode 100644 index 000000000..4325fd48d Binary files /dev/null and b/public/editormd/emoji/pouting_cat.png differ diff --git a/public/editormd/emoji/pray.png b/public/editormd/emoji/pray.png new file mode 100644 index 000000000..f86c992d5 Binary files /dev/null and b/public/editormd/emoji/pray.png differ diff --git a/public/editormd/emoji/princess.png b/public/editormd/emoji/princess.png new file mode 100644 index 000000000..1ebb2ce9b Binary files /dev/null and b/public/editormd/emoji/princess.png differ diff --git a/public/editormd/emoji/punch.png b/public/editormd/emoji/punch.png new file mode 100644 index 000000000..277047b7c Binary files /dev/null and b/public/editormd/emoji/punch.png differ diff --git a/public/editormd/emoji/purple_heart.png b/public/editormd/emoji/purple_heart.png new file mode 100644 index 000000000..f5197cd37 Binary files /dev/null and b/public/editormd/emoji/purple_heart.png differ diff --git a/public/editormd/emoji/purse.png b/public/editormd/emoji/purse.png new file mode 100644 index 000000000..8f06a2b93 Binary files /dev/null and b/public/editormd/emoji/purse.png differ diff --git a/public/editormd/emoji/pushpin.png b/public/editormd/emoji/pushpin.png new file mode 100644 index 000000000..540c4ecb8 Binary files /dev/null and b/public/editormd/emoji/pushpin.png differ diff --git a/public/editormd/emoji/put_litter_in_its_place.png b/public/editormd/emoji/put_litter_in_its_place.png new file mode 100644 index 000000000..c2e350c2d Binary files /dev/null and b/public/editormd/emoji/put_litter_in_its_place.png differ diff --git a/public/editormd/emoji/question.png b/public/editormd/emoji/question.png new file mode 100644 index 000000000..38cedf560 Binary files /dev/null and b/public/editormd/emoji/question.png differ diff --git a/public/editormd/emoji/rabbit.png b/public/editormd/emoji/rabbit.png new file mode 100644 index 000000000..5cb3ef6f0 Binary files /dev/null and b/public/editormd/emoji/rabbit.png differ diff --git a/public/editormd/emoji/rabbit2.png b/public/editormd/emoji/rabbit2.png new file mode 100644 index 000000000..a9fd24dc1 Binary files /dev/null and b/public/editormd/emoji/rabbit2.png differ diff --git a/public/editormd/emoji/racehorse.png b/public/editormd/emoji/racehorse.png new file mode 100644 index 000000000..dbe9fb808 Binary files /dev/null and b/public/editormd/emoji/racehorse.png differ diff --git a/public/editormd/emoji/radio.png b/public/editormd/emoji/radio.png new file mode 100644 index 000000000..ea589efe3 Binary files /dev/null and b/public/editormd/emoji/radio.png differ diff --git a/public/editormd/emoji/radio_button.png b/public/editormd/emoji/radio_button.png new file mode 100644 index 000000000..63755eec2 Binary files /dev/null and b/public/editormd/emoji/radio_button.png differ diff --git a/public/editormd/emoji/rage.png b/public/editormd/emoji/rage.png new file mode 100644 index 000000000..9ca2b8cc2 Binary files /dev/null and b/public/editormd/emoji/rage.png differ diff --git a/public/editormd/emoji/rage1.png b/public/editormd/emoji/rage1.png new file mode 100644 index 000000000..e23dd5b24 Binary files /dev/null and b/public/editormd/emoji/rage1.png differ diff --git a/public/editormd/emoji/rage2.png b/public/editormd/emoji/rage2.png new file mode 100644 index 000000000..1348b925c Binary files /dev/null and b/public/editormd/emoji/rage2.png differ diff --git a/public/editormd/emoji/rage3.png b/public/editormd/emoji/rage3.png new file mode 100644 index 000000000..34a931aa4 Binary files /dev/null and b/public/editormd/emoji/rage3.png differ diff --git a/public/editormd/emoji/rage4.png b/public/editormd/emoji/rage4.png new file mode 100644 index 000000000..2e5b80eff Binary files /dev/null and b/public/editormd/emoji/rage4.png differ diff --git a/public/editormd/emoji/railway_car.png b/public/editormd/emoji/railway_car.png new file mode 100644 index 000000000..1094528c5 Binary files /dev/null and b/public/editormd/emoji/railway_car.png differ diff --git a/public/editormd/emoji/rainbow.png b/public/editormd/emoji/rainbow.png new file mode 100644 index 000000000..82bb2f9ae Binary files /dev/null and b/public/editormd/emoji/rainbow.png differ diff --git a/public/editormd/emoji/raised_hand.png b/public/editormd/emoji/raised_hand.png new file mode 100644 index 000000000..a289dca1d Binary files /dev/null and b/public/editormd/emoji/raised_hand.png differ diff --git a/public/editormd/emoji/raised_hands.png b/public/editormd/emoji/raised_hands.png new file mode 100644 index 000000000..e03142bdc Binary files /dev/null and b/public/editormd/emoji/raised_hands.png differ diff --git a/public/editormd/emoji/raising_hand.png b/public/editormd/emoji/raising_hand.png new file mode 100644 index 000000000..e1741a40e Binary files /dev/null and b/public/editormd/emoji/raising_hand.png differ diff --git a/public/editormd/emoji/ram.png b/public/editormd/emoji/ram.png new file mode 100644 index 000000000..5ea7bfbc0 Binary files /dev/null and b/public/editormd/emoji/ram.png differ diff --git a/public/editormd/emoji/ramen.png b/public/editormd/emoji/ramen.png new file mode 100644 index 000000000..600d2bce8 Binary files /dev/null and b/public/editormd/emoji/ramen.png differ diff --git a/public/editormd/emoji/rat.png b/public/editormd/emoji/rat.png new file mode 100644 index 000000000..fa7dd401c Binary files /dev/null and b/public/editormd/emoji/rat.png differ diff --git a/public/editormd/emoji/recycle.png b/public/editormd/emoji/recycle.png new file mode 100644 index 000000000..99104c0e9 Binary files /dev/null and b/public/editormd/emoji/recycle.png differ diff --git a/public/editormd/emoji/red_car.png b/public/editormd/emoji/red_car.png new file mode 100644 index 000000000..8896a8c1f Binary files /dev/null and b/public/editormd/emoji/red_car.png differ diff --git a/public/editormd/emoji/red_circle.png b/public/editormd/emoji/red_circle.png new file mode 100644 index 000000000..8fa3a313e Binary files /dev/null and b/public/editormd/emoji/red_circle.png differ diff --git a/public/editormd/emoji/registered.png b/public/editormd/emoji/registered.png new file mode 100644 index 000000000..31c68a80b Binary files /dev/null and b/public/editormd/emoji/registered.png differ diff --git a/public/editormd/emoji/relaxed.png b/public/editormd/emoji/relaxed.png new file mode 100644 index 000000000..327f6df7b Binary files /dev/null and b/public/editormd/emoji/relaxed.png differ diff --git a/public/editormd/emoji/relieved.png b/public/editormd/emoji/relieved.png new file mode 100644 index 000000000..a396dccfa Binary files /dev/null and b/public/editormd/emoji/relieved.png differ diff --git a/public/editormd/emoji/repeat.png b/public/editormd/emoji/repeat.png new file mode 100644 index 000000000..80113b692 Binary files /dev/null and b/public/editormd/emoji/repeat.png differ diff --git a/public/editormd/emoji/repeat_one.png b/public/editormd/emoji/repeat_one.png new file mode 100644 index 000000000..3c47bcc1f Binary files /dev/null and b/public/editormd/emoji/repeat_one.png differ diff --git a/public/editormd/emoji/restroom.png b/public/editormd/emoji/restroom.png new file mode 100644 index 000000000..a56a32627 Binary files /dev/null and b/public/editormd/emoji/restroom.png differ diff --git a/public/editormd/emoji/revolving_hearts.png b/public/editormd/emoji/revolving_hearts.png new file mode 100644 index 000000000..ea3317c47 Binary files /dev/null and b/public/editormd/emoji/revolving_hearts.png differ diff --git a/public/editormd/emoji/rewind.png b/public/editormd/emoji/rewind.png new file mode 100644 index 000000000..a9695e78a Binary files /dev/null and b/public/editormd/emoji/rewind.png differ diff --git a/public/editormd/emoji/ribbon.png b/public/editormd/emoji/ribbon.png new file mode 100644 index 000000000..63ee5ba5a Binary files /dev/null and b/public/editormd/emoji/ribbon.png differ diff --git a/public/editormd/emoji/rice.png b/public/editormd/emoji/rice.png new file mode 100644 index 000000000..ad9dedd01 Binary files /dev/null and b/public/editormd/emoji/rice.png differ diff --git a/public/editormd/emoji/rice_ball.png b/public/editormd/emoji/rice_ball.png new file mode 100644 index 000000000..ade7c45d3 Binary files /dev/null and b/public/editormd/emoji/rice_ball.png differ diff --git a/public/editormd/emoji/rice_cracker.png b/public/editormd/emoji/rice_cracker.png new file mode 100644 index 000000000..954c901e9 Binary files /dev/null and b/public/editormd/emoji/rice_cracker.png differ diff --git a/public/editormd/emoji/rice_scene.png b/public/editormd/emoji/rice_scene.png new file mode 100644 index 000000000..5851636cf Binary files /dev/null and b/public/editormd/emoji/rice_scene.png differ diff --git a/public/editormd/emoji/ring.png b/public/editormd/emoji/ring.png new file mode 100644 index 000000000..8a57fd68b Binary files /dev/null and b/public/editormd/emoji/ring.png differ diff --git a/public/editormd/emoji/rocket.png b/public/editormd/emoji/rocket.png new file mode 100644 index 000000000..783078d37 Binary files /dev/null and b/public/editormd/emoji/rocket.png differ diff --git a/public/editormd/emoji/roller_coaster.png b/public/editormd/emoji/roller_coaster.png new file mode 100644 index 000000000..429a5bf84 Binary files /dev/null and b/public/editormd/emoji/roller_coaster.png differ diff --git a/public/editormd/emoji/rooster.png b/public/editormd/emoji/rooster.png new file mode 100644 index 000000000..fab23ad36 Binary files /dev/null and b/public/editormd/emoji/rooster.png differ diff --git a/public/editormd/emoji/rose.png b/public/editormd/emoji/rose.png new file mode 100644 index 000000000..aea1c7172 Binary files /dev/null and b/public/editormd/emoji/rose.png differ diff --git a/public/editormd/emoji/rotating_light.png b/public/editormd/emoji/rotating_light.png new file mode 100644 index 000000000..6cf4a775e Binary files /dev/null and b/public/editormd/emoji/rotating_light.png differ diff --git a/public/editormd/emoji/round_pushpin.png b/public/editormd/emoji/round_pushpin.png new file mode 100644 index 000000000..21b78c67d Binary files /dev/null and b/public/editormd/emoji/round_pushpin.png differ diff --git a/public/editormd/emoji/rowboat.png b/public/editormd/emoji/rowboat.png new file mode 100644 index 000000000..3a299e873 Binary files /dev/null and b/public/editormd/emoji/rowboat.png differ diff --git a/public/editormd/emoji/ru.png b/public/editormd/emoji/ru.png new file mode 100644 index 000000000..6dd4a1e93 Binary files /dev/null and b/public/editormd/emoji/ru.png differ diff --git a/public/editormd/emoji/rugby_football.png b/public/editormd/emoji/rugby_football.png new file mode 100644 index 000000000..f8db67d70 Binary files /dev/null and b/public/editormd/emoji/rugby_football.png differ diff --git a/public/editormd/emoji/runner.png b/public/editormd/emoji/runner.png new file mode 100644 index 000000000..cb0042962 Binary files /dev/null and b/public/editormd/emoji/runner.png differ diff --git a/public/editormd/emoji/running.png b/public/editormd/emoji/running.png new file mode 100644 index 000000000..cb0042962 Binary files /dev/null and b/public/editormd/emoji/running.png differ diff --git a/public/editormd/emoji/running_shirt_with_sash.png b/public/editormd/emoji/running_shirt_with_sash.png new file mode 100644 index 000000000..0d68bba09 Binary files /dev/null and b/public/editormd/emoji/running_shirt_with_sash.png differ diff --git a/public/editormd/emoji/sa.png b/public/editormd/emoji/sa.png new file mode 100644 index 000000000..387f098b9 Binary files /dev/null and b/public/editormd/emoji/sa.png differ diff --git a/public/editormd/emoji/sagittarius.png b/public/editormd/emoji/sagittarius.png new file mode 100644 index 000000000..8b5435baa Binary files /dev/null and b/public/editormd/emoji/sagittarius.png differ diff --git a/public/editormd/emoji/sailboat.png b/public/editormd/emoji/sailboat.png new file mode 100644 index 000000000..ff656dc62 Binary files /dev/null and b/public/editormd/emoji/sailboat.png differ diff --git a/public/editormd/emoji/sake.png b/public/editormd/emoji/sake.png new file mode 100644 index 000000000..1f69907e5 Binary files /dev/null and b/public/editormd/emoji/sake.png differ diff --git a/public/editormd/emoji/sandal.png b/public/editormd/emoji/sandal.png new file mode 100644 index 000000000..0bb3f663f Binary files /dev/null and b/public/editormd/emoji/sandal.png differ diff --git a/public/editormd/emoji/santa.png b/public/editormd/emoji/santa.png new file mode 100644 index 000000000..a2240c07e Binary files /dev/null and b/public/editormd/emoji/santa.png differ diff --git a/public/editormd/emoji/satellite.png b/public/editormd/emoji/satellite.png new file mode 100644 index 000000000..3481cc2ef Binary files /dev/null and b/public/editormd/emoji/satellite.png differ diff --git a/public/editormd/emoji/satisfied.png b/public/editormd/emoji/satisfied.png new file mode 100644 index 000000000..87c2f0334 Binary files /dev/null and b/public/editormd/emoji/satisfied.png differ diff --git a/public/editormd/emoji/saxophone.png b/public/editormd/emoji/saxophone.png new file mode 100644 index 000000000..011559a76 Binary files /dev/null and b/public/editormd/emoji/saxophone.png differ diff --git a/public/editormd/emoji/school.png b/public/editormd/emoji/school.png new file mode 100644 index 000000000..afd922bf1 Binary files /dev/null and b/public/editormd/emoji/school.png differ diff --git a/public/editormd/emoji/school_satchel.png b/public/editormd/emoji/school_satchel.png new file mode 100644 index 000000000..cf1ac7612 Binary files /dev/null and b/public/editormd/emoji/school_satchel.png differ diff --git a/public/editormd/emoji/scissors.png b/public/editormd/emoji/scissors.png new file mode 100644 index 000000000..d99b8aea0 Binary files /dev/null and b/public/editormd/emoji/scissors.png differ diff --git a/public/editormd/emoji/scorpius.png b/public/editormd/emoji/scorpius.png new file mode 100644 index 000000000..67fcea165 Binary files /dev/null and b/public/editormd/emoji/scorpius.png differ diff --git a/public/editormd/emoji/scream.png b/public/editormd/emoji/scream.png new file mode 100644 index 000000000..0acf61064 Binary files /dev/null and b/public/editormd/emoji/scream.png differ diff --git a/public/editormd/emoji/scream_cat.png b/public/editormd/emoji/scream_cat.png new file mode 100644 index 000000000..d94cd34ff Binary files /dev/null and b/public/editormd/emoji/scream_cat.png differ diff --git a/public/editormd/emoji/scroll.png b/public/editormd/emoji/scroll.png new file mode 100644 index 000000000..c5a10e6b8 Binary files /dev/null and b/public/editormd/emoji/scroll.png differ diff --git a/public/editormd/emoji/seat.png b/public/editormd/emoji/seat.png new file mode 100644 index 000000000..d1cb864b4 Binary files /dev/null and b/public/editormd/emoji/seat.png differ diff --git a/public/editormd/emoji/secret.png b/public/editormd/emoji/secret.png new file mode 100644 index 000000000..82e383a60 Binary files /dev/null and b/public/editormd/emoji/secret.png differ diff --git a/public/editormd/emoji/see_no_evil.png b/public/editormd/emoji/see_no_evil.png new file mode 100644 index 000000000..0890a6222 Binary files /dev/null and b/public/editormd/emoji/see_no_evil.png differ diff --git a/public/editormd/emoji/seedling.png b/public/editormd/emoji/seedling.png new file mode 100644 index 000000000..2ab079310 Binary files /dev/null and b/public/editormd/emoji/seedling.png differ diff --git a/public/editormd/emoji/seven.png b/public/editormd/emoji/seven.png new file mode 100644 index 000000000..354e89ae7 Binary files /dev/null and b/public/editormd/emoji/seven.png differ diff --git a/public/editormd/emoji/shaved_ice.png b/public/editormd/emoji/shaved_ice.png new file mode 100644 index 000000000..f50890778 Binary files /dev/null and b/public/editormd/emoji/shaved_ice.png differ diff --git a/public/editormd/emoji/sheep.png b/public/editormd/emoji/sheep.png new file mode 100644 index 000000000..c7277d289 Binary files /dev/null and b/public/editormd/emoji/sheep.png differ diff --git a/public/editormd/emoji/shell.png b/public/editormd/emoji/shell.png new file mode 100644 index 000000000..3145b5649 Binary files /dev/null and b/public/editormd/emoji/shell.png differ diff --git a/public/editormd/emoji/ship.png b/public/editormd/emoji/ship.png new file mode 100644 index 000000000..f941e34af Binary files /dev/null and b/public/editormd/emoji/ship.png differ diff --git a/public/editormd/emoji/shipit.png b/public/editormd/emoji/shipit.png new file mode 100644 index 000000000..a58a47f62 Binary files /dev/null and b/public/editormd/emoji/shipit.png differ diff --git a/public/editormd/emoji/shirt.png b/public/editormd/emoji/shirt.png new file mode 100644 index 000000000..297a6d63e Binary files /dev/null and b/public/editormd/emoji/shirt.png differ diff --git a/public/editormd/emoji/shit.png b/public/editormd/emoji/shit.png new file mode 100644 index 000000000..73a4dc840 Binary files /dev/null and b/public/editormd/emoji/shit.png differ diff --git a/public/editormd/emoji/shoe.png b/public/editormd/emoji/shoe.png new file mode 100644 index 000000000..45b82e61c Binary files /dev/null and b/public/editormd/emoji/shoe.png differ diff --git a/public/editormd/emoji/shower.png b/public/editormd/emoji/shower.png new file mode 100644 index 000000000..0d72ab86b Binary files /dev/null and b/public/editormd/emoji/shower.png differ diff --git a/public/editormd/emoji/signal_strength.png b/public/editormd/emoji/signal_strength.png new file mode 100644 index 000000000..a4bd23ebf Binary files /dev/null and b/public/editormd/emoji/signal_strength.png differ diff --git a/public/editormd/emoji/simple_smile.png b/public/editormd/emoji/simple_smile.png new file mode 100644 index 000000000..2f744b562 Binary files /dev/null and b/public/editormd/emoji/simple_smile.png differ diff --git a/public/editormd/emoji/six.png b/public/editormd/emoji/six.png new file mode 100644 index 000000000..1fa62a395 Binary files /dev/null and b/public/editormd/emoji/six.png differ diff --git a/public/editormd/emoji/six_pointed_star.png b/public/editormd/emoji/six_pointed_star.png new file mode 100644 index 000000000..c11af14c8 Binary files /dev/null and b/public/editormd/emoji/six_pointed_star.png differ diff --git a/public/editormd/emoji/ski.png b/public/editormd/emoji/ski.png new file mode 100644 index 000000000..98f5cb0f4 Binary files /dev/null and b/public/editormd/emoji/ski.png differ diff --git a/public/editormd/emoji/skull.png b/public/editormd/emoji/skull.png new file mode 100644 index 000000000..bd4ee3829 Binary files /dev/null and b/public/editormd/emoji/skull.png differ diff --git a/public/editormd/emoji/sleeping.png b/public/editormd/emoji/sleeping.png new file mode 100644 index 000000000..d353e0718 Binary files /dev/null and b/public/editormd/emoji/sleeping.png differ diff --git a/public/editormd/emoji/sleepy.png b/public/editormd/emoji/sleepy.png new file mode 100644 index 000000000..9b011733f Binary files /dev/null and b/public/editormd/emoji/sleepy.png differ diff --git a/public/editormd/emoji/slot_machine.png b/public/editormd/emoji/slot_machine.png new file mode 100644 index 000000000..f8842026b Binary files /dev/null and b/public/editormd/emoji/slot_machine.png differ diff --git a/public/editormd/emoji/small_blue_diamond.png b/public/editormd/emoji/small_blue_diamond.png new file mode 100644 index 000000000..8cd49205f Binary files /dev/null and b/public/editormd/emoji/small_blue_diamond.png differ diff --git a/public/editormd/emoji/small_orange_diamond.png b/public/editormd/emoji/small_orange_diamond.png new file mode 100644 index 000000000..cbe2d4fe2 Binary files /dev/null and b/public/editormd/emoji/small_orange_diamond.png differ diff --git a/public/editormd/emoji/small_red_triangle.png b/public/editormd/emoji/small_red_triangle.png new file mode 100644 index 000000000..8c4428da8 Binary files /dev/null and b/public/editormd/emoji/small_red_triangle.png differ diff --git a/public/editormd/emoji/small_red_triangle_down.png b/public/editormd/emoji/small_red_triangle_down.png new file mode 100644 index 000000000..94832f060 Binary files /dev/null and b/public/editormd/emoji/small_red_triangle_down.png differ diff --git a/public/editormd/emoji/smile.png b/public/editormd/emoji/smile.png new file mode 100644 index 000000000..d112f8bfc Binary files /dev/null and b/public/editormd/emoji/smile.png differ diff --git a/public/editormd/emoji/smile_cat.png b/public/editormd/emoji/smile_cat.png new file mode 100644 index 000000000..ad333ba3b Binary files /dev/null and b/public/editormd/emoji/smile_cat.png differ diff --git a/public/editormd/emoji/smiley.png b/public/editormd/emoji/smiley.png new file mode 100644 index 000000000..089fb984c Binary files /dev/null and b/public/editormd/emoji/smiley.png differ diff --git a/public/editormd/emoji/smiley_cat.png b/public/editormd/emoji/smiley_cat.png new file mode 100644 index 000000000..dbf1b0276 Binary files /dev/null and b/public/editormd/emoji/smiley_cat.png differ diff --git a/public/editormd/emoji/smiling_imp.png b/public/editormd/emoji/smiling_imp.png new file mode 100644 index 000000000..1e8431ddd Binary files /dev/null and b/public/editormd/emoji/smiling_imp.png differ diff --git a/public/editormd/emoji/smirk.png b/public/editormd/emoji/smirk.png new file mode 100644 index 000000000..b898b75eb Binary files /dev/null and b/public/editormd/emoji/smirk.png differ diff --git a/public/editormd/emoji/smirk_cat.png b/public/editormd/emoji/smirk_cat.png new file mode 100644 index 000000000..351565e24 Binary files /dev/null and b/public/editormd/emoji/smirk_cat.png differ diff --git a/public/editormd/emoji/smoking.png b/public/editormd/emoji/smoking.png new file mode 100644 index 000000000..9784a34d0 Binary files /dev/null and b/public/editormd/emoji/smoking.png differ diff --git a/public/editormd/emoji/snail.png b/public/editormd/emoji/snail.png new file mode 100644 index 000000000..e75e69a84 Binary files /dev/null and b/public/editormd/emoji/snail.png differ diff --git a/public/editormd/emoji/snake.png b/public/editormd/emoji/snake.png new file mode 100644 index 000000000..ef58933e2 Binary files /dev/null and b/public/editormd/emoji/snake.png differ diff --git a/public/editormd/emoji/snowboarder.png b/public/editormd/emoji/snowboarder.png new file mode 100644 index 000000000..aeda5c8d8 Binary files /dev/null and b/public/editormd/emoji/snowboarder.png differ diff --git a/public/editormd/emoji/snowflake.png b/public/editormd/emoji/snowflake.png new file mode 100644 index 000000000..bcacdd23d Binary files /dev/null and b/public/editormd/emoji/snowflake.png differ diff --git a/public/editormd/emoji/snowman.png b/public/editormd/emoji/snowman.png new file mode 100644 index 000000000..a97902e53 Binary files /dev/null and b/public/editormd/emoji/snowman.png differ diff --git a/public/editormd/emoji/sob.png b/public/editormd/emoji/sob.png new file mode 100644 index 000000000..3561e4944 Binary files /dev/null and b/public/editormd/emoji/sob.png differ diff --git a/public/editormd/emoji/soccer.png b/public/editormd/emoji/soccer.png new file mode 100644 index 000000000..b0f9246d6 Binary files /dev/null and b/public/editormd/emoji/soccer.png differ diff --git a/public/editormd/emoji/soon.png b/public/editormd/emoji/soon.png new file mode 100644 index 000000000..ba129b992 Binary files /dev/null and b/public/editormd/emoji/soon.png differ diff --git a/public/editormd/emoji/sos.png b/public/editormd/emoji/sos.png new file mode 100644 index 000000000..e3e16ef73 Binary files /dev/null and b/public/editormd/emoji/sos.png differ diff --git a/public/editormd/emoji/sound.png b/public/editormd/emoji/sound.png new file mode 100644 index 000000000..6aa4dbff4 Binary files /dev/null and b/public/editormd/emoji/sound.png differ diff --git a/public/editormd/emoji/space_invader.png b/public/editormd/emoji/space_invader.png new file mode 100644 index 000000000..c296ad06e Binary files /dev/null and b/public/editormd/emoji/space_invader.png differ diff --git a/public/editormd/emoji/spades.png b/public/editormd/emoji/spades.png new file mode 100644 index 000000000..09279749a Binary files /dev/null and b/public/editormd/emoji/spades.png differ diff --git a/public/editormd/emoji/spaghetti.png b/public/editormd/emoji/spaghetti.png new file mode 100644 index 000000000..7174e6250 Binary files /dev/null and b/public/editormd/emoji/spaghetti.png differ diff --git a/public/editormd/emoji/sparkle.png b/public/editormd/emoji/sparkle.png new file mode 100644 index 000000000..4945f1429 Binary files /dev/null and b/public/editormd/emoji/sparkle.png differ diff --git a/public/editormd/emoji/sparkler.png b/public/editormd/emoji/sparkler.png new file mode 100644 index 000000000..009df2007 Binary files /dev/null and b/public/editormd/emoji/sparkler.png differ diff --git a/public/editormd/emoji/sparkles.png b/public/editormd/emoji/sparkles.png new file mode 100644 index 000000000..51307bcfc Binary files /dev/null and b/public/editormd/emoji/sparkles.png differ diff --git a/public/editormd/emoji/sparkling_heart.png b/public/editormd/emoji/sparkling_heart.png new file mode 100644 index 000000000..64ac06663 Binary files /dev/null and b/public/editormd/emoji/sparkling_heart.png differ diff --git a/public/editormd/emoji/speak_no_evil.png b/public/editormd/emoji/speak_no_evil.png new file mode 100644 index 000000000..87944c4de Binary files /dev/null and b/public/editormd/emoji/speak_no_evil.png differ diff --git a/public/editormd/emoji/speaker.png b/public/editormd/emoji/speaker.png new file mode 100644 index 000000000..470476e18 Binary files /dev/null and b/public/editormd/emoji/speaker.png differ diff --git a/public/editormd/emoji/speech_balloon.png b/public/editormd/emoji/speech_balloon.png new file mode 100644 index 000000000..2896c2788 Binary files /dev/null and b/public/editormd/emoji/speech_balloon.png differ diff --git a/public/editormd/emoji/speedboat.png b/public/editormd/emoji/speedboat.png new file mode 100644 index 000000000..fb37340ee Binary files /dev/null and b/public/editormd/emoji/speedboat.png differ diff --git a/public/editormd/emoji/squirrel.png b/public/editormd/emoji/squirrel.png new file mode 100644 index 000000000..a58a47f62 Binary files /dev/null and b/public/editormd/emoji/squirrel.png differ diff --git a/public/editormd/emoji/star.png b/public/editormd/emoji/star.png new file mode 100644 index 000000000..1bfddc862 Binary files /dev/null and b/public/editormd/emoji/star.png differ diff --git a/public/editormd/emoji/star2.png b/public/editormd/emoji/star2.png new file mode 100644 index 000000000..8b40ff4c8 Binary files /dev/null and b/public/editormd/emoji/star2.png differ diff --git a/public/editormd/emoji/stars.png b/public/editormd/emoji/stars.png new file mode 100644 index 000000000..d3d4671a3 Binary files /dev/null and b/public/editormd/emoji/stars.png differ diff --git a/public/editormd/emoji/station.png b/public/editormd/emoji/station.png new file mode 100644 index 000000000..e77daa8a7 Binary files /dev/null and b/public/editormd/emoji/station.png differ diff --git a/public/editormd/emoji/statue_of_liberty.png b/public/editormd/emoji/statue_of_liberty.png new file mode 100644 index 000000000..32c6f9e7e Binary files /dev/null and b/public/editormd/emoji/statue_of_liberty.png differ diff --git a/public/editormd/emoji/steam_locomotive.png b/public/editormd/emoji/steam_locomotive.png new file mode 100644 index 000000000..549507766 Binary files /dev/null and b/public/editormd/emoji/steam_locomotive.png differ diff --git a/public/editormd/emoji/stew.png b/public/editormd/emoji/stew.png new file mode 100644 index 000000000..c254c974a Binary files /dev/null and b/public/editormd/emoji/stew.png differ diff --git a/public/editormd/emoji/straight_ruler.png b/public/editormd/emoji/straight_ruler.png new file mode 100644 index 000000000..9b5f9eded Binary files /dev/null and b/public/editormd/emoji/straight_ruler.png differ diff --git a/public/editormd/emoji/strawberry.png b/public/editormd/emoji/strawberry.png new file mode 100644 index 000000000..13eb827ab Binary files /dev/null and b/public/editormd/emoji/strawberry.png differ diff --git a/public/editormd/emoji/stuck_out_tongue.png b/public/editormd/emoji/stuck_out_tongue.png new file mode 100644 index 000000000..9312dbee0 Binary files /dev/null and b/public/editormd/emoji/stuck_out_tongue.png differ diff --git a/public/editormd/emoji/stuck_out_tongue_closed_eyes.png b/public/editormd/emoji/stuck_out_tongue_closed_eyes.png new file mode 100644 index 000000000..e231375d5 Binary files /dev/null and b/public/editormd/emoji/stuck_out_tongue_closed_eyes.png differ diff --git a/public/editormd/emoji/stuck_out_tongue_winking_eye.png b/public/editormd/emoji/stuck_out_tongue_winking_eye.png new file mode 100644 index 000000000..3afa090cb Binary files /dev/null and b/public/editormd/emoji/stuck_out_tongue_winking_eye.png differ diff --git a/public/editormd/emoji/sun_with_face.png b/public/editormd/emoji/sun_with_face.png new file mode 100644 index 000000000..ee276636f Binary files /dev/null and b/public/editormd/emoji/sun_with_face.png differ diff --git a/public/editormd/emoji/sunflower.png b/public/editormd/emoji/sunflower.png new file mode 100644 index 000000000..d9bad194a Binary files /dev/null and b/public/editormd/emoji/sunflower.png differ diff --git a/public/editormd/emoji/sunglasses.png b/public/editormd/emoji/sunglasses.png new file mode 100644 index 000000000..8c84235a7 Binary files /dev/null and b/public/editormd/emoji/sunglasses.png differ diff --git a/public/editormd/emoji/sunny.png b/public/editormd/emoji/sunny.png new file mode 100644 index 000000000..d43e83e4a Binary files /dev/null and b/public/editormd/emoji/sunny.png differ diff --git a/public/editormd/emoji/sunrise.png b/public/editormd/emoji/sunrise.png new file mode 100644 index 000000000..18237c288 Binary files /dev/null and b/public/editormd/emoji/sunrise.png differ diff --git a/public/editormd/emoji/sunrise_over_mountains.png b/public/editormd/emoji/sunrise_over_mountains.png new file mode 100644 index 000000000..8799b97ab Binary files /dev/null and b/public/editormd/emoji/sunrise_over_mountains.png differ diff --git a/public/editormd/emoji/surfer.png b/public/editormd/emoji/surfer.png new file mode 100644 index 000000000..b067e8cb3 Binary files /dev/null and b/public/editormd/emoji/surfer.png differ diff --git a/public/editormd/emoji/sushi.png b/public/editormd/emoji/sushi.png new file mode 100644 index 000000000..981c93330 Binary files /dev/null and b/public/editormd/emoji/sushi.png differ diff --git a/public/editormd/emoji/suspect.png b/public/editormd/emoji/suspect.png new file mode 100644 index 000000000..64f56dce7 Binary files /dev/null and b/public/editormd/emoji/suspect.png differ diff --git a/public/editormd/emoji/suspension_railway.png b/public/editormd/emoji/suspension_railway.png new file mode 100644 index 000000000..aaa45f61f Binary files /dev/null and b/public/editormd/emoji/suspension_railway.png differ diff --git a/public/editormd/emoji/sweat.png b/public/editormd/emoji/sweat.png new file mode 100644 index 000000000..935c3a1f8 Binary files /dev/null and b/public/editormd/emoji/sweat.png differ diff --git a/public/editormd/emoji/sweat_drops.png b/public/editormd/emoji/sweat_drops.png new file mode 100644 index 000000000..a83b3e960 Binary files /dev/null and b/public/editormd/emoji/sweat_drops.png differ diff --git a/public/editormd/emoji/sweat_smile.png b/public/editormd/emoji/sweat_smile.png new file mode 100644 index 000000000..f44ee7b29 Binary files /dev/null and b/public/editormd/emoji/sweat_smile.png differ diff --git a/public/editormd/emoji/sweet_potato.png b/public/editormd/emoji/sweet_potato.png new file mode 100644 index 000000000..cde7880a1 Binary files /dev/null and b/public/editormd/emoji/sweet_potato.png differ diff --git a/public/editormd/emoji/swimmer.png b/public/editormd/emoji/swimmer.png new file mode 100644 index 000000000..9fe2bf142 Binary files /dev/null and b/public/editormd/emoji/swimmer.png differ diff --git a/public/editormd/emoji/symbols.png b/public/editormd/emoji/symbols.png new file mode 100644 index 000000000..16bc1da92 Binary files /dev/null and b/public/editormd/emoji/symbols.png differ diff --git a/public/editormd/emoji/syringe.png b/public/editormd/emoji/syringe.png new file mode 100644 index 000000000..36aa8fed5 Binary files /dev/null and b/public/editormd/emoji/syringe.png differ diff --git a/public/editormd/emoji/tada.png b/public/editormd/emoji/tada.png new file mode 100644 index 000000000..4c129c2b6 Binary files /dev/null and b/public/editormd/emoji/tada.png differ diff --git a/public/editormd/emoji/tanabata_tree.png b/public/editormd/emoji/tanabata_tree.png new file mode 100644 index 000000000..6dea4b2d4 Binary files /dev/null and b/public/editormd/emoji/tanabata_tree.png differ diff --git a/public/editormd/emoji/tangerine.png b/public/editormd/emoji/tangerine.png new file mode 100644 index 000000000..c6a109b72 Binary files /dev/null and b/public/editormd/emoji/tangerine.png differ diff --git a/public/editormd/emoji/taurus.png b/public/editormd/emoji/taurus.png new file mode 100644 index 000000000..6af582f69 Binary files /dev/null and b/public/editormd/emoji/taurus.png differ diff --git a/public/editormd/emoji/taxi.png b/public/editormd/emoji/taxi.png new file mode 100644 index 000000000..8b2df31e1 Binary files /dev/null and b/public/editormd/emoji/taxi.png differ diff --git a/public/editormd/emoji/tea.png b/public/editormd/emoji/tea.png new file mode 100644 index 000000000..e913ca743 Binary files /dev/null and b/public/editormd/emoji/tea.png differ diff --git a/public/editormd/emoji/telephone.png b/public/editormd/emoji/telephone.png new file mode 100644 index 000000000..87d2559b5 Binary files /dev/null and b/public/editormd/emoji/telephone.png differ diff --git a/public/editormd/emoji/telephone_receiver.png b/public/editormd/emoji/telephone_receiver.png new file mode 100644 index 000000000..36e21e012 Binary files /dev/null and b/public/editormd/emoji/telephone_receiver.png differ diff --git a/public/editormd/emoji/telescope.png b/public/editormd/emoji/telescope.png new file mode 100644 index 000000000..98e57558a Binary files /dev/null and b/public/editormd/emoji/telescope.png differ diff --git a/public/editormd/emoji/tennis.png b/public/editormd/emoji/tennis.png new file mode 100644 index 000000000..6375e4956 Binary files /dev/null and b/public/editormd/emoji/tennis.png differ diff --git a/public/editormd/emoji/tent.png b/public/editormd/emoji/tent.png new file mode 100644 index 000000000..c9d3e0215 Binary files /dev/null and b/public/editormd/emoji/tent.png differ diff --git a/public/editormd/emoji/thought_balloon.png b/public/editormd/emoji/thought_balloon.png new file mode 100644 index 000000000..56076e2c9 Binary files /dev/null and b/public/editormd/emoji/thought_balloon.png differ diff --git a/public/editormd/emoji/three.png b/public/editormd/emoji/three.png new file mode 100644 index 000000000..55644c990 Binary files /dev/null and b/public/editormd/emoji/three.png differ diff --git a/public/editormd/emoji/thumbsdown.png b/public/editormd/emoji/thumbsdown.png new file mode 100644 index 000000000..41c6b825d Binary files /dev/null and b/public/editormd/emoji/thumbsdown.png differ diff --git a/public/editormd/emoji/thumbsup.png b/public/editormd/emoji/thumbsup.png new file mode 100644 index 000000000..ec7af7f6c Binary files /dev/null and b/public/editormd/emoji/thumbsup.png differ diff --git a/public/editormd/emoji/ticket.png b/public/editormd/emoji/ticket.png new file mode 100644 index 000000000..75a050f41 Binary files /dev/null and b/public/editormd/emoji/ticket.png differ diff --git a/public/editormd/emoji/tiger.png b/public/editormd/emoji/tiger.png new file mode 100644 index 000000000..d6cc84a3b Binary files /dev/null and b/public/editormd/emoji/tiger.png differ diff --git a/public/editormd/emoji/tiger2.png b/public/editormd/emoji/tiger2.png new file mode 100644 index 000000000..b0c7d8dc3 Binary files /dev/null and b/public/editormd/emoji/tiger2.png differ diff --git a/public/editormd/emoji/tired_face.png b/public/editormd/emoji/tired_face.png new file mode 100644 index 000000000..82a80bf42 Binary files /dev/null and b/public/editormd/emoji/tired_face.png differ diff --git a/public/editormd/emoji/tm.png b/public/editormd/emoji/tm.png new file mode 100644 index 000000000..603f79d89 Binary files /dev/null and b/public/editormd/emoji/tm.png differ diff --git a/public/editormd/emoji/toilet.png b/public/editormd/emoji/toilet.png new file mode 100644 index 000000000..e5cc4119a Binary files /dev/null and b/public/editormd/emoji/toilet.png differ diff --git a/public/editormd/emoji/tokyo_tower.png b/public/editormd/emoji/tokyo_tower.png new file mode 100644 index 000000000..ddceaed15 Binary files /dev/null and b/public/editormd/emoji/tokyo_tower.png differ diff --git a/public/editormd/emoji/tomato.png b/public/editormd/emoji/tomato.png new file mode 100644 index 000000000..53029d900 Binary files /dev/null and b/public/editormd/emoji/tomato.png differ diff --git a/public/editormd/emoji/tongue.png b/public/editormd/emoji/tongue.png new file mode 100644 index 000000000..432a326b1 Binary files /dev/null and b/public/editormd/emoji/tongue.png differ diff --git a/public/editormd/emoji/top.png b/public/editormd/emoji/top.png new file mode 100644 index 000000000..5aa4dd442 Binary files /dev/null and b/public/editormd/emoji/top.png differ diff --git a/public/editormd/emoji/tophat.png b/public/editormd/emoji/tophat.png new file mode 100644 index 000000000..7d27134d6 Binary files /dev/null and b/public/editormd/emoji/tophat.png differ diff --git a/public/editormd/emoji/tractor.png b/public/editormd/emoji/tractor.png new file mode 100644 index 000000000..ac9ceeed1 Binary files /dev/null and b/public/editormd/emoji/tractor.png differ diff --git a/public/editormd/emoji/traffic_light.png b/public/editormd/emoji/traffic_light.png new file mode 100644 index 000000000..b5f3dbe39 Binary files /dev/null and b/public/editormd/emoji/traffic_light.png differ diff --git a/public/editormd/emoji/train.png b/public/editormd/emoji/train.png new file mode 100644 index 000000000..9d498abe6 Binary files /dev/null and b/public/editormd/emoji/train.png differ diff --git a/public/editormd/emoji/train2.png b/public/editormd/emoji/train2.png new file mode 100644 index 000000000..9c0d3ab64 Binary files /dev/null and b/public/editormd/emoji/train2.png differ diff --git a/public/editormd/emoji/tram.png b/public/editormd/emoji/tram.png new file mode 100644 index 000000000..5eb29fb71 Binary files /dev/null and b/public/editormd/emoji/tram.png differ diff --git a/public/editormd/emoji/triangular_flag_on_post.png b/public/editormd/emoji/triangular_flag_on_post.png new file mode 100644 index 000000000..f9a3f32d7 Binary files /dev/null and b/public/editormd/emoji/triangular_flag_on_post.png differ diff --git a/public/editormd/emoji/triangular_ruler.png b/public/editormd/emoji/triangular_ruler.png new file mode 100644 index 000000000..383677cb7 Binary files /dev/null and b/public/editormd/emoji/triangular_ruler.png differ diff --git a/public/editormd/emoji/trident.png b/public/editormd/emoji/trident.png new file mode 100644 index 000000000..91afb3dda Binary files /dev/null and b/public/editormd/emoji/trident.png differ diff --git a/public/editormd/emoji/triumph.png b/public/editormd/emoji/triumph.png new file mode 100644 index 000000000..4260344d0 Binary files /dev/null and b/public/editormd/emoji/triumph.png differ diff --git a/public/editormd/emoji/trolleybus.png b/public/editormd/emoji/trolleybus.png new file mode 100644 index 000000000..4fc7dc3ee Binary files /dev/null and b/public/editormd/emoji/trolleybus.png differ diff --git a/public/editormd/emoji/trollface.png b/public/editormd/emoji/trollface.png new file mode 100644 index 000000000..536783f7b Binary files /dev/null and b/public/editormd/emoji/trollface.png differ diff --git a/public/editormd/emoji/trophy.png b/public/editormd/emoji/trophy.png new file mode 100644 index 000000000..95d3b63f5 Binary files /dev/null and b/public/editormd/emoji/trophy.png differ diff --git a/public/editormd/emoji/tropical_drink.png b/public/editormd/emoji/tropical_drink.png new file mode 100644 index 000000000..55ca9eeda Binary files /dev/null and b/public/editormd/emoji/tropical_drink.png differ diff --git a/public/editormd/emoji/tropical_fish.png b/public/editormd/emoji/tropical_fish.png new file mode 100644 index 000000000..26ee3f355 Binary files /dev/null and b/public/editormd/emoji/tropical_fish.png differ diff --git a/public/editormd/emoji/truck.png b/public/editormd/emoji/truck.png new file mode 100644 index 000000000..7ab124526 Binary files /dev/null and b/public/editormd/emoji/truck.png differ diff --git a/public/editormd/emoji/trumpet.png b/public/editormd/emoji/trumpet.png new file mode 100644 index 000000000..c84cfb13e Binary files /dev/null and b/public/editormd/emoji/trumpet.png differ diff --git a/public/editormd/emoji/tshirt.png b/public/editormd/emoji/tshirt.png new file mode 100644 index 000000000..297a6d63e Binary files /dev/null and b/public/editormd/emoji/tshirt.png differ diff --git a/public/editormd/emoji/tulip.png b/public/editormd/emoji/tulip.png new file mode 100644 index 000000000..b3ee1102a Binary files /dev/null and b/public/editormd/emoji/tulip.png differ diff --git a/public/editormd/emoji/turtle.png b/public/editormd/emoji/turtle.png new file mode 100644 index 000000000..21256ead9 Binary files /dev/null and b/public/editormd/emoji/turtle.png differ diff --git a/public/editormd/emoji/tv.png b/public/editormd/emoji/tv.png new file mode 100644 index 000000000..803dc3d41 Binary files /dev/null and b/public/editormd/emoji/tv.png differ diff --git a/public/editormd/emoji/twisted_rightwards_arrows.png b/public/editormd/emoji/twisted_rightwards_arrows.png new file mode 100644 index 000000000..25cde18b2 Binary files /dev/null and b/public/editormd/emoji/twisted_rightwards_arrows.png differ diff --git a/public/editormd/emoji/two.png b/public/editormd/emoji/two.png new file mode 100644 index 000000000..c191f8a32 Binary files /dev/null and b/public/editormd/emoji/two.png differ diff --git a/public/editormd/emoji/two_hearts.png b/public/editormd/emoji/two_hearts.png new file mode 100644 index 000000000..d44223088 Binary files /dev/null and b/public/editormd/emoji/two_hearts.png differ diff --git a/public/editormd/emoji/two_men_holding_hands.png b/public/editormd/emoji/two_men_holding_hands.png new file mode 100644 index 000000000..d1099f21f Binary files /dev/null and b/public/editormd/emoji/two_men_holding_hands.png differ diff --git a/public/editormd/emoji/two_women_holding_hands.png b/public/editormd/emoji/two_women_holding_hands.png new file mode 100644 index 000000000..619646c4e Binary files /dev/null and b/public/editormd/emoji/two_women_holding_hands.png differ diff --git a/public/editormd/emoji/u5272.png b/public/editormd/emoji/u5272.png new file mode 100644 index 000000000..2148253fc Binary files /dev/null and b/public/editormd/emoji/u5272.png differ diff --git a/public/editormd/emoji/u5408.png b/public/editormd/emoji/u5408.png new file mode 100644 index 000000000..03ab0d874 Binary files /dev/null and b/public/editormd/emoji/u5408.png differ diff --git a/public/editormd/emoji/u55b6.png b/public/editormd/emoji/u55b6.png new file mode 100644 index 000000000..0e914e53a Binary files /dev/null and b/public/editormd/emoji/u55b6.png differ diff --git a/public/editormd/emoji/u6307.png b/public/editormd/emoji/u6307.png new file mode 100644 index 000000000..75b2734d1 Binary files /dev/null and b/public/editormd/emoji/u6307.png differ diff --git a/public/editormd/emoji/u6708.png b/public/editormd/emoji/u6708.png new file mode 100644 index 000000000..03ae7f171 Binary files /dev/null and b/public/editormd/emoji/u6708.png differ diff --git a/public/editormd/emoji/u6709.png b/public/editormd/emoji/u6709.png new file mode 100644 index 000000000..9f3a7578a Binary files /dev/null and b/public/editormd/emoji/u6709.png differ diff --git a/public/editormd/emoji/u6e80.png b/public/editormd/emoji/u6e80.png new file mode 100644 index 000000000..c1ef7fd2b Binary files /dev/null and b/public/editormd/emoji/u6e80.png differ diff --git a/public/editormd/emoji/u7121.png b/public/editormd/emoji/u7121.png new file mode 100644 index 000000000..4d248c95b Binary files /dev/null and b/public/editormd/emoji/u7121.png differ diff --git a/public/editormd/emoji/u7533.png b/public/editormd/emoji/u7533.png new file mode 100644 index 000000000..8f3bd1a73 Binary files /dev/null and b/public/editormd/emoji/u7533.png differ diff --git a/public/editormd/emoji/u7981.png b/public/editormd/emoji/u7981.png new file mode 100644 index 000000000..f550a573d Binary files /dev/null and b/public/editormd/emoji/u7981.png differ diff --git a/public/editormd/emoji/u7a7a.png b/public/editormd/emoji/u7a7a.png new file mode 100644 index 000000000..afefae9ed Binary files /dev/null and b/public/editormd/emoji/u7a7a.png differ diff --git a/public/editormd/emoji/uk.png b/public/editormd/emoji/uk.png new file mode 100644 index 000000000..b6ef6c199 Binary files /dev/null and b/public/editormd/emoji/uk.png differ diff --git a/public/editormd/emoji/umbrella.png b/public/editormd/emoji/umbrella.png new file mode 100644 index 000000000..1db722fa6 Binary files /dev/null and b/public/editormd/emoji/umbrella.png differ diff --git a/public/editormd/emoji/unamused.png b/public/editormd/emoji/unamused.png new file mode 100644 index 000000000..f63ac221b Binary files /dev/null and b/public/editormd/emoji/unamused.png differ diff --git a/public/editormd/emoji/underage.png b/public/editormd/emoji/underage.png new file mode 100644 index 000000000..a789b3c62 Binary files /dev/null and b/public/editormd/emoji/underage.png differ diff --git a/public/editormd/emoji/unlock.png b/public/editormd/emoji/unlock.png new file mode 100644 index 000000000..22b429cd0 Binary files /dev/null and b/public/editormd/emoji/unlock.png differ diff --git a/public/editormd/emoji/up.png b/public/editormd/emoji/up.png new file mode 100644 index 000000000..829219a86 Binary files /dev/null and b/public/editormd/emoji/up.png differ diff --git a/public/editormd/emoji/us.png b/public/editormd/emoji/us.png new file mode 100644 index 000000000..4e8ca3900 Binary files /dev/null and b/public/editormd/emoji/us.png differ diff --git a/public/editormd/emoji/v.png b/public/editormd/emoji/v.png new file mode 100644 index 000000000..f61267c28 Binary files /dev/null and b/public/editormd/emoji/v.png differ diff --git a/public/editormd/emoji/vertical_traffic_light.png b/public/editormd/emoji/vertical_traffic_light.png new file mode 100644 index 000000000..98d36d119 Binary files /dev/null and b/public/editormd/emoji/vertical_traffic_light.png differ diff --git a/public/editormd/emoji/vhs.png b/public/editormd/emoji/vhs.png new file mode 100644 index 000000000..45dee5039 Binary files /dev/null and b/public/editormd/emoji/vhs.png differ diff --git a/public/editormd/emoji/vibration_mode.png b/public/editormd/emoji/vibration_mode.png new file mode 100644 index 000000000..bd3fb3c76 Binary files /dev/null and b/public/editormd/emoji/vibration_mode.png differ diff --git a/public/editormd/emoji/video_camera.png b/public/editormd/emoji/video_camera.png new file mode 100644 index 000000000..7045a92cf Binary files /dev/null and b/public/editormd/emoji/video_camera.png differ diff --git a/public/editormd/emoji/video_game.png b/public/editormd/emoji/video_game.png new file mode 100644 index 000000000..e265a3bd8 Binary files /dev/null and b/public/editormd/emoji/video_game.png differ diff --git a/public/editormd/emoji/violin.png b/public/editormd/emoji/violin.png new file mode 100644 index 000000000..69347b545 Binary files /dev/null and b/public/editormd/emoji/violin.png differ diff --git a/public/editormd/emoji/virgo.png b/public/editormd/emoji/virgo.png new file mode 100644 index 000000000..72e1763f5 Binary files /dev/null and b/public/editormd/emoji/virgo.png differ diff --git a/public/editormd/emoji/volcano.png b/public/editormd/emoji/volcano.png new file mode 100644 index 000000000..fb6e90451 Binary files /dev/null and b/public/editormd/emoji/volcano.png differ diff --git a/public/editormd/emoji/vs.png b/public/editormd/emoji/vs.png new file mode 100644 index 000000000..fddca219b Binary files /dev/null and b/public/editormd/emoji/vs.png differ diff --git a/public/editormd/emoji/walking.png b/public/editormd/emoji/walking.png new file mode 100644 index 000000000..52bc0381c Binary files /dev/null and b/public/editormd/emoji/walking.png differ diff --git a/public/editormd/emoji/waning_crescent_moon.png b/public/editormd/emoji/waning_crescent_moon.png new file mode 100644 index 000000000..30387780f Binary files /dev/null and b/public/editormd/emoji/waning_crescent_moon.png differ diff --git a/public/editormd/emoji/waning_gibbous_moon.png b/public/editormd/emoji/waning_gibbous_moon.png new file mode 100644 index 000000000..510099070 Binary files /dev/null and b/public/editormd/emoji/waning_gibbous_moon.png differ diff --git a/public/editormd/emoji/warning.png b/public/editormd/emoji/warning.png new file mode 100644 index 000000000..2c03dfe29 Binary files /dev/null and b/public/editormd/emoji/warning.png differ diff --git a/public/editormd/emoji/watch.png b/public/editormd/emoji/watch.png new file mode 100644 index 000000000..d503bb87c Binary files /dev/null and b/public/editormd/emoji/watch.png differ diff --git a/public/editormd/emoji/water_buffalo.png b/public/editormd/emoji/water_buffalo.png new file mode 100644 index 000000000..3bcde3edd Binary files /dev/null and b/public/editormd/emoji/water_buffalo.png differ diff --git a/public/editormd/emoji/watermelon.png b/public/editormd/emoji/watermelon.png new file mode 100644 index 000000000..fc212be78 Binary files /dev/null and b/public/editormd/emoji/watermelon.png differ diff --git a/public/editormd/emoji/wave.png b/public/editormd/emoji/wave.png new file mode 100644 index 000000000..56e6e822b Binary files /dev/null and b/public/editormd/emoji/wave.png differ diff --git a/public/editormd/emoji/wavy_dash.png b/public/editormd/emoji/wavy_dash.png new file mode 100644 index 000000000..b71a8c7b2 Binary files /dev/null and b/public/editormd/emoji/wavy_dash.png differ diff --git a/public/editormd/emoji/waxing_crescent_moon.png b/public/editormd/emoji/waxing_crescent_moon.png new file mode 100644 index 000000000..c8f13dd31 Binary files /dev/null and b/public/editormd/emoji/waxing_crescent_moon.png differ diff --git a/public/editormd/emoji/waxing_gibbous_moon.png b/public/editormd/emoji/waxing_gibbous_moon.png new file mode 100644 index 000000000..54e7ec671 Binary files /dev/null and b/public/editormd/emoji/waxing_gibbous_moon.png differ diff --git a/public/editormd/emoji/wc.png b/public/editormd/emoji/wc.png new file mode 100644 index 000000000..00756ebd7 Binary files /dev/null and b/public/editormd/emoji/wc.png differ diff --git a/public/editormd/emoji/weary.png b/public/editormd/emoji/weary.png new file mode 100644 index 000000000..57be4dc87 Binary files /dev/null and b/public/editormd/emoji/weary.png differ diff --git a/public/editormd/emoji/wedding.png b/public/editormd/emoji/wedding.png new file mode 100644 index 000000000..358570d1b Binary files /dev/null and b/public/editormd/emoji/wedding.png differ diff --git a/public/editormd/emoji/whale.png b/public/editormd/emoji/whale.png new file mode 100644 index 000000000..8de67d088 Binary files /dev/null and b/public/editormd/emoji/whale.png differ diff --git a/public/editormd/emoji/whale2.png b/public/editormd/emoji/whale2.png new file mode 100644 index 000000000..0ef4ea94f Binary files /dev/null and b/public/editormd/emoji/whale2.png differ diff --git a/public/editormd/emoji/wheelchair.png b/public/editormd/emoji/wheelchair.png new file mode 100644 index 000000000..f7a01e461 Binary files /dev/null and b/public/editormd/emoji/wheelchair.png differ diff --git a/public/editormd/emoji/white_check_mark.png b/public/editormd/emoji/white_check_mark.png new file mode 100644 index 000000000..61dc0583c Binary files /dev/null and b/public/editormd/emoji/white_check_mark.png differ diff --git a/public/editormd/emoji/white_circle.png b/public/editormd/emoji/white_circle.png new file mode 100644 index 000000000..c88b511a1 Binary files /dev/null and b/public/editormd/emoji/white_circle.png differ diff --git a/public/editormd/emoji/white_flower.png b/public/editormd/emoji/white_flower.png new file mode 100644 index 000000000..c0929d0dd Binary files /dev/null and b/public/editormd/emoji/white_flower.png differ diff --git a/public/editormd/emoji/white_large_square.png b/public/editormd/emoji/white_large_square.png new file mode 100644 index 000000000..782de0cd6 Binary files /dev/null and b/public/editormd/emoji/white_large_square.png differ diff --git a/public/editormd/emoji/white_medium_small_square.png b/public/editormd/emoji/white_medium_small_square.png new file mode 100644 index 000000000..574daa4fb Binary files /dev/null and b/public/editormd/emoji/white_medium_small_square.png differ diff --git a/public/editormd/emoji/white_medium_square.png b/public/editormd/emoji/white_medium_square.png new file mode 100644 index 000000000..8779a4081 Binary files /dev/null and b/public/editormd/emoji/white_medium_square.png differ diff --git a/public/editormd/emoji/white_small_square.png b/public/editormd/emoji/white_small_square.png new file mode 100644 index 000000000..4771c330b Binary files /dev/null and b/public/editormd/emoji/white_small_square.png differ diff --git a/public/editormd/emoji/white_square_button.png b/public/editormd/emoji/white_square_button.png new file mode 100644 index 000000000..e64987a6d Binary files /dev/null and b/public/editormd/emoji/white_square_button.png differ diff --git a/public/editormd/emoji/wind_chime.png b/public/editormd/emoji/wind_chime.png new file mode 100644 index 000000000..efacf5dd4 Binary files /dev/null and b/public/editormd/emoji/wind_chime.png differ diff --git a/public/editormd/emoji/wine_glass.png b/public/editormd/emoji/wine_glass.png new file mode 100644 index 000000000..82b0f0005 Binary files /dev/null and b/public/editormd/emoji/wine_glass.png differ diff --git a/public/editormd/emoji/wink.png b/public/editormd/emoji/wink.png new file mode 100644 index 000000000..45b2dc6fe Binary files /dev/null and b/public/editormd/emoji/wink.png differ diff --git a/public/editormd/emoji/wolf.png b/public/editormd/emoji/wolf.png new file mode 100644 index 000000000..c60c96895 Binary files /dev/null and b/public/editormd/emoji/wolf.png differ diff --git a/public/editormd/emoji/woman.png b/public/editormd/emoji/woman.png new file mode 100644 index 000000000..6bf0d2b12 Binary files /dev/null and b/public/editormd/emoji/woman.png differ diff --git a/public/editormd/emoji/womans_clothes.png b/public/editormd/emoji/womans_clothes.png new file mode 100644 index 000000000..aa297c7b6 Binary files /dev/null and b/public/editormd/emoji/womans_clothes.png differ diff --git a/public/editormd/emoji/womans_hat.png b/public/editormd/emoji/womans_hat.png new file mode 100644 index 000000000..4cb2e6a69 Binary files /dev/null and b/public/editormd/emoji/womans_hat.png differ diff --git a/public/editormd/emoji/womens.png b/public/editormd/emoji/womens.png new file mode 100644 index 000000000..eefdeb1fe Binary files /dev/null and b/public/editormd/emoji/womens.png differ diff --git a/public/editormd/emoji/worried.png b/public/editormd/emoji/worried.png new file mode 100644 index 000000000..5d9030332 Binary files /dev/null and b/public/editormd/emoji/worried.png differ diff --git a/public/editormd/emoji/wrench.png b/public/editormd/emoji/wrench.png new file mode 100644 index 000000000..a87072ad1 Binary files /dev/null and b/public/editormd/emoji/wrench.png differ diff --git a/public/editormd/emoji/x.png b/public/editormd/emoji/x.png new file mode 100644 index 000000000..dff9efa8b Binary files /dev/null and b/public/editormd/emoji/x.png differ diff --git a/public/editormd/emoji/yellow_heart.png b/public/editormd/emoji/yellow_heart.png new file mode 100644 index 000000000..30ad33ff3 Binary files /dev/null and b/public/editormd/emoji/yellow_heart.png differ diff --git a/public/editormd/emoji/yen.png b/public/editormd/emoji/yen.png new file mode 100644 index 000000000..564e443d4 Binary files /dev/null and b/public/editormd/emoji/yen.png differ diff --git a/public/editormd/emoji/yum.png b/public/editormd/emoji/yum.png new file mode 100644 index 000000000..a0cbe68c4 Binary files /dev/null and b/public/editormd/emoji/yum.png differ diff --git a/public/editormd/emoji/zap.png b/public/editormd/emoji/zap.png new file mode 100644 index 000000000..260c531b9 Binary files /dev/null and b/public/editormd/emoji/zap.png differ diff --git a/public/editormd/emoji/zero.png b/public/editormd/emoji/zero.png new file mode 100644 index 000000000..6e57b3343 Binary files /dev/null and b/public/editormd/emoji/zero.png differ diff --git a/public/editormd/emoji/zzz.png b/public/editormd/emoji/zzz.png new file mode 100644 index 000000000..fb3003bb9 Binary files /dev/null and b/public/editormd/emoji/zzz.png differ diff --git a/public/editormd/examples/@links.html b/public/editormd/examples/@links.html new file mode 100644 index 000000000..d032d9426 --- /dev/null +++ b/public/editormd/examples/@links.html @@ -0,0 +1,135 @@ + + + + + @links - Editor.md examples + + + + + +
                        +
                        +

                        @links

                        +

                        Github Flavored Markdown extras syntax

                        +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/auto-height.html b/public/editormd/examples/auto-height.html new file mode 100644 index 000000000..23469303a --- /dev/null +++ b/public/editormd/examples/auto-height.html @@ -0,0 +1,55 @@ + + + + + Auto height - Editor.md examples + + + + + +
                        +
                        +

                        Auto height test

                        +
                        +
                        + +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/change-mode.html b/public/editormd/examples/change-mode.html new file mode 100644 index 000000000..91d780a8a --- /dev/null +++ b/public/editormd/examples/change-mode.html @@ -0,0 +1,508 @@ + + + + + Chnage mode - Editor.md examples + + + + + + +
                        +
                        +

                        Chnage mode

                        +

                        Become to the code editor

                        +

                        Modes :   Themes : + +

                        +
                        +
                        + + +
                        +
                        + + + + + + + + + + +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/code-fold.html b/public/editormd/examples/code-fold.html new file mode 100644 index 000000000..9e0dd5260 --- /dev/null +++ b/public/editormd/examples/code-fold.html @@ -0,0 +1,44 @@ + + + + + Code folding - Editor.md examples + + + + + +
                        +
                        +

                        Code folding

                        +

                        Switch code folding : Press Ctrl + Q / Command + Q

                        +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/css/style.css b/public/editormd/examples/css/style.css new file mode 100644 index 000000000..03918d4b8 --- /dev/null +++ b/public/editormd/examples/css/style.css @@ -0,0 +1,94 @@ +* { + padding: 0; + margin: 0; +} + +*, *:before, *:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{ + margin: 0; + padding: 0; +} + +article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary { + display: block; +} + +audio, canvas, video { + display: inline-block; +} + +img { + border: none; + vertical-align: middle; +} + +ul, ol { + /*list-style: none;*/ +} + +.clear { + *zoom: 1; /* for IE 6/7 */ +} + +.clear:before, .clear:after { + height: 0; + content: ""; + font-size: 0; + display: table; + line-height: 0; /* for Opera */ + visibility: hidden; +} + +.clear:after { + clear: both; +} + +body { + font-size: 14px; + color: #666; + font-family: "Microsoft YaHei", "微软雅黑", Helvetica, Tahoma, STXihei, "华文细黑", STHeiti, "Helvetica Neue", Helvetica, Tahoma, "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, "宋体", Heiti, "黑体", sans-serif; + background: #fff; + text-align: center; +} + +#layout { + text-align: left; +} + +#layout > header, .btns { + padding: 15px 0; + width: 90%; + margin: 0 auto; +} + +.btns { + padding-top: 0; +} + +.btns button { + padding: 2px 8px; +} + +#layout > header > h1 { + font-size: 20px; + margin-bottom: 10px; +} + +.btns button, .btn { + padding: 8px 10px; + background: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 3px; + border-radius: 3px; + cursor: pointer; + -webkit-transition: background 300ms ease-out; + transition: background 300ms ease-out; +} + +.btns button:hover, .btn:hover { + background: #f6f6f6; +} \ No newline at end of file diff --git a/public/editormd/examples/custom-keyboard-shortcuts.html b/public/editormd/examples/custom-keyboard-shortcuts.html new file mode 100644 index 000000000..fd8338e88 --- /dev/null +++ b/public/editormd/examples/custom-keyboard-shortcuts.html @@ -0,0 +1,118 @@ + + + + + Custom keyboard shortcuts - Editor.md examples + + + + + +
                        +
                        +

                        Custom keyboard shortcuts

                        +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/custom-toolbar.html b/public/editormd/examples/custom-toolbar.html new file mode 100644 index 000000000..295b5f33c --- /dev/null +++ b/public/editormd/examples/custom-toolbar.html @@ -0,0 +1,178 @@ + + + + + 自定义工具栏 - Editor.md examples + + + + + +
                        +
                        +

                        自定义工具栏

                        +

                        Custom toolbar (icons handler)

                        +
                        +
                        + +
                        +
                        + + + + + + + + \ No newline at end of file diff --git a/public/editormd/examples/define-plugin.html b/public/editormd/examples/define-plugin.html new file mode 100644 index 000000000..0780ab4b9 --- /dev/null +++ b/public/editormd/examples/define-plugin.html @@ -0,0 +1,151 @@ + + + + + Define extention plugins for Editor.md - Editor.md examples + + + + + +
                        +
                        +

                        Define extention plugins for Editor.md

                        +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/delay-renderer-preview.html b/public/editormd/examples/delay-renderer-preview.html new file mode 100644 index 000000000..8b52ccea6 --- /dev/null +++ b/public/editormd/examples/delay-renderer-preview.html @@ -0,0 +1,56 @@ + + + + + Delay Rerender & Preview - Editor.md examples + + + + + +
                        +
                        +

                        Delay Rerender & Preview

                        +

                        P.S. If you input the content too much and too fast, You can setting the delay value.

                        +

                        P.S. 适用于输入内容太多太快的情形,但要是一个合理的值,不然会显得预览太慢。打字慢会相对显得慢,打字快时则相对显得快。

                        +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/dynamic-create-editormd.html b/public/editormd/examples/dynamic-create-editormd.html new file mode 100644 index 000000000..44577c5e4 --- /dev/null +++ b/public/editormd/examples/dynamic-create-editormd.html @@ -0,0 +1,47 @@ + + + + + 动态创建 Editor.md - Editor.md examples + + + + + +
                        +
                        +

                        动态创建 Editor.md

                        +

                        Dynamic create Editor.md

                        +
                        +
                        + + +
                        +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/emoji.html b/public/editormd/examples/emoji.html new file mode 100644 index 000000000..51cea4501 --- /dev/null +++ b/public/editormd/examples/emoji.html @@ -0,0 +1,191 @@ + + + + + Emoji - Editor.md examples + + + + + + +
                        +
                        +

                        Emoji 表情

                        +

                        Supports:

                        + +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/extends.html b/public/editormd/examples/extends.html new file mode 100644 index 000000000..36587bffc --- /dev/null +++ b/public/editormd/examples/extends.html @@ -0,0 +1,153 @@ + + + + + Expanded Editor.md - Editor.md examples + + + + + +
                        +
                        +

                        Expanded Editor.md

                        +

                        Expanded of member methods and properties

                        +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/external-use.html b/public/editormd/examples/external-use.html new file mode 100644 index 000000000..69545dfea --- /dev/null +++ b/public/editormd/examples/external-use.html @@ -0,0 +1,119 @@ + + + + + External use - Editor.md examples + + + + + +
                        +
                        +

                        External use

                        +

                        External use of toolbar handlers / modal dialog

                        +
                        +
                        + + + + + + + + +
                        +
                        + +
                        +
                        + + + + + + + + \ No newline at end of file diff --git a/public/editormd/examples/flowchart.html b/public/editormd/examples/flowchart.html new file mode 100644 index 000000000..d8db673ea --- /dev/null +++ b/public/editormd/examples/flowchart.html @@ -0,0 +1,53 @@ + + + + + FlowChart - Editor.md examples + + + + + +
                        +
                        +

                        FlowChart 流程图

                        +

                        Based on flowchart.js:http://adrai.github.io/flowchart.js/

                        +
                        +
                        + +
                        +
                        + + + + + + \ No newline at end of file diff --git a/public/editormd/examples/form-get-value.html b/public/editormd/examples/form-get-value.html new file mode 100644 index 000000000..6b9cbf390 --- /dev/null +++ b/public/editormd/examples/form-get-value.html @@ -0,0 +1,92 @@ + + + + + Form get textarea value - Editor.md examples + + + + + +
                        +
                        +

                        表单取值

                        +

                        Form get textarea value.

                        +
                        +
                        +
                        + + +
                        +
                        + +
                        +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/full.html b/public/editormd/examples/full.html new file mode 100644 index 000000000..08f845d2a --- /dev/null +++ b/public/editormd/examples/full.html @@ -0,0 +1,231 @@ + + + + + Full example - Editor.md examples + + + + + + +
                        +
                        +

                        完整示例

                        +

                        Full example

                        +
                          +
                        • Enable HTML tags decode
                        • +
                        • Enable TeX, Flowchart, Sequence Diagram, Emoji, FontAwesome, Task lists
                        • +
                        • Enable Image upload
                        • +
                        • Enable [TOCM], Search Replace, Code fold
                        • +
                        +
                        +
                        + + + + + + + + + + + + + +
                        +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/goto-line.html b/public/editormd/examples/goto-line.html new file mode 100644 index 000000000..e85350225 --- /dev/null +++ b/public/editormd/examples/goto-line.html @@ -0,0 +1,84 @@ + + + + + Goto line - Editor.md examples + + + + + +
                        +
                        +

                        Goto line

                        +
                        +
                        + + + + + + + +
                        +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/html-preview-markdown-to-html-custom-toc-container.html b/public/editormd/examples/html-preview-markdown-to-html-custom-toc-container.html new file mode 100644 index 000000000..a610e8c96 --- /dev/null +++ b/public/editormd/examples/html-preview-markdown-to-html-custom-toc-container.html @@ -0,0 +1,180 @@ + + + + + HTML Preview (markdown to html) - Editor.md examples + + + + + + +
                        +
                        +

                        Markdown转HTML的显示处理之自定义 ToC 容器

                        +

                        即:非编辑情况下的HTML预览

                        +

                        HTML Preview (markdown to html and custom ToC container)

                        +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        +
                        + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/editormd/examples/html-preview-markdown-to-html.html b/public/editormd/examples/html-preview-markdown-to-html.html new file mode 100644 index 000000000..2cc7d2537 --- /dev/null +++ b/public/editormd/examples/html-preview-markdown-to-html.html @@ -0,0 +1,142 @@ + + + + + HTML Preview(markdown to html) - Editor.md examples + + + + + + +
                        +
                        +

                        Markdown转HTML的显示处理

                        +

                        即:非编辑情况下的HTML预览

                        +

                        HTML Preview(markdown to html)

                        +
                        +
                        + +
                        +
                        + +
                        +
                        + +
                        +
                        + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/editormd/examples/html-tags-decode.html b/public/editormd/examples/html-tags-decode.html new file mode 100644 index 000000000..c05221c04 --- /dev/null +++ b/public/editormd/examples/html-tags-decode.html @@ -0,0 +1,119 @@ + + + + + 识别和解析 HTML 标签 - Editor.md examples + + + + + +
                        +
                        +

                        识别和解析HTML标签

                        +

                        HTML tags (filter) decode, You can increase safety by filtering the danger label.

                        +

                        注:虽然此功能能极大地扩展 Markdown 语法,但也面临着安全上的风险,所以默认是不开启的。

                        +

                        Update: 可以通过设置 `settings.htmlDecode = "style,script,iframe|on*"`来实现过滤指定标签及属性的解析,提高安全性;

                        +
                        +
                        + + + + +
                        +
                        + +
                        +
                        + + + + + + \ No newline at end of file diff --git a/public/editormd/examples/image-cross-domain-upload.html b/public/editormd/examples/image-cross-domain-upload.html new file mode 100644 index 000000000..3c4228854 --- /dev/null +++ b/public/editormd/examples/image-cross-domain-upload.html @@ -0,0 +1,109 @@ + + + + + 图片跨域上传示例 - Editor.md examples + + + + + +
                        +
                        +

                        图片跨域上传示例

                        +

                        Image cross-domain upload example.

                        +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/image-upload.html b/public/editormd/examples/image-upload.html new file mode 100644 index 000000000..69014cc75 --- /dev/null +++ b/public/editormd/examples/image-upload.html @@ -0,0 +1,68 @@ + + + + + 图片上传示例 - Editor.md examples + + + + + +
                        +
                        +

                        图片上传示例

                        +

                        Image upload example

                        +
                        +
                        + +
                        +
                        + + + + + \ No newline at end of file diff --git a/public/editormd/examples/images/4.jpg b/public/editormd/examples/images/4.jpg new file mode 100644 index 000000000..948f88c0b Binary files /dev/null and b/public/editormd/examples/images/4.jpg differ diff --git a/public/editormd/examples/images/7.jpg b/public/editormd/examples/images/7.jpg new file mode 100644 index 000000000..c1806731c Binary files /dev/null and b/public/editormd/examples/images/7.jpg differ diff --git a/public/editormd/examples/images/8.jpg b/public/editormd/examples/images/8.jpg new file mode 100644 index 000000000..f56e66eb6 Binary files /dev/null and b/public/editormd/examples/images/8.jpg differ diff --git a/public/editormd/examples/images/editormd-screenshot.png b/public/editormd/examples/images/editormd-screenshot.png new file mode 100644 index 000000000..f63f633ba Binary files /dev/null and b/public/editormd/examples/images/editormd-screenshot.png differ diff --git a/public/editormd/examples/index.html b/public/editormd/examples/index.html new file mode 100644 index 000000000..69c0b4248 --- /dev/null +++ b/public/editormd/examples/index.html @@ -0,0 +1,356 @@ + + + + + Editor.md examples + + + + + + + +
                        + +

                        Basic

                        + +

                        + TOP + 自定义 Customs +

                        + +

                        + TOP + Markdown Extras +

                        + +

                        + TOP + Image Upload +

                        + +

                        + TOP + 事件处理 Events handle +

                        + +
                        + +
                        + + + + \ No newline at end of file diff --git a/public/editormd/examples/js/jquery.min.js b/public/editormd/examples/js/jquery.min.js new file mode 100644 index 000000000..348704637 --- /dev/null +++ b/public/editormd/examples/js/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
                        ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; +if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
                        a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
                        ","
                        "],area:[1,"",""],param:[1,"",""],thead:[1,"","
                        "],tr:[2,"","
                        "],col:[2,"","
                        "],td:[3,"","
                        "],_default:k.htmlSerialize?[0,"",""]:[1,"X
                        ","
                        "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("" : "" ) + + "" + + "" + (function(){ + return (settings.imageUpload) ? "
                        " + + "" + + // "" + + "" + + "
                        " : ""; + })() + + "
                        " + + "" + + "" + + "
                        " + + "" + + "" + + "
                        " + + ( (settings.imageUpload) ? "" : ""); + + //var imageFooterHTML = ""; + + dialog = this.createDialog({ + title : imageLang.title, + width : (settings.imageUpload) ? 465 : 380, + height : 278, + name : dialogName, + content : dialogContent, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + lockScreen : false, // settings.dialogLockScreen, 这个setting从哪里传来的 + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var url = this.find("[data-url]").val(); + var alt = this.find("[data-alt]").val(); + var link = this.find("[data-link]").val(); + + if (url === "") + { + alert(imageLang.imageURLEmpty); + return false; + } + + var altAttr = (alt !== "") ? " \"" + alt + "\"" : ""; + + if (link === "" || link === "http://") + { + cm.replaceSelection("![" + alt + "](" + url + altAttr + ")"); + } + else + { + cm.replaceSelection("[![" + alt + "](" + url + altAttr + ")](" + link + altAttr + ")"); + } + + if (alt === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + + dialog.attr("id", classPrefix + "image-dialog-" + guid); + + if (!settings.imageUpload) { + return ; + } + + var fileInput = dialog.find("[name=\"" + classPrefix + "image-file\"]"); + + fileInput.bind("change", function() { + var fileName = fileInput.val(); + var isImage = new RegExp("(\\.(" + settings.imageFormats.join("|") + "))$"); // /(\.(webp|jpg|jpeg|gif|bmp|png))$/ + + if (fileName === "") + { + alert(imageLang.uploadFileEmpty); + + return false; + } + + if (!isImage.test(fileName)) + { + alert(imageLang.formatNotAllowed + settings.imageFormats.join(", ")); + + return false; + } + + loading(true); + + var submitHandler = function() { + + // 解決多个弹出框时,getElementById(iframeName);总是返回第一个dialog的iframe的问题 + var uploadIframe = $(this).parents('.editormd-dialog-container').find('#editormd-image-iframe')[0]; +// var uploadIframe = document.getElementById(iframeName); + + uploadIframe.onload = function() { + + + var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body; + var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null); + + json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")"); + + // https://www.trustie.net/issues/16197 + // 问题描述:当一个页面有2个mdeditor时,先在下面这个md上传图片,再去上面那个md上传图片后,dialog一直显示加载中 + // 这里,visibleDialog是用户看到的dialog,但是实际用来处理跨域请求的dialog在这个场景下是那个看不见的dialog + // 暂没有更好的处理方式,只好将可见的dialog和看不见的dialog分开处理 + // 可见的dialog: 请求成功后 需要调用loading方法隐藏dialog;需要调用val方法将请求返回的url值写到dialog输入框里 + // 不可见的dialog:该dialog的iframe里有跨域请求的json响应信息 + var visibleDialog = $('.editormd-dialog:visible'); + loading(false, visibleDialog); + // 新版 {"id":227354,"filesize":8253} + if (json.id) { + visibleDialog.find("[data-url]").val('/api/attachments/' + json.id); + } else if (json.success === 1) + { + visibleDialog.find("[data-url]").val(json.url); + } + else + { + alert(json.message); + } + + return false; + }; + }; + + dialog.find("[type=\"submit\"]").bind("click", submitHandler).trigger("click"); + }); + } + + dialog = editor.find("." + dialogName); + dialog.find("[type=\"text\"]").val(""); + dialog.find("[type=\"file\"]").val(""); + dialog.find("[data-link]").val("http://"); + + this.dialogShowMask(dialog); + // this.dialogLockScreen(); + dialog.show(); + + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/public/editormd/plugins/link-dialog/link-dialog.js b/public/editormd/plugins/link-dialog/link-dialog.js new file mode 100644 index 000000000..c0c0c581a --- /dev/null +++ b/public/editormd/plugins/link-dialog/link-dialog.js @@ -0,0 +1,133 @@ +/*! + * Link dialog plugin for Editor.md + * + * @file link-dialog.js + * @author pandao + * @version 1.2.1 + * @updateTime 2015-06-09 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var pluginName = "link-dialog"; + + exports.fn.linkDialog = function() { + + var _this = this; + var cm = this.cm; + var editor = this.editor; + var settings = this.settings; + var selection = cm.getSelection(); + var lang = this.lang; + var linkLang = lang.dialog.link; + var classPrefix = this.classPrefix; + var dialogName = classPrefix + pluginName, dialog; + + cm.focus(); + + if (editor.find("." + dialogName).length > 0) + { + dialog = editor.find("." + dialogName); + dialog.find("[data-url]").val("http://"); + dialog.find("[data-title]").val(selection); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + } + else + { + var dialogHTML = "
                        " + + "" + + "" + + "
                        " + + "" + + "" + + "
                        " + + "
                        "; + + dialog = this.createDialog({ + title : linkLang.title, + width : 380, + height : 211, + content : dialogHTML, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var url = this.find("[data-url]").val(); + var title = this.find("[data-title]").val(); + + if (url === "http://" || url === "") + { + alert(linkLang.urlEmpty); + return false; + } + + /*if (title === "") + { + alert(linkLang.titleEmpty); + return false; + }*/ + + var str = "[" + title + "](" + url + " \"" + title + "\")"; + + if (title == "") + { + str = "[" + url + "](" + url + ")"; + } + + cm.replaceSelection(str); + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/public/editormd/plugins/plugin-template.js b/public/editormd/plugins/plugin-template.js new file mode 100644 index 000000000..836d8c63e --- /dev/null +++ b/public/editormd/plugins/plugin-template.js @@ -0,0 +1,111 @@ +/*! + * Link dialog plugin for Editor.md + * + * @file link-dialog.js + * @author pandao + * @version 1.2.0 + * @updateTime 2015-03-07 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var $ = jQuery; // if using module loader(Require.js/Sea.js). + + var langs = { + "zh-cn" : { + toolbar : { + table : "表格" + }, + dialog : { + table : { + title : "添加表格", + cellsLabel : "单元格数", + alignLabel : "对齐方式", + rows : "行数", + cols : "列数", + aligns : ["默认", "左对齐", "居中对齐", "右对齐"] + } + } + }, + "zh-tw" : { + toolbar : { + table : "添加表格" + }, + dialog : { + table : { + title : "添加表格", + cellsLabel : "單元格數", + alignLabel : "對齊方式", + rows : "行數", + cols : "列數", + aligns : ["默認", "左對齊", "居中對齊", "右對齊"] + } + } + }, + "en" : { + toolbar : { + table : "Tables" + }, + dialog : { + table : { + title : "Tables", + cellsLabel : "Cells", + alignLabel : "Align", + rows : "Rows", + cols : "Cols", + aligns : ["Default", "Left align", "Center align", "Right align"] + } + } + } + }; + + exports.fn.htmlEntities = function() { + /* + var _this = this; // this == the current instance object of Editor.md + var lang = _this.lang; + var settings = _this.settings; + var editor = this.editor; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var classPrefix = this.classPrefix; + + $.extend(true, this.lang, langs[this.lang.name]); // l18n + this.setToolbar(); + + cm.focus(); + */ + //.... + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/public/editormd/plugins/preformatted-text-dialog/preformatted-text-dialog.js b/public/editormd/plugins/preformatted-text-dialog/preformatted-text-dialog.js new file mode 100644 index 000000000..e19bbd54a --- /dev/null +++ b/public/editormd/plugins/preformatted-text-dialog/preformatted-text-dialog.js @@ -0,0 +1,172 @@ +/*! + * Preformatted text dialog plugin for Editor.md + * + * @file preformatted-text-dialog.js + * @author pandao + * @version 1.2.0 + * @updateTime 2015-03-07 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + var cmEditor; + var pluginName = "preformatted-text-dialog"; + + exports.fn.preformattedTextDialog = function() { + + var _this = this; + var cm = this.cm; + var lang = this.lang; + var editor = this.editor; + var settings = this.settings; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var classPrefix = this.classPrefix; + var dialogLang = lang.dialog.preformattedText; + var dialogName = classPrefix + pluginName, dialog; + + cm.focus(); + + if (editor.find("." + dialogName).length > 0) + { + dialog = editor.find("." + dialogName); + dialog.find("textarea").val(selection); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + } + else + { + var dialogContent = ""; + + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 780, + height : 540, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + content : dialogContent, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var codeTexts = this.find("textarea").val(); + + if (codeTexts === "") + { + alert(dialogLang.emptyAlert); + return false; + } + + codeTexts = codeTexts.split("\n"); + + for (var i in codeTexts) + { + codeTexts[i] = " " + codeTexts[i]; + } + + codeTexts = codeTexts.join("\n"); + + if (cursor.ch !== 0) { + codeTexts = "\r\n\r\n" + codeTexts; + } + + cm.replaceSelection(codeTexts); + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + var cmConfig = { + mode : "text/html", + theme : settings.theme, + tabSize : 4, + autofocus : true, + autoCloseTags : true, + indentUnit : 4, + lineNumbers : true, + lineWrapping : true, + extraKeys : {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, + foldGutter : true, + gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + matchBrackets : true, + indentWithTabs : true, + styleActiveLine : true, + styleSelectedText : true, + autoCloseBrackets : true, + showTrailingSpace : true, + highlightSelectionMatches : true + }; + + var textarea = dialog.find("textarea"); + var cmObj = dialog.find(".CodeMirror"); + + if (dialog.find(".CodeMirror").length < 1) + { + cmEditor = exports.$CodeMirror.fromTextArea(textarea[0], cmConfig); + cmObj = dialog.find(".CodeMirror"); + + cmObj.css({ + "float" : "none", + margin : "0 0 5px", + border : "1px solid #ddd", + fontSize : settings.fontSize, + width : "100%", + height : "410px" + }); + + cmEditor.on("change", function(cm) { + textarea.val(cm.getValue()); + }); + } + else + { + cmEditor.setValue(cm.getSelection()); + } + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/public/editormd/plugins/reference-link-dialog/reference-link-dialog.js b/public/editormd/plugins/reference-link-dialog/reference-link-dialog.js new file mode 100644 index 000000000..fea88f294 --- /dev/null +++ b/public/editormd/plugins/reference-link-dialog/reference-link-dialog.js @@ -0,0 +1,153 @@ +/*! + * Reference link dialog plugin for Editor.md + * + * @file reference-link-dialog.js + * @author pandao + * @version 1.2.1 + * @updateTime 2015-06-09 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var pluginName = "reference-link-dialog"; + var ReLinkId = 1; + + exports.fn.referenceLinkDialog = function() { + + var _this = this; + var cm = this.cm; + var lang = this.lang; + var editor = this.editor; + var settings = this.settings; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var dialogLang = lang.dialog.referenceLink; + var classPrefix = this.classPrefix; + var dialogName = classPrefix + pluginName, dialog; + + cm.focus(); + + if (editor.find("." + dialogName).length < 1) + { + var dialogHTML = "
                        " + + "" + + "" + + "
                        " + + "" + + "" + + "
                        " + + "" + + "" + + "
                        " + + "" + + "" + + "
                        " + + "
                        "; + + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 380, + height : 296, + content : dialogHTML, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var name = this.find("[data-name]").val(); + var url = this.find("[data-url]").val(); + var rid = this.find("[data-url-id]").val(); + var title = this.find("[data-title]").val(); + + if (name === "") + { + alert(dialogLang.nameEmpty); + return false; + } + + if (rid === "") + { + alert(dialogLang.idEmpty); + return false; + } + + if (url === "http://" || url === "") + { + alert(dialogLang.urlEmpty); + return false; + } + + //cm.replaceSelection("[" + title + "][" + name + "]\n[" + name + "]: " + url + ""); + cm.replaceSelection("[" + name + "][" + rid + "]"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + + title = (title === "") ? "" : " \"" + title + "\""; + + cm.setValue(cm.getValue() + "\n[" + rid + "]: " + url + title + ""); + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + dialog = editor.find("." + dialogName); + dialog.find("[data-name]").val("[" + ReLinkId + "]"); + dialog.find("[data-url-id]").val(""); + dialog.find("[data-url]").val("http://"); + dialog.find("[data-title]").val(selection); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + + ReLinkId++; + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/public/editormd/plugins/table-dialog/table-dialog.js b/public/editormd/plugins/table-dialog/table-dialog.js new file mode 100644 index 000000000..366083f25 --- /dev/null +++ b/public/editormd/plugins/table-dialog/table-dialog.js @@ -0,0 +1,218 @@ +/*! + * Table dialog plugin for Editor.md + * + * @file table-dialog.js + * @author pandao + * @version 1.2.1 + * @updateTime 2015-06-09 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var $ = jQuery; + var pluginName = "table-dialog"; + + var langs = { + "zh-cn" : { + toolbar : { + table : "表格" + }, + dialog : { + table : { + title : "添加表格", + cellsLabel : "单元格数", + alignLabel : "对齐方式", + rows : "行数", + cols : "列数", + aligns : ["默认", "左对齐", "居中对齐", "右对齐"] + } + } + }, + "zh-tw" : { + toolbar : { + table : "添加表格" + }, + dialog : { + table : { + title : "添加表格", + cellsLabel : "單元格數", + alignLabel : "對齊方式", + rows : "行數", + cols : "列數", + aligns : ["默認", "左對齊", "居中對齊", "右對齊"] + } + } + }, + "en" : { + toolbar : { + table : "Tables" + }, + dialog : { + table : { + title : "Tables", + cellsLabel : "Cells", + alignLabel : "Align", + rows : "Rows", + cols : "Cols", + aligns : ["Default", "Left align", "Center align", "Right align"] + } + } + } + }; + + exports.fn.tableDialog = function() { + var _this = this; + var cm = this.cm; + var editor = this.editor; + var settings = this.settings; + var path = settings.path + "../plugins/" + pluginName +"/"; + var classPrefix = this.classPrefix; + var dialogName = classPrefix + pluginName, dialog; + + $.extend(true, this.lang, langs[this.lang.name]); + this.setToolbar(); + + var lang = this.lang; + var dialogLang = lang.dialog.table; + + var dialogContent = [ + "
                        ", + "", + dialogLang.rows + "   ", + dialogLang.cols + "
                        ", + "", + "
                        ", + "
                        " + ].join("\n"); + + if (editor.find("." + dialogName).length > 0) + { + dialog = editor.find("." + dialogName); + + this.dialogShowMask(dialog); + this.dialogLockScreen(); + dialog.show(); + } + else + { + dialog = this.createDialog({ + name : dialogName, + title : dialogLang.title, + width : 360, + height : 244, + mask : settings.dialogShowMask, + drag : settings.dialogDraggable, + content : dialogContent, + lockScreen : settings.dialogLockScreen, + maskStyle : { + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }, + buttons : { + enter : [lang.buttons.enter, function() { + var rows = parseInt(this.find("[data-rows]").val()); + var cols = parseInt(this.find("[data-cols]").val()); + var align = this.find("[name=\"table-align\"]:checked").val(); + var table = ""; + var hrLine = "------------"; + + var alignSign = { + _default : hrLine, + left : ":" + hrLine, + center : ":" + hrLine + ":", + right : hrLine + ":" + }; + + if ( rows > 1 && cols > 0) + { + for (var r = 0, len = rows; r < len; r++) + { + var row = []; + var head = []; + + for (var c = 0, len2 = cols; c < len2; c++) + { + if (r === 1) { + head.push(alignSign[align]); + } + + row.push(" "); + } + + if (r === 1) { + table += "| " + head.join(" | ") + " |" + "\n"; + } + + table += "| " + row.join( (cols === 1) ? "" : " | " ) + " |" + "\n"; + } + } + + cm.replaceSelection(table); + + this.hide().lockScreen(false).hideMask(); + + return false; + }], + + cancel : [lang.buttons.cancel, function() { + this.hide().lockScreen(false).hideMask(); + + return false; + }] + } + }); + } + + var faBtns = dialog.find(".fa-btns"); + + if (faBtns.html() === "") + { + var icons = ["align-justify", "align-left", "align-center", "align-right"]; + var _lang = dialogLang.aligns; + var values = ["_default", "left", "center", "right"]; + + for (var i = 0, len = icons.length; i < len; i++) + { + var checked = (i === 0) ? " checked=\"checked\"" : ""; + var btn = ""; + + faBtns.append(btn); + } + } + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/public/editormd/plugins/test-plugin/test-plugin.js b/public/editormd/plugins/test-plugin/test-plugin.js new file mode 100644 index 000000000..573a9b50a --- /dev/null +++ b/public/editormd/plugins/test-plugin/test-plugin.js @@ -0,0 +1,66 @@ +/*! + * Test plugin for Editor.md + * + * @file test-plugin.js + * @author pandao + * @version 1.2.0 + * @updateTime 2015-03-07 + * {@link https://github.com/pandao/editor.md} + * @license MIT + */ + +(function() { + + var factory = function (exports) { + + var $ = jQuery; // if using module loader(Require.js/Sea.js). + + exports.testPlugin = function(){ + alert("testPlugin"); + }; + + exports.fn.testPluginMethodA = function() { + /* + var _this = this; // this == the current instance object of Editor.md + var lang = _this.lang; + var settings = _this.settings; + var editor = this.editor; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var classPrefix = this.classPrefix; + + cm.focus(); + */ + //.... + + alert("testPluginMethodA"); + }; + + }; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) { // for Require.js + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("./../../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); diff --git a/public/editormd/scss/editormd.codemirror.scss b/public/editormd/scss/editormd.codemirror.scss new file mode 100644 index 000000000..ad400b022 --- /dev/null +++ b/public/editormd/scss/editormd.codemirror.scss @@ -0,0 +1,89 @@ +@charset "UTF-8"; + +.editormd .CodeMirror, #{$prefix}preview { + display: inline-block; + width: 50%; + height: 100%; + vertical-align: top; + @include box-sizing(border-box); + margin: 0; +} + +#{$prefix}preview { + position: absolute; + top: 35px; + right: 0; + right: -1px\0; + overflow: auto; + line-height: 1.6; + display: none; + background: #fff; +} + +.editormd { + + .CodeMirror { + z-index: 10; + float: left; + border-right: 1px solid $borderColor; + font-size: 14px; + font-family: "YaHei Consolas Hybrid", Consolas, "微软雅黑", "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, "Monaco", courier, monospace; + line-height: 1.6; + margin-top: 35px; + + pre { + font-size: 14px; + padding: 0 12px; + } + } + + .CodeMirror-linenumbers { + padding: 0 5px; + } + + .CodeMirror-selected { + background: #70B7FF; + } + + .CodeMirror-focused .CodeMirror-selected { + background: #70B7FF; + } + + .CodeMirror, .CodeMirror-scroll, #{$prefix}preview { + -webkit-overflow-scrolling : touch; + } + + .styled-background { + background-color: #ff7; + } + + .CodeMirror-focused .cm-matchhighlight { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==); + background-position: bottom; + background-repeat: repeat-x; + } + + .CodeMirror-empty { + //outline: 1px solid #c22; + + &.CodeMirror-focused { + outline: none; + } + } + + .CodeMirror pre.CodeMirror-placeholder { + color: #999; + } + + .cm-trailingspace { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; + } + + .cm-tab { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=); + background-position: right; + background-repeat: no-repeat; + } +} \ No newline at end of file diff --git a/public/editormd/scss/editormd.dialog.scss b/public/editormd/scss/editormd.dialog.scss new file mode 100644 index 000000000..34168ef5b --- /dev/null +++ b/public/editormd/scss/editormd.dialog.scss @@ -0,0 +1,184 @@ +@charset "UTF-8"; + +#{$prefix}dialog { + color: $color; + position: fixed; + z-index: 99999; + display: none; + @include border-radius(3px); + @include box-shadow(0 0 10px rgba(0, 0, 0, 0.3)); + //@include user-select(none); + background: #fff; + font-size: 14px; +} + +#{$prefix}dialog-container { + position: relative; + padding: 20px; + line-height: 1.4; + + h1 { + font-size: 24px; + margin-bottom: 10px; + + .fa { + color: #2C7EEA; + padding-right: 5px; + } + + small { + padding-left: 5px; + font-weight: normal; + font-size: 12px; + color: #999; + } + } + + select { + color: #999; + padding: 3px 8px; + border: 1px solid $borderColor; + } +} + +#{$prefix}dialog-close { + position: absolute; + top: 12px; + right: 15px; + font-size: 18px; + color: #ccc; + @include transition(color 300ms ease-out); + + &:hover { + color: #999; + } +} + +#{$prefix}dialog-header { + padding: 11px 20px; + border-bottom: 1px solid #eee; + @include transition(background 300ms ease-out); + + &:hover { + background: #f6f6f6; + } +} + +#{$prefix}dialog-title { + font-size: 14px; +} + +#{$prefix}dialog-footer { + padding: 10px 0 0 0; + text-align: right; +} + +#{$prefix}dialog-info { + width: 420px; + + h1 { + font-weight: normal; + } + + #{$prefix}dialog-container { + padding: 20px 25px 25px; + } + + #{$prefix}dialog-close { + top: 10px; + right: 10px; + } + + p > a, .hover-link:hover { + color: #2196F3; + } + + .hover-link { + color: #666; + } + + a { + .fa-external-link { + display: none; + } + + &:hover { + color: #2196F3; + + .fa-external-link { + display: inline-block; + } + } + } +} + +#{$prefix}mask, +#{$prefix}container-mask, +#{$prefix}dialog-mask { + display: none; + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; +} + +#{$prefix}mask, +#{$prefix}dialog-mask-bg { + background: #fff; + opacity: 0.5; + filter: alpha(opacity=50); +} + +#{$prefix}mask { + position: fixed; + background: #000; + @include opacity(0.2); + z-index: 99998; +} + +#{$prefix}container-mask, +#{$prefix}dialog-mask-con { + background: url(../images/loading.gif) no-repeat center center; + @include background-size(32px 32px); +} + +#{$prefix}container-mask { + z-index: 20; + display: block; + background-color: #fff; +} + +@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) { + #{$prefix}container-mask, + #{$prefix}dialog-mask-con { + background-image: url(../images/loading@2x.gif); + } +} + +@media only screen and (-webkit-min-device-pixel-ratio: 3), only screen and (min-device-pixel-ratio: 3) { + #{$prefix}container-mask, + #{$prefix}dialog-mask-con { + background-image: url(../images/loading@3x.gif); + } +} + +#{$prefix}code-block-dialog, +#{$prefix}preformatted-text-dialog { + textarea { + width: 100%; + height: 400px; + margin-bottom: 6px; + overflow: auto; + border: 1px solid #eee; + background: #fff; + padding: 15px; + resize: none; + } +} + +#{$prefix}code-toolbar { + color: #999; + font-size: 14px; + margin: -5px 0 10px; +} \ No newline at end of file diff --git a/public/editormd/scss/editormd.form.scss b/public/editormd/scss/editormd.form.scss new file mode 100644 index 000000000..8a12c70c2 --- /dev/null +++ b/public/editormd/scss/editormd.form.scss @@ -0,0 +1,130 @@ +@charset "UTF-8"; + +// Form + +#{$prefix}form { + color: $color; + + label { + float: left; + display: block; + width: 75px; + text-align: left; + padding: 7px 0 15px 5px; + margin: 0 0 2px; + font-weight: normal; + } + + br { + clear: both; + } + + iframe { + display: none; + } + + input:focus { + outline: 0; + } + + input[type="text"], input[type="number"] { + color: #999; + padding: 8px; + border: 1px solid $borderColor; + } + + input[type="number"] { + width: 40px; + display: inline-block; + padding: 6px 8px; + } + + input[type="text"] { + display: inline-block; + width: 264px; + } + + .fa-btns { + display: inline-block; + + a { + color: #999; + padding: 7px 10px 0 0; + display: inline-block; + text-decoration: none; + text-align: center; + } + + .fa { + font-size: 1.3em; + } + + label { + float: none; + display: inline-block; + width: auto; + text-align: left; + padding: 0 0 0 5px; + cursor: pointer; + } + } +} + +#{$prefix}form, +#{$prefix}dialog-container, +#{$prefix}dialog-footer { + + input[type="submit"], #{$prefix}btn, button { + color: $color; + min-width: 75px; + cursor: pointer; + background: #fff; + padding: 7px 10px; + border: 1px solid #ddd; + @include border-radius(3px); + @include transition(background 300ms ease-out); + + &:hover { + background: #eee; + } + } + + #{$prefix}btn { + padding: 5px 8px 4px\0; + } + + #{$prefix}btn + #{$prefix}btn { + margin-left: 8px; + } +} + +#{$prefix}file-input { + width: 75px; + height: 32px; + margin-left: 8px; + position: relative; + display: inline-block; + + input[type="file"] { + width: 75px; + height: 32px; + opacity: 0; + cursor: pointer; + background: #000; + display: inline-block; + position: absolute; + top: 0; + right: 0; + + &::-webkit-file-upload-button { + visibility: hidden; + } + } + + input[type="submit"] { + } + + &:hover input[type="submit"] { + background: #eee; + } +} \ No newline at end of file diff --git a/public/editormd/scss/editormd.grid.scss b/public/editormd/scss/editormd.grid.scss new file mode 100644 index 000000000..1946183ee --- /dev/null +++ b/public/editormd/scss/editormd.grid.scss @@ -0,0 +1,36 @@ +@charset "utf-8"; + +.editormd-grid-table { + width: 99%; + display: table; + border: 1px solid #ddd; + border-collapse: collapse; +} + +.editormd-grid-table-row { + width: 100%; + display: table-row; + + a { + font-size: 1.4em; + width: 5%; + height: 36px; + color: #999; + text-align: center; + display: table-cell; + vertical-align: middle; + border: 1px solid #ddd; + text-decoration: none; + @include transition(background-color 300ms ease-out, color 100ms ease-in); + + &.selected { + color: #666; + background-color: #eee; + } + + &:hover { + color: #777; + background-color: #f6f6f6; + } + } +} \ No newline at end of file diff --git a/public/editormd/scss/editormd.logo.scss b/public/editormd/scss/editormd.logo.scss new file mode 100644 index 000000000..7f4c3b846 --- /dev/null +++ b/public/editormd/scss/editormd.logo.scss @@ -0,0 +1,89 @@ +@charset "UTF-8"; + +@import "lib/variables"; +@import "lib/prefixes"; + +@font-face { + font-family: 'editormd-logo'; + src:url('../fonts/editormd-logo.eot?-5y8q6h'); + src:url('.../fonts/editormd-logo.eot?#iefix-5y8q6h') format('embedded-opentype'), + url('../fonts/editormd-logo.woff?-5y8q6h') format('woff'), + url('../fonts/editormd-logo.ttf?-5y8q6h') format('truetype'), + url('../fonts/editormd-logo.svg?-5y8q6h#icomoon') format('svg'); + font-weight: normal; + font-style: normal; +} + +#{$prefix}logo, +#{$prefix}logo-1x, +#{$prefix}logo-2x, +#{$prefix}logo-3x, +#{$prefix}logo-4x, +#{$prefix}logo-5x, +#{$prefix}logo-6x, +#{$prefix}logo-7x, +#{$prefix}logo-8x { + font-family: 'editormd-logo'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + font-size: inherit; + line-height: 1; + display: inline-block; + text-rendering: auto; + vertical-align: inherit; + + //Better Font Rendering + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + &:before { + content: "\e1987"; + /* + HTML Entity 󡦇 + example: + */ + } +} + +#{$prefix}logo-1x { + font-size: 1em; +} + +#{$prefix}logo-lg { + font-size: 1.2em; +} + +#{$prefix}logo-2x { + font-size: 2em; +} + +#{$prefix}logo-3x { + font-size: 3em; +} + +#{$prefix}logo-4x { + font-size: 4em; +} + +#{$prefix}logo-5x { + font-size: 5em; +} + +#{$prefix}logo-6x { + font-size: 6em; +} + +#{$prefix}logo-7x { + font-size: 7em; +} + +#{$prefix}logo-8x { + font-size: 8em; +} + +#{$prefix}logo-color { + color: $mainColor; +} \ No newline at end of file diff --git a/public/editormd/scss/editormd.menu.scss b/public/editormd/scss/editormd.menu.scss new file mode 100644 index 000000000..cfb5db4cb --- /dev/null +++ b/public/editormd/scss/editormd.menu.scss @@ -0,0 +1,113 @@ +@charset "UTF-8"; + +#{$prefix}menu { + margin: 0; + padding: 0; + list-style: none; + + > li { + margin: 0; + padding: 5px 1px; + display: inline-block; + position: relative; + + &.divider { + display: inline-block; + text-indent: -9999px; + margin: 0 5px; + height: 65%; + border-right: 1px solid $borderColor; + } + + > a { + outline: 0; + color: $color; + display: inline-block; + min-width: 24px; + font-size: 16px; + text-decoration: none; + text-align: center; + @include border-radius(2px); + border: 1px solid #fff; + @include transition(all 300ms ease-out); + + &:hover, &.active { + border: 1px solid $borderColor; + background: #eee; + } + + > .fa { + text-align: center; + display: block; + padding: 5px; + } + + > #{$prefix}bold { + padding: 5px 2px; + display: inline-block; + font-weight: bold; + } + } + + &:hover #{$prefix}dropdown-menu { + display: block; + } + } + + > li + li > a { + margin-left: 3px; + } +} + +#{$prefix}dropdown-menu { + display: none; + background: #fff; + border: 1px solid $borderColor; + width: 148px; + list-style: none; + position: absolute; + top: 33px; + left: 0; + z-index: 100; + @include box-shadow(1px 2px 6px rgba(0, 0, 0, 0.15)); + + &:before, &:after { + width: 0; + height: 0; + display: block; + content: ""; + position: absolute; + top: -11px; + left: 8px; + border: 5px solid transparent; + } + + &:before { + border-bottom-color: #ccc; + } + + &:after { + border-bottom-color: #ffffff; + top: -10px; + } + + + > li { + + > a { + color: $color; + display: block; + text-decoration: none; + padding: 8px 10px; + + &:hover { + background: #f6f6f6; + @include transition(all 300ms ease-out); + } + } + } + + > li + li { + border-top: 1px solid $borderColor; + } +} \ No newline at end of file diff --git a/public/editormd/scss/editormd.preview.scss b/public/editormd/scss/editormd.preview.scss new file mode 100644 index 000000000..7673b2602 --- /dev/null +++ b/public/editormd/scss/editormd.preview.scss @@ -0,0 +1,322 @@ +@charset "UTF-8"; + +@import "lib/variables"; +@import "lib/prefixes"; +@import "font-awesome"; + +@import "editormd.logo"; + +// github-markdown.css +@import "github-markdown"; + +#{$prefix}preview-container, #{$prefix}html-preview { + text-align: left; + font-size: 14px; + line-height: 1.6; + padding: 20px; + overflow: auto; + width: 100%; + background-color: #fff; + + blockquote { + color: $color; + border-left: 4px solid $borderColor; + padding-left: 20px; + margin-left: 0; + font-size: 14px; + font-style: italic; + } + + p code { + margin-left: 5px; + margin-right: 4px; + } + + abbr { + background: #ffffdd; + } + + hr { + height: 1px; + border: none; + border-top: 1px solid $borderColor; + background: none; + } + + code { + border: 1px solid $borderColor; + background: #f6f6f6; + padding: 3px; + border-radius: 3px; + font-size: 14px; + } + + pre { + border: 1px solid $borderColor; + background: #f6f6f6; + padding: 10px; + @include border-radius(3px); + + code { + padding: 0; + } + } + + pre, code, kbd { + font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; + } + + table thead tr { + background-color: #F8F8F8; + } + + .markdown-toc { + } + + .markdown-toc-list { + } + + p#{$prefix}tex { + text-align: center; + } + + span#{$prefix}tex { + margin: 0 5px; + } + + .emoji { + width: 24px; + height: 24px; + } + + .katex { + font-size: 1.4em; + } + + .sequence-diagram, .flowchart { + margin: 0 auto; + text-align: center; + + svg { + margin: 0 auto; + } + + text { + font-size : 15px !important; + font-family: "YaHei Consolas Hybrid", Consolas, "Microsoft YaHei", "Malgun Gothic", "Segoe UI", Helvetica, Arial !important; + } + } +} + +//Pretty printing styles. Used with prettify.js. + +@import "prettify"; + +#{$prefix}preview-container, #{$prefix}html-preview { + pre.prettyprint { + padding: 10px; + border: 1px solid $borderColor; + white-space: pre-wrap; + word-wrap: break-word; + } + + ol.linenums { + color: #999; + padding-left: 2.5em; + + li { + list-style-type: decimal; + + code { + border: none; + background:none; + padding: 0; + } + } + } +} + +#{$prefix}preview-container, #{$prefix}html-preview { + + #{$prefix}toc-menu { + margin: 8px 0 12px 0; + display: inline-block; + + > .markdown-toc { + position: relative; + @include border-radius(4px); + border: 1px solid #ddd; + display: inline-block; + font-size: 1em; + + > ul { + width : 160%; + min-width: 180px; + position: absolute; + left: -1px; + top: -2px; + z-index: 100; + padding: 0 10px 10px; + display: none; + background: #fff; + border: 1px solid #ddd; + @include border-radius(4px); + @include box-shadow(0 3px 5px rgba(0, 0, 0, 0.2)); + + > li ul { + width: 100%; + min-width: 180px; + border: 1px solid #ddd; + display: none; + background: #fff; + @include border-radius(4px); + } + + > li a { + color: #666; + padding: 6px 10px; + display: block; + @include transition(background-color 500ms ease-out); + + &:hover { + background-color: #f6f6f6; + } + } + } + + li { + position: relative; + + > ul { + position: absolute; + top: 32px; + left: 10%; + display: none; + @include box-shadow(0 3px 5px rgba(0, 0, 0, 0.2)); + + &:before, &:after { + pointer-events: pointer-events; + position: absolute; + left: 15px; + top: -6px; + display: block; + content: ""; + width: 0; + height: 0; + border: 6px solid transparent; + border-width: 0 6px 6px; + z-index: 10; + } + + &:before { + border-bottom-color: #ccc; + } + + &:after { + border-bottom-color: #ffffff; + top: -5px; + } + } + } + } + + ul { + list-style: none; + } + + a { + text-decoration: none; + } + + h1 { + font-size: 16px; + padding: 5px 0 10px 10px; + line-height: 1; + border-bottom: 1px solid #eee; + + .fa { + padding-left: 10px; + } + } + + .toc-menu-btn { + color: #666; + min-width: 180px; + padding: 5px 10px; + border-radius: 4px; + display: inline-block; + @include transition(background-color 500ms ease-out); + + &:hover { + background-color: #f6f6f6; + } + + .fa { + float: right; + padding: 3px 0 0 10px; + font-size: 1.3em; + } + } + } +} + +.markdown-body { + #{$prefix}toc-menu { + ul { + padding-left: 0; + } + } + + .highlight pre, pre { + line-height: 1.6; + } +} + +hr.editormd-page-break { + border: 1px dotted #ccc; + font-size: 0; + height: 2px; +} + +@media only print { + hr.editormd-page-break { + background: none; + border: none; + height: 0; + } +} + +#{$prefix}html-preview { + textarea { + display : none; + } + + hr.editormd-page-break { + background: none; + border: none; + height: 0; + } +} + +#{$prefix}preview-close-btn { + color: #fff; + padding: 4px 6px; + font-size: 18px; + @include border-radius(500px); + display: none; + background-color: #ccc; + position: absolute; + top: 25px; + right: 35px; + z-index: 19; + @include transition(background-color 300ms ease-out); + + &:hover { + background-color: #999; + } +} + +.editormd-preview-active { + width: 100%; + padding: 40px; +} \ No newline at end of file diff --git a/public/editormd/scss/editormd.preview.themes.scss b/public/editormd/scss/editormd.preview.themes.scss new file mode 100644 index 000000000..bb3829444 --- /dev/null +++ b/public/editormd/scss/editormd.preview.themes.scss @@ -0,0 +1,131 @@ +/* Preview dark theme */ + +#{$prefix}preview-theme-dark { + color: #777; + background:#2C2827; + + #{$prefix}preview-container { + color: #888; + background-color: #2C2827; + //font-family: "Meiryo UI", "Helvetica Neue", "Microsoft YaHei"; + + pre.prettyprint { + border: none; + } + + blockquote { + color: #555; + padding: 0.5em; + background: #222; + border-color: #333; + } + + abbr { + color: #fff; + padding: 1px 3px; + @include border-radius(3px); + background:#ff9900; + } + + code { + color: #fff; + border: none; + padding: 1px 3px; + @include border-radius(3px); + background: #5A9600; + } + + table { + border: none; + } + + .fa-emoji { + color: #B4BF42; + } + + .katex { + color: #FEC93F; + } + } + + .editormd-toc-menu { + > .markdown-toc { + background:#fff; + border:none; + + h1 { + border-color:#ddd; + } + } + } + + .markdown-body { + h1, h2, hr { + border-color: #222; + } + } + + pre { + color: #999; + background-color: #111; + background-color: rgba(0,0,0,.4); + + /* plain text */ + .pln { + color: #999; + } + } + + li.L1, li.L3, li.L5, li.L7, li.L9 { + background: none; + } + + [class*=editormd-logo] { + color: #2196F3; + } + + .sequence-diagram { + text { + fill: #fff; + } + + rect, path { + color:#fff; + fill : #64D1CB; + stroke : #64D1CB; + } + } + + .flowchart { + rect, path { + stroke : #A6C6FF; + } + + rect { + fill: #A6C6FF; + } + + text { + fill: #5879B4; + } + } +} + +@media screen { + + #{$prefix}preview-theme-dark { + .str { color: #080 } /* string content */ + .kwd { color: #ff9900; } /* a keyword */ + .com { color: #444444; } /* a comment */ + .typ { color: #606 } /* a type name */ + .lit { color: #066 } /* a literal value */ + /* punctuation, lisp open bracket, lisp close bracket */ + .pun, .opn, .clo { color: #660 } + .tag { color: #ff9900; } /* a markup tag name */ + .atn { color: #6C95F5; } /* a markup attribute name */ + .atv { color: #080 } /* a markup attribute value */ + .dec, .var { color: #008BA7; } /* a declaration; a variable name */ + .fun { color: red } /* a function name */ + } + +} \ No newline at end of file diff --git a/public/editormd/scss/editormd.scss b/public/editormd/scss/editormd.scss new file mode 100644 index 000000000..e8592ef4e --- /dev/null +++ b/public/editormd/scss/editormd.scss @@ -0,0 +1,137 @@ +@charset "UTF-8"; + +@import "lib/variables"; +@import "lib/prefixes"; + +.editormd { + width: 90%; + height: 640px; + margin: 0 auto; + text-align: left; + overflow: hidden; + position: relative; + margin-bottom: 15px; + border: 1px solid $borderColor; + font-family: "Meiryo UI", "Microsoft YaHei", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, "Monaco", monospace, Tahoma, STXihei, "华文细黑", STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, "宋体", Heiti, "黑体", sans-serif; + + *, *:before, *:after { + @include box-sizing(border-box); + } + + a { + text-decoration: none; + } + + img { + border: none; + vertical-align: middle; + } + + > textarea, + #{$prefix}html-textarea, + #{$prefix}markdown-textarea { + width: 0; + height: 0; + outline: 0; + resize:none; + } + + #{$prefix}html-textarea, + #{$prefix}markdown-textarea { + display : none; + } + + input[type="text"], + input[type="button"], + input[type="submit"], + select, textarea, button { + @include appearance(none); + } + + ::-webkit-scrollbar { + height: 10px; + width: 7px; + background: rgba(0, 0, 0, .1); + + &:hover { + background: rgba(0, 0, 0, .2); + } + } + + ::-webkit-scrollbar-thumb { + background: rgba(0,0,0,0.3); + @include border-radius(6px); + + &:hover { + @include box-shadow(inset 1px 1px 1px rgba(0, 0, 0, .25)); + background-color: rgba(0, 0, 0, .4); + } + } +} + +#{$prefix}user-unselect { + @include user-select(none); +} + +#{$prefix}toolbar { + width: 100%; + min-height: 37px; + background: #fff; + display: none; + position: absolute; + top: 0; + left: 0; + z-index: 10; + border-bottom: 1px solid $borderColor; +} + +#{$prefix}toolbar-container { + padding: 0 8px; + min-height: 35px; + @include user-select(none); +} + +@import "editormd.menu"; + +#{$prefix}container { + margin: 0; + width: 100%; + height: 100%; + overflow: hidden; + padding: 35px 0 0; + position: relative; + background: #fff; + @include box-sizing(border-box); +} + +@import "editormd.dialog"; +@import "editormd.grid"; +@import "editormd.tab"; +@import "editormd.form"; +@import "editormd.codemirror"; +@import "editormd.preview"; +@import "editormd.preview.themes"; + +#{$prefix}onlyread { + #{$prefix}toolbar { + display: none; + } + + .CodeMirror { + margin-top: 0; + } + + #{$prefix}preview { + top: 0; + } +} + +#{$prefix}fullscreen { + position: fixed; + top : 0; + left : 0; + border: none; + margin: 0 auto; +} + +@import "editormd.themes"; \ No newline at end of file diff --git a/public/editormd/scss/editormd.tab.scss b/public/editormd/scss/editormd.tab.scss new file mode 100644 index 000000000..f53bae3e9 --- /dev/null +++ b/public/editormd/scss/editormd.tab.scss @@ -0,0 +1,49 @@ +@charset "utf-8"; + +.editormd-tab { +} + +.editormd-tab-head { + list-style: none; + border-bottom: 1px solid #ddd; + + li { + display: inline-block; + + a { + color: #999; + display: block; + padding: 6px 12px 5px; + text-align: center; + text-decoration: none; + margin-bottom: -1px; + border: 1px solid #ddd; + @include border-top-left-radius(3px); + @include border-top-right-radius(3px); + background: #f6f6f6; + @include transition(all 300ms ease-out); + + &:hover { + color: #666; + background: #eee; + } + } + + &.active a { + color: #666; + background: #fff; + border-bottom-color: #fff; + } + } + + li + li { + margin-left: 3px; + } +} + +.editormd-tab-container { +} + +.editormd-tab-box { + padding: 20px 0; +} \ No newline at end of file diff --git a/public/editormd/scss/editormd.themes.scss b/public/editormd/scss/editormd.themes.scss new file mode 100644 index 000000000..7e206f608 --- /dev/null +++ b/public/editormd/scss/editormd.themes.scss @@ -0,0 +1,28 @@ +/* Editor.md Dark theme */ + +#{$prefix}theme-dark { + border-color: #1a1a17; + + #{$prefix}toolbar { + background: #1A1A17; + border-color: #1a1a17; + } + + #{$prefix}menu > li > a { + color: #777; + border-color: #1a1a17; + + &:hover, &.active { + border-color: #333; + background: #333; + } + } + + #{$prefix}menu > li.divider { + border-right: 1px solid #111; + } + + .CodeMirror { + border-right: 1px solid rgba(0,0,0,0.1); + } +} \ No newline at end of file diff --git a/public/editormd/scss/font-awesome.scss b/public/editormd/scss/font-awesome.scss new file mode 100644 index 000000000..8a9f1cc3b --- /dev/null +++ b/public/editormd/scss/font-awesome.scss @@ -0,0 +1,1801 @@ +/*! + * Font Awesome 4.3.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"; +} diff --git a/public/editormd/scss/github-markdown.scss b/public/editormd/scss/github-markdown.scss new file mode 100644 index 000000000..aa6b38062 --- /dev/null +++ b/public/editormd/scss/github-markdown.scss @@ -0,0 +1,665 @@ +@charset "UTF-8"; + +/*! github-markdown-css | The MIT License (MIT) | Copyright (c) Sindre Sorhus (sindresorhus.com) | https://github.com/sindresorhus/github-markdown-css */ +@font-face { + font-family: octicons-anchor; + src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format('woff'); +} + +.markdown-body { + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + color: #333; + overflow: hidden; + //font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; + font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", "Monaco", monospace, Tahoma, STXihei, "华文细黑", STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, "宋体", Heiti, "黑体", sans-serif; + font-size: 16px; + line-height: 1.6; + word-wrap: break-word; +} + +.markdown-body a { + background: transparent; +} + +.markdown-body a:active, +.markdown-body a:hover { + outline: 0; +} + +.markdown-body strong { + font-weight: bold; +} + +.markdown-body h1 { + font-size: 2em; + margin: 0.67em 0; +} + +.markdown-body img { + border: 0; +} + +.markdown-body hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +.markdown-body pre { + overflow: auto; +} + +.markdown-body code, +.markdown-body kbd, +.markdown-body pre { + font-family: "Meiryo UI", "YaHei Consolas Hybrid", Consolas, "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; + font-size: 1em; +} + +.markdown-body input { + color: inherit; + font: inherit; + margin: 0; +} + +.markdown-body html input[disabled] { + cursor: default; +} + +.markdown-body input { + line-height: normal; +} + +.markdown-body input[type="checkbox"] { + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 0; +} + +.markdown-body table { + border-collapse: collapse; + border-spacing: 0; +} + +.markdown-body td, +.markdown-body th { + padding: 0; +} + +.markdown-body * { + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.markdown-body input { + font: 13px/1.4 Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; +} + +.markdown-body a { + color: #4183c4; + text-decoration: none; +} + +.markdown-body a:hover, +.markdown-body a:active { + text-decoration: underline; +} + +.markdown-body hr { + height: 0; + margin: 15px 0; + overflow: hidden; + background: transparent; + border: 0; + border-bottom: 1px solid #ddd; +} + +.markdown-body hr:before { + display: table; + content: ""; +} + +.markdown-body hr:after { + display: table; + clear: both; + content: ""; +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + margin-top: 15px; + margin-bottom: 15px; + line-height: 1.1; +} + +.markdown-body h1 { + font-size: 30px; +} + +.markdown-body h2 { + font-size: 21px; +} + +.markdown-body h3 { + font-size: 16px; +} + +.markdown-body h4 { + font-size: 14px; +} + +.markdown-body h5 { + font-size: 12px; +} + +.markdown-body h6 { + font-size: 11px; +} + +.markdown-body blockquote { + margin: 0; +} + +.markdown-body ul, +.markdown-body ol { + padding: 0; + margin-top: 0; + margin-bottom: 0; +} + +.markdown-body ol ol, +.markdown-body ul ol { + list-style-type: lower-roman; +} + +.markdown-body ul ul ol, +.markdown-body ul ol ol, +.markdown-body ol ul ol, +.markdown-body ol ol ol { + list-style-type: lower-alpha; +} + +.markdown-body dd { + margin-left: 0; +} + +.markdown-body code { + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 12px; +} + +.markdown-body pre { + margin-top: 0; + margin-bottom: 0; + font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace; +} + +.markdown-body .octicon { + font: normal normal 16px octicons-anchor; + line-height: 1; + display: inline-block; + text-decoration: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.markdown-body .octicon-link:before { + content: '\f05c'; +} + +.markdown-body>*:first-child { + margin-top: 0 !important; +} + +.markdown-body>*:last-child { + margin-bottom: 0 !important; +} + +.markdown-body .anchor { + position: absolute; + top: 0; + left: 0; + display: block; + padding-right: 6px; + padding-left: 30px; + margin-left: -30px; +} + +.markdown-body .anchor:focus { + outline: none; +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + position: relative; + margin-top: 1em; + margin-bottom: 16px; + font-weight: bold; + line-height: 1.4; +} + +.markdown-body h1 .octicon-link, +.markdown-body h2 .octicon-link, +.markdown-body h3 .octicon-link, +.markdown-body h4 .octicon-link, +.markdown-body h5 .octicon-link, +.markdown-body h6 .octicon-link { + display: none; + color: #000; + vertical-align: middle; +} + +.markdown-body h1:hover .anchor, +.markdown-body h2:hover .anchor, +.markdown-body h3:hover .anchor, +.markdown-body h4:hover .anchor, +.markdown-body h5:hover .anchor, +.markdown-body h6:hover .anchor { + padding-left: 8px; + margin-left: -30px; + text-decoration: none; +} + +.markdown-body h1:hover .anchor .octicon-link, +.markdown-body h2:hover .anchor .octicon-link, +.markdown-body h3:hover .anchor .octicon-link, +.markdown-body h4:hover .anchor .octicon-link, +.markdown-body h5:hover .anchor .octicon-link, +.markdown-body h6:hover .anchor .octicon-link { + display: inline-block; +} + +.markdown-body h1 { + padding-bottom: 0.3em; + font-size: 2.25em; + line-height: 1.2; + border-bottom: 1px solid #eee; +} + +.markdown-body h1 .anchor { + line-height: 1; +} + +.markdown-body h2 { + padding-bottom: 0.3em; + font-size: 1.75em; + line-height: 1.225; + border-bottom: 1px solid #eee; +} + +.markdown-body h2 .anchor { + line-height: 1; +} + +.markdown-body h3 { + font-size: 1.5em; + line-height: 1.43; +} + +.markdown-body h3 .anchor { + line-height: 1.2; +} + +.markdown-body h4 { + font-size: 1.25em; +} + +.markdown-body h4 .anchor { + line-height: 1.2; +} + +.markdown-body h5 { + font-size: 1em; +} + +.markdown-body h5 .anchor { + line-height: 1.1; +} + +.markdown-body h6 { + font-size: 1em; + color: #777; +} + +.markdown-body h6 .anchor { + line-height: 1.1; +} + +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body pre { + margin-top: 0; + margin-bottom: 16px; +} +/* +.markdown-body hr { + height: 4px; + padding: 0; + margin: 16px 0; + background-color: #e7e7e7; + border: 0 none; +}*/ + +.markdown-body ul, +.markdown-body ol { + padding-left: 2em; +} + +.markdown-body ul ul, +.markdown-body ul ol, +.markdown-body ol ol, +.markdown-body ol ul { + margin-top: 0; + margin-bottom: 0; +} + +.markdown-body li>p { + margin-top: 16px; +} + +.markdown-body dl { + padding: 0; +} + +.markdown-body dl dt { + padding: 0; + margin-top: 16px; + font-size: 1em; + font-style: italic; + font-weight: bold; +} + +.markdown-body dl dd { + padding: 0 16px; + margin-bottom: 16px; +} + +.markdown-body blockquote { + padding: 0 15px; + color: #777; + border-left: 4px solid #ddd; +} + +.markdown-body blockquote>:first-child { + margin-top: 0; +} + +.markdown-body blockquote>:last-child { + margin-bottom: 0; +} + +.markdown-body table { + display: block; + width: 100%; + overflow: auto; + word-break: normal; + word-break: keep-all; +} + +.markdown-body table th { + font-weight: bold; +} + +.markdown-body table th, +.markdown-body table td { + padding: 6px 13px; + border: 1px solid #ddd; +} + +.markdown-body table tr { + background-color: #fff; + border-top: 1px solid #ccc; +} + +.markdown-body table tr:nth-child(2n) { + background-color: #f8f8f8; +} + +.markdown-body img { + max-width: 100%; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.markdown-body code { + padding: 0; + padding-top: 0.2em; + padding-bottom: 0.2em; + margin: 0; + font-size: 85%; + background-color: rgba(0,0,0,0.04); + border-radius: 3px; +} + +.markdown-body code:before, +.markdown-body code:after { + letter-spacing: -0.2em; + content: "\00a0"; +} + +.markdown-body pre>code { + padding: 0; + margin: 0; + font-size: 100%; + word-break: normal; + white-space: pre; + background: transparent; + border: 0; +} + +.markdown-body .highlight { + margin-bottom: 16px; +} + +.markdown-body .highlight pre, +.markdown-body pre { + padding: 16px; + overflow: auto; + font-size: 85%; + line-height: 1.45; + background-color: #f7f7f7; + border-radius: 3px; +} + +.markdown-body .highlight pre { + margin-bottom: 0; + word-break: normal; +} + +.markdown-body pre { + word-wrap: normal; +} + +.markdown-body pre code { + display: inline; + max-width: initial; + padding: 0; + margin: 0; + overflow: initial; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0; +} + +.markdown-body pre code:before, +.markdown-body pre code:after { + content: normal; +} + +.markdown-body kbd { + display: inline-block; + padding: 3px 5px; + font-size: 11px; + line-height: 10px; + color: #555; + vertical-align: middle; + background-color: #fcfcfc; + border: solid 1px #ccc; + border-bottom-color: #bbb; + border-radius: 3px; + box-shadow: inset 0 -1px 0 #bbb; +} + +.markdown-body .pl-c { + color: #969896; +} + +.markdown-body .pl-c1, +.markdown-body .pl-mdh, +.markdown-body .pl-mm, +.markdown-body .pl-mp, +.markdown-body .pl-mr, +.markdown-body .pl-s1 .pl-v, +.markdown-body .pl-s3, +.markdown-body .pl-sc, +.markdown-body .pl-sv { + color: #0086b3; +} + +.markdown-body .pl-e, +.markdown-body .pl-en { + color: #795da3; +} + +.markdown-body .pl-s1 .pl-s2, +.markdown-body .pl-smi, +.markdown-body .pl-smp, +.markdown-body .pl-stj, +.markdown-body .pl-vo, +.markdown-body .pl-vpf { + color: #333; +} + +.markdown-body .pl-ent { + color: #63a35c; +} + +.markdown-body .pl-k, +.markdown-body .pl-s, +.markdown-body .pl-st { + color: #a71d5d; +} + +.markdown-body .pl-pds, +.markdown-body .pl-s1, +.markdown-body .pl-s1 .pl-pse .pl-s2, +.markdown-body .pl-sr, +.markdown-body .pl-sr .pl-cce, +.markdown-body .pl-sr .pl-sra, +.markdown-body .pl-sr .pl-sre, +.markdown-body .pl-src { + color: #df5000; +} + +.markdown-body .pl-mo, +.markdown-body .pl-v { + color: #1d3e81; +} + +.markdown-body .pl-id { + color: #b52a1d; +} + +.markdown-body .pl-ii { + background-color: #b52a1d; + color: #f8f8f8; +} + +.markdown-body .pl-sr .pl-cce { + color: #63a35c; + font-weight: bold; +} + +.markdown-body .pl-ml { + color: #693a17; +} + +.markdown-body .pl-mh, +.markdown-body .pl-mh .pl-en, +.markdown-body .pl-ms { + color: #1d3e81; + font-weight: bold; +} + +.markdown-body .pl-mq { + color: #008080; +} + +.markdown-body .pl-mi { + color: #333; + font-style: italic; +} + +.markdown-body .pl-mb { + color: #333; + font-weight: bold; +} + +.markdown-body .pl-md, +.markdown-body .pl-mdhf { + background-color: #ffecec; + color: #bd2c00; +} + +.markdown-body .pl-mdht, +.markdown-body .pl-mi1 { + background-color: #eaffea; + color: #55a532; +} + +.markdown-body .pl-mdr { + color: #795da3; + font-weight: bold; +} + +.markdown-body kbd { + display: inline-block; + padding: 3px 5px; + font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace; + line-height: 10px; + color: #555; + vertical-align: middle; + background-color: #fcfcfc; + border: solid 1px #ccc; + border-bottom-color: #bbb; + border-radius: 3px; + box-shadow: inset 0 -1px 0 #bbb; +} + +.markdown-body .task-list-item { + list-style-type: none; +} + +.markdown-body .task-list-item+.task-list-item { + margin-top: 3px; +} + +.markdown-body .task-list-item input { + float: left; + margin: 0.3em 0 0.25em -1.6em; + vertical-align: middle; +} + +.markdown-body :checked+.radio-label { + z-index: 1; + position: relative; + border-color: #4183c4; +} diff --git a/public/editormd/scss/lib/prefixes.scss b/public/editormd/scss/lib/prefixes.scss new file mode 100644 index 000000000..66a2eaf0c --- /dev/null +++ b/public/editormd/scss/lib/prefixes.scss @@ -0,0 +1,784 @@ +@charset "UTF-8"; + +/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */ + +// appearance + +@mixin appearance($value) { + -webkit-appearance: $value; + -moz-appearance: $value; + -ms-appearance: $value; + appearance: $value; +} + +// clearfix + +@mixin clearfix() { + &:before, &:after { + content: " "; + display: table; + } + + &:after { + clear: both; + } +} + +// viewport + +@mixin viewport-device-width() { + width: device-width; + user-zoom: fixed; +} + +@mixin viewport() { + @-webkit-viewport { + @include viewport-device-width(); + } + @-moz-viewport { + @include viewport-device-width(); + } + + @-ms-viewport { + @include viewport-device-width(); + } + + @-o-viewport { + @include viewport-device-width(); + } + + @viewport { + @include viewport-device-width(); + } +} + +// Transform + +@mixin transform($transform) { + -webkit-transform: $transform; /* Safari, Chrome */ + -moz-transform: $transform; /* Firefox 3.5~16.0 */ + -ms-transform: $transform; /* IE9~10 */ + -o-transform: $transform; /* Opera 10.5~12.10 */ + transform: $transform; +} + +@mixin transform-origin($origin) { + -webkit-transform-origin: $origin; + -moz-transform-origin: $origin; /* Firefox 3.5~16.0 */ + -ms-transform-origin: $origin; /* IE9~10 */ + -o-transform-origin: $origin; /* Opera 10.5~12.10 */ + transform-origin: $origin; +} + +@mixin transform-origin-x($origin) { + -webkit-transform-origin-x: $origin; /* Blink, Webkit */ + transform-origin-x: $origin; /* IE11+ */ +} + +@mixin transform-origin-y($origin) { + -webkit-transform-origin-y: $origin; /* Blink, Webkit */ + transform-origin-y: $origin; /* IE11+ */ +} + +@mixin transform-origin-z($origin) { + -webkit-transform-origin-z: $origin; /* Blink, Webkit */ + transform-origin-z: $origin; /* IE11+ */ +} + +@mixin transform-style($style) { + -webkit-transform-style: $style; + -moz-transform-style: $style; /* Firefox 10~16.0 */ + -ms-transform-style: $style; /* IE9~10 */ + transform-style: $style; /* Firefox, Blink, IE11+ */ +} + +// perspective + +@mixin perspective($value) { + -webkit-perspective: $value; /* Safari, Chrome */ + perspective: $value; /* None yet / Non-standard */ +} + +@mixin perspective-origin($value) { + -webkit-perspective-origin: $value; /* Safari, Chrome 12+ */ + -moz-perspective-origin: $value; /* Firefox 10~16 */ + perspective-origin: $value; /* Opera 15+, IE10+ */ +} + +@mixin perspective-origin-x($value) { + -webkit-perspective-origin-x: $value; /* Safari, Chrome 12+ */ + perspective-origin-x: $value; /* IE10+ */ +} + +@mixin perspective-origin-y($value) { + -webkit-perspective-origin-y: $value; /* Safari, Chrome 12+ */ + perspective-origin-y: $value; /* IE10+ */ +} + +@mixin backface-visibility($value : hidden) { + -webkit-backface-visibility: $value; /* Chrome, Safari, Opera 15+ */ + -moz-backface-visibility: $value; /* Firefox */ + -ms-backface-visibility: $value; /* IE10 */ + backface-visibility: $value; +} + +// Transitions IE10+ + +@mixin transition($transition...) { + -webkit-transition: $transition; /* Safari, Chrome */ + -moz-transition: $transition; /* Firefox 4.0~16.0 */ + transition: $transition; /* IE >9, FF >15, Opera >12.0 */ +} + +@mixin transition-property($property) { + -webkit-transition-property: $property; + -moz-transition-property: $property; /* Firefox 4.0~16.0 */ + transition-property: $property; +} + +@mixin transition-duration($duration) { + -webkit-transition-duration: $duration; + -moz-transition-duration: $duration; /* Firefox 4.0~16.0 */ + transition-duration: $duration; +} + +@mixin transition-timing-function($easing) { + -webkit-transition-timing-function: $easing; + -moz-transition-timing-function: $easing; /* Firefox 4.0~16.0 */ + transition-timing-function: $easing; +} + +@mixin transition-delay($delay) { + -webkit-transition-delay: $delay; + -moz-transition-delay: $delay; /* Firefox 4.0~16.0 */ + transition-delay: $delay; +} + +// Flex align + +@mixin align-content($value) { + -webkit-align-content: $value; /* Chrome 21.0+, Safari Not supported. */ + align-content: $value; /* Firefox 28+, Opera 12.10, IE Not supported. */ +} + +@mixin align-items($value) { + -webkit-align-items: $value; /* Safari 7.0+, Chrome 21.0+ */ + align-items: $value; /* Firefox 20.0+, IE11+, Opera 12.10 */ +} + +@mixin align-self($value) { + -webkit-align-self: $value; /* Chrome 21~36, Safari Not supported. */ + align-self: $value; /* Firefox 28+, Opera 12.10, IE Not supported. */ +} + +// Animations IE10+ + +@mixin keyframes($name) { + @-webkit-keyframes #{$name} { + @content; + } + + @-moz-keyframes #{$name} { + @content; + } + + @keyframes #{$name} { + @content; + } +} + +@mixin animation($animation...) { + -webkit-animation: $animation; + -moz-animation: $animation; /* Firefox 5.0~16.0 */ + animation: $animation; /* IE10+ */ +} + +@mixin animation-name($name) { + -webkit-animation-name: $name; + -moz-animation-name: $name; /* Firefox 5.0~16.0 */ + animation-name: $name; +} + +@mixin animation-duration($time : 1s) { + -webkit-animation-duration: $time; + -moz-animation-duration: $time; /* Firefox 5.0~16.0 */ + animation-duration: $time; +} + +@mixin animation-timing-function($easing : ease) { + -webkit-animation-timing-function: $easing; + -moz-animation-timing-function: $easing; /* Firefox 5.0~16.0 */ + animation-timing-function: $easing; +} + +@mixin animation-delay($delay : 1s) { + -webkit-animation-delay: $delay; + -moz-animation-delay: $delay; /* Firefox 5.0~16.0 */ + animation-delay: $delay; +} + +@mixin animation-iteration-count($count : infinite) { + -webkit-animation-iteration-count: $count; + -moz-animation-iteration-count: $count; /* Firefox 5.0~16.0 */ + animation-iteration-count: $count; +} + +// normal or alternate +@mixin animation-direction($direction : normal) { + -webkit-animation-direction: $direction; + -moz-animation-direction: $direction; /* Firefox 5.0~16.0 */ + animation-direction: $direction; +} + +// paused or running + +@mixin animation-play-state($state) { + -webkit-animation-play-state: $state; + -moz-animation-play-state: $state; /* Firefox 5.0~16.0 */ + animation-play-state: $state; +} + +// animation-fill-mode + +@mixin animation-fill-mode($mode) { + -webkit-animation-fill-mode: $mode; + -moz-animation-fill-mode: $mode; + animation-fill-mode: $mode; +} + +// user-select + +@mixin user-select($type) { + -webkit-user-select: $type; + -moz-user-select: $type; + -ms-user-select: $type; + -o-user-select: $type; + user-select: $type; +} + +// border-radius + +@mixin border-radius($radius: 4px) { + -webkit-border-radius: $radius; + -moz-border-radius: $radius; + -ms-border-radius: $radius; + -o-border-radius: $radius; + border-radius: $radius; +} + +@mixin border-top-left-radius($radius: 4px) { + -webkit-border-top-left-radius: $radius; + -moz-border-top-left-radius: $radius; + -ms-border-top-left-radius: $radius; + -o-border-top-left-radius: $radius; + border-top-left-radius: $radius; +} + +@mixin border-top-right-radius($radius: 4px) { + -webkit-border-top-right-radius: $radius; + -moz-border-top-right-radius: $radius; + -ms-border-top-right-radius: $radius; + -o-border-top-right-radius: $radius; + border-top-right-radius: $radius; +} + +@mixin border-bottom-left-radius($radius: 4px) { + -webkit-border-bottom-left-radius: $radius; + -moz-border-bottom-left-radius: $radius; + -ms-border-bottom-left-radius: $radius; + -o-border-bottom-left-radius: $radius; + border-bottom-left-radius: $radius; +} + +@mixin border-bottom-right-radius($radius: 4px) { + -webkit-border-bottom-right-radius: $radius; + -moz-border-bottom-right-radius: $radius; + -ms-border-bottom-right-radius: $radius; + -o-border-bottom-right-radius: $radius; + border-bottom-right-radius: $radius; +} + +// border-image + +@mixin border-image($value) { + -webkit-border-image: $value; /* Safari 5, Chrome */ + -moz-border-image: $value; /* Firefox 3.5~15.0 */ + -o-border-image: $value; /* Opera */ + border-image: $value; /* Safari 6+, Chrome, New */ +} + +@mixin border-image-source($value) { + -webkit-border-image-source: $value; /* Safari 5, Chrome */ + border-image-source: $value; /* Safari 6+, Chrome, IE11+, Opera 15+ */ +} + +@mixin border-image-slice($value) { + -webkit-border-image-slice: $value; /* Safari 5, Chrome */ + border-image-slice: $value; /* Safari 6+, Chrome, IE11+, Opera 15+ */ +} + +@mixin border-image-width($value) { + -webkit-border-image-width: $value; /* Safari 5, Chrome */ + border-image-width: $value; /* Safari 6+, Chrome, IE11+, Opera 15+ */ +} + +@mixin border-image-outset($value) { + -webkit-border-image-outset: $value; /* Safari 5, Chrome */ + border-image-outset: $value; /* Safari 6+, Chrome, IE11+, Opera 15+ */ +} + +@mixin border-image-repeat($value) { + -webkit-border-image-repeat: $value; /* Safari 5, Chrome */ + border-image-repeat: $value; /* Safari 6+, Chrome, IE11+, Opera 15+ */ +} + +// box-shadow + +@mixin box-shadow($value) { + -webkit-box-shadow: $value; /* Webkit browsers */ + -moz-box-shadow: $value; /* Firefox */ + -ms-box-shadow: $value; /* IE9 */ + -o-box-shadow: $value; /* Opera(Old) */ + box-shadow: $value; /* IE9+, News */ +} + +//box-sizing + +@mixin box-sizing($value) { + -webkit-box-sizing: $value; + -moz-box-sizing: $value; + box-sizing: $value; +} + +// box-reflect + +@mixin box-reflect($value) { + -webkit-box-reflect: $value; /* Chrome, Safari, iOS, Blackberry */ + box-reflect: $value; /* None yet / Non-standard */ +} + +// background + +@mixin linear-gradient($start-color, $end-color, $position : top, $perStart : 0%, $perEnd : 100%) { + background: -webkit-linear-gradient($position, $start-color, $end-color); /* Webkit browsers */ + background: -moz-linear-gradient( $position, $start-color, $end-color); /* Firefox(old) */ + background: -o-linear-gradient( $position, $start-color, $end-color); /* Opera(old) */ + background: -ms-linear-gradient( $position, $start-color $perStart, $end-color $perEnd); /* IE10 */ + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, start-colorstr=#{$start-color}, end-colorstr=#{$end-color}); /* IE9 */ + ms-filter: "progid:DXImageTransform.Microsoft.gradient (GradientType=0, start-colorstr=#{$start-color}, end-colorstr=#{$end-color})"; /* IE8 */ + background: linear-gradient( $position, $start-color $perStart, $end-color $perEnd); /* W3C */ +} + +@mixin background-clip($value) { + -webkit-background-clip: $value; + background-clip: $value; /* Firefox 4.0, IE9+, Opera 10.5+, Chrome, Safari 3.0+ */ +} + +@mixin background-origin($value) { + -webkit-background-origin: $value; + background-origin: $value; /* IE9+, Other */ +} + +@mixin background-size($value) { + -webkit-background-size: $value; /* Chrome, iOS, Safari */ + -moz-background-size: $value; /* Firefox 3.6~4.0 */ + -o-background-size: $value; /* Opera 9.5 */ + background-size: $value; /* IE9+, New */ +} + +// Column + +@mixin column-count($value) { + -webkit-column-count: $value; /* Chrome, Safari, Android, Blackberry */ + -moz-column-count: $value; /* Firefox 34+ */ + column-count: $value; /* IE 10+, Opera 11.1+, New */ +} + +@mixin column-gap($value) { + -webkit-column-gap: $value; /* Chrome, Safari, Android, Blackberry */ + -moz-column-gap: $value; /* Firefox 34+ */ + column-gap: $value; /* IE 10+, Opera 11.1+, New */ +} + +@mixin column-rule($value) { + -webkit-column-rule: $value; /* Chrome, Safari, Android, Blackberry */ + -moz-column-rule: $value; /* Firefox 34+ */ + column-rule: $value; /* IE 10+, Opera 11.1+, New */ +} + +@mixin column-rule-color($value) { + -webkit-column-rule-color: $value; /* Chrome, Safari, Android, Blackberry */ + -moz-column-rule-color: $value; /* Firefox 34+ */ + column-rule-color: $value; /* IE 10+, Opera 11.1+, New */ +} + +@mixin column-rule-style($value) { + -webkit-column-rule-style: $value; /* Chrome, Safari, Android, Blackberry */ + -moz-column-rule-style: $value; /* Firefox 34+ */ + column-rule-style: $value; /* IE 10+, Opera 11.1+, New */ +} + +@mixin column-rule-width($value) { + -webkit-column-rule-width: $value; /* Chrome, Safari, Android, Blackberry */ + -moz-column-rule-width: $value; /* Firefox 34+ */ + column-rule-width: $value; /* IE 10+, Opera 11.1+, New */ +} + +@mixin column-fill($value) { + -webkit-column-fill: $value; /* None yet */ + -moz-column-fill: $value; /* Firefox 13.0+ */ + column-fill: $value; /* None yet / Non-standard */ +} + +@mixin column-span($value) { + -webkit-column-span: $value; /* Safari, Chrome, iOS 7.0+, Android, Opera 26+ */ + -moz-column-span: $value; /* Firefox 34+ */ + column-span: $value; /* IE10+, Opera Mini */ +} + +@mixin column-width($value) { + -webkit-column-width: $value; /* Safari, Chrome, iOS 7.0+, Android, Opera 26+ */ + -moz-column-width: $value; /* Firefox */ + column-width: $value; /* IE10+, Opera */ +} + +// columns: column-width column-count; + +@mixin columns($value) { + -webkit-columns: $value; /* Safari, Chrome, iOS 7.0+, Android, Opera 26+ */ + -moz-columns: $value; /* Firefox */ + columns: $value; /* IE10+, Opera */ +} + +// clip-path + +@mixin clip-path($value) { + -webkit-clip-path: $value; /* Chrome, iOS, Safari */ + clip-path: $value; +} + +// display + +@mixin display-grid() { + display: -ms-grid; /* IE 10 */ + display: grid; /* None yet */ +} + +@mixin display-flex() { + display: -webkit-box; /* Old - iOS 6-, Safari 3.1~6, Blackberry 7 */ + display: -ms-flexbox; /* TWEENER - IE 10 */ + display: -webkit-flex; /* New - Safari 6.1+. iOS 7.1+, Blackberry 10 */ + display: flex; /* New, Spec - Firefox, Chrome, Opera */ +} + +@mixin inline-flex($value) { + -webkit-inline-flex: $value; /* Chrome 21.0+ */ + inline-flex: $value; /* Firefox 20+, Opera 12.5 */ +} + +@mixin flex($value) { + -webkit-box-flex: $value; /* Old - iOS 6-, Safari 3.1~6 */ + -webkit-flex: $value; /* Safari 6.1+. iOS 7.1+, Blackberry 10 */ + -ms-flex: $value; /* IE 10 */ + flex: $value; /* New, Spec - Firefox, Chrome, Opera */ +} + +@mixin flex-direction($value) { + -webkit-flex-direction: $value; /* Chrome 21.0+, But Safari & Android & iOS Not supported. */ + flex-direction: $value; /* Firefox 28+, IE11, Opera 12.10 */ +} + +@mixin flex-basis($value) { + -webkit-flex-basis: $value; /* Chrome 21.0+, But Safari & Android & iOS Not supported. */ + flex-basis: $value; /* Firefox 22+, IE11, Opera 12.10 */ +} + +@mixin flex-flow($value) { + -webkit-flex-flow: $value; /* Chrome 21.0+, But Safari & Android & iOS Not supported. */ + flex-flow: $value; /* Firefox 28+, IE11, Opera 12.10 */ +} + +@mixin flex-grow($value) { + -webkit-flex-grow: $value; /* Chrome 21.0+, But Safari & Android & iOS Not supported. */ + flex-grow: $value; /* Firefox 20+, Opera 12.10, IE Not supported. */ +} + +@mixin flex-shrink($value) { + -webkit-flex-shrink: $value; /* Chrome 21.0+, But Safari & Android & iOS Not supported. */ + flex-shrink: $value; /* Firefox 20+, Opera 12.10, IE Not supported. */ +} + +@mixin flex-wrap($value) { + -webkit-flex-wrap: $value; /* Safari 6.1+, Chrome 21.0+, Android 4.4+, iOS 7.0+ */ + flex-wrap: $value; /* Firefox 28+, IE11, Opera 12.10 */ +} + +@mixin order($value) { + -webkit-order: $value; /* Chrome 21+, Safari Not supported. */ + -ms-flex-order: $value; /* IE 10.0 */ + order: $value; /* Firefox 20+, Opera 12.10 */ +} + +// flow + +@mixin flow-into($value) { + -webkit-flow-into: $value; /* Safari 7.1+, iOS Safari 7.1+ */ + -ms-flow-into: $value; /* IE10+ */ + flow-into: $value; /* None yet */ +} + +@mixin flow-from($value) { + -webkit-flow-from: $value; /* Safari 7.1+, iOS Safari 7.1+ */ + -ms-flow-from: $value; /* IE10+ */ + flow-from: $value; /* None yet */ +} + +// filter + +@mixin filter($value) { + -webkit-filter: $value; /* Chrome 23+, Safari 6.0+, Blackberry 10.0+ */ + filter: $value; /* None yet */ +} + +// filter blur + +@mixin filter-blur($value : 10px, $ie-value : 10) { + filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=#{$ie-value}, MakeShadow=false); /* IE6~IE9 */ + -webkit-filter: blur($value); /* Chrome, Opera, iOS, Safari */ + -moz-filter: blur($value); /* Firefox(Old) */ + -ms-filter: blur($value); + filter: blur($value); +} + +@mixin font-kerning($value) { + -webkit-font-kerning: $value; + font-kerning: $value; +} + +// font-feature-settings + +@mixin font-feature-settings($value) { + -webkit-font-feature-settings: $value; /* Chrome 16-26, Blackberry 10 */ + -moz-font-feature-settings: $value; /* Firefox 4-21 */ + font-feature-settings: $value; /* IE 10, Safari 4.0-6.0 */ +} + +@mixin font-variant-ligatures($value) { + -webkit-font-variant-ligatures: $value; + font-variant-ligatures: $value; +} + +// hyphens + +@mixin hyphens($value : auto) { + // Chrome 29- and Android 4.0 Browser support "-webkit-hyphens: none", but not the "auto" property. + -webkit-hyphens: $value; /* Safari 5.1+, Chrome */ + -moz-hyphens: $value; /* Firefox 6.0+ */ + -ms-hyphens: $value; /* IE 10+ */ + hyphens: $value; /* None yet */ +} + +@mixin justify-content($value) { + -webkit-justify-content: $value; /* Chrome 21+, Safari Not supported. */ + justify-content: $value; /* Firefox 20+, Opera 12.10, IE Not supported. */ +} + +// line + +@mixin line-break($value) { + -webkit-line-break: $value; + line-break: $value; +} + +// margin + +@mixin margin-start($value) { + -webkit-margin-start: $value; /* Safari 3.0+, Chrome */ + -moz-margin-start: $value; /* Firefox 1.0+ */ + margin-start: $value; /* None yet / Non-standard */ +} + +@mixin margin-end($value) { + -webkit-margin-end: $value; /* Safari 3.0+, Chrome */ + -moz-margin-end: $value; /* Firefox 1.0+ */ + margin-end: $value; /* None yet / Non-standard */ +} + +// mask + +@mixin mask-image($value) { + -webkit-mask-image: $value; /* Chrome, iOS, Safari */ + mask-image: $value; /* None yet / Non-standard */ +} + +@mixin mask-size($value) { + -webkit-mask-size: $value; /* Chrome, iOS, Safari */ + mask-size: $value; /* None yet / Non-standard */ +} + +@mixin mask-clip($value) { + -webkit-mask-clip: $value; /* Chrome, iOS, Safari */ + mask-clip: $value; /* None yet / Non-standard */ +} + +@mixin mask-position($value) { + -webkit-mask-position: $value; /* Chrome, iOS, Safari */ + mask-position: $value; /* None yet / Non-standard */ +} + +@mixin mask-position-x($value) { + -webkit-mask-position-x: $value; /* Chrome, iOS, Safari */ + mask-position-x: $value; /* None yet / Non-standard */ +} + +@mixin mask-position-y($value) { + -webkit-mask-position-y: $value; /* Chrome, iOS, Safari */ + mask-position-y: $value; /* None yet / Non-standard */ +} + +@mixin mask-origin($value) { + -webkit-mask-origin: $value; /* Chrome, iOS, Safari */ + mask-origin: $value; /* None yet / Non-standard */ +} + +@mixin mask-repeat($value) { + -webkit-mask-repeat: $value; /* Chrome, iOS, Safari */ + mask-repeat: $value; /* None yet / Non-standard */ +} + +@mixin mask-attachment($value) { + -webkit-mask-attachment: $value; /* Chrome, iOS, Safari */ + mask-attachment: $value; /* None yet / Non-standard */ +} + +@mixin mask-composite($value) { + -webkit-mask-composite: $value; /* Chrome, iOS, Safari */ + mask-composite: $value; /* None yet / Non-standard */ +} + +@mixin mask-box-image($value) { + -webkit-mask-box-image: $value; /* Chrome, iOS, Safari */ + mask-box-image: $value; /* None yet / Non-standard */ +} + +// opacity + +@mixin opacity($opacity) { + opacity: $opacity; /* W3C */ + filter: alpha(opacity=($opacity * 100)); /* IE */ +} + +// padding + +@mixin padding-start($value) { + -webkit-padding-start: $value; /* Safari, Chrome, WebKit */ + -moz-padding-start: $value; /* Firefox 3+ */ + padding-start: $value; +} + +@mixin padding-end($value) { + -webkit-padding-end: $value; /* Safari, Chrome, WebKit */ + -moz-padding-end: $value; /* Firefox 3+ */ + padding-end: $value; +} + +// ruby-position + +@mixin ruby-position($value) { + -webkit-ruby-position: $value; /* Blink, Webkit */ + ruby-position: $value; /* Firefox, IE */ +} + +// Text + +@mixin text-size-adjust($value) { + -webkit-text-size-adjust: $value; /* Chrome 27+ */ + -moz-text-size-adjust: $value; /* Firefox */ + text-size-adjust: $value; /* None yet */ +} + +@mixin text-align-last($value) { + -webkit-text-align-last: $value; /* Chrome 35+, Safari Not supported. */ + -moz-text-align-last: $value; /* Firefox 12.0 */ + text-align-last: $value; /* IE 5.5+ */ +} + +@mixin text-justify($value) { + -webkit-text-justify: $value; + text-justify: $value; +} + +@mixin text-decoration-color($value) { + -webkit-text-decoration-color: $value; + text-decoration-color: $value; +} + +@mixin text-decoration-line($value) { + -webkit-text-decoration-line: $value; + text-decoration-line: $value; +} + +@mixin text-decoration-style($value) { + -webkit-text-decoration-style: $value; + text-decoration-style: $value; +} + +@mixin text-orientation($value) { + -webkit-text-orientation: $value; + text-orientation: $value; +} + +@mixin text-underline-position($value) { + -webkit-text-underline-position: $value; /* Chrome 33 not fully supported. */ + text-underline-position: $value; /* IE 5 not fully supported. */ +} + +@mixin text-emphasis($value) { + -webkit-text-emphasis: $value; /* Blink */ + text-emphasis: $value; /* WebKit */ +} + +@mixin text-emphasis-color($value) { + -webkit-text-emphasis-color: $value; /* Blink */ + text-emphasis-color: $value; /* WebKit */ +} + +@mixin text-emphasis-style($value) { + -webkit-text-emphasis-style: $value; /* Blink */ + text-emphasis-style: $value; /* WebKit */ +} + +@mixin text-emphasis-position($value) { + -webkit-text-emphasis-position: $value; /* Blink */ + text-emphasis-position: $value; /* WebKit */ +} + +// tab + +@mixin tab-size($value) { + -webkit-tab-size: $value; /* Chrome 21+, Safari 6.1+ */ + -moz-tab-size: $value; /* Firefox 4.0 */ + -o-tab-size: $value; /* Opera 10.6~15 */ + tab-size: $value; /* Blink & Webkit */ +} + +// input-placeholder + +@mixin input-placeholder($seletor) { + + #{$seletor}::-webkit-input-placeholder { + @content; + } + + #{$seletor}:-moz-placeholder { /* Firefox 4~18 */ + @content; + } + + #{$seletor}::-moz-placeholder { /* Firefox 19+ */ + @content; + } + + #{$seletor}:-ms-input-placeholder { /* IE10+ */ + @content; + } +} \ No newline at end of file diff --git a/public/editormd/scss/lib/variables.scss b/public/editormd/scss/lib/variables.scss new file mode 100644 index 000000000..e5f4b6fda --- /dev/null +++ b/public/editormd/scss/lib/variables.scss @@ -0,0 +1,11 @@ +@charset "UTF-8"; + +// Global Variables + +$prefix : ".editormd-"; +$color : #666; +$mainColor : #2196F3; +$primaryColor : $mainColor; +$secondColor : #33CC66; +$thirdColor : #999999; +$borderColor : #ddd; \ No newline at end of file diff --git a/public/editormd/scss/prettify.scss b/public/editormd/scss/prettify.scss new file mode 100644 index 000000000..c4dd2f681 --- /dev/null +++ b/public/editormd/scss/prettify.scss @@ -0,0 +1,53 @@ +@charset "UTF-8"; + +/*! Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +.pln { color: #000 } /* plain text */ + +@media screen { + .str { color: #080 } /* string content */ + .kwd { color: #008 } /* a keyword */ + .com { color: #800 } /* a comment */ + .typ { color: #606 } /* a type name */ + .lit { color: #066 } /* a literal value */ + /* punctuation, lisp open bracket, lisp close bracket */ + .pun, .opn, .clo { color: #660 } + .tag { color: #008 } /* a markup tag name */ + .atn { color: #606 } /* a markup attribute name */ + .atv { color: #080 } /* a markup attribute value */ + .dec, .var { color: #606 } /* a declaration; a variable name */ + .fun { color: red } /* a function name */ +} + +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { color: #060 } + .kwd { color: #006; font-weight: bold } + .com { color: #600; font-style: italic } + .typ { color: #404; font-weight: bold } + .lit { color: #044 } + .pun, .opn, .clo { color: #440 } + .tag { color: #006; font-weight: bold } + .atn { color: #404 } + .atv { color: #060 } +} + +/* Put a border around prettyprinted code snippets. */ +// pre.prettyprint { padding: 2px; border: 1px solid #888 } + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { margin-top: 0; margin-bottom: 0 } /* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L5, +li.L6, +li.L7, +li.L8 { list-style-type: none } +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { background: #eee } \ No newline at end of file diff --git a/public/editormd/src/editormd.js b/public/editormd/src/editormd.js new file mode 100644 index 000000000..95c65b42f --- /dev/null +++ b/public/editormd/src/editormd.js @@ -0,0 +1,4585 @@ +;(function(factory) { + "use strict"; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) // for Require.js + { + /* Require.js define replace */ + } + else + { + define(["jquery"], factory); // for Sea.js + } + } + else + { + window.editormd = factory(); + } + +}(function() { + + /* Require.js assignment replace */ + + "use strict"; + + var $ = (typeof (jQuery) !== "undefined") ? jQuery : Zepto; + + if (typeof ($) === "undefined") { + return ; + } + + /** + * editormd + * + * @param {String} id 编辑器的ID + * @param {Object} options 配置选项 Key/Value + * @returns {Object} editormd 返回editormd对象 + */ + + var editormd = function (id, options) { + return new editormd.fn.init(id, options); + }; + + editormd.title = editormd.$name = "Editor.md"; + editormd.version = "1.5.0"; + editormd.homePage = "https://pandao.github.io/editor.md/"; + editormd.classPrefix = "editormd-"; + + editormd.toolbarModes = { + full : [ + "undo", "redo", "|", + "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|", + "h1", "h2", "h3", "h4", "h5", "h6", "|", + "list-ul", "list-ol", "hr", "|", + "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|", + "goto-line", "watch", "preview", "fullscreen", "clear", "search", "|", + "help", "info" + ], + simple : [ + "undo", "redo", "|", + "bold", "del", "italic", "quote", "uppercase", "lowercase", "|", + "h1", "h2", "h3", "h4", "h5", "h6", "|", + "list-ul", "list-ol", "hr", "|", + "watch", "preview", "fullscreen", "|", + "help", "info" + ], + mini : [ + "undo", "redo", "|", + "watch", "preview", "|", + "help", "info" + ] + }; + + editormd.defaults = { + mode : "gfm", //gfm or markdown + name : "", // Form element name + value : "", // value for CodeMirror, if mode not gfm/markdown + theme : "", // Editor.md self themes, before v1.5.0 is CodeMirror theme, default empty + editorTheme : "default", // Editor area, this is CodeMirror theme at v1.5.0 + previewTheme : "", // Preview area theme, default empty + markdown : "", // Markdown source code + appendMarkdown : "", // if in init textarea value not empty, append markdown to textarea + width : "100%", + height : "100%", + path : "./lib/", // Dependents module file directory + pluginPath : "", // If this empty, default use settings.path + "../plugins/" + delay : 300, // Delay parse markdown to html, Uint : ms + autoLoadModules : true, // Automatic load dependent module files + watch : true, + placeholder : "Enjoy Markdown! coding now...", + gotoLine : true, + codeFold : false, + autoHeight : false, + autoFocus : true, + autoCloseTags : true, + searchReplace : true, + syncScrolling : true, // true | false | "single", default true + readOnly : false, + tabSize : 4, + indentUnit : 4, + lineNumbers : true, + lineWrapping : true, + autoCloseBrackets : true, + showTrailingSpace : true, + matchBrackets : true, + indentWithTabs : true, + styleSelectedText : true, + matchWordHighlight : true, // options: true, false, "onselected" + styleActiveLine : true, // Highlight the current line + dialogLockScreen : true, + dialogShowMask : true, + dialogDraggable : true, + dialogMaskBgColor : "#fff", + dialogMaskOpacity : 0.1, + fontSize : "13px", + saveHTMLToTextarea : false, + disabledKeyMaps : [], + + onload : function() {}, + onresize : function() {}, + onchange : function() {}, + onwatch : null, + onunwatch : null, + onpreviewing : function() {}, + onpreviewed : function() {}, + onfullscreen : function() {}, + onfullscreenExit : function() {}, + onscroll : function() {}, + onpreviewscroll : function() {}, + + imageUpload : false, + imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"], + imageUploadURL : "", + crossDomainUpload : false, + uploadCallbackURL : "", + + toc : true, // Table of contents + tocm : false, // Using [TOCM], auto create ToC dropdown menu + tocTitle : "", // for ToC dropdown menu btn + tocDropdown : false, + tocContainer : "", + tocStartLevel : 1, // Said from H1 to create ToC + htmlDecode : false, // Open the HTML tag identification + pageBreak : true, // Enable parse page break [========] + atLink : true, // for @link + emailLink : true, // for email address auto link + taskList : false, // Enable Github Flavored Markdown task lists + emoji : false, // :emoji: , Support Github emoji, Twitter Emoji (Twemoji); + // Support FontAwesome icon emoji :fa-xxx: > Using fontAwesome icon web fonts; + // Support Editor.md logo icon emoji :editormd-logo: :editormd-logo-1x: > 1~8x; + tex : false, // TeX(LaTeX), based on KaTeX + flowChart : false, // flowChart.js only support IE9+ + sequenceDiagram : false, // sequenceDiagram.js only support IE9+ + previewCodeHighlight : true, + + toolbar : true, // show/hide toolbar + toolbarAutoFixed : true, // on window scroll auto fixed position + toolbarIcons : "full", + toolbarTitles : {}, + toolbarHandlers : { + ucwords : function() { + return editormd.toolbarHandlers.ucwords; + }, + lowercase : function() { + return editormd.toolbarHandlers.lowercase; + } + }, + toolbarCustomIcons : { // using html tag create toolbar icon, unused default tag. + lowercase : "a", + "ucwords" : "Aa" + }, + toolbarIconsClass : { + undo : "fa-undo", + redo : "fa-repeat", + bold : "fa-bold", + del : "fa-strikethrough", + italic : "fa-italic", + quote : "fa-quote-left", + uppercase : "fa-font", + h1 : editormd.classPrefix + "bold", + h2 : editormd.classPrefix + "bold", + h3 : editormd.classPrefix + "bold", + h4 : editormd.classPrefix + "bold", + h5 : editormd.classPrefix + "bold", + h6 : editormd.classPrefix + "bold", + "list-ul" : "fa-list-ul", + "list-ol" : "fa-list-ol", + hr : "fa-minus", + link : "fa-link", + "reference-link" : "fa-anchor", + image : "fa-picture-o", + code : "fa-code", + "preformatted-text" : "fa-file-code-o", + "code-block" : "fa-file-code-o", + table : "fa-table", + datetime : "fa-clock-o", + emoji : "fa-smile-o", + "html-entities" : "fa-copyright", + pagebreak : "fa-newspaper-o", + "goto-line" : "fa-terminal", // fa-crosshairs + watch : "fa-eye-slash", + unwatch : "fa-eye", + preview : "fa-desktop", + search : "fa-search", + fullscreen : "fa-arrows-alt", + clear : "fa-eraser", + help : "fa-question-circle", + info : "fa-info-circle" + }, + toolbarIconTexts : {}, + + lang : { + name : "zh-cn", + description : "开源在线Markdown编辑器
                        Open source online Markdown editor.", + tocTitle : "目录", + toolbar : { + undo : "撤销(Ctrl+Z)", + redo : "重做(Ctrl+Y)", + bold : "粗体", + del : "删除线", + italic : "斜体", + quote : "引用", + ucwords : "将每个单词首字母转成大写", + uppercase : "将所选转换成大写", + lowercase : "将所选转换成小写", + h1 : "标题1", + h2 : "标题2", + h3 : "标题3", + h4 : "标题4", + h5 : "标题5", + h6 : "标题6", + "list-ul" : "无序列表", + "list-ol" : "有序列表", + hr : "横线", + link : "链接", + "reference-link" : "引用链接", + image : "添加图片", + code : "行内代码", + "preformatted-text" : "预格式文本 / 代码块(缩进风格)", + "code-block" : "代码块(多语言风格)", + table : "添加表格", + datetime : "日期时间", + emoji : "Emoji表情", + "html-entities" : "HTML实体字符", + pagebreak : "插入分页符", + "goto-line" : "跳转到行", + watch : "关闭实时预览", + unwatch : "开启实时预览", + preview : "全窗口预览HTML(按 Shift + ESC还原)", + fullscreen : "全屏(按ESC还原)", + clear : "清空", + search : "搜索", + help : "使用帮助", + info : "关于" + editormd.title + }, + buttons : { + enter : "确定", + cancel : "取消", + close : "关闭" + }, + dialog : { + link : { + title : "添加链接", + url : "链接地址", + urlTitle : "链接标题", + urlEmpty : "错误:请填写链接地址。" + }, + referenceLink : { + title : "添加引用链接", + name : "引用名称", + url : "链接地址", + urlId : "链接ID", + urlTitle : "链接标题", + nameEmpty: "错误:引用链接的名称不能为空。", + idEmpty : "错误:请填写引用链接的ID。", + urlEmpty : "错误:请填写引用链接的URL地址。" + }, + image : { + title : "添加图片", + url : "图片地址", + link : "图片链接", + alt : "图片描述", + uploadButton : "本地上传", + imageURLEmpty : "错误:图片地址不能为空。", + uploadFileEmpty : "错误:上传的图片不能为空。", + formatNotAllowed : "错误:只允许上传图片文件,允许上传的图片文件格式有:" + }, + preformattedText : { + title : "添加预格式文本或代码块", + emptyAlert : "错误:请填写预格式文本或代码的内容。" + }, + codeBlock : { + title : "添加代码块", + selectLabel : "代码语言:", + selectDefaultText : "请选择代码语言", + otherLanguage : "其他语言", + unselectedLanguageAlert : "错误:请选择代码所属的语言类型。", + codeEmptyAlert : "错误:请填写代码内容。" + }, + htmlEntities : { + title : "HTML 实体字符" + }, + help : { + title : "使用帮助" + } + } + } + }; + + editormd.classNames = { + tex : editormd.classPrefix + "tex" + }; + + editormd.dialogZindex = 99999; + + editormd.$katex = null; + editormd.$marked = null; + editormd.$CodeMirror = null; + editormd.$prettyPrint = null; + + var timer, flowchartTimer; + + editormd.prototype = editormd.fn = { + state : { + watching : false, + loaded : false, + preview : false, + fullscreen : false + }, + + /** + * 构造函数/实例初始化 + * Constructor / instance initialization + * + * @param {String} id 编辑器的ID + * @param {Object} [options={}] 配置选项 Key/Value + * @returns {editormd} 返回editormd的实例对象 + */ + + init : function (id, options) { + + options = options || {}; + + if (typeof id === "object") + { + options = id; + } + + var _this = this; + var classPrefix = this.classPrefix = editormd.classPrefix; + var settings = this.settings = $.extend(true, editormd.defaults, options); + + id = (typeof id === "object") ? settings.id : id; + + var editor = this.editor = $("#" + id); + + this.id = id; + this.lang = settings.lang; + + var classNames = this.classNames = { + textarea : { + html : classPrefix + "html-textarea", + markdown : classPrefix + "markdown-textarea" + } + }; + + settings.pluginPath = (settings.pluginPath === "") ? settings.path + "../plugins/" : settings.pluginPath; + + this.state.watching = (settings.watch) ? true : false; + + if ( !editor.hasClass("editormd") ) { + editor.addClass("editormd"); + } + + editor.css({ + width : (typeof settings.width === "number") ? settings.width + "px" : settings.width, + height : (typeof settings.height === "number") ? settings.height + "px" : settings.height + }); + + if (settings.autoHeight) + { + editor.css("height", "auto"); + } + + var markdownTextarea = this.markdownTextarea = editor.children("textarea"); + + if (markdownTextarea.length < 1) + { + editor.append(""); + markdownTextarea = this.markdownTextarea = editor.children("textarea"); + } + + markdownTextarea.addClass(classNames.textarea.markdown).attr("placeholder", settings.placeholder); + + if (typeof markdownTextarea.attr("name") === "undefined" || markdownTextarea.attr("name") === "") + { + markdownTextarea.attr("name", (settings.name !== "") ? settings.name : id + "-markdown-doc"); + } + + var appendElements = [ + (!settings.readOnly) ? "" : "", + ( (settings.saveHTMLToTextarea) ? "" : "" ), + "
                        ", + "
                        ", + "
                        " + ].join("\n"); + + editor.append(appendElements).addClass(classPrefix + "vertical"); + + if (settings.theme !== "") + { + editor.addClass(classPrefix + "theme-" + settings.theme); + } + + this.mask = editor.children("." + classPrefix + "mask"); + this.containerMask = editor.children("." + classPrefix + "container-mask"); + + if (settings.markdown !== "") + { + markdownTextarea.val(settings.markdown); + } + + if (settings.appendMarkdown !== "") + { + markdownTextarea.val(markdownTextarea.val() + settings.appendMarkdown); + } + + this.htmlTextarea = editor.children("." + classNames.textarea.html); + this.preview = editor.children("." + classPrefix + "preview"); + this.previewContainer = this.preview.children("." + classPrefix + "preview-container"); + + if (settings.previewTheme !== "") + { + this.preview.addClass(classPrefix + "preview-theme-" + settings.previewTheme); + } + + if (typeof define === "function" && define.amd) + { + if (typeof katex !== "undefined") + { + editormd.$katex = katex; + } + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(settings.path + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(settings.path + "codemirror/addon/search/matchesonscrollbar"); + } + } + + if ((typeof define === "function" && define.amd) || !settings.autoLoadModules) + { + if (typeof CodeMirror !== "undefined") { + editormd.$CodeMirror = CodeMirror; + } + + if (typeof marked !== "undefined") { + editormd.$marked = marked; + } + + this.setCodeMirror().setToolbar().loadedDisplay(); + } + else + { + this.loadQueues(); + } + + return this; + }, + + /** + * 所需组件加载队列 + * Required components loading queue + * + * @returns {editormd} 返回editormd的实例对象 + */ + + loadQueues : function() { + var _this = this; + var settings = this.settings; + var loadPath = settings.path; + + var loadFlowChartOrSequenceDiagram = function() { + + if (editormd.isIE8) + { + _this.loadedDisplay(); + + return ; + } + + if (settings.flowChart || settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "raphael.min", function() { + + editormd.loadScript(loadPath + "underscore.min", function() { + + if (!settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + } + else if (settings.flowChart && !settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + _this.loadedDisplay(); + }); + }); + } + else if (settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + }); + }); + } + }); + + }); + } + else + { + _this.loadedDisplay(); + } + }; + + editormd.loadCSS(loadPath + "codemirror/codemirror.min"); + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(loadPath + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(loadPath + "codemirror/addon/search/matchesonscrollbar"); + } + + if (settings.codeFold) + { + editormd.loadCSS(loadPath + "codemirror/addon/fold/foldgutter"); + } + + editormd.loadScript(loadPath + "codemirror/codemirror.min", function() { + editormd.$CodeMirror = CodeMirror; + + editormd.loadScript(loadPath + "codemirror/modes.min", function() { + + editormd.loadScript(loadPath + "codemirror/addons.min", function() { + + _this.setCodeMirror(); + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + _this.loadedDisplay(); + + return false; + } + + _this.setToolbar(); + + editormd.loadScript(loadPath + "marked.min", function() { + + editormd.$marked = marked; + + if (settings.previewCodeHighlight) + { + editormd.loadScript(loadPath + "prettify.min", function() { + loadFlowChartOrSequenceDiagram(); + }); + } + else + { + loadFlowChartOrSequenceDiagram(); + } + }); + + }); + + }); + + }); + + return this; + }, + + /** + * 设置 Editor.md 的整体主题,主要是工具栏 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setTheme : function(theme) { + var editor = this.editor; + var oldTheme = this.settings.theme; + var themePrefix = this.classPrefix + "theme-"; + + editor.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + this.settings.theme = theme; + + return this; + }, + + /** + * 设置 CodeMirror(编辑区)的主题 + * Setting CodeMirror (Editor area) theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setEditorTheme : function(theme) { + var settings = this.settings; + settings.editorTheme = theme; + + if (theme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + this.cm.setOption("theme", theme); + + return this; + }, + + /** + * setEditorTheme() 的别名 + * setEditorTheme() alias + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorTheme : function (theme) { + this.setEditorTheme(theme); + + return this; + }, + + /** + * 设置 Editor.md 的主题 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setPreviewTheme : function(theme) { + var preview = this.preview; + var oldTheme = this.settings.previewTheme; + var themePrefix = this.classPrefix + "preview-theme-"; + + preview.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + this.settings.previewTheme = theme; + + return this; + }, + + /** + * 配置和初始化CodeMirror组件 + * CodeMirror initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirror : function() { + var settings = this.settings; + var editor = this.editor; + + if (settings.editorTheme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + var codeMirrorConfig = { + mode : settings.mode, + theme : settings.editorTheme, + tabSize : settings.tabSize, + dragDrop : false, + autofocus : settings.autoFocus, + autoCloseTags : settings.autoCloseTags, + readOnly : (settings.readOnly) ? "nocursor" : false, + indentUnit : settings.indentUnit, + lineNumbers : settings.lineNumbers, + lineWrapping : settings.lineWrapping, + extraKeys : { + "Ctrl-Q": function(cm) { + cm.foldCode(cm.getCursor()); + } + }, + foldGutter : settings.codeFold, + gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + matchBrackets : settings.matchBrackets, + indentWithTabs : settings.indentWithTabs, + styleActiveLine : settings.styleActiveLine, + styleSelectedText : settings.styleSelectedText, + autoCloseBrackets : settings.autoCloseBrackets, + showTrailingSpace : settings.showTrailingSpace, + highlightSelectionMatches : ( (!settings.matchWordHighlight) ? false : { showToken: (settings.matchWordHighlight === "onselected") ? false : /\w/ } ) + }; + + this.codeEditor = this.cm = editormd.$CodeMirror.fromTextArea(this.markdownTextarea[0], codeMirrorConfig); + this.codeMirror = this.cmElement = editor.children(".CodeMirror"); + + if (settings.value !== "") + { + this.cm.setValue(settings.value); + } + + this.codeMirror.css({ + fontSize : settings.fontSize, + width : (!settings.watch) ? "100%" : "50%" + }); + + if (settings.autoHeight) + { + this.codeMirror.css("height", "auto"); + this.cm.setOption("viewportMargin", Infinity); + } + + if (!settings.lineNumbers) + { + this.codeMirror.find(".CodeMirror-gutters").css("border-right", "none"); + } + + return this; + }, + + /** + * 获取CodeMirror的配置选项 + * Get CodeMirror setting options + * + * @returns {Mixed} return CodeMirror setting option value + */ + + getCodeMirrorOption : function(key) { + return this.cm.getOption(key); + }, + + /** + * 配置和重配置CodeMirror的选项 + * CodeMirror setting options / resettings + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorOption : function(key, value) { + + this.cm.setOption(key, value); + + return this; + }, + + /** + * 添加 CodeMirror 键盘快捷键 + * Add CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + addKeyMap : function(map, bottom) { + this.cm.addKeyMap(map, bottom); + + return this; + }, + + /** + * 移除 CodeMirror 键盘快捷键 + * Remove CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + removeKeyMap : function(map) { + this.cm.removeKeyMap(map); + + return this; + }, + + /** + * 跳转到指定的行 + * Goto CodeMirror line + * + * @param {String|Intiger} line line number or "first"|"last" + * @returns {editormd} 返回editormd的实例对象 + */ + + gotoLine : function (line) { + + var settings = this.settings; + + if (!settings.gotoLine) + { + return this; + } + + var cm = this.cm; + var editor = this.editor; + var count = cm.lineCount(); + var preview = this.preview; + + if (typeof line === "string") + { + if(line === "last") + { + line = count; + } + + if (line === "first") + { + line = 1; + } + } + + if (typeof line !== "number") + { + alert("Error: The line number must be an integer."); + return this; + } + + line = parseInt(line) - 1; + + if (line > count) + { + alert("Error: The line number range 1-" + count); + + return this; + } + + cm.setCursor( {line : line, ch : 0} ); + + var scrollInfo = cm.getScrollInfo(); + var clientHeight = scrollInfo.clientHeight; + var coords = cm.charCoords({line : line, ch : 0}, "local"); + + cm.scrollTo(null, (coords.top + coords.bottom - clientHeight) / 2); + + if (settings.watch) + { + var cmScroll = this.codeMirror.find(".CodeMirror-scroll")[0]; + var height = $(cmScroll).height(); + var scrollTop = cmScroll.scrollTop; + var percent = (scrollTop / cmScroll.scrollHeight); + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= cmScroll.scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop(preview[0].scrollHeight * percent); + } + } + + cm.focus(); + + return this; + }, + + /** + * 扩展当前实例对象,可同时设置多个或者只设置一个 + * Extend editormd instance object, can mutil setting. + * + * @returns {editormd} this(editormd instance object.) + */ + + extend : function() { + if (typeof arguments[1] !== "undefined") + { + if (typeof arguments[1] === "function") + { + arguments[1] = $.proxy(arguments[1], this); + } + + this[arguments[0]] = arguments[1]; + } + + if (typeof arguments[0] === "object" && typeof arguments[0].length === "undefined") + { + $.extend(true, this, arguments[0]); + } + + return this; + }, + + /** + * 设置或扩展当前实例对象,单个设置 + * Extend editormd instance object, one by one + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + set : function (key, value) { + + if (typeof value !== "undefined" && typeof value === "function") + { + value = $.proxy(value, this); + } + + this[key] = value; + + return this; + }, + + /** + * 重新配置 + * Resetting editor options + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + config : function(key, value) { + var settings = this.settings; + + if (typeof key === "object") + { + settings = $.extend(true, settings, key); + } + + if (typeof key === "string") + { + settings[key] = value; + } + + this.settings = settings; + this.recreate(); + + return this; + }, + + /** + * 注册事件处理方法 + * Bind editor event handle + * + * @param {String} eventType event type + * @param {Function} callback 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + on : function(eventType, callback) { + var settings = this.settings; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = $.proxy(callback, this); + } + + return this; + }, + + /** + * 解除事件处理方法 + * Unbind editor event handle + * + * @param {String} eventType event type + * @returns {editormd} this(editormd instance object.) + */ + + off : function(eventType) { + var settings = this.settings; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = function(){}; + } + + return this; + }, + + /** + * 显示工具栏 + * Display toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + showToolbar : function(callback) { + var settings = this.settings; + + if(settings.readOnly) { + return this; + } + + if (settings.toolbar && (this.toolbar.length < 1 || this.toolbar.find("." + this.classPrefix + "menu").html() === "") ) + { + this.setToolbar(); + } + + settings.toolbar = true; + + this.toolbar.show(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 隐藏工具栏 + * Hide toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + hideToolbar : function(callback) { + var settings = this.settings; + + settings.toolbar = false; + this.toolbar.hide(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 页面滚动时工具栏的固定定位 + * Set toolbar in window scroll auto fixed position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarAutoFixed : function(fixed) { + + var state = this.state; + var editor = this.editor; + var toolbar = this.toolbar; + var settings = this.settings; + + if (typeof fixed !== "undefined") + { + settings.toolbarAutoFixed = fixed; + } + + var autoFixedHandle = function(){ + var $window = $(window); + var top = $window.scrollTop(); + + if (!settings.toolbarAutoFixed) + { + return false; + } + + if (top - editor.offset().top > 10 && top < editor.height()) + { + toolbar.css({ + position : "fixed", + width : editor.width() + "px", + left : ($window.width() - editor.width()) / 2 + "px" + }); + } + else + { + toolbar.css({ + position : "absolute", + width : "100%", + left : 0 + }); + } + }; + + if (!state.fullscreen && !state.preview && settings.toolbar && settings.toolbarAutoFixed) + { + $(window).bind("scroll", autoFixedHandle); + } + + return this; + }, + + /** + * 配置和初始化工具栏 + * Set toolbar and Initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbar : function() { + var settings = this.settings; + + if(settings.readOnly) { + return this; + } + + var editor = this.editor; + var preview = this.preview; + var classPrefix = this.classPrefix; + + var toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + + if (settings.toolbar && toolbar.length < 1) + { + var toolbarHTML = "
                          "; + + editor.append(toolbarHTML); + toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + } + + if (!settings.toolbar) + { + toolbar.hide(); + + return this; + } + + toolbar.show(); + + var icons = (typeof settings.toolbarIcons === "function") ? settings.toolbarIcons() + : ((typeof settings.toolbarIcons === "string") ? editormd.toolbarModes[settings.toolbarIcons] : settings.toolbarIcons); + + var toolbarMenu = toolbar.find("." + this.classPrefix + "menu"), menu = ""; + var pullRight = false; + + for (var i = 0, len = icons.length; i < len; i++) + { + var name = icons[i]; + + if (name === "||") + { + pullRight = true; + } + else if (name === "|") + { + menu += "
                        • |
                        • "; + } + else + { + var isHeader = (/h(\d)/.test(name)); + var index = name; + + if (name === "watch" && !settings.watch) { + index = "unwatch"; + } + + var title = settings.lang.toolbar[index]; + var iconTexts = settings.toolbarIconTexts[index]; + var iconClass = settings.toolbarIconsClass[index]; + + title = (typeof title === "undefined") ? "" : title; + iconTexts = (typeof iconTexts === "undefined") ? "" : iconTexts; + iconClass = (typeof iconClass === "undefined") ? "" : iconClass; + + var menuItem = pullRight ? "
                        • " : "
                        • "; + + if (typeof settings.toolbarCustomIcons[name] !== "undefined" && typeof settings.toolbarCustomIcons[name] !== "function") + { + menuItem += settings.toolbarCustomIcons[name]; + } + else + { + menuItem += ""; + menuItem += ""+((isHeader) ? name.toUpperCase() : ( (iconClass === "") ? iconTexts : "") ) + ""; + menuItem += ""; + } + + menuItem += "
                        • "; + + menu = pullRight ? menuItem + menu : menu + menuItem; + } + } + + toolbarMenu.html(menu); + + toolbarMenu.find("[title=\"Lowercase\"]").attr("title", settings.lang.toolbar.lowercase); + toolbarMenu.find("[title=\"ucwords\"]").attr("title", settings.lang.toolbar.ucwords); + + this.setToolbarHandler(); + this.setToolbarAutoFixed(); + + return this; + }, + + /** + * 工具栏图标事件处理对象序列 + * Get toolbar icons event handlers + * + * @param {Object} cm CodeMirror的实例对象 + * @param {String} name 要获取的事件处理器名称 + * @returns {Object} 返回处理对象序列 + */ + + dialogLockScreen : function() { + $.proxy(editormd.dialogLockScreen, this)(); + + return this; + }, + + dialogShowMask : function(dialog) { + $.proxy(editormd.dialogShowMask, this)(dialog); + + return this; + }, + + getToolbarHandles : function(name) { + var toolbarHandlers = this.toolbarHandlers = editormd.toolbarHandlers; + + return (name && typeof toolbarIconHandlers[name] !== "undefined") ? toolbarHandlers[name] : toolbarHandlers; + }, + + /** + * 工具栏图标事件处理器 + * Bind toolbar icons event handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarHandler : function() { + var _this = this; + var settings = this.settings; + + if (!settings.toolbar || settings.readOnly) { + return this; + } + + var toolbar = this.toolbar; + var cm = this.cm; + var classPrefix = this.classPrefix; + var toolbarIcons = this.toolbarIcons = toolbar.find("." + classPrefix + "menu > li > a"); + var toolbarIconHandlers = this.getToolbarHandles(); + + toolbarIcons.bind(editormd.mouseOrTouch("click", "touchend"), function(event) { + + var icon = $(this).children(".fa"); + var name = icon.attr("name"); + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (name === "") { + return ; + } + + _this.activeIcon = icon; + + if (typeof toolbarIconHandlers[name] !== "undefined") + { + $.proxy(toolbarIconHandlers[name], _this)(cm); + } + else + { + if (typeof settings.toolbarHandlers[name] !== "undefined") + { + $.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection); + } + } + + if (name !== "link" && name !== "reference-link" && name !== "image" && name !== "code-block" && + name !== "preformatted-text" && name !== "watch" && name !== "preview" && name !== "search" && name !== "fullscreen" && name !== "info") + { + cm.focus(); + } + + return false; + + }); + + return this; + }, + + /** + * 动态创建对话框 + * Creating custom dialogs + * + * @param {Object} options 配置项键值对 Key/Value + * @returns {dialog} 返回创建的dialog的jQuery实例对象 + */ + + createDialog : function(options) { + return $.proxy(editormd.createDialog, this)(options); + }, + + /** + * 创建关于Editor.md的对话框 + * Create about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + createInfoDialog : function() { + var _this = this; + var editor = this.editor; + var classPrefix = this.classPrefix; + + var infoDialogHTML = [ + "
                          ", + "
                          ", + "

                          " + editormd.title + "v" + editormd.version + "

                          ", + "

                          " + this.lang.description + "

                          ", + "

                          " + editormd.homePage + "

                          ", + "

                          Copyright © 2015 Pandao, The MIT License.

                          ", + "
                          ", + "", + "
                          " + ].join("\n"); + + editor.append(infoDialogHTML); + + var infoDialog = this.infoDialog = editor.children("." + classPrefix + "dialog-info"); + + infoDialog.find("." + classPrefix + "dialog-close").bind(editormd.mouseOrTouch("click", "touchend"), function() { + _this.hideInfoDialog(); + }); + + infoDialog.css("border", (editormd.isIE8) ? "1px solid #ddd" : "").css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 关于Editor.md对话居中定位 + * Editor.md dialog position handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + infoDialogPosition : function() { + var infoDialog = this.infoDialog; + + var _infoDialogPosition = function() { + infoDialog.css({ + top : ($(window).height() - infoDialog.height()) / 2 + "px", + left : ($(window).width() - infoDialog.width()) / 2 + "px" + }); + }; + + _infoDialogPosition(); + + $(window).resize(_infoDialogPosition); + + return this; + }, + + /** + * 显示关于Editor.md + * Display about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + showInfoDialog : function() { + + $("html,body").css("overflow-x", "hidden"); + + var _this = this; + var editor = this.editor; + var settings = this.settings; + var infoDialog = this.infoDialog = editor.children("." + this.classPrefix + "dialog-info"); + + if (infoDialog.length < 1) + { + this.createInfoDialog(); + } + + this.lockScreen(true); + + this.mask.css({ + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }).show(); + + infoDialog.css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 隐藏关于Editor.md + * Hide about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + hideInfoDialog : function() { + $("html,body").css("overflow-x", ""); + this.infoDialog.hide(); + this.mask.hide(); + this.lockScreen(false); + + return this; + }, + + /** + * 锁屏 + * lock screen + * + * @param {Boolean} lock Boolean 布尔值,是否锁屏 + * @returns {editormd} 返回editormd的实例对象 + */ + + lockScreen : function(lock) { + editormd.lockScreen(lock); + this.resize(); + + return this; + }, + + /** + * 编辑器界面重建,用于动态语言包或模块加载等 + * Recreate editor + * + * @returns {editormd} 返回editormd的实例对象 + */ + + recreate : function() { + var _this = this; + var editor = this.editor; + var settings = this.settings; + + this.codeMirror.remove(); + + this.setCodeMirror(); + + if (!settings.readOnly) + { + if (editor.find(".editormd-dialog").length > 0) { + editor.find(".editormd-dialog").remove(); + } + + if (settings.toolbar) + { + this.getToolbarHandles(); + this.setToolbar(); + } + } + + this.loadedDisplay(true); + + return this; + }, + + /** + * 高亮预览HTML的pre代码部分 + * highlight of preview codes + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewCodeHighlight : function() { + var settings = this.settings; + var previewContainer = this.previewContainer; + + if (settings.previewCodeHighlight) + { + previewContainer.find("pre").addClass("prettyprint linenums"); + + if (typeof prettyPrint !== "undefined") + { + prettyPrint(); + } + } + + return this; + }, + + /** + * 解析TeX(KaTeX)科学公式 + * TeX(KaTeX) Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + katexRender : function() { + + if (timer === null) + { + return this; + } + + this.previewContainer.find("." + editormd.classNames.tex).each(function(){ + var tex = $(this); + editormd.$katex.render(tex.text(), tex[0]); + + tex.find(".katex").css("font-size", "1.6em"); + }); + + return this; + }, + + /** + * 解析和渲染流程图及时序图 + * FlowChart and SequenceDiagram Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + flowChartAndSequenceDiagramRender : function() { + var $this = this; + var settings = this.settings; + var previewContainer = this.previewContainer; + + if (editormd.isIE8) { + return this; + } + + if (settings.flowChart) { + if (flowchartTimer === null) { + return this; + } + + previewContainer.find(".flowchart").flowChart(); + } + + if (settings.sequenceDiagram) { + previewContainer.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); + } + + var preview = $this.preview; + var codeMirror = $this.codeMirror; + var codeView = codeMirror.find(".CodeMirror-scroll"); + + var height = codeView.height(); + var scrollTop = codeView.scrollTop(); + var percent = (scrollTop / codeView[0].scrollHeight); + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= codeView[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + return this; + }, + + /** + * 注册键盘快捷键处理 + * Register CodeMirror keyMaps (keyboard shortcuts). + * + * @param {Object} keyMap KeyMap key/value {"(Ctrl/Shift/Alt)-Key" : function(){}} + * @returns {editormd} return this + */ + + registerKeyMaps : function(keyMap) { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + var toolbarHandlers = editormd.toolbarHandlers; + var disabledKeyMaps = settings.disabledKeyMaps; + + keyMap = keyMap || null; + + if (keyMap) + { + for (var i in keyMap) + { + if ($.inArray(i, disabledKeyMaps) < 0) + { + var map = {}; + map[i] = keyMap[i]; + + cm.addKeyMap(keyMap); + } + } + } + else + { + for (var k in editormd.keyMaps) + { + var _keyMap = editormd.keyMaps[k]; + var handle = (typeof _keyMap === "string") ? $.proxy(toolbarHandlers[_keyMap], _this) : $.proxy(_keyMap, _this); + + if ($.inArray(k, ["F9", "F10", "F11"]) < 0 && $.inArray(k, disabledKeyMaps) < 0) + { + var _map = {}; + _map[k] = handle; + + cm.addKeyMap(_map); + } + } + + $(window).keydown(function(event) { + + var keymaps = { + "120" : "F9", + "121" : "F10", + "122" : "F11" + }; + + if ( $.inArray(keymaps[event.keyCode], disabledKeyMaps) < 0 ) + { + switch (event.keyCode) + { + case 120: + $.proxy(toolbarHandlers["watch"], _this)(); + return false; + break; + + case 121: + $.proxy(toolbarHandlers["preview"], _this)(); + return false; + break; + + case 122: + $.proxy(toolbarHandlers["fullscreen"], _this)(); + return false; + break; + + default: + break; + } + } + }); + } + + return this; + }, + + /** + * 绑定同步滚动 + * + * @returns {editormd} return this + */ + + bindScrollEvent : function() { + + var _this = this; + var preview = this.preview; + var settings = this.settings; + var codeMirror = this.codeMirror; + var mouseOrTouch = editormd.mouseOrTouch; + + if (!settings.syncScrolling) { + return this; + } + + var cmBindScroll = function() { + codeMirror.find(".CodeMirror-scroll").bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + $.proxy(settings.onscroll, _this)(event); + }); + }; + + var cmUnbindScroll = function() { + codeMirror.find(".CodeMirror-scroll").unbind(mouseOrTouch("scroll", "touchmove")); + }; + + var previewBindScroll = function() { + + preview.bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + var codeView = codeMirror.find(".CodeMirror-scroll"); + + if(scrollTop === 0) + { + codeView.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight) + { + codeView.scrollTop(codeView[0].scrollHeight); + } + else + { + codeView.scrollTop(codeView[0].scrollHeight * percent); + } + + $.proxy(settings.onpreviewscroll, _this)(event); + }); + + }; + + var previewUnbindScroll = function() { + preview.unbind(mouseOrTouch("scroll", "touchmove")); + }; + + codeMirror.bind({ + mouseover : cmBindScroll, + mouseout : cmUnbindScroll, + touchstart : cmBindScroll, + touchend : cmUnbindScroll + }); + + if (settings.syncScrolling === "single") { + return this; + } + + preview.bind({ + mouseover : previewBindScroll, + mouseout : previewUnbindScroll, + touchstart : previewBindScroll, + touchend : previewUnbindScroll + }); + + return this; + }, + + bindChangeEvent : function() { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + + if (!settings.syncScrolling) { + return this; + } + + cm.on("change", function(_cm, changeObj) { + + if (settings.watch) + { + _this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + } + + timer = setTimeout(function() { + clearTimeout(timer); + _this.save(); + timer = null; + }, settings.delay); + }); + + return this; + }, + + /** + * 加载队列完成之后的显示处理 + * Display handle of the module queues loaded after. + * + * @param {Boolean} recreate 是否为重建编辑器 + * @returns {editormd} 返回editormd的实例对象 + */ + + loadedDisplay : function(recreate) { + + recreate = recreate || false; + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var settings = this.settings; + + this.containerMask.hide(); + + this.save(); + + if (settings.watch) { + preview.show(); + } + + editor.data("oldWidth", editor.width()).data("oldHeight", editor.height()); // 为了兼容Zepto + + this.resize(); + this.registerKeyMaps(); + + $(window).resize(function(){ + _this.resize(); + }); + + this.bindScrollEvent().bindChangeEvent(); + + if (!recreate) + { + $.proxy(settings.onload, this)(); + } + + this.state.loaded = true; + + return this; + }, + + /** + * 设置编辑器的宽度 + * Set editor width + * + * @param {Number|String} width 编辑器宽度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + width : function(width) { + + this.editor.css("width", (typeof width === "number") ? width + "px" : width); + this.resize(); + + return this; + }, + + /** + * 设置编辑器的高度 + * Set editor height + * + * @param {Number|String} height 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + height : function(height) { + + this.editor.css("height", (typeof height === "number") ? height + "px" : height); + this.resize(); + + return this; + }, + + /** + * 调整编辑器的尺寸和布局 + * Resize editor layout + * + * @param {Number|String} [width=null] 编辑器宽度值 + * @param {Number|String} [height=null] 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + resize : function(width, height) { + + width = width || null; + height = height || null; + + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var codeMirror = this.codeMirror; + + if (width) + { + editor.css("width", (typeof width === "number") ? width + "px" : width); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + editor.css("height", "auto"); + codeMirror.css("height", "auto"); + } + else + { + if (height) + { + editor.css("height", (typeof height === "number") ? height + "px" : height); + } + + if (state.fullscreen) + { + editor.height($(window).height()); + } + + if (settings.toolbar && !settings.readOnly) + { + codeMirror.css("margin-top", toolbar.height() + 1).height(editor.height() - toolbar.height()); + } + else + { + codeMirror.css("margin-top", 0).height(editor.height()); + } + } + + if(settings.watch) + { + codeMirror.width(editor.width() / 2); + preview.width((!state.preview) ? editor.width() / 2 : editor.width()); + + this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + + if (settings.toolbar && !settings.readOnly) + { + preview.css("top", toolbar.height() + 1); + } + else + { + preview.css("top", 0); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + preview.height(""); + } + else + { + var previewHeight = (settings.toolbar && !settings.readOnly) ? editor.height() - toolbar.height() : editor.height(); + + preview.height(previewHeight); + } + } + else + { + codeMirror.width(editor.width()); + preview.hide(); + } + + if (state.loaded) + { + $.proxy(settings.onresize, this)(); + } + + return this; + }, + + /** + * 解析和保存Markdown代码 + * Parse & Saving Markdown source code + * + * @returns {editormd} 返回editormd的实例对象 + */ + + save : function() { + + if (timer === null) + { + return this; + } + + var _this = this; + var state = this.state; + var settings = this.settings; + var cm = this.cm; + var cmValue = cm.getValue(); + var previewContainer = this.previewContainer; + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + this.markdownTextarea.val(cmValue); + + return this; + } + + var marked = editormd.$marked; + var markdownToC = this.markdownToC = []; + var rendererOptions = this.markedRendererOptions = { + toc : settings.toc, + tocm : settings.tocm, + tocStartLevel : settings.tocStartLevel, + pageBreak : settings.pageBreak, + taskList : settings.taskList, + emoji : settings.emoji, + tex : settings.tex, + atLink : settings.atLink, // for @link + emailLink : settings.emailLink, // for mail address auto link + flowChart : settings.flowChart, + sequenceDiagram : settings.sequenceDiagram, + previewCodeHighlight : settings.previewCodeHighlight, + }; + + var markedOptions = this.markedOptions = { + renderer : editormd.markedRenderer(markdownToC, rendererOptions), + gfm : true, + tables : true, + breaks : true, + pedantic : false, + sanitize : (settings.htmlDecode) ? false : true, // 关闭忽略HTML标签,即开启识别HTML标签,默认为false + smartLists : true, + smartypants : true + }; + + marked.setOptions(markedOptions); + + var newMarkdownDoc = editormd.$marked(cmValue, markedOptions); + + //console.info("cmValue", cmValue, newMarkdownDoc); + + newMarkdownDoc = editormd.filterHTMLTags(newMarkdownDoc, settings.htmlDecode); + + //console.error("cmValue", cmValue, newMarkdownDoc); + + this.markdownTextarea.text(cmValue); + + cm.save(); + + if (settings.saveHTMLToTextarea) + { + this.htmlTextarea.text(newMarkdownDoc); + } + + if(settings.watch || (!settings.watch && state.preview)) + { + previewContainer.html(newMarkdownDoc); + + this.previewCodeHighlight(); + + if (settings.toc) + { + var tocContainer = (settings.tocContainer === "") ? previewContainer : $(settings.tocContainer); + var tocMenu = tocContainer.find("." + this.classPrefix + "toc-menu"); + + tocContainer.attr("previewContainer", (settings.tocContainer === "") ? "true" : "false"); + + if (settings.tocContainer !== "" && tocMenu.length > 0) + { + tocMenu.remove(); + } + + editormd.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); + + if (settings.tocDropdown || tocContainer.find("." + this.classPrefix + "toc-menu").length > 0) + { + editormd.tocDropdownMenu(tocContainer, (settings.tocTitle !== "") ? settings.tocTitle : this.lang.tocTitle); + } + + if (settings.tocContainer !== "") + { + previewContainer.find(".markdown-toc").css("border", "none"); + } + } + + if (settings.tex) + { + if (!editormd.kaTeXLoaded && settings.autoLoadModules) + { + editormd.loadKaTeX(function() { + editormd.$katex = katex; + editormd.kaTeXLoaded = true; + _this.katexRender(); + }); + } + else + { + editormd.$katex = katex; + this.katexRender(); + } + } + + if (settings.flowChart || settings.sequenceDiagram) + { + flowchartTimer = setTimeout(function(){ + clearTimeout(flowchartTimer); + _this.flowChartAndSequenceDiagramRender(); + flowchartTimer = null; + }, 10); + } + + if (state.loaded) + { + $.proxy(settings.onchange, this)(); + } + } + + return this; + }, + + /** + * 聚焦光标位置 + * Focusing the cursor position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + focus : function() { + this.cm.focus(); + + return this; + }, + + /** + * 设置光标的位置 + * Set cursor position + * + * @param {Object} cursor 要设置的光标位置键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setCursor : function(cursor) { + this.cm.setCursor(cursor); + + return this; + }, + + /** + * 获取当前光标的位置 + * Get the current position of the cursor + * + * @returns {Cursor} 返回一个光标Cursor对象 + */ + + getCursor : function() { + return this.cm.getCursor(); + }, + + /** + * 设置光标选中的范围 + * Set cursor selected ranges + * + * @param {Object} from 开始位置的光标键值对象,例:{line:1, ch:0} + * @param {Object} to 结束位置的光标键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setSelection : function(from, to) { + + this.cm.setSelection(from, to); + + return this; + }, + + /** + * 获取光标选中的文本 + * Get the texts from cursor selected + * + * @returns {String} 返回选中文本的字符串形式 + */ + + getSelection : function() { + return this.cm.getSelection(); + }, + + /** + * 设置光标选中的文本范围 + * Set the cursor selection ranges + * + * @param {Array} ranges cursor selection ranges array + * @returns {Array} return this + */ + + setSelections : function(ranges) { + this.cm.setSelections(ranges); + + return this; + }, + + /** + * 获取光标选中的文本范围 + * Get the cursor selection ranges + * + * @returns {Array} return selection ranges array + */ + + getSelections : function() { + return this.cm.getSelections(); + }, + + /** + * 替换当前光标选中的文本或在当前光标处插入新字符 + * Replace the text at the current cursor selected or insert a new character at the current cursor position + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + replaceSelection : function(value) { + this.cm.replaceSelection(value); + + return this; + }, + + /** + * 在当前光标处插入新字符 + * Insert a new character at the current cursor position + * + * 同replaceSelection()方法 + * With the replaceSelection() method + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + insertValue : function(value) { + this.replaceSelection(value); + + return this; + }, + + /** + * 追加markdown + * append Markdown to editor + * + * @param {String} md 要追加的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + appendMarkdown : function(md) { + var settings = this.settings; + var cm = this.cm; + + cm.setValue(cm.getValue() + md); + + return this; + }, + + /** + * 设置和传入编辑器的markdown源文档 + * Set Markdown source document + * + * @param {String} md 要传入的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + setMarkdown : function(md) { + this.cm.setValue(md || this.settings.markdown); + + return this; + }, + + /** + * 获取编辑器的markdown源文档 + * Set Editor.md markdown/CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getMarkdown : function() { + return this.cm.getValue(); + }, + + /** + * 获取编辑器的源文档 + * Get CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getValue : function() { + return this.cm.getValue(); + }, + + /** + * 设置编辑器的源文档 + * Set CodeMirror value + * + * @param {String} value set code/value/string/text + * @returns {editormd} 返回editormd的实例对象 + */ + + setValue : function(value) { + this.cm.setValue(value); + + return this; + }, + + /** + * 清空编辑器 + * Empty CodeMirror editor container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + clear : function() { + this.cm.setValue(""); + + return this; + }, + + /** + * 获取解析后存放在Textarea的HTML源码 + * Get parsed html code from Textarea + * + * @returns {String} 返回HTML源码 + */ + + getHTML : function() { + if (!this.settings.saveHTMLToTextarea) + { + alert("Error: settings.saveHTMLToTextarea == false"); + + return false; + } + + return this.htmlTextarea.val(); + }, + + /** + * getHTML()的别名 + * getHTML (alias) + * + * @returns {String} Return html code 返回HTML源码 + */ + + getTextareaSavedHTML : function() { + return this.getHTML(); + }, + + /** + * 获取预览窗口的HTML源码 + * Get html from preview container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getPreviewedHTML : function() { + if (!this.settings.watch) + { + alert("Error: settings.watch == false"); + + return false; + } + + return this.previewContainer.html(); + }, + + /** + * 开启实时预览 + * Enable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + watch : function(callback) { + var settings = this.settings; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) + { + return this; + } + + this.state.watching = settings.watch = true; + this.preview.show(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.watch); + icon.removeClass(unWatchIcon).addClass(watchIcon); + } + + this.codeMirror.css("border-right", "1px solid #ddd").width(this.editor.width() / 2); + + timer = 0; + + this.save().resize(); + + if (!settings.onwatch) + { + settings.onwatch = callback || function() {}; + } + + $.proxy(settings.onwatch, this)(); + + return this; + }, + + /** + * 关闭实时预览 + * Disable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + unwatch : function(callback) { + var settings = this.settings; + this.state.watching = settings.watch = false; + this.preview.hide(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.unwatch); + icon.removeClass(watchIcon).addClass(unWatchIcon); + } + + this.codeMirror.css("border-right", "none").width(this.editor.width()); + + this.resize(); + + if (!settings.onunwatch) + { + settings.onunwatch = callback || function() {}; + } + + $.proxy(settings.onunwatch, this)(); + + return this; + }, + + /** + * 显示编辑器 + * Show editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + show : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.show(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器 + * Hide editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + hide : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.hide(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器部分,只预览HTML + * Enter preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewing : function() { + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var codeMirror = this.codeMirror; + var previewContainer = this.previewContainer; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) { + return this; + } + + if (settings.toolbar && toolbar) { + toolbar.toggle(); + toolbar.find(".fa[name=preview]").toggleClass("active"); + } + + codeMirror.toggle(); + + var escHandle = function(event) { + if (event.shiftKey && event.keyCode === 27) { + _this.previewed(); + } + }; + + if (codeMirror.css("display") === "none") // 为了兼容Zepto,而不使用codeMirror.is(":hidden") + { + this.state.preview = true; + + if (this.state.fullscreen) { + preview.css("background", "#fff"); + } + + editor.find("." + this.classPrefix + "preview-close-btn").show().bind(editormd.mouseOrTouch("click", "touchend"), function(){ + _this.previewed(); + }); + + if (!settings.watch) + { + this.save(); + } + else + { + previewContainer.css("padding", ""); + } + + previewContainer.addClass(this.classPrefix + "preview-active"); + + preview.show().css({ + position : "", + top : 0, + width : editor.width(), + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewing, this)(); + } + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.previewed(); + } + }, + + /** + * 显示编辑器部分,退出只预览HTML + * Exit preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewed : function() { + + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var previewContainer = this.previewContainer; + var previewCloseBtn = editor.find("." + this.classPrefix + "preview-close-btn"); + + this.state.preview = false; + + this.codeMirror.show(); + + if (settings.toolbar) { + toolbar.show(); + } + + preview[(settings.watch) ? "show" : "hide"](); + + previewCloseBtn.hide().unbind(editormd.mouseOrTouch("click", "touchend")); + + previewContainer.removeClass(this.classPrefix + "preview-active"); + + if (settings.watch) + { + previewContainer.css("padding", "20px"); + } + + preview.css({ + background : null, + position : "absolute", + width : editor.width() / 2, + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() - toolbar.height(), + top : (settings.toolbar) ? toolbar.height() : 0 + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewed, this)(); + } + + return this; + }, + + /** + * 编辑器全屏显示 + * Fullscreen show + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreen : function() { + + var _this = this; + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var fullscreenClass = this.classPrefix + "fullscreen"; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().toggleClass("active"); + } + + var escHandle = function(event) { + if (!event.shiftKey && event.keyCode === 27) + { + if (state.fullscreen) + { + _this.fullscreenExit(); + } + } + }; + + if (!editor.hasClass(fullscreenClass)) + { + state.fullscreen = true; + + $("html,body").css("overflow", "hidden"); + + editor.css({ + width : $(window).width(), + height : $(window).height() + }).addClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreen, this)(); + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.fullscreenExit(); + } + + return this; + }, + + /** + * 编辑器退出全屏显示 + * Exit fullscreen state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreenExit : function() { + + var editor = this.editor; + var settings = this.settings; + var toolbar = this.toolbar; + var fullscreenClass = this.classPrefix + "fullscreen"; + + this.state.fullscreen = false; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().removeClass("active"); + } + + $("html,body").css("overflow", ""); + + editor.css({ + width : editor.data("oldWidth"), + height : editor.data("oldHeight") + }).removeClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreenExit, this)(); + + return this; + }, + + /** + * 加载并执行插件 + * Load and execute the plugin + * + * @param {String} name plugin name / function name + * @param {String} path plugin load path + * @returns {editormd} 返回editormd的实例对象 + */ + + executePlugin : function(name, path) { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + + path = settings.pluginPath + path; + + if (typeof define === "function") + { + if (typeof this[name] === "undefined") + { + alert("Error: " + name + " plugin is not found, you are not load this plugin."); + + return this; + } + + this[name](cm); + + return this; + } + + if ($.inArray(path, editormd.loadFiles.plugin) < 0) + { + editormd.loadPlugin(path, function() { + editormd.loadPlugins[name] = _this[name]; + _this[name](cm); + }); + } + else + { + $.proxy(editormd.loadPlugins[name], this)(cm); + } + + return this; + }, + + /** + * 搜索替换 + * Search & replace + * + * @param {String} command CodeMirror serach commands, "find, fintNext, fintPrev, clearSearch, replace, replaceAll" + * @returns {editormd} return this + */ + + search : function(command) { + var settings = this.settings; + + if (!settings.searchReplace) + { + alert("Error: settings.searchReplace == false"); + return this; + } + + if (!settings.readOnly) + { + this.cm.execCommand(command || "find"); + } + + return this; + }, + + searchReplace : function() { + this.search("replace"); + + return this; + }, + + searchReplaceAll : function() { + this.search("replaceAll"); + + return this; + } + }; + + editormd.fn.init.prototype = editormd.fn; + + /** + * 锁屏 + * lock screen when dialog opening + * + * @returns {void} + */ + + editormd.dialogLockScreen = function() { + var settings = this.settings || {dialogLockScreen : true}; + + if (settings.dialogLockScreen) + { + $("html,body").css("overflow", "hidden"); + this.resize(); + } + }; + + /** + * 显示透明背景层 + * Display mask layer when dialog opening + * + * @param {Object} dialog dialog jQuery object + * @returns {void} + */ + + editormd.dialogShowMask = function(dialog) { + var editor = this.editor; + var settings = this.settings || {dialogShowMask : true}; + + dialog.css({ + top : ($(window).height() - dialog.height()) / 2 + "px", + left : ($(window).width() - dialog.width()) / 2 + "px" + }); + + if (settings.dialogShowMask) { + editor.children("." + this.classPrefix + "mask").css("z-index", parseInt(dialog.css("z-index")) - 1).show(); + } + }; + + editormd.toolbarHandlers = { + undo : function() { + this.cm.undo(); + }, + + redo : function() { + this.cm.redo(); + }, + + bold : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("**" + selection + "**"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + del : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("~~" + selection + "~~"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + italic : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("*" + selection + "*"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + quote : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("> " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("> " + selection); + } + + //cm.replaceSelection("> " + selection); + //cm.setCursor(cursor.line, (selection === "") ? cursor.ch + 2 : cursor.ch + selection.length + 2); + }, + + ucfirst : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.firstUpperCase(selection)); + cm.setSelections(selections); + }, + + ucwords : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.wordsFirstUpperCase(selection)); + cm.setSelections(selections); + }, + + uppercase : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toUpperCase()); + cm.setSelections(selections); + }, + + lowercase : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toLowerCase()); + cm.setSelections(selections); + }, + + h1 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("# " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("# " + selection); + } + }, + + h2 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("## " + selection); + cm.setCursor(cursor.line, cursor.ch + 3); + } + else + { + cm.replaceSelection("## " + selection); + } + }, + + h3 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("### " + selection); + cm.setCursor(cursor.line, cursor.ch + 4); + } + else + { + cm.replaceSelection("### " + selection); + } + }, + + h4 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("#### " + selection); + cm.setCursor(cursor.line, cursor.ch + 5); + } + else + { + cm.replaceSelection("#### " + selection); + } + }, + + h5 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("##### " + selection); + cm.setCursor(cursor.line, cursor.ch + 6); + } + else + { + cm.replaceSelection("##### " + selection); + } + }, + + h6 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("###### " + selection); + cm.setCursor(cursor.line, cursor.ch + 7); + } + else + { + cm.replaceSelection("###### " + selection); + } + }, + + "list-ul" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (selection === "") + { + cm.replaceSelection("- " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : "- " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + "list-ol" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if(selection === "") + { + cm.replaceSelection("1. " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : (i+1) + ". " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + hr : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(((cursor.ch !== 0) ? "\n\n" : "\n") + "------------\n\n"); + }, + + tex : function() { + if (!this.settings.tex) + { + alert("settings.tex === false"); + return this; + } + + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("$$" + selection + "$$"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + link : function() { + this.executePlugin("linkDialog", "link-dialog/link-dialog"); + }, + + "reference-link" : function() { + this.executePlugin("referenceLinkDialog", "reference-link-dialog/reference-link-dialog"); + }, + + pagebreak : function() { + if (!this.settings.pageBreak) + { + alert("settings.pageBreak === false"); + return this; + } + + var cm = this.cm; + var selection = cm.getSelection(); + + cm.replaceSelection("\r\n[========]\r\n"); + }, + + image : function() { + this.executePlugin("imageDialog", "image-dialog/image-dialog"); + }, + + code : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("`" + selection + "`"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "code-block" : function() { + this.executePlugin("codeBlockDialog", "code-block-dialog/code-block-dialog"); + }, + + "preformatted-text" : function() { + this.executePlugin("preformattedTextDialog", "preformatted-text-dialog/preformatted-text-dialog"); + }, + + table : function() { + this.executePlugin("tableDialog", "table-dialog/table-dialog"); + }, + + datetime : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var date = new Date(); + var langName = this.settings.lang.name; + var datefmt = editormd.dateFormat() + " " + editormd.dateFormat((langName === "zh-cn" || langName === "zh-tw") ? "cn-week-day" : "week-day"); + + cm.replaceSelection(datefmt); + }, + + emoji : function() { + this.executePlugin("emojiDialog", "emoji-dialog/emoji-dialog"); + }, + + "html-entities" : function() { + this.executePlugin("htmlEntitiesDialog", "html-entities-dialog/html-entities-dialog"); + }, + + "goto-line" : function() { + this.executePlugin("gotoLineDialog", "goto-line-dialog/goto-line-dialog"); + }, + + watch : function() { + this[this.settings.watch ? "unwatch" : "watch"](); + }, + + preview : function() { + this.previewing(); + }, + + fullscreen : function() { + this.fullscreen(); + }, + + clear : function() { + this.clear(); + }, + + search : function() { + this.search(); + }, + + help : function() { + this.executePlugin("helpDialog", "help-dialog/help-dialog"); + }, + + info : function() { + this.showInfoDialog(); + } + }; + + editormd.keyMaps = { + "Ctrl-1" : "h1", + "Ctrl-2" : "h2", + "Ctrl-3" : "h3", + "Ctrl-4" : "h4", + "Ctrl-5" : "h5", + "Ctrl-6" : "h6", + "Ctrl-B" : "bold", // if this is string == editormd.toolbarHandlers.xxxx + "Ctrl-D" : "datetime", + + "Ctrl-E" : function() { // emoji + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!this.settings.emoji) + { + alert("Error: settings.emoji == false"); + return ; + } + + cm.replaceSelection(":" + selection + ":"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-Alt-G" : "goto-line", + "Ctrl-H" : "hr", + "Ctrl-I" : "italic", + "Ctrl-K" : "code", + + "Ctrl-L" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("[" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-U" : "list-ul", + + "Shift-Ctrl-A" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!this.settings.atLink) + { + alert("Error: settings.atLink == false"); + return ; + } + + cm.replaceSelection("@" + selection); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "Shift-Ctrl-C" : "code", + "Shift-Ctrl-Q" : "quote", + "Shift-Ctrl-S" : "del", + "Shift-Ctrl-K" : "tex", // KaTeX + + "Shift-Alt-C" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(["```", selection, "```"].join("\n")); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 3); + } + }, + + "Shift-Ctrl-Alt-C" : "code-block", + "Shift-Ctrl-H" : "html-entities", + "Shift-Alt-H" : "help", + "Shift-Ctrl-E" : "emoji", + "Shift-Ctrl-U" : "uppercase", + "Shift-Alt-U" : "ucwords", + "Shift-Ctrl-Alt-U" : "ucfirst", + "Shift-Alt-L" : "lowercase", + + "Shift-Ctrl-I" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("![" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 4); + } + }, + + "Shift-Ctrl-Alt-I" : "image", + "Shift-Ctrl-L" : "link", + "Shift-Ctrl-O" : "list-ol", + "Shift-Ctrl-P" : "preformatted-text", + "Shift-Ctrl-T" : "table", + "Shift-Alt-P" : "pagebreak", + "F9" : "watch", + "F10" : "preview", + "F11" : "fullscreen", + }; + + /** + * 清除字符串两边的空格 + * Clear the space of strings both sides. + * + * @param {String} str string + * @returns {String} trimed string + */ + + var trim = function(str) { + return (!String.prototype.trim) ? str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "") : str.trim(); + }; + + editormd.trim = trim; + + /** + * 所有单词首字母大写 + * Words first to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var ucwords = function (str) { + return str.toLowerCase().replace(/\b(\w)|\s(\w)/g, function($1) { + return $1.toUpperCase(); + }); + }; + + editormd.ucwords = editormd.wordsFirstUpperCase = ucwords; + + /** + * 字符串首字母大写 + * Only string first char to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var firstUpperCase = function(str) { + return str.toLowerCase().replace(/\b(\w)/, function($1){ + return $1.toUpperCase(); + }); + }; + + var ucfirst = firstUpperCase; + + editormd.firstUpperCase = editormd.ucfirst = firstUpperCase; + + editormd.urls = { + atLinkBase : "https://github.com/" + }; + + editormd.regexs = { + atLink : /@(\w+)/g, + email : /(\w+)@(\w+)\.(\w+)\.?(\w+)?/g, + emailLink : /(mailto:)?([\w\.\_]+)@(\w+)\.(\w+)\.?(\w+)?/g, + emoji : /:([\w\+-]+):/g, + emojiDatetime : /(\d{2}:\d{2}:\d{2})/g, + twemoji : /:(tw-([\w]+)-?(\w+)?):/g, + fontAwesome : /:(fa-([\w]+)(-(\w+)){0,}):/g, + editormdLogo : /:(editormd-logo-?(\w+)?):/g, + pageBreak : /^\[[=]{8,}\]$/ + }; + + // Emoji graphics files url path + editormd.emoji = { + path : "http://www.emoji-cheat-sheet.com/graphics/emojis/", + ext : ".png" + }; + + // Twitter Emoji (Twemoji) graphics files url path + editormd.twemoji = { + path : "http://twemoji.maxcdn.com/36x36/", + ext : ".png" + }; + + /** + * 自定义marked的解析器 + * Custom Marked renderer rules + * + * @param {Array} markdownToC 传入用于接收TOC的数组 + * @returns {Renderer} markedRenderer 返回marked的Renderer自定义对象 + */ + + editormd.markedRenderer = function(markdownToC, options) { + var defaults = { + toc : true, // Table of contents + tocm : false, + tocStartLevel : 1, // Said from H1 to create ToC + pageBreak : true, + atLink : true, // for @link + emailLink : true, // for mail address auto link + taskList : false, // Enable Github Flavored Markdown task lists + emoji : false, // :emoji: , Support Twemoji, fontAwesome, Editor.md logo emojis. + tex : false, // TeX(LaTeX), based on KaTeX + flowChart : false, // flowChart.js only support IE9+ + sequenceDiagram : false, // sequenceDiagram.js only support IE9+ + }; + + var settings = $.extend(defaults, options || {}); + var marked = editormd.$marked; + var markedRenderer = new marked.Renderer(); + markdownToC = markdownToC || []; + + var regexs = editormd.regexs; + var atLinkReg = regexs.atLink; + var emojiReg = regexs.emoji; + var emailReg = regexs.email; + var emailLinkReg = regexs.emailLink; + var twemojiReg = regexs.twemoji; + var faIconReg = regexs.fontAwesome; + var editormdLogoReg = regexs.editormdLogo; + var pageBreakReg = regexs.pageBreak; + + markedRenderer.emoji = function(text) { + + text = text.replace(editormd.regexs.emojiDatetime, function($1) { + return $1.replace(/:/g, ":"); + }); + + var matchs = text.match(emojiReg); + + if (!matchs || !settings.emoji) { + return text; + } + + for (var i = 0, len = matchs.length; i < len; i++) + { + if (matchs[i] === ":+1:") { + matchs[i] = ":\\+1:"; + } + + text = text.replace(new RegExp(matchs[i]), function($1, $2){ + var faMatchs = $1.match(faIconReg); + var name = $1.replace(/:/g, ""); + + if (faMatchs) + { + for (var fa = 0, len1 = faMatchs.length; fa < len1; fa++) + { + var faName = faMatchs[fa].replace(/:/g, ""); + + return ""; + } + } + else + { + var emdlogoMathcs = $1.match(editormdLogoReg); + var twemojiMatchs = $1.match(twemojiReg); + + if (emdlogoMathcs) + { + for (var x = 0, len2 = emdlogoMathcs.length; x < len2; x++) + { + var logoName = emdlogoMathcs[x].replace(/:/g, ""); + return ""; + } + } + else if (twemojiMatchs) + { + for (var t = 0, len3 = twemojiMatchs.length; t < len3; t++) + { + var twe = twemojiMatchs[t].replace(/:/g, "").replace("tw-", ""); + return "\"twemoji-""; + } + } + else + { + var src = (name === "+1") ? "plus1" : name; + src = (src === "black_large_square") ? "black_square" : src; + src = (src === "moon") ? "waxing_gibbous_moon" : src; + + return "\":""; + } + } + }); + } + + return text; + }; + + markedRenderer.atLink = function(text) { + + if (atLinkReg.test(text)) + { + if (settings.atLink) + { + text = text.replace(emailReg, function($1, $2, $3, $4) { + return $1.replace(/@/g, "_#_@_#_"); + }); + + text = text.replace(atLinkReg, function($1, $2) { + return "" + $1 + ""; + }).replace(/_#_@_#_/g, "@"); + } + + if (settings.emailLink) + { + text = text.replace(emailLinkReg, function($1, $2, $3, $4, $5) { + return (!$2 && $.inArray($5, "jpg|jpeg|png|gif|webp|ico|icon|pdf".split("|")) < 0) ? ""+$1+"" : $1; + }); + } + + return text; + } + + return text; + }; + + markedRenderer.link = function (href, title, text) { + + if (this.options.sanitize) { + try { + var prot = decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase(); + } catch(e) { + return ""; + } + + if (prot.indexOf("javascript:") === 0) { + return ""; + } + } + + var out = "" + text.replace(/@/g, "@") + ""; + } + + if (title) { + out += " title=\"" + title + "\""; + } + + out += ">" + text + ""; + + return out; + }; + + markedRenderer.heading = function(text, level, raw) { + + var linkText = text; + var hasLinkReg = /\s*\]*)\>(.*)\<\/a\>\s*/; + var getLinkTextReg = /\s*\]+)\>([^\>]*)\<\/a\>\s*/g; + + if (hasLinkReg.test(text)) + { + var tempText = []; + text = text.split(/\]+)\>([^\>]*)\<\/a\>/); + + for (var i = 0, len = text.length; i < len; i++) + { + tempText.push(text[i].replace(/\s*href\=\"(.*)\"\s*/g, "")); + } + + text = tempText.join(" "); + } + + text = trim(text); + + var escapedText = text.toLowerCase().replace(/[^\w]+/g, "-"); + var toc = { + text : text, + level : level, + slug : escapedText + }; + + var isChinese = /^[\u4e00-\u9fa5]+$/.test(text); + var id = (isChinese) ? escape(text).replace(/\%/g, "") : text.toLowerCase().replace(/[^\w]+/g, "-"); + + markdownToC.push(toc); + + var headingHTML = ""; + + headingHTML += ""; + headingHTML += ""; + headingHTML += (hasLinkReg) ? this.atLink(this.emoji(linkText)) : this.atLink(this.emoji(text)); + headingHTML += ""; + + return headingHTML; + }; + + markedRenderer.pageBreak = function(text) { + if (pageBreakReg.test(text) && settings.pageBreak) + { + text = "
                          "; + } + + return text; + }; + + markedRenderer.paragraph = function(text) { + var isTeXInline = /\$\$(.*)\$\$/g.test(text); + var isTeXLine = /^\$\$(.*)\$\$$/.test(text); + var isTeXAddClass = (isTeXLine) ? " class=\"" + editormd.classNames.tex + "\"" : ""; + var isToC = (settings.tocm) ? /^(\[TOC\]|\[TOCM\])$/.test(text) : /^\[TOC\]$/.test(text); + var isToCMenu = /^\[TOCM\]$/.test(text); + + if (!isTeXLine && isTeXInline) + { + text = text.replace(/(\$\$([^\$]*)\$\$)+/g, function($1, $2) { + return "" + $2.replace(/\$/g, "") + ""; + }); + } + else + { + text = (isTeXLine) ? text.replace(/\$/g, "") : text; + } + + var tocHTML = "
                          " + text + "
                          "; + + return (isToC) ? ( (isToCMenu) ? "
                          " + tocHTML + "

                          " : tocHTML ) + : ( (pageBreakReg.test(text)) ? this.pageBreak(text) : "" + this.atLink(this.emoji(text)) + "

                          \n" ); + }; + + markedRenderer.code = function (code, lang, escaped) { + + if (lang === "seq" || lang === "sequence") + { + return "
                          " + code + "
                          "; + } + else if ( lang === "flow") + { + return "
                          " + code + "
                          "; + } + else if ( lang === "math" || lang === "latex" || lang === "katex") + { + return "

                          " + code + "

                          "; + } + else + { + + return marked.Renderer.prototype.code.apply(this, arguments); + } + }; + + markedRenderer.tablecell = function(content, flags) { + var type = (flags.header) ? "th" : "td"; + var tag = (flags.align) ? "<" + type +" style=\"text-align:" + flags.align + "\">" : "<" + type + ">"; + + return tag + this.atLink(this.emoji(content)) + "\n"; + }; + + markedRenderer.listitem = function(text) { + if (settings.taskList && /^\s*\[[x\s]\]\s*/.test(text)) + { + text = text.replace(/^\s*\[\s\]\s*/, " ") + .replace(/^\s*\[x\]\s*/, " "); + + return "
                        • " + this.atLink(this.emoji(text)) + "
                        • "; + } + else + { + return "
                        • " + this.atLink(this.emoji(text)) + "
                        • "; + } + }; + + return markedRenderer; + }; + + /** + * + * 生成TOC(Table of Contents) + * Creating ToC (Table of Contents) + * + * @param {Array} toc 从marked获取的TOC数组列表 + * @param {Element} container 插入TOC的容器元素 + * @param {Integer} startLevel Hx 起始层级 + * @returns {Object} tocContainer 返回ToC列表容器层的jQuery对象元素 + */ + + editormd.markdownToCRenderer = function(toc, container, tocDropdown, startLevel) { + + var html = ""; + var lastLevel = 0; + var classPrefix = this.classPrefix; + + startLevel = startLevel || 1; + + for (var i = 0, len = toc.length; i < len; i++) + { + var text = toc[i].text; + var level = toc[i].level; + + if (level < startLevel) { + continue; + } + + if (level > lastLevel) + { + html += ""; + } + else if (level < lastLevel) + { + html += (new Array(lastLevel - level + 2)).join(""); + } + else + { + html += ""; + } + + html += "
                        • " + text + "
                            "; + lastLevel = level; + } + + var tocContainer = container.find(".markdown-toc"); + + if ((tocContainer.length < 1 && container.attr("previewContainer") === "false")) + { + var tocHTML = "
                            "; + + tocHTML = (tocDropdown) ? "
                            " + tocHTML + "
                            " : tocHTML; + + container.html(tocHTML); + + tocContainer = container.find(".markdown-toc"); + } + + if (tocDropdown) + { + tocContainer.wrap("

                            "); + } + + tocContainer.html("
                              ").children(".markdown-toc-list").html(html.replace(/\r?\n?\\<\/ul\>/g, "")); + + return tocContainer; + }; + + /** + * + * 生成TOC下拉菜单 + * Creating ToC dropdown menu + * + * @param {Object} container 插入TOC的容器jQuery对象元素 + * @param {String} tocTitle ToC title + * @returns {Object} return toc-menu object + */ + + editormd.tocDropdownMenu = function(container, tocTitle) { + + tocTitle = tocTitle || "Table of Contents"; + + var zindex = 400; + var tocMenus = container.find("." + this.classPrefix + "toc-menu"); + + tocMenus.each(function() { + var $this = $(this); + var toc = $this.children(".markdown-toc"); + var icon = ""; + var btn = "" + icon + tocTitle + ""; + var menu = toc.children("ul"); + var list = menu.find("li"); + + toc.append(btn); + + list.first().before("
                            • " + tocTitle + " " + icon + "

                            • "); + + $this.mouseover(function(){ + menu.show(); + + list.each(function(){ + var li = $(this); + var ul = li.children("ul"); + + if (ul.html() === "") + { + ul.remove(); + } + + if (ul.length > 0 && ul.html() !== "") + { + var firstA = li.children("a").first(); + + if (firstA.children(".fa").length < 1) + { + firstA.append( $(icon).css({ float:"right", paddingTop:"4px" }) ); + } + } + + li.mouseover(function(){ + ul.css("z-index", zindex).show(); + zindex += 1; + }).mouseleave(function(){ + ul.hide(); + }); + }); + }).mouseleave(function(){ + menu.hide(); + }); + }); + + return tocMenus; + }; + + /** + * 简单地过滤指定的HTML标签 + * Filter custom html tags + * + * @param {String} html 要过滤HTML + * @param {String} filters 要过滤的标签 + * @returns {String} html 返回过滤的HTML + */ + + editormd.filterHTMLTags = function(html, filters) { + + if (typeof html !== "string") { + html = new String(html); + } + + if (typeof filters !== "string") { + return html; + } + + var expression = filters.split("|"); + var filterTags = expression[0].split(","); + var attrs = expression[1]; + + for (var i = 0, len = filterTags.length; i < len; i++) + { + var tag = filterTags[i]; + + html = html.replace(new RegExp("\<\s*" + tag + "\s*([^\>]*)\>([^\>]*)\<\s*\/" + tag + "\s*\>", "igm"), ""); + } + + //return html; + + if (typeof attrs !== "undefined") + { + var htmlTagRegex = /\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/ig; + + if (attrs === "*") + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { + return "<" + $2 + ">" + $4 + ""; + }); + } + else if (attrs === "on*") + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { + var el = $("<" + $2 + ">" + $4 + ""); + var _attrs = $($1)[0].attributes; + var $attrs = {}; + + $.each(_attrs, function(i, e) { + if (e.nodeName !== '"') $attrs[e.nodeName] = e.nodeValue; + }); + + $.each($attrs, function(i) { + if (i.indexOf("on") === 0) { + delete $attrs[i]; + } + }); + + el.attr($attrs); + + var text = (typeof el[1] !== "undefined") ? $(el[1]).text() : ""; + + return el[0].outerHTML + text; + }); + } + else + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4) { + var filterAttrs = attrs.split(","); + var el = $($1); + el.html($4); + + $.each(filterAttrs, function(i) { + el.attr(filterAttrs[i], null); + }); + + return el[0].outerHTML; + }); + } + } + + return html; + }; + + /** + * 将Markdown文档解析为HTML用于前台显示 + * Parse Markdown to HTML for Font-end preview. + * + * @param {String} id 用于显示HTML的对象ID + * @param {Object} [options={}] 配置选项,可选 + * @returns {Object} div 返回jQuery对象元素 + */ + + editormd.markdownToHTML = function(id, options) { + var defaults = { + gfm : true, + toc : true, + tocm : false, + tocStartLevel : 1, + tocTitle : "目录", + tocDropdown : false, + tocContainer : "", + markdown : "", + markdownSourceCode : false, + htmlDecode : false, + autoLoadKaTeX : true, + pageBreak : true, + atLink : true, // for @link + emailLink : true, // for mail address auto link + tex : false, + taskList : false, // Github Flavored Markdown task lists + emoji : false, + flowChart : false, + sequenceDiagram : false, + previewCodeHighlight : true + }; + + editormd.$marked = marked; + + var div = $("#" + id); + var settings = div.settings = $.extend(true, defaults, options || {}); + var saveTo = div.find("textarea"); + + if (saveTo.length < 1) + { + div.append(""); + saveTo = div.find("textarea"); + } + + var markdownDoc = (settings.markdown === "") ? saveTo.val() : settings.markdown; + var markdownToC = []; + + var rendererOptions = { + toc : settings.toc, + tocm : settings.tocm, + tocStartLevel : settings.tocStartLevel, + taskList : settings.taskList, + emoji : settings.emoji, + tex : settings.tex, + pageBreak : settings.pageBreak, + atLink : settings.atLink, // for @link + emailLink : settings.emailLink, // for mail address auto link + flowChart : settings.flowChart, + sequenceDiagram : settings.sequenceDiagram, + previewCodeHighlight : settings.previewCodeHighlight, + }; + + var markedOptions = { + renderer : editormd.markedRenderer(markdownToC, rendererOptions), + gfm : settings.gfm, + tables : true, + breaks : true, + pedantic : false, + sanitize : (settings.htmlDecode) ? false : true, // 是否忽略HTML标签,即是否开启HTML标签解析,为了安全性,默认不开启 + smartLists : true, + smartypants : true + }; + + markdownDoc = new String(markdownDoc); + + var markdownParsed = marked(markdownDoc, markedOptions); + + markdownParsed = editormd.filterHTMLTags(markdownParsed, settings.htmlDecode); + + if (settings.markdownSourceCode) { + saveTo.text(markdownDoc); + } else { + saveTo.remove(); + } + + div.addClass("markdown-body " + this.classPrefix + "html-preview").append(markdownParsed); + + var tocContainer = (settings.tocContainer !== "") ? $(settings.tocContainer) : div; + + if (settings.tocContainer !== "") + { + tocContainer.attr("previewContainer", false); + } + + if (settings.toc) + { + div.tocContainer = this.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); + + if (settings.tocDropdown || div.find("." + this.classPrefix + "toc-menu").length > 0) + { + this.tocDropdownMenu(div, settings.tocTitle); + } + + if (settings.tocContainer !== "") + { + div.find(".editormd-toc-menu, .editormd-markdown-toc").remove(); + } + } + + if (settings.previewCodeHighlight) + { + div.find("pre").addClass("prettyprint linenums"); + prettyPrint(); + } + + if (!editormd.isIE8) + { + if (settings.flowChart) { + div.find(".flowchart").flowChart(); + } + + if (settings.sequenceDiagram) { + div.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); + } + } + + if (settings.tex) + { + var katexHandle = function() { + div.find("." + editormd.classNames.tex).each(function(){ + var tex = $(this); + katex.render(tex.html().replace(/</g, "<").replace(/>/g, ">"), tex[0]); + tex.find(".katex").css("font-size", "1.6em"); + }); + }; + + if (settings.autoLoadKaTeX && !editormd.$katex && !editormd.kaTeXLoaded) + { + this.loadKaTeX(function() { + editormd.$katex = katex; + editormd.kaTeXLoaded = true; + katexHandle(); + }); + } + else + { + katexHandle(); + } + } + + div.getMarkdown = function() { + return saveTo.val(); + }; + + return div; + }; + + // Editor.md themes, change toolbar themes etc. + // added @1.5.0 + editormd.themes = ["default", "dark"]; + + // Preview area themes + // added @1.5.0 + editormd.previewThemes = ["default", "dark"]; + + // CodeMirror / editor area themes + // @1.5.0 rename -> editorThemes, old version -> themes + editormd.editorThemes = [ + "default", "3024-day", "3024-night", + "ambiance", "ambiance-mobile", + "base16-dark", "base16-light", "blackboard", + "cobalt", + "eclipse", "elegant", "erlang-dark", + "lesser-dark", + "mbo", "mdn-like", "midnight", "monokai", + "neat", "neo", "night", + "paraiso-dark", "paraiso-light", "pastel-on-dark", + "rubyblue", + "solarized", + "the-matrix", "tomorrow-night-eighties", "twilight", + "vibrant-ink", + "xq-dark", "xq-light" + ]; + + editormd.loadPlugins = {}; + + editormd.loadFiles = { + js : [], + css : [], + plugin : [] + }; + + /** + * 动态加载Editor.md插件,但不立即执行 + * Load editor.md plugins + * + * @param {String} fileName 插件文件路径 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadPlugin = function(fileName, callback, into) { + callback = callback || function() {}; + + this.loadScript(fileName, function() { + editormd.loadFiles.plugin.push(fileName); + callback(); + }, into); + }; + + /** + * 动态加载CSS文件的方法 + * Load css file method + * + * @param {String} fileName CSS文件名 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadCSS = function(fileName, callback, into) { + into = into || "head"; + callback = callback || function() {}; + + var css = document.createElement("link"); + css.type = "text/css"; + css.rel = "stylesheet"; + css.onload = css.onreadystatechange = function() { + editormd.loadFiles.css.push(fileName); + callback(); + }; + + css.href = fileName + ".css"; + + if(into === "head") { + document.getElementsByTagName("head")[0].appendChild(css); + } else { + document.body.appendChild(css); + } + }; + + editormd.isIE = (navigator.appName == "Microsoft Internet Explorer"); + editormd.isIE8 = (editormd.isIE && navigator.appVersion.match(/8./i) == "8."); + + /** + * 动态加载JS文件的方法 + * Load javascript file method + * + * @param {String} fileName JS文件名 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadScript = function(fileName, callback, into) { + + into = into || "head"; + callback = callback || function() {}; + + var script = null; + script = document.createElement("script"); + script.id = fileName.replace(/[\./]+/g, "-"); + script.type = "text/javascript"; + script.src = fileName + ".js"; + + if (editormd.isIE8) + { + script.onreadystatechange = function() { + if(script.readyState) + { + if (script.readyState === "loaded" || script.readyState === "complete") + { + script.onreadystatechange = null; + editormd.loadFiles.js.push(fileName); + callback(); + } + } + }; + } + else + { + script.onload = function() { + editormd.loadFiles.js.push(fileName); + callback(); + }; + } + + if (into === "head") { + document.getElementsByTagName("head")[0].appendChild(script); + } else { + document.body.appendChild(script); + } + }; + + // 使用国外的CDN,加载速度有时会很慢,或者自定义URL + // You can custom KaTeX load url. + editormd.katexURL = { + css : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min", + js : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min" + }; + + editormd.kaTeXLoaded = false; + + /** + * 加载KaTeX文件 + * load KaTeX files + * + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + */ + + editormd.loadKaTeX = function (callback) { + editormd.loadCSS(editormd.katexURL.css, function(){ + editormd.loadScript(editormd.katexURL.js, callback || function(){}); + }); + }; + + /** + * 锁屏 + * lock screen + * + * @param {Boolean} lock Boolean 布尔值,是否锁屏 + * @returns {void} + */ + + editormd.lockScreen = function(lock) { + $("html,body").css("overflow", (lock) ? "hidden" : ""); + }; + + /** + * 动态创建对话框 + * Creating custom dialogs + * + * @param {Object} options 配置项键值对 Key/Value + * @returns {dialog} 返回创建的dialog的jQuery实例对象 + */ + + editormd.createDialog = function(options) { + var defaults = { + name : "", + width : 420, + height: 240, + title : "", + drag : true, + closed : true, + content : "", + mask : true, + maskStyle : { + backgroundColor : "#fff", + opacity : 0.1 + }, + lockScreen : true, + footer : true, + buttons : false + }; + + options = $.extend(true, defaults, options); + + var $this = this; + var editor = this.editor; + var classPrefix = editormd.classPrefix; + var guid = (new Date()).getTime(); + var dialogName = ( (options.name === "") ? classPrefix + "dialog-" + guid : options.name); + var mouseOrTouch = editormd.mouseOrTouch; + + var html = "
                              "; + + if (options.title !== "") + { + html += "
                              "; + html += "" + options.title + ""; + html += "
                              "; + } + + if (options.closed) + { + html += ""; + } + + html += "
                              " + options.content; + + if (options.footer || typeof options.footer === "string") + { + html += "
                              " + ( (typeof options.footer === "boolean") ? "" : options.footer) + "
                              "; + } + + html += "
                              "; + + html += "
                              "; + html += "
                              "; + html += "
                              "; + + editor.append(html); + + var dialog = editor.find("." + dialogName); + + dialog.lockScreen = function(lock) { + if (options.lockScreen) + { + $("html,body").css("overflow", (lock) ? "hidden" : ""); + $this.resize(); + } + + return dialog; + }; + + dialog.showMask = function() { + if (options.mask) + { + editor.find("." + classPrefix + "mask").css(options.maskStyle).css("z-index", editormd.dialogZindex - 1).show(); + } + return dialog; + }; + + dialog.hideMask = function() { + if (options.mask) + { + editor.find("." + classPrefix + "mask").hide(); + } + + return dialog; + }; + + dialog.loading = function(show) { + var loading = dialog.find("." + classPrefix + "dialog-mask"); + loading[(show) ? "show" : "hide"](); + + return dialog; + }; + + dialog.lockScreen(true).showMask(); + + dialog.show().css({ + zIndex : editormd.dialogZindex, + border : (editormd.isIE8) ? "1px solid #ddd" : "", + width : (typeof options.width === "number") ? options.width + "px" : options.width, + height : (typeof options.height === "number") ? options.height + "px" : options.height + }); + + var dialogPosition = function(){ + dialog.css({ + top : ($(window).height() - dialog.height()) / 2 + "px", + left : ($(window).width() - dialog.width()) / 2 + "px" + }); + }; + + dialogPosition(); + + $(window).resize(dialogPosition); + + dialog.children("." + classPrefix + "dialog-close").bind(mouseOrTouch("click", "touchend"), function() { + dialog.hide().lockScreen(false).hideMask(); + }); + + if (typeof options.buttons === "object") + { + var footer = dialog.footer = dialog.find("." + classPrefix + "dialog-footer"); + + for (var key in options.buttons) + { + var btn = options.buttons[key]; + var btnClassName = classPrefix + key + "-btn"; + + footer.append(""); + btn[1] = $.proxy(btn[1], dialog); + footer.children("." + btnClassName).bind(mouseOrTouch("click", "touchend"), btn[1]); + } + } + + if (options.title !== "" && options.drag) + { + var posX, posY; + var dialogHeader = dialog.children("." + classPrefix + "dialog-header"); + + if (!options.mask) { + dialogHeader.bind(mouseOrTouch("click", "touchend"), function(){ + editormd.dialogZindex += 2; + dialog.css("z-index", editormd.dialogZindex); + }); + } + + dialogHeader.mousedown(function(e) { + e = e || window.event; //IE + posX = e.clientX - parseInt(dialog[0].style.left); + posY = e.clientY - parseInt(dialog[0].style.top); + + document.onmousemove = moveAction; + }); + + var userCanSelect = function (obj) { + obj.removeClass(classPrefix + "user-unselect").off("selectstart"); + }; + + var userUnselect = function (obj) { + obj.addClass(classPrefix + "user-unselect").on("selectstart", function(event) { // selectstart for IE + return false; + }); + }; + + var moveAction = function (e) { + e = e || window.event; //IE + + var left, top, nowLeft = parseInt(dialog[0].style.left), nowTop = parseInt(dialog[0].style.top); + + if( nowLeft >= 0 ) { + if( nowLeft + dialog.width() <= $(window).width()) { + left = e.clientX - posX; + } else { + left = $(window).width() - dialog.width(); + document.onmousemove = null; + } + } else { + left = 0; + document.onmousemove = null; + } + + if( nowTop >= 0 ) { + top = e.clientY - posY; + } else { + top = 0; + document.onmousemove = null; + } + + + document.onselectstart = function() { + return false; + }; + + userUnselect($("body")); + userUnselect(dialog); + dialog[0].style.left = left + "px"; + dialog[0].style.top = top + "px"; + }; + + document.onmouseup = function() { + userCanSelect($("body")); + userCanSelect(dialog); + + document.onselectstart = null; + document.onmousemove = null; + }; + + dialogHeader.touchDraggable = function() { + var offset = null; + var start = function(e) { + var orig = e.originalEvent; + var pos = $(this).parent().position(); + + offset = { + x : orig.changedTouches[0].pageX - pos.left, + y : orig.changedTouches[0].pageY - pos.top + }; + }; + + var move = function(e) { + e.preventDefault(); + var orig = e.originalEvent; + + $(this).parent().css({ + top : orig.changedTouches[0].pageY - offset.y, + left : orig.changedTouches[0].pageX - offset.x + }); + }; + + this.bind("touchstart", start).bind("touchmove", move); + }; + + dialogHeader.touchDraggable(); + } + + editormd.dialogZindex += 2; + + return dialog; + }; + + /** + * 鼠标和触摸事件的判断/选择方法 + * MouseEvent or TouchEvent type switch + * + * @param {String} [mouseEventType="click"] 供选择的鼠标事件 + * @param {String} [touchEventType="touchend"] 供选择的触摸事件 + * @returns {String} EventType 返回事件类型名称 + */ + + editormd.mouseOrTouch = function(mouseEventType, touchEventType) { + mouseEventType = mouseEventType || "click"; + touchEventType = touchEventType || "touchend"; + + var eventType = mouseEventType; + + try { + document.createEvent("TouchEvent"); + eventType = touchEventType; + } catch(e) {} + + return eventType; + }; + + /** + * 日期时间的格式化方法 + * Datetime format method + * + * @param {String} [format=""] 日期时间的格式,类似PHP的格式 + * @returns {String} datefmt 返回格式化后的日期时间字符串 + */ + + editormd.dateFormat = function(format) { + format = format || ""; + + var addZero = function(d) { + return (d < 10) ? "0" + d : d; + }; + + var date = new Date(); + var year = date.getFullYear(); + var year2 = year.toString().slice(2, 4); + var month = addZero(date.getMonth() + 1); + var day = addZero(date.getDate()); + var weekDay = date.getDay(); + var hour = addZero(date.getHours()); + var min = addZero(date.getMinutes()); + var second = addZero(date.getSeconds()); + var ms = addZero(date.getMilliseconds()); + var datefmt = ""; + + var ymd = year2 + "-" + month + "-" + day; + var fymd = year + "-" + month + "-" + day; + var hms = hour + ":" + min + ":" + second; + + switch (format) + { + case "UNIX Time" : + datefmt = date.getTime(); + break; + + case "UTC" : + datefmt = date.toUTCString(); + break; + + case "yy" : + datefmt = year2; + break; + + case "year" : + case "yyyy" : + datefmt = year; + break; + + case "month" : + case "mm" : + datefmt = month; + break; + + case "cn-week-day" : + case "cn-wd" : + var cnWeekDays = ["日", "一", "二", "三", "四", "五", "六"]; + datefmt = "星期" + cnWeekDays[weekDay]; + break; + + case "week-day" : + case "wd" : + var weekDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + datefmt = weekDays[weekDay]; + break; + + case "day" : + case "dd" : + datefmt = day; + break; + + case "hour" : + case "hh" : + datefmt = hour; + break; + + case "min" : + case "ii" : + datefmt = min; + break; + + case "second" : + case "ss" : + datefmt = second; + break; + + case "ms" : + datefmt = ms; + break; + + case "yy-mm-dd" : + datefmt = ymd; + break; + + case "yyyy-mm-dd" : + datefmt = fymd; + break; + + case "yyyy-mm-dd h:i:s ms" : + case "full + ms" : + datefmt = fymd + " " + hms + " " + ms; + break; + + case "full" : + case "yyyy-mm-dd h:i:s" : + default: + datefmt = fymd + " " + hms; + break; + } + + return datefmt; + }; + + return editormd; + +})); diff --git a/public/editormd/tests/bootstrap-test.html b/public/editormd/tests/bootstrap-test.html new file mode 100644 index 000000000..2b339be60 --- /dev/null +++ b/public/editormd/tests/bootstrap-test.html @@ -0,0 +1,63 @@ + + + + + Bootstrap 兼容测试 - Editor.md tests + + + + + + + + + + +
                              +
                              +

                              Bootstrap 兼容测试

                              +
                              +
                              + +
                              +
                              + + + + + + + + \ No newline at end of file diff --git a/public/editormd/tests/codemirror-searchbox-test.html b/public/editormd/tests/codemirror-searchbox-test.html new file mode 100644 index 000000000..5260eb24c --- /dev/null +++ b/public/editormd/tests/codemirror-searchbox-test.html @@ -0,0 +1,109 @@ + + + + CodeMirror searchbox Test + + + + + + +
                              + +
                              + + + + + + + + + + \ No newline at end of file diff --git a/public/editormd/tests/codemirror-test.html b/public/editormd/tests/codemirror-test.html new file mode 100644 index 000000000..83388cc73 --- /dev/null +++ b/public/editormd/tests/codemirror-test.html @@ -0,0 +1,75 @@ + + + + CodeMirror Test + + + + + + +
                              + +
                              + + + + + + + + + + + \ No newline at end of file diff --git a/public/editormd/tests/css/bootstrap-theme.min.css b/public/editormd/tests/css/bootstrap-theme.min.css new file mode 100644 index 000000000..b5500a628 --- /dev/null +++ b/public/editormd/tests/css/bootstrap-theme.min.css @@ -0,0 +1,5 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary:disabled,.btn-primary[disabled]{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} \ No newline at end of file diff --git a/public/editormd/tests/css/bootstrap.min.css b/public/editormd/tests/css/bootstrap.min.css new file mode 100644 index 000000000..46db47e4a --- /dev/null +++ b/public/editormd/tests/css/bootstrap.min.css @@ -0,0 +1,5 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.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}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px \9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.form-group-sm .form-control{height:30px;line-height:30px}select[multiple].form-group-sm .form-control,textarea.form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:5px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.form-group-lg .form-control{height:46px;line-height:46px}select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:10px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.active,.btn-default.focus,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.active,.btn-primary.focus,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.active,.btn-success.focus,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.active,.btn-info.focus,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.active,.btn-warning.focus,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.active,.btn-danger.focus,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px)and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px)and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px)and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file diff --git a/public/editormd/tests/js/bootstrap.min.js b/public/editormd/tests/js/bootstrap.min.js new file mode 100644 index 000000000..097b84020 --- /dev/null +++ b/public/editormd/tests/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.4",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.4",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.4",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.4",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport),this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-mp.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.4",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.4",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.4",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a(document.body).height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/public/editormd/tests/js/searchbox.js b/public/editormd/tests/js/searchbox.js new file mode 100644 index 000000000..aa0cf128b --- /dev/null +++ b/public/editormd/tests/js/searchbox.js @@ -0,0 +1,674 @@ +/* global CodeMirror */ +/* global define */ + +(function(mod) { + 'use strict'; + + if (typeof exports === 'object' && typeof module === 'object') // CommonJS + mod(require('../../lib/codemirror')); + else if (typeof define === 'function' && define.amd) // AMD + define(['../../lib/codemirror'], mod); + else + mod(CodeMirror); +})(function(CodeMirror) { + 'use strict'; + + var Search; + + CodeMirror.defineOption('searchbox', false, function(cm) { + cm.addKeyMap({ + 'Ctrl-F': function() { + if (!Search) + Search = new SearchBox(cm); + + Search.show(); + }, + + 'Esc': function() { + if (Search && Search.isVisible()) { + Search.hide(); + + if (typeof event !== 'undefined') + event.stopPropagation(); + } + + return false; + }, + + 'Cmd-F': function() { + if (!Search) + Search = new SearchBox(cm); + + Search.show(); + } + }); + }); + + function SearchBox(cm) { + var self = this; + + init(); + + function initElements(el) { + self.searchBox = el.querySelector('.ace_search_form'); + self.replaceBox = el.querySelector('.ace_replace_form'); + self.searchOptions = el.querySelector('.ace_search_options'); + + self.regExpOption = el.querySelector('[action=toggleRegexpMode]'); + self.caseSensitiveOption = el.querySelector('[action=toggleCaseSensitive]'); + self.wholeWordOption = el.querySelector('[action=toggleWholeWords]'); + + self.searchInput = self.searchBox.querySelector('.ace_search_field'); + self.replaceInput = self.replaceBox.querySelector('.ace_search_field'); + } + + function init() { + var el = self.element = addHtml(); + + addStyle(); + + initElements(el); + bindKeys(); + + el.addEventListener('mousedown', function(e) { + setTimeout(function(){ + self.activeInput.focus(); + }, 0); + + e.stopPropagation(); + }); + + el.addEventListener('click', function(e) { + var t = e.target || e.srcElement; + var action = t.getAttribute('action'); + if (action && self[action]) + self[action](); + else if (self.commands[action]) + self.commands[action](); + + e.stopPropagation(); + }); + + self.searchInput.addEventListener('input', function() { + self.$onChange.schedule(20); + }); + + self.searchInput.addEventListener('focus', function() { + self.activeInput = self.searchInput; + }); + + self.replaceInput.addEventListener('focus', function() { + self.activeInput = self.replaceInput; + }); + + self.$onChange = delayedCall(function() { + self.find(false, false); + }); + } + + function bindKeys() { + var sb = self, + obj = { + 'Ctrl-F|Cmd-F|Ctrl-H|Command-Alt-F': function() { + var isReplace = sb.isReplace = !sb.isReplace; + sb.replaceBox.style.display = isReplace ? '' : 'none'; + sb[isReplace ? 'replaceInput' : 'searchInput'].focus(); + }, + 'Ctrl-G|Cmd-G': function() { + sb.findNext(); + }, + 'Ctrl-Shift-G|Cmd-Shift-G': function() { + sb.findPrev(); + }, + 'Esc': function() { + setTimeout(function() { sb.hide();}); + }, + 'Enter': function() { + if (sb.activeInput === sb.replaceInput) + sb.replace(); + sb.findNext(); + }, + 'Shift-Enter': function() { + if (sb.activeInput === sb.replaceInput) + sb.replace(); + sb.findPrev(); + }, + 'Alt-Enter': function() { + if (sb.activeInput === sb.replaceInput) + sb.replaceAll(); + sb.findAll(); + }, + 'Tab': function() { + if (self.activeInput === self.replaceInput) + self.searchInput.focus(); + else + self.replaceInput.focus(); + } + }; + + self.element.addEventListener('keydown', function(event) { + Object.keys(obj).some(function(name) { + var is = key(name, event); + + if (is) { + event.stopPropagation(); + event.preventDefault(); + obj[name](event); + } + + return is; + }); + }); + } + + this.commands = { + toggleRegexpMode: function() { + self.regExpOption.checked = !self.regExpOption.checked; + self.$syncOptions(); + }, + + toggleCaseSensitive: function() { + self.caseSensitiveOption.checked = !self.caseSensitiveOption.checked; + self.$syncOptions(); + }, + + toggleWholeWords: function() { + self.wholeWordOption.checked = !self.wholeWordOption.checked; + self.$syncOptions(); + } + }; + + this.$syncOptions = function() { + setCssClass(this.regExpOption, 'checked', this.regExpOption.checked); + setCssClass(this.wholeWordOption, 'checked', this.wholeWordOption.checked); + setCssClass(this.caseSensitiveOption, 'checked', this.caseSensitiveOption.checked); + + this.find(false, false); + }; + + this.find = function(skipCurrent, backwards) { + var value = this.searchInput.value, + options = { + skipCurrent: skipCurrent, + backwards: backwards, + regExp: this.regExpOption.checked, + caseSensitive: this.caseSensitiveOption.checked, + wholeWord: this.wholeWordOption.checked + }; + + find(value, options, function(searchCursor) { + var current = searchCursor.matches(false, searchCursor.from()); + cm.setSelection(current.from, current.to); + }); + }; + + function find(value, options, callback) { + var done, + noMatch, searchCursor, next, prev, matches, cursor, + position, + o = options, + is = true, + caseSensitive = o.caseSensitive, + regExp = o.regExp, + wholeWord = o.wholeWord; + + if (regExp || wholeWord) { + if (options.wholeWord) + value = '\\b' + value + '\\b'; + + value = RegExp(value); + } + + if (o.backwards) + position = o.skipCurrent ? 'from': 'to'; + else + position = o.skipCurrent ? 'to' : 'from'; + + cursor = cm.getCursor(position); + searchCursor = cm.getSearchCursor(value, cursor, !caseSensitive); + + next = searchCursor.findNext.bind(searchCursor), + prev = searchCursor.findPrevious.bind(searchCursor), + matches = searchCursor.matches.bind(searchCursor); + + if (o.backwards && !prev()) { + is = next(); + + if (is) { + cm.setCursor(cm.doc.size - 1, 0); + find(true, true, callback); + done = true; + } + } else if (!o.backwards && !next()) { + is = prev(); + + if (is) { + cm.setCursor(0, 0); + find(true, false, callback); + done = true; + } + } + + noMatch = !is && self.searchInput.value; + setCssClass(self.searchBox, 'ace_nomatch', noMatch); + + if (!done && is) + callback(searchCursor); + } + + this.findNext = function() { + this.find(true, false); + }; + + this.findPrev = function() { + this.find(true, true); + }; + + this.findAll = function(){ + /* + var range = this.editor.findAll(this.searchInput.value, { + regExp: this.regExpOption.checked, + caseSensitive: this.caseSensitiveOption.checked, + wholeWord: this.wholeWordOption.checked + }); + */ + + var value = this.searchInput.value, + range, + noMatch = !range && this.searchInput.value; + + setCssClass(this.searchBox, 'ace_nomatch', noMatch); + + if (cm.showMatchesOnScrollbar) + cm.showMatchesOnScrollbar(value); + + this.hide(); + }; + + this.replace = function() { + if (!cm.getOption('readOnly')) + cm.replaceSelection(this.replaceInput.value, 'start'); + }; + + this.replaceAndFindNext = function() { + if (!cm.getOption('readOnly')) { + this.editor.replace(this.replaceInput.value); + this.findNext(); + } + }; + + this.replaceAll = function() { + var value, + cursor, + from = this.searchInput.value, + to = this.replaceInput.value, + reg = RegExp(from, 'g'); + + if (!cm.getOption('readOnly')) { + cursor = cm.getCursor(); + value = cm.getValue(); + value = value.replace(reg, to); + + cm.setValue(value); + cm.setCursor(cursor); + } + }; + + this.hide = function() { + this.element.style.display = 'none'; + cm.focus(); + }; + + this.isVisible = function() { + var is = this.element.style.display === ''; + + return is; + }; + + this.show = function(value, isReplace) { + this.element.style.display = ''; + this.replaceBox.style.display = isReplace ? '' : 'none'; + + this.isReplace = isReplace; + + if (value) + this.searchInput.value = value; + + this.searchInput.focus(); + this.searchInput.select(); + }; + + this.isFocused = function() { + var el = document.activeElement; + return el === this.searchInput || el === this.replaceInput; + }; + + function addStyle() { + var style = document.createElement('style'), + css = [ + '.ace_search {', + 'background-color: #ddd;', + 'border: 1px solid #cbcbcb;', + 'border-top: 0 none;', + 'max-width: 325px;', + 'overflow: hidden;', + 'margin: 0;', + 'padding: 4px;', + 'padding-right: 6px;', + 'padding-bottom: 0;', + 'position: absolute;', + 'top: 0px;', + 'z-index: 99;', + 'white-space: normal;', + '}', + '.ace_search.left {', + 'border-left: 0 none;', + 'border-radius: 0px 0px 5px 0px;', + 'left: 0;', + '}', + '.ace_search.right {', + 'border-radius: 0px 0px 0px 5px;', + 'border-right: 0 none;', + 'right: 0;', + '}', + '.ace_search_form, .ace_replace_form {', + 'border-radius: 3px;', + 'border: 1px solid #cbcbcb;', + 'float: left;', + 'margin-bottom: 4px;', + 'overflow: hidden;', + '}', + '.ace_search_form.ace_nomatch {', + 'outline: 1px solid red;', + '}', + '.ace_search_field {', + 'background-color: white;', + 'border-right: 1px solid #cbcbcb;', + 'border: 0 none;', + '-webkit-box-sizing: border-box;', + '-moz-box-sizing: border-box;', + 'box-sizing: border-box;', + 'float: left;', + 'height: 22px;', + 'outline: 0;', + 'padding: 0 7px;', + 'width: 214px;', + 'margin: 0;', + '}', + '.ace_searchbtn,', + '.ace_replacebtn {', + 'background: #fff;', + 'border: 0 none;', + 'border-left: 1px solid #dcdcdc;', + 'cursor: pointer;', + 'float: left;', + 'height: 22px;', + 'margin: 0;', + 'padding: 0;', + 'position: relative;', + '}', + '.ace_searchbtn:last-child,', + '.ace_replacebtn:last-child {', + 'border-top-right-radius: 3px;', + 'border-bottom-right-radius: 3px;', + '}', + '.ace_searchbtn:disabled {', + 'background: none;', + 'cursor: default;', + '}', + '.ace_searchbtn {', + 'background-position: 50% 50%;', + 'background-repeat: no-repeat;', + 'width: 27px;', + '}', + '.ace_searchbtn.prev {', + 'background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADFJREFUeNpiSU1NZUAC/6E0I0yACYskCpsJiySKIiY0SUZk40FyTEgCjGgKwTRAgAEAQJUIPCE+qfkAAAAASUVORK5CYII=); ', + '}', + '.ace_searchbtn.next {', + 'background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNpiTE1NZQCC/0DMyIAKwGJMUAYDEo3M/s+EpvM/mkKwCQxYjIeLMaELoLMBAgwAU7UJObTKsvAAAAAASUVORK5CYII=); ', + '}', + '.ace_searchbtn_close {', + 'background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;', + 'border-radius: 50%;', + 'border: 0 none;', + 'color: #656565;', + 'cursor: pointer;', + 'float: right;', + 'font: 16px/16px Arial;', + 'height: 14px;', + 'margin: 5px 1px 9px 5px;', + 'padding: 0;', + 'text-align: center;', + 'width: 14px;', + '}', + '.ace_searchbtn_close:hover {', + 'background-color: #656565;', + 'background-position: 50% 100%;', + 'color: white;', + '}', + '.ace_replacebtn.prev {', + 'width: 54px', + '}', + '.ace_replacebtn.next {', + 'width: 27px', + '}', + '.ace_button {', + 'margin-left: 2px;', + 'cursor: pointer;', + '-webkit-user-select: none;', + '-moz-user-select: none;', + '-o-user-select: none;', + '-ms-user-select: none;', + 'user-select: none;', + 'overflow: hidden;', + 'opacity: 0.7;', + 'border: 1px solid rgba(100,100,100,0.23);', + 'padding: 1px;', + '-moz-box-sizing: border-box;', + 'box-sizing: border-box;', + 'color: black;', + '}', + '.ace_button:hover {', + 'background-color: #eee;', + 'opacity:1;', + '}', + '.ace_button:active {', + 'background-color: #ddd;', + '}', + '.ace_button.checked {', + 'border-color: #3399ff;', + 'opacity:1;', + '}', + '.ace_search_options{', + 'margin-bottom: 3px;', + 'text-align: right;', + '-webkit-user-select: none;', + '-moz-user-select: none;', + '-o-user-select: none;', + '-ms-user-select: none;', + 'user-select: none;', + '}' + ].join(''); + + style.setAttribute('data-name', 'js-searchbox'); + + style.textContent = css; + + document.head.appendChild(style); + } + + function addHtml() { + var elSearch, + el = document.querySelector('.CodeMirror'), + div = document.createElement('div'), + html = [ + '' + ].join(''); + + div.innerHTML = html; + + elSearch = div.firstChild; + + el.parentElement.appendChild(elSearch); + + return elSearch; + } + } + + function setCssClass(el, className, condition) { + var list = el.classList; + + list[condition ? 'add' : 'remove'](className); + } + + function delayedCall(fcn, defaultTimeout) { + var timer, + callback = function() { + timer = null; + fcn(); + }, + + _self = function(timeout) { + if (!timer) + timer = setTimeout(callback, timeout || defaultTimeout); + }; + + _self.delay = function(timeout) { + timer && clearTimeout(timer); + timer = setTimeout(callback, timeout || defaultTimeout); + }; + _self.schedule = _self; + + _self.call = function() { + this.cancel(); + fcn(); + }; + + _self.cancel = function() { + timer && clearTimeout(timer); + timer = null; + }; + + _self.isPending = function() { + return timer; + }; + + return _self; + } + + /* https://github.com/coderaiser/key */ + function key(str, event) { + var right, + KEY = { + BACKSPACE : 8, + TAB : 9, + ENTER : 13, + ESC : 27, + + SPACE : 32, + PAGE_UP : 33, + PAGE_DOWN : 34, + END : 35, + HOME : 36, + UP : 38, + DOWN : 40, + + INSERT : 45, + DELETE : 46, + + INSERT_MAC : 96, + + ASTERISK : 106, + PLUS : 107, + MINUS : 109, + + F1 : 112, + F2 : 113, + F3 : 114, + F4 : 115, + F5 : 116, + F6 : 117, + F7 : 118, + F8 : 119, + F9 : 120, + F10 : 121, + + SLASH : 191, + TRA : 192, /* Typewritten Reverse Apostrophe (`) */ + BACKSLASH : 220 + }; + + keyCheck(str, event); + + right = str.split('|').some(function(combination) { + var wrong; + + wrong = combination.split('-').some(function(key) { + var right; + + switch(key) { + case 'Ctrl': + right = event.ctrlKey; + break; + + case 'Shift': + right = event.shiftKey; + break; + + case 'Alt': + right = event.altKey; + break; + + case 'Cmd': + right = event.metaKey; + break; + + default: + if (key.length === 1) + right = event.keyCode === key.charCodeAt(0); + else + Object.keys(KEY).some(function(name) { + var up = key.toUpperCase(); + + if (up === name) + right = event.keyCode === KEY[name]; + }); + break; + } + + return !right; + }); + + return !wrong; + }); + + return right; + } + + function keyCheck(str, event) { + if (typeof str !== 'string') + throw(Error('str should be string!')); + + if (typeof event !== 'object') + throw(Error('event should be object!')); + } + +}); diff --git a/public/editormd/tests/katex-tests.html b/public/editormd/tests/katex-tests.html new file mode 100644 index 000000000..be33a13fd --- /dev/null +++ b/public/editormd/tests/katex-tests.html @@ -0,0 +1,132 @@ + + + + KaTeX Tests + + + + + + + http://khan.github.io/KaTeX/

                              + http://meta.wikimedia.org/wiki/Help:Displaying_a_formula +

                              + a^2 + a^{2+2} + a_2 + {x_2}^3 + x_2^3 + 10^{10^{8}} + a_{i,j} + _nP_k + E=MC^2 + \left \{ \frac{a}{b} \right \} \quad \left \lbrace \frac{a}{b} \right \rbrace + \left [ \frac{a}{b} \right ] \quad \left \lbrack \frac{a}{b} \right \rbrack + \left ( \frac{a}{b} \right ) + \left \langle \frac{a}{b} \right \rangle + x > y = 100 + c = \pm\sqrt{a^2 + b^2} + \left . \frac{A}{B} \right \} \to X + \left / \frac{a}{b} \right \backslash + \left \lfloor \frac{a}{b} \right \rfloor \left \lceil \frac{c}{d} \right \rceil + \frac{1}{2}=0.5 + \dfrac{k}{k-1} = 0.5 + \dbinom{n}{k} \binom{n}{k} + \oint_C x^3\, dx + 4y^2\, dy + \bigcap_1^n p \bigcup_1^k p + \phi_n(\kappa) = + \frac{1}{4\pi^2\kappa^2} \int_0^\infty + \frac{\sin(\kappa R)}{\kappa R} + \frac{\partial}{\partial R} + \left[R^2\frac{\partial D_n(R)}{\partial R}\right]\,dR + \sum_{m=1}^\infty\sum_{n=1}^\infty\frac{m^2\,n} + {3^m\left(m\,3^n+n\,3^m\right)} + e^{i \pi} + 1 = 0 + \left ( \frac{1}{2} \right ) + x_{1,2}=\frac{-b\pm\sqrt{\color{Red}b^2-4ac}}{2a} + {\color{Blue}x^2}+{\color{YellowOrange}2x}-{\color{OliveGreen}1} + \textstyle \sum_{k=1}^N k^2 + \dfrac{ \tfrac{1}{2}[1-(\tfrac{1}{2})^n] }{ 1-\tfrac{1}{2} } = s_n + \binom{n}{k} + 0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+\cdots + f(x) = \int_{-\infty}^\infty + \hat f(\xi)\,e^{2 \pi i \xi x} + \,d\xi + \displaystyle \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\cdots} } } } + \displaystyle \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) + \displaystyle 1 + \frac{q^2}{(1-q)}+\frac{q^6}{(1-q)(1-q^2)}+\cdots = \prod_{j=0}^{\infty}\frac{1}{(1-q^{5j+2})(1-q^{5j+3})}, \quad\quad \text{for }\lvert q\rvert<1. + 2 = \left( + \frac{\left(3-x\right) \times 2}{3-x} + \right) + S_{\text{new}} = S_{\text{old}} - \frac{ \left( 5-T \right) ^2} {2} + x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} + ax^2 + bx + c = 0\, + \int_a^x \!\!\!\int_a^s f(y)\,dy\,ds + = \int_a^x f(y)(x-y)\,dy + \sum_{m=1}^\infty\sum_{n=1}^\infty\frac{m^2\,n} + {3^m\left(m\,3^n+n\,3^m\right)} + u'' + p(x)u' + q(x)u=f(x),\quad x>a + |\bar{z}| = |z|, + |(\bar{z})^n| = |z|^n, + \arg(z^n) = n \arg(z) + \lim_{z\rightarrow z_0} f(z)=f(z_0) + \phi_n(\kappa) = + 0.033C_n^2\kappa^{-11/3},\quad + \frac{1}{L_0}\ll\kappa\ll\frac{1}{l_0} + \sum_{k=1}^N k^2 + \textstyle \sum_{k=1}^N k^2 + \prod_{i=1}^N x_i + \textstyle \prod_{i=1}^N x_i + \coprod_{i=1}^N x_i + \textstyle \coprod_{i=1}^N x_i + \int_{1}^{3}\frac{e^3/x}{x^2}\, dx + \int_C x^3\, dx + 4y^2\, dy + {}_1^2\!\Omega_3^4 + x', y'', f', f'' + \dot{x}, \ddot{x} + \hat a \ \bar b \ \vec c + \lessapprox \lesssim \eqslantless \leqslant \leqq \geqq \geqslant \eqslantgtr \gtrsim \gtrapprox + \smile \frown \wr \triangleleft \triangleright \infty \bot \top + \leftarrow \gets \rightarrow \to \nleftarrow \nrightarrow \leftrightarrow \nleftrightarrow \longleftarrow \longrightarrow \longleftrightarrow + \uparrow \downarrow \updownarrow \Uparrow \Downarrow \Updownarrow \nearrow \searrow \swarrow \nwarrow + \rightharpoonup \rightharpoondown \leftharpoonup \leftharpoondown \upharpoonleft \upharpoonright \downharpoonleft \downharpoonright \rightleftharpoons \leftrightharpoons + \curvearrowleft \circlearrowleft \Lsh \upuparrows \rightrightarrows \rightleftarrows \Rrightarrow \rightarrowtail \looparrowright + \curvearrowright \circlearrowright \Rsh \downdownarrows \leftleftarrows \leftrightarrows \Lleftarrow \leftarrowtail \looparrowleft + \mapsto \longmapsto \hookrightarrow \hookleftarrow \multimap \leftrightsquigarrow \rightsquigarrow + \Diamond \Box \triangle \angle \perp \mid \nmid \| 45^\circ + +\sim \approx \simeq \cong \dot= \overset{\underset{\mathrm{def}}{}}{=} + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/editormd/tests/marked-@at-test.html b/public/editormd/tests/marked-@at-test.html new file mode 100644 index 000000000..be8239d22 --- /dev/null +++ b/public/editormd/tests/marked-@at-test.html @@ -0,0 +1,221 @@ + + + + Marked @ Test + + + + + + + +
                               ~~@mentions~~, #refs @tylerlong `inline code @tylerlong`, [links](), **formatting**, and tags supported @pandao;
                              +list syntax required (any unordered or ordered list supported) @pandao;
                              +this is @pandao a complete item @pandao;
                              +link [@pandao](https://github.com/pandao "@pandao") @
                              +link [@pandao](https://github.com/pandao "@pandao") 
                              +this is an incomplete item **@pandao**;
                              +*@pandao* this is an incomplete item ___@pandao___;
                              +# Github: @pandao
                              +## Github: @pandao
                              +### Github: @tylerlong
                              +#### Github: @tylerlong
                              +##### Github: @tylerlong
                              +###### Github: @tylerlong
                              + 
                              +- dafssdfsdaf@chjj dfsdfsdf
                              +- dafssdfsdaf@chjj dfsdfsdf     
                              +    - dafssdfsdaf@chjj dfsdfsdf
                              +    - dafss@pandao dfsdaf@chjj dfsdfsdf
                              +- dafssd:  @pandao fsdaf@chjj dfsdfsdf @codemirror  @pandao
                              +    + dafssdfsdaf@chjj dfsdfsdf
                              +    + dafss@pandaodfsdaf@chjj dfsdfsdf
                              +
                              +
                              +1. @chjj 第一行@pandao fsdaf@chjj dfsdfsdf :fa-save::  @pandao
                              +    - dafssdfsdaf@chjj dfsdfsdf
                              +    - dafss@pandao dfsdaf@chjj dfsdfsdf
                              +2. @chjj 第二行@pandao fsdaf@chjj dfsdfsdf @codemirror  @pandao
                              +3. 第三行@pandao fsdaf@chjj dfsdfsdf :fa-save::  @pandao
                              +
                              +> Blockquotes @pandao
                              +
                              +> dd@pandao引用文本(Blockquotes @pandao)fdasfad @_pandao fdasfad @xxx454xxx fdasfad @xx_x454xxx454
                              +
                              +|@pandao First Header  | Second@pandao Header@pandao |
                              +| ------------- | ------------- |
                              +| Content@pandao Cell  | @pandao Content Cell @pandao|
                              +| Con@pandao tent Cell@pandao  | Content@pan-dao Cell dfsdfsdf @pan_dao |
                              +
                              +dsfdf@pandao fasdfsdfsfddffd@pandao
                              +
                              +    dfasfasdfasdf:bangbang:
                              +
                              +This is an H1 @pandao
                              +=============
                              +
                              +This @pandao an H2 @pandao
                              +-------------
                              +
                              + + + + + \ No newline at end of file diff --git a/public/editormd/tests/marked-emoji-test.html b/public/editormd/tests/marked-emoji-test.html new file mode 100644 index 000000000..f54dbca4a --- /dev/null +++ b/public/editormd/tests/marked-emoji-test.html @@ -0,0 +1,231 @@ + + + + Marked Emoji Test + + + + + + + +
                              +
                              > Blockquotes
                              +dasfsadfasdf:fa-edit: :warning: :smiley:dsafsdfsad\:fdsfdf\:f dfdf:   :fa-save::fa-star:  :fa-truck:
                              +**fdfasd:smiley:dsfsdfsfd** ~~fsdfds:smiley:dfsdfsdf :fa-info:~~
                              +*dsfdfsfd:smiley:dsfsfdsfd:smiley:dsfdf*
                              +___Emphasis :fa-gear: Italic:smiley:___  __Emphasis:smiley:__
                              +# H1 dsfdfsfd:smiley:dsfsfdsfd:smiley:dsfdf
                              +## H2 dsfdfsfd:smiley:dsfsfdsfd:smiley:dsfdf
                              +### H3 dsfdfsfd:smiley:dsfsfdsfd:smiley:dsfdf:fa-edit: fdsfsdf:fa-save:dsfsdf
                              +#### H4 dsfdfsfd:smiley:dsfsfdsfd:smiley:dsfdf:fa-edit: fdsfsdf:fa-save:dsfsdf
                              +##### H5 dsfdfsfd:smiley:dsfsfdsfd:smiley:dsfdf:fa-edit: fdsfsdf:fa-save:dsfsdf
                              +###### H6 dsfdfsfd:smiley:dsfsfdsfd:smiley:dsfdf:fa-edit: fdsfsdf:fa-star:dsfsdf
                              +[:smiley:](http://www.emoji-cheat-sheet.com/ "link + emoji") link + emoji
                              +- dafssdfsdaf:smiley:dfsdfsdf
                              +- dafssdfsdaf:smiley:dfsdfsdf     
                              +    - dafssdfsdaf:smiley:dfsdfsdf
                              +    - dafss:fa-truck:dfsdaf:smiley:dfsdfsdf
                              +- dafssd:  :fa-truck:fsdaf:smiley:dfsdfsdf :fa-star::  :fa-truck:
                              +    + dafssdfsdaf:smiley:dfsdfsdf
                              +    + dafss:fa-truck:dfsdaf:smiley:dfsdfsdf
                              +
                              +
                              +1. :smiley:第一行:fa-truck:fsdaf:smiley:dfsdfsdf :fa-save::  :fa-truck:
                              +    - dafssdfsdaf:smiley:dfsdfsdf
                              +    - dafss:fa-truck:dfsdaf:smiley:dfsdfsdf
                              +2. :smiley:第二行:fa-truck:fsdaf:smiley:dfsdfsdf :fa-star::  :fa-truck:
                              +3. 第三行:fa-truck:fsdaf:smiley:dfsdfsdf :fa-save::  :fa-truck:
                              +
                              +> Blockquotes
                              +
                              +> dd:smiley:引用文本(Blockquotes:smiley:)fdasfad :fa-star:: dfd :fa-truck:
                              +
                              +|:100: First Header  | Second:smiley: Header:smiley: |
                              +| ------------- | ------------- |
                              +| Content:fa-truck: Cell  | :smiley:Content Cell :smiley: |
                              +| Con:fa-truck:tent Cell:bangbang:  | Content Cell dfsdfsdf :fa-star: :dfdf  :fa-truck: |
                              +
                              +:fa-heart:fasdfsdfsfddffd:editormd-logo: :editormd-logo: :editormd-logo-4x:
                              +
                              +    dfasfasdfasdf:bangbang:
                              +
                              +This is an H1 :editormd-logo-4x:
                              +=============
                              +
                              +This  :fa-save::  :fa-truck:is an H2 :100:
                              +-------------
                              +
                              + + + + + \ No newline at end of file diff --git a/public/editormd/tests/marked-heading-link-test.html b/public/editormd/tests/marked-heading-link-test.html new file mode 100644 index 000000000..bd6d6d0d5 --- /dev/null +++ b/public/editormd/tests/marked-heading-link-test.html @@ -0,0 +1,138 @@ + + + + Marked heading link Test + + + + + + + + + + + \ No newline at end of file diff --git a/public/editormd/tests/marked-todo-list-test.html b/public/editormd/tests/marked-todo-list-test.html new file mode 100644 index 000000000..1c2ea2374 --- /dev/null +++ b/public/editormd/tests/marked-todo-list-test.html @@ -0,0 +1,61 @@ + + + + Marked Emoji Test + + + + + + + + + + + \ No newline at end of file diff --git a/public/editormd/tests/qunit/qunit-1.16.0.css b/public/editormd/tests/qunit/qunit-1.16.0.css new file mode 100644 index 000000000..2ec38cc9b --- /dev/null +++ b/public/editormd/tests/qunit/qunit-1.16.0.css @@ -0,0 +1,264 @@ +/*! + * QUnit 1.16.0 + * http://qunitjs.com/ + * + * Copyright 2006, 2014 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-12-03T16:32Z + */ + +/** Font Family and Sizes */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; +} + +#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-tests { font-size: smaller; } + + +/** Resets */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { + margin: 0; + padding: 0; +} + + +/** Header */ + +#qunit-header { + padding: 0.5em 0 0.5em 1em; + + color: #8699A4; + background-color: #0D3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: 400; + + border-radius: 5px 5px 0 0; +} + +#qunit-header a { + text-decoration: none; + color: #C2CCD1; +} + +#qunit-header a:hover, +#qunit-header a:focus { + color: #FFF; +} + +#qunit-testrunner-toolbar label { + display: inline-block; + padding: 0 0.5em 0 0.1em; +} + +#qunit-banner { + height: 5px; +} + +#qunit-testrunner-toolbar { + padding: 0.5em 1em 0.5em 1em; + color: #5E740B; + background-color: #EEE; + overflow: hidden; +} + +#qunit-userAgent { + padding: 0.5em 1em 0.5em 1em; + background-color: #2B81AF; + color: #FFF; + text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; +} + +#qunit-modulefilter-container { + float: right; +} + +/** Tests: Pass/Fail */ + +#qunit-tests { + list-style-position: inside; +} + +#qunit-tests li { + padding: 0.4em 1em 0.4em 1em; + border-bottom: 1px solid #FFF; + list-style-position: inside; +} + +#qunit-tests > li { + display: none; +} + +#qunit-tests li.pass, #qunit-tests li.running, #qunit-tests li.fail { + display: list-item; +} + +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + +#qunit-tests li strong { + cursor: pointer; +} + +#qunit-tests li.skipped strong { + cursor: default; +} + +#qunit-tests li a { + padding: 0.5em; + color: #C2CCD1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + +#qunit-tests li .runtime { + float: right; + font-size: smaller; +} + +.qunit-assert-list { + margin-top: 0.5em; + padding: 0.5em; + + background-color: #FFF; + + border-radius: 5px; +} + +.qunit-collapsed { + display: none; +} + +#qunit-tests table { + border-collapse: collapse; + margin-top: 0.2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 0.5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #E0F2BE; + color: #374E0C; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #FFCACA; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: #000; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + +#qunit-tests li li { + padding: 5px; + background-color: #FFF; + border-bottom: none; + list-style-position: inside; +} + +/*** Passing Styles */ + +#qunit-tests li li.pass { + color: #3C510C; + background-color: #FFF; + border-left: 10px solid #C6E746; +} + +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } + +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999; } + +#qunit-banner.qunit-pass { background-color: #C6E746; } + +/*** Failing Styles */ + +#qunit-tests li li.fail { + color: #710909; + background-color: #FFF; + border-left: 10px solid #EE5757; + white-space: pre; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 5px 5px; +} + +#qunit-tests .fail { color: #000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: #008000; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + +/*** Skipped tests */ + +#qunit-tests .skipped { + background-color: #EBECE9; +} + +#qunit-tests .qunit-skipped-label { + background-color: #F4FF77; + display: inline-block; + font-style: normal; + color: #366097; + line-height: 1.8em; + padding: 0 0.5em; + margin: -0.4em 0.4em -0.4em 0; +} + +/** Result */ + +#qunit-testresult { + padding: 0.5em 1em 0.5em 1em; + + color: #2B81AF; + background-color: #D2E0E6; + + border-bottom: 1px solid #FFF; +} +#qunit-testresult .module-name { + font-weight: 700; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; + width: 1000px; + height: 1000px; +} diff --git a/public/editormd/tests/qunit/qunit-1.16.0.js b/public/editormd/tests/qunit/qunit-1.16.0.js new file mode 100644 index 000000000..c639b8c13 --- /dev/null +++ b/public/editormd/tests/qunit/qunit-1.16.0.js @@ -0,0 +1,2819 @@ +/*! + * QUnit 1.16.0 + * http://qunitjs.com/ + * + * Copyright 2006, 2014 jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-12-03T16:32Z + */ + +(function( window ) { + +var QUnit, + config, + onErrorFnPrev, + loggingCallbacks = {}, + fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ), + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + // Keep a local reference to Date (GH-283) + Date = window.Date, + now = Date.now || function() { + return new Date().getTime(); + }, + globalStartCalled = false, + runStarted = false, + setTimeout = window.setTimeout, + clearTimeout = window.clearTimeout, + defined = { + document: window.document !== undefined, + setTimeout: window.setTimeout !== undefined, + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch ( e ) { + return false; + } + }()) + }, + /** + * Provides a normalized error string, correcting an issue + * with IE 7 (and prior) where Error.prototype.toString is + * not properly implemented + * + * Based on http://es5.github.com/#x15.11.4.4 + * + * @param {String|Error} error + * @return {String} error message + */ + errorString = function( error ) { + var name, message, + errorString = error.toString(); + if ( errorString.substring( 0, 7 ) === "[object" ) { + name = error.name ? error.name.toString() : "Error"; + message = error.message ? error.message.toString() : ""; + if ( name && message ) { + return name + ": " + message; + } else if ( name ) { + return name; + } else if ( message ) { + return message; + } else { + return "Error"; + } + } else { + return errorString; + } + }, + /** + * Makes a clone of an object using only Array or Object as base, + * and copies over the own enumerable properties. + * + * @param {Object} obj + * @return {Object} New object with only the own properties (recursively). + */ + objectValues = function( obj ) { + var key, val, + vals = QUnit.is( "array", obj ) ? [] : {}; + for ( key in obj ) { + if ( hasOwn.call( obj, key ) ) { + val = obj[ key ]; + vals[ key ] = val === Object( val ) ? objectValues( val ) : val; + } + } + return vals; + }; + +QUnit = {}; + +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ +config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + // by default, scroll to top of the page when suite is done + scrolltop: true, + + // when enabled, all tests must call expect() + requireExpects: false, + + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "hidepassed", + label: "Hide passed tests", + tooltip: "Only show tests and assertions that fail. Stored as query-strings." + }, + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the " + + "`window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " + + "exceptions in IE reasonable. Stored as query-strings." + } + ], + + // Set of all modules. + modules: [], + + // The first unnamed module + currentModule: { + name: "", + tests: [] + }, + + callbacks: {} +}; + +// Push a loose unnamed module to the modules collection +config.modules.push( config.currentModule ); + +// Initialize more QUnit.config and QUnit.urlParams +(function() { + var i, current, + location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}; + + if ( params[ 0 ] ) { + for ( i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + if ( urlParams[ current[ 0 ] ] ) { + urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] ); + } else { + urlParams[ current[ 0 ] ] = current[ 1 ]; + } + } + } + + QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName + config.filter = urlParams.filter; + + config.testId = []; + if ( urlParams.testId ) { + + // Ensure that urlParams.testId is an array + urlParams.testId = [].concat( urlParams.testId ); + for ( i = 0; i < urlParams.testId.length; i++ ) { + config.testId.push( urlParams.testId[ i ] ); + } + } + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = location.protocol === "file:"; +}()); + +// Root QUnit object. +// `QUnit` initialized at top of scope +extend( QUnit, { + + // call on start of module test to prepend name to all tests + module: function( name, testEnvironment ) { + var currentModule = { + name: name, + testEnvironment: testEnvironment, + tests: [] + }; + + // DEPRECATED: handles setup/teardown functions, + // beforeEach and afterEach should be used instead + if ( testEnvironment && testEnvironment.setup ) { + testEnvironment.beforeEach = testEnvironment.setup; + delete testEnvironment.setup; + } + if ( testEnvironment && testEnvironment.teardown ) { + testEnvironment.afterEach = testEnvironment.teardown; + delete testEnvironment.teardown; + } + + config.modules.push( currentModule ); + config.currentModule = currentModule; + }, + + // DEPRECATED: QUnit.asyncTest() will be removed in QUnit 2.0. + asyncTest: function( testName, expected, callback ) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test( testName, expected, callback, true ); + }, + + test: function( testName, expected, callback, async ) { + var test; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + test = new Test({ + testName: testName, + expected: expected, + async: async, + callback: callback + }); + + test.queue(); + }, + + skip: function( testName ) { + var test = new Test({ + testName: testName, + skip: true + }); + + test.queue(); + }, + + // DEPRECATED: The functionality of QUnit.start() will be altered in QUnit 2.0. + // In QUnit 2.0, invoking it will ONLY affect the `QUnit.config.autostart` blocking behavior. + start: function( count ) { + var globalStartAlreadyCalled = globalStartCalled; + + if ( !config.current ) { + globalStartCalled = true; + + if ( runStarted ) { + throw new Error( "Called start() outside of a test context while already started" ); + } else if ( globalStartAlreadyCalled || count > 1 ) { + throw new Error( "Called start() outside of a test context too many times" ); + } else if ( config.autostart ) { + throw new Error( "Called start() outside of a test context when " + + "QUnit.config.autostart was true" ); + } else if ( !config.pageLoaded ) { + + // The page isn't completely loaded yet, so bail out and let `QUnit.load` handle it + config.autostart = true; + return; + } + } else { + + // If a test is running, adjust its semaphore + config.current.semaphore -= count || 1; + + // Don't start until equal number of stop-calls + if ( config.current.semaphore > 0 ) { + return; + } + + // throw an Error if start is called more often than stop + if ( config.current.semaphore < 0 ) { + config.current.semaphore = 0; + + QUnit.pushFailure( + "Called start() while already started (test's semaphore was 0 already)", + sourceFromStacktrace( 2 ) + ); + return; + } + } + + resumeProcessing(); + }, + + // DEPRECATED: QUnit.stop() will be removed in QUnit 2.0. + stop: function( count ) { + + // If there isn't a test running, don't allow QUnit.stop() to be called + if ( !config.current ) { + throw new Error( "Called stop() outside of a test context" ); + } + + // If a test is running, adjust its semaphore + config.current.semaphore += count || 1; + + pauseProcessing(); + }, + + config: config, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) === type; + }, + + objectType: function( obj ) { + if ( typeof obj === "undefined" ) { + return "undefined"; + } + + // Consider: typeof null === object + if ( obj === null ) { + return "null"; + } + + var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ), + type = match && match[ 1 ] || ""; + + switch ( type ) { + case "Number": + if ( isNaN( obj ) ) { + return "nan"; + } + return "number"; + case "String": + case "Boolean": + case "Array": + case "Date": + case "RegExp": + case "Function": + return type.toLowerCase(); + } + if ( typeof obj === "object" ) { + return "object"; + } + return undefined; + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var key, + querystring = "?"; + + for ( key in params ) { + if ( hasOwn.call( params, key ) ) { + querystring += encodeURIComponent( key ); + if ( params[ key ] !== true ) { + querystring += "=" + encodeURIComponent( params[ key ] ); + } + querystring += "&"; + } + } + return location.protocol + "//" + location.host + + location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + + load: function() { + config.pageLoaded = true; + + // Initialize the configuration options + extend( config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: 0, + updateRate: 1000, + autostart: true, + filter: "" + }, true ); + + config.blocking = false; + + if ( config.autostart ) { + resumeProcessing(); + } + } +}); + +// Register logging callbacks +(function() { + var i, l, key, + callbacks = [ "begin", "done", "log", "testStart", "testDone", + "moduleStart", "moduleDone" ]; + + function registerLoggingCallback( key ) { + var loggingCallback = function( callback ) { + if ( QUnit.objectType( callback ) !== "function" ) { + throw new Error( + "QUnit logging methods require a callback function as their first parameters." + ); + } + + config.callbacks[ key ].push( callback ); + }; + + // DEPRECATED: This will be removed on QUnit 2.0.0+ + // Stores the registered functions allowing restoring + // at verifyLoggingCallbacks() if modified + loggingCallbacks[ key ] = loggingCallback; + + return loggingCallback; + } + + for ( i = 0, l = callbacks.length; i < l; i++ ) { + key = callbacks[ i ]; + + // Initialize key collection of logging callback + if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) { + config.callbacks[ key ] = []; + } + + QUnit[ key ] = registerLoggingCallback( key ); + } +})(); + +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will suppress the default browser handler, +// returning false will let it run. +window.onerror = function( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not suppressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", extend(function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }, { validTest: true } ) ); + } + return false; + } + + return ret; +}; + +function done() { + var runtime, passed; + + config.autorun = true; + + // Log the last module results + if ( config.previousModule ) { + runLoggingCallbacks( "moduleDone", { + name: config.previousModule.name, + tests: config.previousModule.tests, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all, + runtime: now() - config.moduleStats.started + }); + } + delete config.previousModule; + + runtime = now() - config.started; + passed = config.stats.all - config.stats.bad; + + runLoggingCallbacks( "done", { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + }); +} + +// Doesn't support IE6 to IE9 +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 4 : offset; + + var stack, include, i; + + if ( e.stacktrace ) { + + // Opera 12.x + return e.stacktrace.split( "\n" )[ offset + 3 ]; + } else if ( e.stack ) { + + // Firefox, Chrome, Safari 6+, IE10+, PhantomJS and Node + stack = e.stack.split( "\n" ); + if ( /^error$/i.test( stack[ 0 ] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) !== -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } + return stack[ offset ]; + } else if ( e.sourceURL ) { + + // Safari < 6 + // exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + + // for actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} + +function sourceFromStacktrace( offset ) { + var e = new Error(); + if ( !e.stack ) { + try { + throw e; + } catch ( err ) { + // This should already be true in most browsers + e = err; + } + } + return extractStacktrace( e, offset ); +} + +function synchronize( callback, last ) { + if ( QUnit.objectType( callback ) === "array" ) { + while ( callback.length ) { + synchronize( callback.shift() ); + } + return; + } + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process( last ); + } +} + +function process( last ) { + function next() { + process( last ); + } + var start = now(); + config.depth = config.depth ? config.depth + 1 : 1; + + while ( config.queue.length && !config.blocking ) { + if ( !defined.setTimeout || config.updateRate <= 0 || + ( ( now() - start ) < config.updateRate ) ) { + if ( config.current ) { + + // Reset async tracking for each phase of the Test lifecycle + config.current.usedAsync = false; + } + config.queue.shift()(); + } else { + setTimeout( next, 13 ); + break; + } + } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } +} + +function begin() { + var i, l, + modulesLog = []; + + // If the test run hasn't officially begun yet + if ( !config.started ) { + + // Record the time of the test run's beginning + config.started = now(); + + verifyLoggingCallbacks(); + + // Delete the loose unnamed module if unused. + if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) { + config.modules.shift(); + } + + // Avoid unnecessary information by not logging modules' test environments + for ( i = 0, l = config.modules.length; i < l; i++ ) { + modulesLog.push({ + name: config.modules[ i ].name, + tests: config.modules[ i ].tests + }); + } + + // The test run is officially beginning now + runLoggingCallbacks( "begin", { + totalTests: Test.count, + modules: modulesLog + }); + } + + config.blocking = false; + process( true ); +} + +function resumeProcessing() { + runStarted = true; + + // A slight delay to allow this iteration of the event loop to finish (more assertions, etc.) + if ( defined.setTimeout ) { + setTimeout(function() { + if ( config.current && config.current.semaphore > 0 ) { + return; + } + if ( config.timeout ) { + clearTimeout( config.timeout ); + } + + begin(); + }, 13 ); + } else { + begin(); + } +} + +function pauseProcessing() { + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = setTimeout(function() { + if ( config.current ) { + config.current.semaphore = 0; + QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) ); + } else { + throw new Error( "Test timed out" ); + } + resumeProcessing(); + }, config.testTimeout ); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + if ( hasOwn.call( window, key ) ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } + } + } +} + +function checkPollution() { + var newGlobals, + deletedGlobals, + old = config.pollution; + + saveGlobal(); + + newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) ); + } + + deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { + if ( result[ i ] === b[ j ] ) { + result.splice( i, 1 ); + i--; + break; + } + } + } + return result; +} + +function extend( a, b, undefOnly ) { + for ( var prop in b ) { + if ( hasOwn.call( b, prop ) ) { + + // Avoid "Member not found" error in IE8 caused by messing with window.constructor + if ( !( prop === "constructor" && a === window ) ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) { + a[ prop ] = b[ prop ]; + } + } + } + } + + return a; +} + +function runLoggingCallbacks( key, args ) { + var i, l, callbacks; + + callbacks = config.callbacks[ key ]; + for ( i = 0, l = callbacks.length; i < l; i++ ) { + callbacks[ i ]( args ); + } +} + +// DEPRECATED: This will be removed on 2.0.0+ +// This function verifies if the loggingCallbacks were modified by the user +// If so, it will restore it, assign the given callback and print a console warning +function verifyLoggingCallbacks() { + var loggingCallback, userCallback; + + for ( loggingCallback in loggingCallbacks ) { + if ( QUnit[ loggingCallback ] !== loggingCallbacks[ loggingCallback ] ) { + + userCallback = QUnit[ loggingCallback ]; + + // Restore the callback function + QUnit[ loggingCallback ] = loggingCallbacks[ loggingCallback ]; + + // Assign the deprecated given callback + QUnit[ loggingCallback ]( userCallback ); + + if ( window.console && window.console.warn ) { + window.console.warn( + "QUnit." + loggingCallback + " was replaced with a new value.\n" + + "Please, check out the documentation on how to apply logging callbacks.\n" + + "Reference: http://api.qunitjs.com/category/callbacks/" + ); + } + } + } +} + +// from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +function Test( settings ) { + var i, l; + + ++Test.count; + + extend( this, settings ); + this.assertions = []; + this.semaphore = 0; + this.usedAsync = false; + this.module = config.currentModule; + this.stack = sourceFromStacktrace( 3 ); + + // Register unique strings + for ( i = 0, l = this.module.tests; i < l.length; i++ ) { + if ( this.module.tests[ i ].name === this.testName ) { + this.testName += " "; + } + } + + this.testId = generateHash( this.module.name, this.testName ); + + this.module.tests.push({ + name: this.testName, + testId: this.testId + }); + + if ( settings.skip ) { + + // Skipped tests will fully ignore any sent callback + this.callback = function() {}; + this.async = false; + this.expected = 0; + } else { + this.assert = new Assert( this ); + } +} + +Test.count = 0; + +Test.prototype = { + before: function() { + if ( + + // Emit moduleStart when we're switching from one module to another + this.module !== config.previousModule || + + // They could be equal (both undefined) but if the previousModule property doesn't + // yet exist it means this is the first test in a suite that isn't wrapped in a + // module, in which case we'll just emit a moduleStart event for 'undefined'. + // Without this, reporters can get testStart before moduleStart which is a problem. + !hasOwn.call( config, "previousModule" ) + ) { + if ( hasOwn.call( config, "previousModule" ) ) { + runLoggingCallbacks( "moduleDone", { + name: config.previousModule.name, + tests: config.previousModule.tests, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all, + runtime: now() - config.moduleStats.started + }); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0, started: now() }; + runLoggingCallbacks( "moduleStart", { + name: this.module.name, + tests: this.module.tests + }); + } + + config.current = this; + + this.testEnvironment = extend( {}, this.module.testEnvironment ); + delete this.testEnvironment.beforeEach; + delete this.testEnvironment.afterEach; + + this.started = now(); + runLoggingCallbacks( "testStart", { + name: this.testName, + module: this.module.name, + testId: this.testId + }); + + if ( !config.pollution ) { + saveGlobal(); + } + }, + + run: function() { + var promise; + + config.current = this; + + if ( this.async ) { + QUnit.stop(); + } + + this.callbackStarted = now(); + + if ( config.notrycatch ) { + promise = this.callback.call( this.testEnvironment, this.assert ); + this.resolvePromise( promise ); + return; + } + + try { + promise = this.callback.call( this.testEnvironment, this.assert ); + this.resolvePromise( promise ); + } catch ( e ) { + this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); + + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + QUnit.start(); + } + } + }, + + after: function() { + checkPollution(); + }, + + queueHook: function( hook, hookName ) { + var promise, + test = this; + return function runHook() { + config.current = test; + if ( config.notrycatch ) { + promise = hook.call( test.testEnvironment, test.assert ); + test.resolvePromise( promise, hookName ); + return; + } + try { + promise = hook.call( test.testEnvironment, test.assert ); + test.resolvePromise( promise, hookName ); + } catch ( error ) { + test.pushFailure( hookName + " failed on " + test.testName + ": " + + ( error.message || error ), extractStacktrace( error, 0 ) ); + } + }; + }, + + // Currently only used for module level hooks, can be used to add global level ones + hooks: function( handler ) { + var hooks = []; + + // Hooks are ignored on skipped tests + if ( this.skip ) { + return hooks; + } + + if ( this.module.testEnvironment && + QUnit.objectType( this.module.testEnvironment[ handler ] ) === "function" ) { + hooks.push( this.queueHook( this.module.testEnvironment[ handler ], handler ) ); + } + + return hooks; + }, + + finish: function() { + config.current = this; + if ( config.requireExpects && this.expected === null ) { + this.pushFailure( "Expected number of assertions to be defined, but expect() was " + + "not called.", this.stack ); + } else if ( this.expected !== null && this.expected !== this.assertions.length ) { + this.pushFailure( "Expected " + this.expected + " assertions, but " + + this.assertions.length + " were run", this.stack ); + } else if ( this.expected === null && !this.assertions.length ) { + this.pushFailure( "Expected at least one assertion, but none were run - call " + + "expect(0) to accept zero assertions.", this.stack ); + } + + var i, + bad = 0; + + this.runtime = now() - this.started; + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + for ( i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[ i ].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + runLoggingCallbacks( "testDone", { + name: this.testName, + module: this.module.name, + skipped: !!this.skip, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length, + runtime: this.runtime, + + // HTML Reporter use + assertions: this.assertions, + testId: this.testId, + + // DEPRECATED: this property will be removed in 2.0.0, use runtime instead + duration: this.runtime + }); + + // QUnit.reset() is deprecated and will be replaced for a new + // fixture reset function on QUnit 2.0/2.1. + // It's still called here for backwards compatibility handling + QUnit.reset(); + + config.current = undefined; + }, + + queue: function() { + var bad, + test = this; + + if ( !this.valid() ) { + return; + } + + function run() { + + // each of these can by async + synchronize([ + function() { + test.before(); + }, + + test.hooks( "beforeEach" ), + + function() { + test.run(); + }, + + test.hooks( "afterEach" ).reverse(), + + function() { + test.after(); + }, + function() { + test.finish(); + } + ]); + } + + // `bad` initialized at top of scope + // defer when previous test run passed, if storage is available + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName ); + + if ( bad ) { + run(); + } else { + synchronize( run, true ); + } + }, + + push: function( result, actual, expected, message ) { + var source, + details = { + module: this.module.name, + name: this.testName, + result: result, + message: message, + actual: actual, + expected: expected, + testId: this.testId, + runtime: now() - this.started + }; + + if ( !result ) { + source = sourceFromStacktrace(); + + if ( source ) { + details.source = source; + } + } + + runLoggingCallbacks( "log", details ); + + this.assertions.push({ + result: !!result, + message: message + }); + }, + + pushFailure: function( message, source, actual ) { + if ( !this instanceof Test ) { + throw new Error( "pushFailure() assertion outside test context, was " + + sourceFromStacktrace( 2 ) ); + } + + var details = { + module: this.module.name, + name: this.testName, + result: false, + message: message || "error", + actual: actual || null, + testId: this.testId, + runtime: now() - this.started + }; + + if ( source ) { + details.source = source; + } + + runLoggingCallbacks( "log", details ); + + this.assertions.push({ + result: false, + message: message + }); + }, + + resolvePromise: function( promise, phase ) { + var then, message, + test = this; + if ( promise != null ) { + then = promise.then; + if ( QUnit.objectType( then ) === "function" ) { + QUnit.stop(); + then.call( + promise, + QUnit.start, + function( error ) { + message = "Promise rejected " + + ( !phase ? "during" : phase.replace( /Each$/, "" ) ) + + " " + test.testName + ": " + ( error.message || error ); + test.pushFailure( message, extractStacktrace( error, 0 ) ); + + // else next test will carry the responsibility + saveGlobal(); + + // Unblock + QUnit.start(); + } + ); + } + } + }, + + valid: function() { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(), + fullName = ( this.module.name + ": " + this.testName ).toLowerCase(); + + // Internally-generated tests are always valid + if ( this.callback && this.callback.validTest ) { + return true; + } + + if ( config.testId.length > 0 && inArray( this.testId, config.testId ) < 0 ) { + return false; + } + + if ( module && ( !this.module.name || this.module.name.toLowerCase() !== module ) ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; + } + +}; + +// Resets the test setup. Useful for tests that modify the DOM. +/* +DEPRECATED: Use multiple tests instead of resetting inside a test. +Use testStart or testDone for custom cleanup. +This method will throw an error in 2.0, and will be removed in 2.1 +*/ +QUnit.reset = function() { + + // Return on non-browser environments + // This is necessary to not break on node tests + if ( typeof window === "undefined" ) { + return; + } + + var fixture = defined.document && document.getElementById && + document.getElementById( "qunit-fixture" ); + + if ( fixture ) { + fixture.innerHTML = config.fixture; + } +}; + +QUnit.pushFailure = function() { + if ( !QUnit.config.current ) { + throw new Error( "pushFailure() assertion outside test context, in " + + sourceFromStacktrace( 2 ) ); + } + + // Gets current test obj + var currentTest = QUnit.config.current; + + return currentTest.pushFailure.apply( currentTest, arguments ); +}; + +// Based on Java's String.hashCode, a simple but not +// rigorously collision resistant hashing function +function generateHash( module, testName ) { + var hex, + i = 0, + hash = 0, + str = module + "\x1C" + testName, + len = str.length; + + for ( ; i < len; i++ ) { + hash = ( ( hash << 5 ) - hash ) + str.charCodeAt( i ); + hash |= 0; + } + + // Convert the possibly negative integer hash code into an 8 character hex string, which isn't + // strictly necessary but increases user understanding that the id is a SHA-like hash + hex = ( 0x100000000 + hash ).toString( 16 ); + if ( hex.length < 8 ) { + hex = "0000000" + hex; + } + + return hex.slice( -8 ); +} + +function Assert( testContext ) { + this.test = testContext; +} + +// Assert helpers +QUnit.assert = Assert.prototype = { + + // Specify the number of expected assertions to guarantee that failed test + // (no assertions are run at all) don't slip through. + expect: function( asserts ) { + if ( arguments.length === 1 ) { + this.test.expected = asserts; + } else { + return this.test.expected; + } + }, + + // Increment this Test's semaphore counter, then return a single-use function that + // decrements that counter a maximum of once. + async: function() { + var test = this.test, + popped = false; + + test.semaphore += 1; + test.usedAsync = true; + pauseProcessing(); + + return function done() { + if ( !popped ) { + test.semaphore -= 1; + popped = true; + resumeProcessing(); + } else { + test.pushFailure( "Called the callback returned from `assert.async` more than once", + sourceFromStacktrace( 2 ) ); + } + }; + }, + + // Exports test.push() to the user API + push: function( /* result, actual, expected, message */ ) { + var assert = this, + currentTest = ( assert instanceof Assert && assert.test ) || QUnit.config.current; + + // Backwards compatibility fix. + // Allows the direct use of global exported assertions and QUnit.assert.* + // Although, it's use is not recommended as it can leak assertions + // to other tests from async tests, because we only get a reference to the current test, + // not exactly the test where assertion were intended to be called. + if ( !currentTest ) { + throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) ); + } + + if ( currentTest.usedAsync === true && currentTest.semaphore === 0 ) { + currentTest.pushFailure( "Assertion after the final `assert.async` was resolved", + sourceFromStacktrace( 2 ) ); + + // Allow this assertion to continue running anyway... + } + + if ( !( assert instanceof Assert ) ) { + assert = currentTest.assert; + } + return assert.test.push.apply( assert.test, arguments ); + }, + + /** + * Asserts rough true-ish result. + * @name ok + * @function + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function( result, message ) { + message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " + + QUnit.dump.parse( result ) ); + this.push( !!result, result, true, message ); + }, + + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @name equal + * @function + * @example equal( format( "{0} bytes.", 2), "2 bytes.", "replaces {0} with next argument" ); + */ + equal: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + this.push( expected == actual, actual, expected, message ); + }, + + /** + * @name notEqual + * @function + */ + notEqual: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + this.push( expected != actual, actual, expected, message ); + }, + + /** + * @name propEqual + * @function + */ + propEqual: function( actual, expected, message ) { + actual = objectValues( actual ); + expected = objectValues( expected ); + this.push( QUnit.equiv( actual, expected ), actual, expected, message ); + }, + + /** + * @name notPropEqual + * @function + */ + notPropEqual: function( actual, expected, message ) { + actual = objectValues( actual ); + expected = objectValues( expected ); + this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); + }, + + /** + * @name deepEqual + * @function + */ + deepEqual: function( actual, expected, message ) { + this.push( QUnit.equiv( actual, expected ), actual, expected, message ); + }, + + /** + * @name notDeepEqual + * @function + */ + notDeepEqual: function( actual, expected, message ) { + this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); + }, + + /** + * @name strictEqual + * @function + */ + strictEqual: function( actual, expected, message ) { + this.push( expected === actual, actual, expected, message ); + }, + + /** + * @name notStrictEqual + * @function + */ + notStrictEqual: function( actual, expected, message ) { + this.push( expected !== actual, actual, expected, message ); + }, + + "throws": function( block, expected, message ) { + var actual, expectedType, + expectedOutput = expected, + ok = false; + + // 'expected' is optional unless doing string comparison + if ( message == null && typeof expected === "string" ) { + message = expected; + expected = null; + } + + this.test.ignoreGlobalErrors = true; + try { + block.call( this.test.testEnvironment ); + } catch (e) { + actual = e; + } + this.test.ignoreGlobalErrors = false; + + if ( actual ) { + expectedType = QUnit.objectType( expected ); + + // we don't want to validate thrown error + if ( !expected ) { + ok = true; + expectedOutput = null; + + // expected is a regexp + } else if ( expectedType === "regexp" ) { + ok = expected.test( errorString( actual ) ); + + // expected is a string + } else if ( expectedType === "string" ) { + ok = expected === errorString( actual ); + + // expected is a constructor, maybe an Error constructor + } else if ( expectedType === "function" && actual instanceof expected ) { + ok = true; + + // expected is an Error object + } else if ( expectedType === "object" ) { + ok = actual instanceof expected.constructor && + actual.name === expected.name && + actual.message === expected.message; + + // expected is a validation function which returns true if validation passed + } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) { + expectedOutput = null; + ok = true; + } + + this.push( ok, actual, expectedOutput, message ); + } else { + this.test.pushFailure( message, null, "No exception was thrown." ); + } + } +}; + +// Provide an alternative to assert.throws(), for enviroments that consider throws a reserved word +// Known to us are: Closure Compiler, Narwhal +(function() { + /*jshint sub:true */ + Assert.prototype.raises = Assert.prototype[ "throws" ]; +}()); + +// Test for equality any JavaScript type. +// Author: Philippe Rathé +QUnit.equiv = (function() { + + // Call the o related callback with the given arguments. + function bindCallbacks( o, callbacks, args ) { + var prop = QUnit.objectType( o ); + if ( prop ) { + if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { + return callbacks[ prop ].apply( callbacks, args ); + } else { + return callbacks[ prop ]; // or undefined + } + } + } + + // the real equiv function + var innerEquiv, + + // stack to decide between skip/abort functions + callers = [], + + // stack to avoiding loops from circular referencing + parents = [], + parentsB = [], + + getProto = Object.getPrototypeOf || function( obj ) { + /* jshint camelcase: false, proto: true */ + return obj.__proto__; + }, + callbacks = (function() { + + // for string, boolean, number and null + function useStrictEquality( b, a ) { + + /*jshint eqeqeq:false */ + if ( b instanceof a.constructor || a instanceof b.constructor ) { + + // to catch short annotation VS 'new' annotation of a + // declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function( b ) { + return isNaN( b ); + }, + + "date": function( b, a ) { + return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function( b, a ) { + return QUnit.objectType( b ) === "regexp" && + + // the regex itself + a.source === b.source && + + // and its modifiers + a.global === b.global && + + // (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline && + a.sticky === b.sticky; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function() { + var caller = callers[ callers.length - 1 ]; + return caller !== Object && typeof caller !== "undefined"; + }, + + "array": function( b, a ) { + var i, j, len, loop, aCircular, bCircular; + + // b could be an object literal here + if ( QUnit.objectType( b ) !== "array" ) { + return false; + } + + len = a.length; + if ( len !== b.length ) { + // safe and faster + return false; + } + + // track reference to avoid circular references + parents.push( a ); + parentsB.push( b ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[ j ] === a[ i ]; + bCircular = parentsB[ j ] === b[ i ]; + if ( aCircular || bCircular ) { + if ( a[ i ] === b[ i ] || aCircular && bCircular ) { + loop = true; + } else { + parents.pop(); + parentsB.pop(); + return false; + } + } + } + if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { + parents.pop(); + parentsB.pop(); + return false; + } + } + parents.pop(); + parentsB.pop(); + return true; + }, + + "object": function( b, a ) { + + /*jshint forin:false */ + var i, j, loop, aCircular, bCircular, + // Default to true + eq = true, + aProperties = [], + bProperties = []; + + // comparing constructors is more strict than using + // instanceof + if ( a.constructor !== b.constructor ) { + + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( !( ( getProto( a ) === null && getProto( b ) === Object.prototype ) || + ( getProto( b ) === null && getProto( a ) === Object.prototype ) ) ) { + return false; + } + } + + // stack constructor before traversing properties + callers.push( a.constructor ); + + // track reference to avoid circular references + parents.push( a ); + parentsB.push( b ); + + // be strict: don't ensure hasOwnProperty and go deep + for ( i in a ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[ j ] === a[ i ]; + bCircular = parentsB[ j ] === b[ i ]; + if ( aCircular || bCircular ) { + if ( a[ i ] === b[ i ] || aCircular && bCircular ) { + loop = true; + } else { + eq = false; + break; + } + } + } + aProperties.push( i ); + if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { + eq = false; + break; + } + } + + parents.pop(); + parentsB.pop(); + callers.pop(); // unstack, we are done + + for ( i in b ) { + bProperties.push( i ); // collect b's properties + } + + // Ensures identical properties name + return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + } + }; + }()); + + innerEquiv = function() { // can take multiple arguments + var args = [].slice.apply( arguments ); + if ( args.length < 2 ) { + return true; // end transition + } + + return ( (function( a, b ) { + if ( a === b ) { + return true; // catch the most you can + } else if ( a === null || b === null || typeof a === "undefined" || + typeof b === "undefined" || + QUnit.objectType( a ) !== QUnit.objectType( b ) ) { + + // don't lose time with error prone cases + return false; + } else { + return bindCallbacks( a, callbacks, [ b, a ] ); + } + + // apply transition with (1..n) arguments + }( args[ 0 ], args[ 1 ] ) ) && + innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) ); + }; + + return innerEquiv; +}()); + +// Based on jsDump by Ariel Flesler +// http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html +QUnit.dump = (function() { + function quote( str ) { + return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; + } + function literal( o ) { + return o + ""; + } + function join( pre, arr, post ) { + var s = dump.separator(), + base = dump.indent(), + inner = dump.indent( 1 ); + if ( arr.join ) { + arr = arr.join( "," + s + inner ); + } + if ( !arr ) { + return pre + post; + } + return [ pre, inner + arr, base + post ].join( s ); + } + function array( arr, stack ) { + var i = arr.length, + ret = new Array( i ); + + if ( dump.maxDepth && dump.depth > dump.maxDepth ) { + return "[object Array]"; + } + + this.up(); + while ( i-- ) { + ret[ i ] = this.parse( arr[ i ], undefined, stack ); + } + this.down(); + return join( "[", ret, "]" ); + } + + var reName = /^function (\w+)/, + dump = { + + // objType is used mostly internally, you can fix a (custom) type in advance + parse: function( obj, objType, stack ) { + stack = stack || []; + var res, parser, parserType, + inStack = inArray( obj, stack ); + + if ( inStack !== -1 ) { + return "recursion(" + ( inStack - stack.length ) + ")"; + } + + objType = objType || this.typeOf( obj ); + parser = this.parsers[ objType ]; + parserType = typeof parser; + + if ( parserType === "function" ) { + stack.push( obj ); + res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + return ( parserType === "string" ) ? parser : this.parsers.error; + }, + typeOf: function( obj ) { + var type; + if ( obj === null ) { + type = "null"; + } else if ( typeof obj === "undefined" ) { + type = "undefined"; + } else if ( QUnit.is( "regexp", obj ) ) { + type = "regexp"; + } else if ( QUnit.is( "date", obj ) ) { + type = "date"; + } else if ( QUnit.is( "function", obj ) ) { + type = "function"; + } else if ( obj.setInterval !== undefined && + obj.document !== undefined && + obj.nodeType === undefined ) { + type = "window"; + } else if ( obj.nodeType === 9 ) { + type = "document"; + } else if ( obj.nodeType ) { + type = "node"; + } else if ( + + // native arrays + toString.call( obj ) === "[object Array]" || + + // NodeList objects + ( typeof obj.length === "number" && obj.item !== undefined && + ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null && + obj[ 0 ] === undefined ) ) ) + ) { + type = "array"; + } else if ( obj.constructor === Error.prototype.constructor ) { + type = "error"; + } else { + type = typeof obj; + } + return type; + }, + separator: function() { + return this.multiline ? this.HTML ? "
                              " : "\n" : this.HTML ? " " : " "; + }, + // extra can be a number, shortcut for increasing-calling-decreasing + indent: function( extra ) { + if ( !this.multiline ) { + return ""; + } + var chr = this.indentChar; + if ( this.HTML ) { + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); + } + return new Array( this.depth + ( extra || 0 ) ).join( chr ); + }, + up: function( a ) { + this.depth += a || 1; + }, + down: function( a ) { + this.depth -= a || 1; + }, + setParser: function( name, parser ) { + this.parsers[ name ] = parser; + }, + // The next 3 are exposed so you can use them + quote: quote, + literal: literal, + join: join, + // + depth: 1, + maxDepth: 5, + + // This is the list of parsers, to modify them, use dump.setParser + parsers: { + window: "[Window]", + document: "[Document]", + error: function( error ) { + return "Error(\"" + error.message + "\")"; + }, + unknown: "[Unknown]", + "null": "null", + "undefined": "undefined", + "function": function( fn ) { + var ret = "function", + + // functions never have name in IE + name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ]; + + if ( name ) { + ret += " " + name; + } + ret += "( "; + + ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" ); + return join( ret, dump.parse( fn, "functionCode" ), "}" ); + }, + array: array, + nodelist: array, + "arguments": array, + object: function( map, stack ) { + var keys, key, val, i, nonEnumerableProperties, + ret = []; + + if ( dump.maxDepth && dump.depth > dump.maxDepth ) { + return "[object Object]"; + } + + dump.up(); + keys = []; + for ( key in map ) { + keys.push( key ); + } + + // Some properties are not always enumerable on Error objects. + nonEnumerableProperties = [ "message", "name" ]; + for ( i in nonEnumerableProperties ) { + key = nonEnumerableProperties[ i ]; + if ( key in map && !( key in keys ) ) { + keys.push( key ); + } + } + keys.sort(); + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + val = map[ key ]; + ret.push( dump.parse( key, "key" ) + ": " + + dump.parse( val, undefined, stack ) ); + } + dump.down(); + return join( "{", ret, "}" ); + }, + node: function( node ) { + var len, i, val, + open = dump.HTML ? "<" : "<", + close = dump.HTML ? ">" : ">", + tag = node.nodeName.toLowerCase(), + ret = open + tag, + attrs = node.attributes; + + if ( attrs ) { + for ( i = 0, len = attrs.length; i < len; i++ ) { + val = attrs[ i ].nodeValue; + + // IE6 includes all attributes in .attributes, even ones not explicitly + // set. Those have values like undefined, null, 0, false, "" or + // "inherit". + if ( val && val !== "inherit" ) { + ret += " " + attrs[ i ].nodeName + "=" + + dump.parse( val, "attribute" ); + } + } + } + ret += close; + + // Show content of TextNode or CDATASection + if ( node.nodeType === 3 || node.nodeType === 4 ) { + ret += node.nodeValue; + } + + return ret + open + "/" + tag + close; + }, + + // function calls it internally, it's the arguments part of the function + functionArgs: function( fn ) { + var args, + l = fn.length; + + if ( !l ) { + return ""; + } + + args = new Array( l ); + while ( l-- ) { + + // 97 is 'a' + args[ l ] = String.fromCharCode( 97 + l ); + } + return " " + args.join( ", " ) + " "; + }, + // object calls it internally, the key part of an item in a map + key: quote, + // function calls it internally, it's the content of the function + functionCode: "[code]", + // node calls it internally, it's an html attribute value + attribute: quote, + string: quote, + date: quote, + regexp: literal, + number: literal, + "boolean": literal + }, + // if true, entities are escaped ( <, >, \t, space and \n ) + HTML: false, + // indentation unit + indentChar: " ", + // if true, items in a collection, are separated by a \n, else just a space. + multiline: true + }; + + return dump; +}()); + +// back compat +QUnit.jsDump = QUnit.dump; + +// For browser, export only select globals +if ( typeof window !== "undefined" ) { + + // Deprecated + // Extend assert methods to QUnit and Global scope through Backwards compatibility + (function() { + var i, + assertions = Assert.prototype; + + function applyCurrent( current ) { + return function() { + var assert = new Assert( QUnit.config.current ); + current.apply( assert, arguments ); + }; + } + + for ( i in assertions ) { + QUnit[ i ] = applyCurrent( assertions[ i ] ); + } + })(); + + (function() { + var i, l, + keys = [ + "test", + "module", + "expect", + "asyncTest", + "start", + "stop", + "ok", + "equal", + "notEqual", + "propEqual", + "notPropEqual", + "deepEqual", + "notDeepEqual", + "strictEqual", + "notStrictEqual", + "throws" + ]; + + for ( i = 0, l = keys.length; i < l; i++ ) { + window[ keys[ i ] ] = QUnit[ keys[ i ] ]; + } + })(); + + window.QUnit = QUnit; +} + +// For nodejs +if ( typeof module !== "undefined" && module.exports ) { + module.exports = QUnit; +} + +// For CommonJS with exports, but without module.exports, like Rhino +if ( typeof exports !== "undefined" ) { + exports.QUnit = QUnit; +} + +// Get a reference to the global object, like window in browsers +}( (function() { + return this; +})() )); + +/*istanbul ignore next */ +// jscs:disable maximumLineLength +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" + */ +QUnit.diff = (function() { + var hasOwn = Object.prototype.hasOwnProperty; + + /*jshint eqeqeq:false, eqnull:true */ + function diff( o, n ) { + var i, + ns = {}, + os = {}; + + for ( i = 0; i < n.length; i++ ) { + if ( !hasOwn.call( ns, n[ i ] ) ) { + ns[ n[ i ] ] = { + rows: [], + o: null + }; + } + ns[ n[ i ] ].rows.push( i ); + } + + for ( i = 0; i < o.length; i++ ) { + if ( !hasOwn.call( os, o[ i ] ) ) { + os[ o[ i ] ] = { + rows: [], + n: null + }; + } + os[ o[ i ] ].rows.push( i ); + } + + for ( i in ns ) { + if ( hasOwn.call( ns, i ) ) { + if ( ns[ i ].rows.length === 1 && hasOwn.call( os, i ) && os[ i ].rows.length === 1 ) { + n[ ns[ i ].rows[ 0 ] ] = { + text: n[ ns[ i ].rows[ 0 ] ], + row: os[ i ].rows[ 0 ] + }; + o[ os[ i ].rows[ 0 ] ] = { + text: o[ os[ i ].rows[ 0 ] ], + row: ns[ i ].rows[ 0 ] + }; + } + } + } + + for ( i = 0; i < n.length - 1; i++ ) { + if ( n[ i ].text != null && n[ i + 1 ].text == null && n[ i ].row + 1 < o.length && o[ n[ i ].row + 1 ].text == null && + n[ i + 1 ] == o[ n[ i ].row + 1 ] ) { + + n[ i + 1 ] = { + text: n[ i + 1 ], + row: n[ i ].row + 1 + }; + o[ n[ i ].row + 1 ] = { + text: o[ n[ i ].row + 1 ], + row: i + 1 + }; + } + } + + for ( i = n.length - 1; i > 0; i-- ) { + if ( n[ i ].text != null && n[ i - 1 ].text == null && n[ i ].row > 0 && o[ n[ i ].row - 1 ].text == null && + n[ i - 1 ] == o[ n[ i ].row - 1 ] ) { + + n[ i - 1 ] = { + text: n[ i - 1 ], + row: n[ i ].row - 1 + }; + o[ n[ i ].row - 1 ] = { + text: o[ n[ i ].row - 1 ], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function( o, n ) { + o = o.replace( /\s+$/, "" ); + n = n.replace( /\s+$/, "" ); + + var i, pre, + str = "", + out = diff( o === "" ? [] : o.split( /\s+/ ), n === "" ? [] : n.split( /\s+/ ) ), + oSpace = o.match( /\s+/g ), + nSpace = n.match( /\s+/g ); + + if ( oSpace == null ) { + oSpace = [ " " ]; + } else { + oSpace.push( " " ); + } + + if ( nSpace == null ) { + nSpace = [ " " ]; + } else { + nSpace.push( " " ); + } + + if ( out.n.length === 0 ) { + for ( i = 0; i < out.o.length; i++ ) { + str += "" + out.o[ i ] + oSpace[ i ] + ""; + } + } else { + if ( out.n[ 0 ].text == null ) { + for ( n = 0; n < out.o.length && out.o[ n ].text == null; n++ ) { + str += "" + out.o[ n ] + oSpace[ n ] + ""; + } + } + + for ( i = 0; i < out.n.length; i++ ) { + if ( out.n[ i ].text == null ) { + str += "" + out.n[ i ] + nSpace[ i ] + ""; + } else { + + // `pre` initialized at top of scope + pre = ""; + + for ( n = out.n[ i ].row + 1; n < out.o.length && out.o[ n ].text == null; n++ ) { + pre += "" + out.o[ n ] + oSpace[ n ] + ""; + } + str += " " + out.n[ i ].text + nSpace[ i ] + pre; + } + } + } + + return str; + }; +}()); +// jscs:enable + +(function() { + +// Deprecated QUnit.init - Ref #530 +// Re-initialize the configuration options +QUnit.init = function() { + var tests, banner, result, qunit, + config = QUnit.config; + + config.stats = { all: 0, bad: 0 }; + config.moduleStats = { all: 0, bad: 0 }; + config.started = 0; + config.updateRate = 1000; + config.blocking = false; + config.autostart = true; + config.autorun = false; + config.filter = ""; + config.queue = []; + + // Return on non-browser environments + // This is necessary to not break on node tests + if ( typeof window === "undefined" ) { + return; + } + + qunit = id( "qunit" ); + if ( qunit ) { + qunit.innerHTML = + "

                              " + escapeText( document.title ) + "

                              " + + "

                              " + + "
                              " + + "

                              " + + "
                                "; + } + + tests = id( "qunit-tests" ); + banner = id( "qunit-banner" ); + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...
                                 "; + } +}; + +// Don't load the HTML Reporter on non-Browser environments +if ( typeof window === "undefined" ) { + return; +} + +var config = QUnit.config, + hasOwn = Object.prototype.hasOwnProperty, + defined = { + document: window.document !== undefined, + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch ( e ) { + return false; + } + }()) + }, + modulesList = []; + +/** +* Escape text for attribute or text content. +*/ +function escapeText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + + // Both single quotes and double quotes (for attributes) + return s.replace( /['"<>&]/g, function( s ) { + switch ( s ) { + case "'": + return "'"; + case "\"": + return """; + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + } + }); +} + +/** + * @param {HTMLElement} elem + * @param {string} type + * @param {Function} fn + */ +function addEvent( elem, type, fn ) { + if ( elem.addEventListener ) { + + // Standards-based browsers + elem.addEventListener( type, fn, false ); + } else if ( elem.attachEvent ) { + + // support: IE <9 + elem.attachEvent( "on" + type, fn ); + } +} + +/** + * @param {Array|NodeList} elems + * @param {string} type + * @param {Function} fn + */ +function addEvents( elems, type, fn ) { + var i = elems.length; + while ( i-- ) { + addEvent( elems[ i ], type, fn ); + } +} + +function hasClass( elem, name ) { + return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0; +} + +function addClass( elem, name ) { + if ( !hasClass( elem, name ) ) { + elem.className += ( elem.className ? " " : "" ) + name; + } +} + +function toggleClass( elem, name ) { + if ( hasClass( elem, name ) ) { + removeClass( elem, name ); + } else { + addClass( elem, name ); + } +} + +function removeClass( elem, name ) { + var set = " " + elem.className + " "; + + // Class name may appear multiple times + while ( set.indexOf( " " + name + " " ) >= 0 ) { + set = set.replace( " " + name + " ", " " ); + } + + // trim for prettiness + elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" ); +} + +function id( name ) { + return defined.document && document.getElementById && document.getElementById( name ); +} + +function getUrlConfigHtml() { + var i, j, val, + escaped, escapedTooltip, + selection = false, + len = config.urlConfig.length, + urlConfigHtml = ""; + + for ( i = 0; i < len; i++ ) { + val = config.urlConfig[ i ]; + if ( typeof val === "string" ) { + val = { + id: val, + label: val + }; + } + + escaped = escapeText( val.id ); + escapedTooltip = escapeText( val.tooltip ); + + config[ val.id ] = QUnit.urlParams[ val.id ]; + if ( !val.value || typeof val.value === "string" ) { + urlConfigHtml += ""; + } else { + urlConfigHtml += ""; + } + } + + return urlConfigHtml; +} + +// Handle "click" events on toolbar checkboxes and "change" for select menus. +// Updates the URL with the new state of `config.urlConfig` values. +function toolbarChanged() { + var updatedUrl, value, + field = this, + params = {}; + + // Detect if field is a select menu or a checkbox + if ( "selectedIndex" in field ) { + value = field.options[ field.selectedIndex ].value || undefined; + } else { + value = field.checked ? ( field.defaultValue || true ) : undefined; + } + + params[ field.name ] = value; + updatedUrl = QUnit.url( params ); + + if ( "hidepassed" === field.name && "replaceState" in window.history ) { + config[ field.name ] = value || false; + if ( value ) { + addClass( id( "qunit-tests" ), "hidepass" ); + } else { + removeClass( id( "qunit-tests" ), "hidepass" ); + } + + // It is not necessary to refresh the whole page + window.history.replaceState( null, "", updatedUrl ); + } else { + window.location = updatedUrl; + } +} + +function toolbarUrlConfigContainer() { + var urlConfigContainer = document.createElement( "span" ); + + urlConfigContainer.innerHTML = getUrlConfigHtml(); + + // For oldIE support: + // * Add handlers to the individual elements instead of the container + // * Use "click" instead of "change" for checkboxes + addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", toolbarChanged ); + addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", toolbarChanged ); + + return urlConfigContainer; +} + +function toolbarModuleFilterHtml() { + var i, + moduleFilterHtml = ""; + + if ( !modulesList.length ) { + return false; + } + + modulesList.sort(function( a, b ) { + return a.localeCompare( b ); + }); + + moduleFilterHtml += "" + + ""; + + return moduleFilterHtml; +} + +function toolbarModuleFilter() { + var toolbar = id( "qunit-testrunner-toolbar" ), + moduleFilter = document.createElement( "span" ), + moduleFilterHtml = toolbarModuleFilterHtml(); + + if ( !moduleFilterHtml ) { + return false; + } + + moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); + moduleFilter.innerHTML = moduleFilterHtml; + + addEvent( moduleFilter.lastChild, "change", function() { + var selectBox = moduleFilter.getElementsByTagName( "select" )[ 0 ], + selection = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value ); + + window.location = QUnit.url({ + module: ( selection === "" ) ? undefined : selection, + + // Remove any existing filters + filter: undefined, + testId: undefined + }); + }); + + toolbar.appendChild( moduleFilter ); +} + +function appendToolbar() { + var toolbar = id( "qunit-testrunner-toolbar" ); + + if ( toolbar ) { + toolbar.appendChild( toolbarUrlConfigContainer() ); + } +} + +function appendBanner() { + var banner = id( "qunit-banner" ); + + if ( banner ) { + banner.className = ""; + banner.innerHTML = "" + banner.innerHTML + " "; + } +} + +function appendTestResults() { + var tests = id( "qunit-tests" ), + result = id( "qunit-testresult" ); + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + tests.innerHTML = ""; + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...
                                 "; + } +} + +function storeFixture() { + var fixture = id( "qunit-fixture" ); + if ( fixture ) { + config.fixture = fixture.innerHTML; + } +} + +function appendUserAgent() { + var userAgent = id( "qunit-userAgent" ); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } +} + +function appendTestsList( modules ) { + var i, l, x, z, test, moduleObj; + + for ( i = 0, l = modules.length; i < l; i++ ) { + moduleObj = modules[ i ]; + + if ( moduleObj.name ) { + modulesList.push( moduleObj.name ); + } + + for ( x = 0, z = moduleObj.tests.length; x < z; x++ ) { + test = moduleObj.tests[ x ]; + + appendTest( test.name, test.testId, moduleObj.name ); + } + } +} + +function appendTest( name, testId, moduleName ) { + var title, rerunTrigger, testBlock, assertList, + tests = id( "qunit-tests" ); + + if ( !tests ) { + return; + } + + title = document.createElement( "strong" ); + title.innerHTML = getNameHtml( name, moduleName ); + + rerunTrigger = document.createElement( "a" ); + rerunTrigger.innerHTML = "Rerun"; + rerunTrigger.href = QUnit.url({ testId: testId }); + + testBlock = document.createElement( "li" ); + testBlock.appendChild( title ); + testBlock.appendChild( rerunTrigger ); + testBlock.id = "qunit-test-output-" + testId; + + assertList = document.createElement( "ol" ); + assertList.className = "qunit-assert-list"; + + testBlock.appendChild( assertList ); + + tests.appendChild( testBlock ); +} + +// HTML Reporter initialization and load +QUnit.begin(function( details ) { + var qunit = id( "qunit" ); + + // Fixture is the only one necessary to run without the #qunit element + storeFixture(); + + if ( !qunit ) { + return; + } + + qunit.innerHTML = + "

                                " + escapeText( document.title ) + "

                                " + + "

                                " + + "
                                " + + "

                                " + + "
                                  "; + + appendBanner(); + appendTestResults(); + appendUserAgent(); + appendToolbar(); + appendTestsList( details.modules ); + toolbarModuleFilter(); + + if ( config.hidepassed ) { + addClass( qunit.lastChild, "hidepass" ); + } +}); + +QUnit.done(function( details ) { + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + html = [ + "Tests completed in ", + details.runtime, + " milliseconds.
                                  ", + "", + details.passed, + " assertions of ", + details.total, + " passed, ", + details.failed, + " failed." + ].join( "" ); + + if ( banner ) { + banner.className = details.failed ? "qunit-fail" : "qunit-pass"; + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && defined.document && document.title ) { + + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( details.failed ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && details.failed === 0 ) { + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } + } + } + + // scroll back to top to show results + if ( config.scrolltop && window.scrollTo ) { + window.scrollTo( 0, 0 ); + } +}); + +function getNameHtml( name, module ) { + var nameHtml = ""; + + if ( module ) { + nameHtml = "" + escapeText( module ) + ": "; + } + + nameHtml += "" + escapeText( name ) + ""; + + return nameHtml; +} + +QUnit.testStart(function( details ) { + var running, testBlock; + + testBlock = id( "qunit-test-output-" + details.testId ); + if ( testBlock ) { + testBlock.className = "running"; + } else { + + // Report later registered tests + appendTest( details.name, details.testId, details.module ); + } + + running = id( "qunit-testresult" ); + if ( running ) { + running.innerHTML = "Running:
                                  " + getNameHtml( details.name, details.module ); + } + +}); + +QUnit.log(function( details ) { + var assertList, assertLi, + message, expected, actual, + testItem = id( "qunit-test-output-" + details.testId ); + + if ( !testItem ) { + return; + } + + message = escapeText( details.message ) || ( details.result ? "okay" : "failed" ); + message = "" + message + ""; + message += "@ " + details.runtime + " ms"; + + // pushFailure doesn't provide details.expected + // when it calls, it's implicit to also not show expected and diff stuff + // Also, we need to check details.expected existence, as it can exist and be undefined + if ( !details.result && hasOwn.call( details, "expected" ) ) { + expected = escapeText( QUnit.dump.parse( details.expected ) ); + actual = escapeText( QUnit.dump.parse( details.actual ) ); + message += "
                              1. "; + + if ( actual !== expected ) { + message += "" + + ""; + } + + if ( details.source ) { + message += ""; + } + + message += "
                                Expected:
                                " +
                                +			expected +
                                +			"
                                Result:
                                " +
                                +				actual + "
                                Diff:
                                " +
                                +				QUnit.diff( expected, actual ) + "
                                Source:
                                " +
                                +				escapeText( details.source ) + "
                                "; + + // this occours when pushFailure is set and we have an extracted stack trace + } else if ( !details.result && details.source ) { + message += "" + + "" + + "
                                Source:
                                " +
                                +			escapeText( details.source ) + "
                                "; + } + + assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; + + assertLi = document.createElement( "li" ); + assertLi.className = details.result ? "pass" : "fail"; + assertLi.innerHTML = message; + assertList.appendChild( assertLi ); +}); + +QUnit.testDone(function( details ) { + var testTitle, time, testItem, assertList, + good, bad, testCounts, skipped, + tests = id( "qunit-tests" ); + + if ( !tests ) { + return; + } + + testItem = id( "qunit-test-output-" + details.testId ); + + assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; + + good = details.passed; + bad = details.failed; + + // store result when possible + if ( config.reorder && defined.sessionStorage ) { + if ( bad ) { + sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad ); + } else { + sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name ); + } + } + + if ( bad === 0 ) { + addClass( assertList, "qunit-collapsed" ); + } + + // testItem.firstChild is the test name + testTitle = testItem.firstChild; + + testCounts = bad ? + "" + bad + ", " + "" + good + ", " : + ""; + + testTitle.innerHTML += " (" + testCounts + + details.assertions.length + ")"; + + if ( details.skipped ) { + addClass( testItem, "skipped" ); + skipped = document.createElement( "em" ); + skipped.className = "qunit-skipped-label"; + skipped.innerHTML = "skipped"; + testItem.insertBefore( skipped, testTitle ); + } else { + addEvent( testTitle, "click", function() { + toggleClass( assertList, "qunit-collapsed" ); + }); + + testItem.className = bad ? "fail" : "pass"; + + time = document.createElement( "span" ); + time.className = "runtime"; + time.innerHTML = details.runtime + " ms"; + testItem.insertBefore( time, assertList ); + } +}); + +if ( !defined.document || document.readyState === "complete" ) { + config.pageLoaded = true; + config.autorun = true; +} + +if ( defined.document ) { + addEvent( window, "load", QUnit.load ); +} + +})(); diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 000000000..e69de29bb diff --git a/public/images/QQ_Logo.png b/public/images/QQ_Logo.png new file mode 100644 index 000000000..1e3815efa Binary files /dev/null and b/public/images/QQ_Logo.png differ diff --git a/public/images/WebFooterCompany/0 b/public/images/WebFooterCompany/0 new file mode 100644 index 000000000..7d228b32b Binary files /dev/null and b/public/images/WebFooterCompany/0 differ diff --git a/public/images/WebUploader/bgblack.png b/public/images/WebUploader/bgblack.png new file mode 100644 index 000000000..22c042aa0 Binary files /dev/null and b/public/images/WebUploader/bgblack.png differ diff --git a/public/images/WebUploader/upload-bj.png b/public/images/WebUploader/upload-bj.png new file mode 100644 index 000000000..9029fec4d Binary files /dev/null and b/public/images/WebUploader/upload-bj.png differ diff --git a/public/images/WebUploader/upload-icon1.png b/public/images/WebUploader/upload-icon1.png new file mode 100644 index 000000000..6b8fdd48f Binary files /dev/null and b/public/images/WebUploader/upload-icon1.png differ diff --git a/public/images/account/shiming150.png b/public/images/account/shiming150.png new file mode 100644 index 000000000..eed1116b0 Binary files /dev/null and b/public/images/account/shiming150.png differ diff --git a/public/images/account/zhiye150.png b/public/images/account/zhiye150.png new file mode 100644 index 000000000..deeff51c2 Binary files /dev/null and b/public/images/account/zhiye150.png differ diff --git a/public/images/bigdata/banner01.png b/public/images/bigdata/banner01.png new file mode 100644 index 000000000..757d14c68 Binary files /dev/null and b/public/images/bigdata/banner01.png differ diff --git a/public/images/bigdata/banner03.png b/public/images/bigdata/banner03.png new file mode 100644 index 000000000..39765b54b Binary files /dev/null and b/public/images/bigdata/banner03.png differ diff --git a/public/images/bigdata/banner04.png b/public/images/bigdata/banner04.png new file mode 100644 index 000000000..532c33515 Binary files /dev/null and b/public/images/bigdata/banner04.png differ diff --git a/public/images/bigdata/banner05.png b/public/images/bigdata/banner05.png new file mode 100644 index 000000000..07c835b18 Binary files /dev/null and b/public/images/bigdata/banner05.png differ diff --git a/public/images/bigdata/banner06.png b/public/images/bigdata/banner06.png new file mode 100644 index 000000000..825016648 Binary files /dev/null and b/public/images/bigdata/banner06.png differ diff --git a/public/images/bigdata/bigdata-logo.2png b/public/images/bigdata/bigdata-logo.2png new file mode 100644 index 000000000..6450ce6d9 Binary files /dev/null and b/public/images/bigdata/bigdata-logo.2png differ diff --git a/public/images/bigdata/bigdata-logo.png b/public/images/bigdata/bigdata-logo.png new file mode 100644 index 000000000..c7b3ba455 Binary files /dev/null and b/public/images/bigdata/bigdata-logo.png differ diff --git a/public/images/bigdata/edu-class/edu-class-img.jpg b/public/images/bigdata/edu-class/edu-class-img.jpg new file mode 100644 index 000000000..cd69bcb05 Binary files /dev/null and b/public/images/bigdata/edu-class/edu-class-img.jpg differ diff --git a/public/images/bigdata/edu-class/edu-nodata.png b/public/images/bigdata/edu-class/edu-nodata.png new file mode 100644 index 000000000..4b158a05f Binary files /dev/null and b/public/images/bigdata/edu-class/edu-nodata.png differ diff --git a/public/images/bigdata/edu-footer-logo.png b/public/images/bigdata/edu-footer-logo.png new file mode 100644 index 000000000..b7c5499df Binary files /dev/null and b/public/images/bigdata/edu-footer-logo.png differ diff --git a/public/images/bigdata/edu-index/banner.jpg b/public/images/bigdata/edu-index/banner.jpg new file mode 100644 index 000000000..55b6036a6 Binary files /dev/null and b/public/images/bigdata/edu-index/banner.jpg differ diff --git a/public/images/bigdata/edu-index/edu-index-apple.png b/public/images/bigdata/edu-index/edu-index-apple.png new file mode 100644 index 000000000..9c4ff2aea Binary files /dev/null and b/public/images/bigdata/edu-index/edu-index-apple.png differ diff --git a/public/images/bigdata/edu-index/edu-index-img01.jpg b/public/images/bigdata/edu-index/edu-index-img01.jpg new file mode 100644 index 000000000..207946989 Binary files /dev/null and b/public/images/bigdata/edu-index/edu-index-img01.jpg differ diff --git a/public/images/bigdata/edu-index/edu-index-img02.png b/public/images/bigdata/edu-index/edu-index-img02.png new file mode 100644 index 000000000..6497ae02e Binary files /dev/null and b/public/images/bigdata/edu-index/edu-index-img02.png differ diff --git a/public/images/bigdata/icons_login.png b/public/images/bigdata/icons_login.png new file mode 100644 index 000000000..64a936888 Binary files /dev/null and b/public/images/bigdata/icons_login.png differ diff --git a/public/images/bigdata/loading2.svg b/public/images/bigdata/loading2.svg new file mode 100644 index 000000000..5ddcbb7e3 --- /dev/null +++ b/public/images/bigdata/loading2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/bigdata/logo-1.png b/public/images/bigdata/logo-1.png new file mode 100644 index 000000000..fd8267784 Binary files /dev/null and b/public/images/bigdata/logo-1.png differ diff --git a/public/images/bigdata/logo.png b/public/images/bigdata/logo.png new file mode 100644 index 000000000..f1d1d774a Binary files /dev/null and b/public/images/bigdata/logo.png differ diff --git a/public/images/bigdata/new-logo.png b/public/images/bigdata/new-logo.png new file mode 100644 index 000000000..2c5862bda Binary files /dev/null and b/public/images/bigdata/new-logo.png differ diff --git a/public/images/bigdata/pointer2.png b/public/images/bigdata/pointer2.png new file mode 100644 index 000000000..6d091af5d Binary files /dev/null and b/public/images/bigdata/pointer2.png differ diff --git a/public/images/bigdata/shenglue-ring.gif b/public/images/bigdata/shenglue-ring.gif new file mode 100644 index 000000000..fc11ec43e Binary files /dev/null and b/public/images/bigdata/shenglue-ring.gif differ diff --git a/public/images/bigdata/singel.png b/public/images/bigdata/singel.png new file mode 100644 index 000000000..c62175e86 Binary files /dev/null and b/public/images/bigdata/singel.png differ diff --git a/public/images/bigdata/slider-bg-1.jpg b/public/images/bigdata/slider-bg-1.jpg new file mode 100644 index 000000000..01ca17ce2 Binary files /dev/null and b/public/images/bigdata/slider-bg-1.jpg differ diff --git a/public/images/bigdata/trustie_QR.jpg b/public/images/bigdata/trustie_QR.jpg new file mode 100644 index 000000000..2b0c38f8b Binary files /dev/null and b/public/images/bigdata/trustie_QR.jpg differ diff --git a/public/images/bigdata/user-renzheng.jpg b/public/images/bigdata/user-renzheng.jpg new file mode 100644 index 000000000..507d67cd3 Binary files /dev/null and b/public/images/bigdata/user-renzheng.jpg differ diff --git a/public/images/bigdata/user-zhengjian.jpg b/public/images/bigdata/user-zhengjian.jpg new file mode 100644 index 000000000..bb7505a6b Binary files /dev/null and b/public/images/bigdata/user-zhengjian.jpg differ diff --git a/public/images/bigdata/wx_help.png b/public/images/bigdata/wx_help.png new file mode 100644 index 000000000..c4ed52ace Binary files /dev/null and b/public/images/bigdata/wx_help.png differ diff --git a/public/images/bigdata/ziliao01.png b/public/images/bigdata/ziliao01.png new file mode 100644 index 000000000..56b86d212 Binary files /dev/null and b/public/images/bigdata/ziliao01.png differ diff --git a/public/images/colorbox/border1.png b/public/images/colorbox/border1.png new file mode 100644 index 000000000..0ddc70405 Binary files /dev/null and b/public/images/colorbox/border1.png differ diff --git a/public/images/colorbox/border2.png b/public/images/colorbox/border2.png new file mode 100644 index 000000000..aa62a0b72 Binary files /dev/null and b/public/images/colorbox/border2.png differ diff --git a/public/images/colorbox/loading.gif b/public/images/colorbox/loading.gif new file mode 100644 index 000000000..602ce3c3a Binary files /dev/null and b/public/images/colorbox/loading.gif differ diff --git a/public/images/compatibility/firefox_icon.png b/public/images/compatibility/firefox_icon.png new file mode 100644 index 000000000..660f67b21 Binary files /dev/null and b/public/images/compatibility/firefox_icon.png differ diff --git a/public/images/compatibility/google-chrome@2x.png b/public/images/compatibility/google-chrome@2x.png new file mode 100644 index 000000000..993b89e84 Binary files /dev/null and b/public/images/compatibility/google-chrome@2x.png differ diff --git a/public/images/compatibility/icon@2x.png b/public/images/compatibility/icon@2x.png new file mode 100644 index 000000000..844fa3f23 Binary files /dev/null and b/public/images/compatibility/icon@2x.png differ diff --git a/public/images/compatibility/internet-explorer@2x.png b/public/images/compatibility/internet-explorer@2x.png new file mode 100644 index 000000000..f93b110e0 Binary files /dev/null and b/public/images/compatibility/internet-explorer@2x.png differ diff --git a/public/images/course/arrow.png b/public/images/course/arrow.png new file mode 100644 index 000000000..2081ddf8d Binary files /dev/null and b/public/images/course/arrow.png differ diff --git a/public/images/course/arrow_up.jpg b/public/images/course/arrow_up.jpg new file mode 100644 index 000000000..7bcfa859c Binary files /dev/null and b/public/images/course/arrow_up.jpg differ diff --git a/public/images/course/arrow_up2.jpg b/public/images/course/arrow_up2.jpg new file mode 100644 index 000000000..bbf348fe1 Binary files /dev/null and b/public/images/course/arrow_up2.jpg differ diff --git a/public/images/course/boutique.png b/public/images/course/boutique.png new file mode 100644 index 000000000..4a73020e1 Binary files /dev/null and b/public/images/course/boutique.png differ diff --git a/public/images/course/hwork_icon.png b/public/images/course/hwork_icon.png new file mode 100644 index 000000000..82c78ac60 Binary files /dev/null and b/public/images/course/hwork_icon.png differ diff --git a/public/images/course/icons.png b/public/images/course/icons.png new file mode 100644 index 000000000..b5d7536ae Binary files /dev/null and b/public/images/course/icons.png differ diff --git a/public/images/course/medal.png b/public/images/course/medal.png new file mode 100644 index 000000000..3ddba6b4a Binary files /dev/null and b/public/images/course/medal.png differ diff --git a/public/images/course/proRelated.png b/public/images/course/proRelated.png new file mode 100644 index 000000000..2cc1252cc Binary files /dev/null and b/public/images/course/proRelated.png differ diff --git a/public/images/course/public_icon.png b/public/images/course/public_icon.png new file mode 100644 index 000000000..8ff999f9a Binary files /dev/null and b/public/images/course/public_icon.png differ diff --git a/public/images/course/right-arrow.png b/public/images/course/right-arrow.png new file mode 100644 index 000000000..b152e9ce9 Binary files /dev/null and b/public/images/course/right-arrow.png differ diff --git a/public/images/course/syllabus.png b/public/images/course/syllabus.png new file mode 100644 index 000000000..32c4bc4cc Binary files /dev/null and b/public/images/course/syllabus.png differ diff --git a/public/images/course/syllabus_icon.png b/public/images/course/syllabus_icon.png new file mode 100644 index 000000000..2b8e17c46 Binary files /dev/null and b/public/images/course/syllabus_icon.png differ diff --git a/public/images/course/syllabus_setting.png b/public/images/course/syllabus_setting.png new file mode 100644 index 000000000..6ee7b02fb Binary files /dev/null and b/public/images/course/syllabus_setting.png differ diff --git a/public/images/course/to_top.png b/public/images/course/to_top.png new file mode 100644 index 000000000..1621b3510 Binary files /dev/null and b/public/images/course/to_top.png differ diff --git a/public/images/edit/edit.png b/public/images/edit/edit.png new file mode 100644 index 000000000..8335716fd Binary files /dev/null and b/public/images/edit/edit.png differ diff --git a/public/images/edu_user/anony.png b/public/images/edu_user/anony.png new file mode 100644 index 000000000..3871702d7 Binary files /dev/null and b/public/images/edu_user/anony.png differ diff --git a/public/images/edu_user/edu-cons1.png b/public/images/edu_user/edu-cons1.png new file mode 100644 index 000000000..4c2a0aae3 Binary files /dev/null and b/public/images/edu_user/edu-cons1.png differ diff --git a/public/images/edu_user/edu-nodata.png b/public/images/edu_user/edu-nodata.png new file mode 100644 index 000000000..4b158a05f Binary files /dev/null and b/public/images/edu_user/edu-nodata.png differ diff --git a/public/images/edu_user/img1.jpg b/public/images/edu_user/img1.jpg new file mode 100644 index 000000000..16b791d69 Binary files /dev/null and b/public/images/edu_user/img1.jpg differ diff --git a/public/images/edu_user/img2.jpg b/public/images/edu_user/img2.jpg new file mode 100644 index 000000000..845d23ac1 Binary files /dev/null and b/public/images/edu_user/img2.jpg differ diff --git a/public/images/edu_user/jt.png b/public/images/edu_user/jt.png new file mode 100644 index 000000000..9a451f5ae Binary files /dev/null and b/public/images/edu_user/jt.png differ diff --git a/public/images/edu_user/logo1.jpg b/public/images/edu_user/logo1.jpg new file mode 100644 index 000000000..598500e93 Binary files /dev/null and b/public/images/edu_user/logo1.jpg differ diff --git a/public/images/edu_user/male.jpg b/public/images/edu_user/male.jpg new file mode 100644 index 000000000..bd2597dd2 Binary files /dev/null and b/public/images/edu_user/male.jpg differ diff --git a/public/images/edu_user/richEditer.png b/public/images/edu_user/richEditer.png new file mode 100644 index 000000000..22ac4d836 Binary files /dev/null and b/public/images/edu_user/richEditer.png differ diff --git a/public/images/edu_user/user-renzheng.jpg b/public/images/edu_user/user-renzheng.jpg new file mode 100644 index 000000000..6157ed7de Binary files /dev/null and b/public/images/edu_user/user-renzheng.jpg differ diff --git a/public/images/educoder/12-1.png b/public/images/educoder/12-1.png new file mode 100644 index 000000000..5033cb23d Binary files /dev/null and b/public/images/educoder/12-1.png differ diff --git a/public/images/educoder/12-2.png b/public/images/educoder/12-2.png new file mode 100644 index 000000000..eff6c5a50 Binary files /dev/null and b/public/images/educoder/12-2.png differ diff --git a/public/images/educoder/12-3.png b/public/images/educoder/12-3.png new file mode 100644 index 000000000..c589efbf6 Binary files /dev/null and b/public/images/educoder/12-3.png differ diff --git a/public/images/educoder/12-4.png b/public/images/educoder/12-4.png new file mode 100644 index 000000000..a8eec8a28 Binary files /dev/null and b/public/images/educoder/12-4.png differ diff --git a/public/images/educoder/13-1.png b/public/images/educoder/13-1.png new file mode 100644 index 000000000..76c477311 Binary files /dev/null and b/public/images/educoder/13-1.png differ diff --git a/public/images/educoder/13-2.png b/public/images/educoder/13-2.png new file mode 100644 index 000000000..5cd0843d1 Binary files /dev/null and b/public/images/educoder/13-2.png differ diff --git a/public/images/educoder/2.jpg b/public/images/educoder/2.jpg new file mode 100644 index 000000000..78d05b28b Binary files /dev/null and b/public/images/educoder/2.jpg differ diff --git a/public/images/educoder/QQ.png b/public/images/educoder/QQ.png new file mode 100644 index 000000000..573df26f8 Binary files /dev/null and b/public/images/educoder/QQ.png differ diff --git a/public/images/educoder/account_bg.png b/public/images/educoder/account_bg.png new file mode 100644 index 000000000..eea371837 Binary files /dev/null and b/public/images/educoder/account_bg.png differ diff --git a/public/images/educoder/auth/banner1.jpg b/public/images/educoder/auth/banner1.jpg new file mode 100644 index 000000000..42c6c4d10 Binary files /dev/null and b/public/images/educoder/auth/banner1.jpg differ diff --git a/public/images/educoder/banner-left.png b/public/images/educoder/banner-left.png new file mode 100644 index 000000000..e4acc22b3 Binary files /dev/null and b/public/images/educoder/banner-left.png differ diff --git a/public/images/educoder/banner-right.png b/public/images/educoder/banner-right.png new file mode 100644 index 000000000..483988352 Binary files /dev/null and b/public/images/educoder/banner-right.png differ diff --git a/public/images/educoder/beijing.png b/public/images/educoder/beijing.png new file mode 100644 index 000000000..a3a6a437e Binary files /dev/null and b/public/images/educoder/beijing.png differ diff --git a/public/images/educoder/business/1.jpg b/public/images/educoder/business/1.jpg new file mode 100644 index 000000000..0f81c9602 Binary files /dev/null and b/public/images/educoder/business/1.jpg differ diff --git a/public/images/educoder/business/careerPathBottom.png b/public/images/educoder/business/careerPathBottom.png new file mode 100644 index 000000000..e394d8646 Binary files /dev/null and b/public/images/educoder/business/careerPathBottom.png differ diff --git a/public/images/educoder/business/careerPathLeft.png b/public/images/educoder/business/careerPathLeft.png new file mode 100644 index 000000000..809e99cd8 Binary files /dev/null and b/public/images/educoder/business/careerPathLeft.png differ diff --git a/public/images/educoder/business/careerPathRight.png b/public/images/educoder/business/careerPathRight.png new file mode 100644 index 000000000..a42b85b72 Binary files /dev/null and b/public/images/educoder/business/careerPathRight.png differ diff --git a/public/images/educoder/business/detailTop.jpg b/public/images/educoder/business/detailTop.jpg new file mode 100644 index 000000000..d1710adca Binary files /dev/null and b/public/images/educoder/business/detailTop.jpg differ diff --git a/public/images/educoder/business/introduce.png b/public/images/educoder/business/introduce.png new file mode 100644 index 000000000..0a2691c1d Binary files /dev/null and b/public/images/educoder/business/introduce.png differ diff --git a/public/images/educoder/business/introduceback.jpg b/public/images/educoder/business/introduceback.jpg new file mode 100644 index 000000000..38924d7e6 Binary files /dev/null and b/public/images/educoder/business/introduceback.jpg differ diff --git a/public/images/educoder/business/vedio.png b/public/images/educoder/business/vedio.png new file mode 100644 index 000000000..62e5a5d3f Binary files /dev/null and b/public/images/educoder/business/vedio.png differ diff --git a/public/images/educoder/c-number.png b/public/images/educoder/c-number.png new file mode 100644 index 000000000..9b5964c2a Binary files /dev/null and b/public/images/educoder/c-number.png differ diff --git a/public/images/educoder/competition/1.png b/public/images/educoder/competition/1.png new file mode 100644 index 000000000..aaa230f3c Binary files /dev/null and b/public/images/educoder/competition/1.png differ diff --git a/public/images/educoder/competition/2.png b/public/images/educoder/competition/2.png new file mode 100644 index 000000000..729bce64a Binary files /dev/null and b/public/images/educoder/competition/2.png differ diff --git a/public/images/educoder/competition/3.png b/public/images/educoder/competition/3.png new file mode 100644 index 000000000..a4c71fdce Binary files /dev/null and b/public/images/educoder/competition/3.png differ diff --git a/public/images/educoder/competition/anon.jpg b/public/images/educoder/competition/anon.jpg new file mode 100644 index 000000000..5520a17c4 Binary files /dev/null and b/public/images/educoder/competition/anon.jpg differ diff --git a/public/images/educoder/competition/boxEnroll.png b/public/images/educoder/competition/boxEnroll.png new file mode 100644 index 000000000..e499c615d Binary files /dev/null and b/public/images/educoder/competition/boxEnroll.png differ diff --git a/public/images/educoder/competition/ccf/CCF1.jpg b/public/images/educoder/competition/ccf/CCF1.jpg new file mode 100644 index 000000000..a8056d632 Binary files /dev/null and b/public/images/educoder/competition/ccf/CCF1.jpg differ diff --git a/public/images/educoder/competition/ccf/CCF2.jpg b/public/images/educoder/competition/ccf/CCF2.jpg new file mode 100644 index 000000000..56e405a70 Binary files /dev/null and b/public/images/educoder/competition/ccf/CCF2.jpg differ diff --git a/public/images/educoder/competition/ccf/CCF3.jpg b/public/images/educoder/competition/ccf/CCF3.jpg new file mode 100644 index 000000000..5a03389a9 Binary files /dev/null and b/public/images/educoder/competition/ccf/CCF3.jpg differ diff --git a/public/images/educoder/competition/ccf/CCF4.jpg b/public/images/educoder/competition/ccf/CCF4.jpg new file mode 100644 index 000000000..706d6c4d1 Binary files /dev/null and b/public/images/educoder/competition/ccf/CCF4.jpg differ diff --git a/public/images/educoder/competition/ccf/CCF5.jpg b/public/images/educoder/competition/ccf/CCF5.jpg new file mode 100644 index 000000000..fae6b7802 Binary files /dev/null and b/public/images/educoder/competition/ccf/CCF5.jpg differ diff --git a/public/images/educoder/competition/ccf/CCF6.jpg b/public/images/educoder/competition/ccf/CCF6.jpg new file mode 100644 index 000000000..317389c50 Binary files /dev/null and b/public/images/educoder/competition/ccf/CCF6.jpg differ diff --git a/public/images/educoder/competition/closelm.png b/public/images/educoder/competition/closelm.png new file mode 100644 index 000000000..6aa39cdd6 Binary files /dev/null and b/public/images/educoder/competition/closelm.png differ diff --git a/public/images/educoder/competition/db/db1.jpg b/public/images/educoder/competition/db/db1.jpg new file mode 100644 index 000000000..812694ddc Binary files /dev/null and b/public/images/educoder/competition/db/db1.jpg differ diff --git a/public/images/educoder/competition/db/db2.jpg b/public/images/educoder/competition/db/db2.jpg new file mode 100644 index 000000000..9f6aa0fb8 Binary files /dev/null and b/public/images/educoder/competition/db/db2.jpg differ diff --git a/public/images/educoder/competition/db/db3.jpg b/public/images/educoder/competition/db/db3.jpg new file mode 100644 index 000000000..9231d4bf9 Binary files /dev/null and b/public/images/educoder/competition/db/db3.jpg differ diff --git a/public/images/educoder/competition/db/db4.jpg b/public/images/educoder/competition/db/db4.jpg new file mode 100644 index 000000000..bfb5da4ec Binary files /dev/null and b/public/images/educoder/competition/db/db4.jpg differ diff --git a/public/images/educoder/competition/db/db5.jpg b/public/images/educoder/competition/db/db5.jpg new file mode 100644 index 000000000..4f5dc8807 Binary files /dev/null and b/public/images/educoder/competition/db/db5.jpg differ diff --git a/public/images/educoder/competition/db/db6.jpg b/public/images/educoder/competition/db/db6.jpg new file mode 100644 index 000000000..f33487642 Binary files /dev/null and b/public/images/educoder/competition/db/db6.jpg differ diff --git a/public/images/educoder/competition/db/db7.jpg b/public/images/educoder/competition/db/db7.jpg new file mode 100644 index 000000000..c0f05acb5 Binary files /dev/null and b/public/images/educoder/competition/db/db7.jpg differ diff --git a/public/images/educoder/competition/dev.jpg b/public/images/educoder/competition/dev.jpg new file mode 100644 index 000000000..16d1714d1 Binary files /dev/null and b/public/images/educoder/competition/dev.jpg differ diff --git a/public/images/educoder/competition/enroll-2.png b/public/images/educoder/competition/enroll-2.png new file mode 100644 index 000000000..97310e8fa Binary files /dev/null and b/public/images/educoder/competition/enroll-2.png differ diff --git a/public/images/educoder/competition/enroll-item.png b/public/images/educoder/competition/enroll-item.png new file mode 100644 index 000000000..39b7336c4 Binary files /dev/null and b/public/images/educoder/competition/enroll-item.png differ diff --git a/public/images/educoder/competition/home/1.jpg b/public/images/educoder/competition/home/1.jpg new file mode 100644 index 000000000..bb7db6ce9 Binary files /dev/null and b/public/images/educoder/competition/home/1.jpg differ diff --git a/public/images/educoder/competition/home/2.jpg b/public/images/educoder/competition/home/2.jpg new file mode 100644 index 000000000..c0d064f44 Binary files /dev/null and b/public/images/educoder/competition/home/2.jpg differ diff --git a/public/images/educoder/competition/home/3.jpg b/public/images/educoder/competition/home/3.jpg new file mode 100644 index 000000000..4bc412551 Binary files /dev/null and b/public/images/educoder/competition/home/3.jpg differ diff --git a/public/images/educoder/competition/home/blue.png b/public/images/educoder/competition/home/blue.png new file mode 100644 index 000000000..5dce066d3 Binary files /dev/null and b/public/images/educoder/competition/home/blue.png differ diff --git a/public/images/educoder/competition/home/grey.png b/public/images/educoder/competition/home/grey.png new file mode 100644 index 000000000..aef49857b Binary files /dev/null and b/public/images/educoder/competition/home/grey.png differ diff --git a/public/images/educoder/competition/home/homepage.jpg b/public/images/educoder/competition/home/homepage.jpg new file mode 100644 index 000000000..4edd4ff66 Binary files /dev/null and b/public/images/educoder/competition/home/homepage.jpg differ diff --git a/public/images/educoder/competition/home/orange.png b/public/images/educoder/competition/home/orange.png new file mode 100644 index 000000000..466f106a1 Binary files /dev/null and b/public/images/educoder/competition/home/orange.png differ diff --git a/public/images/educoder/competition/logo_1.jpg b/public/images/educoder/competition/logo_1.jpg new file mode 100644 index 000000000..5329e36cc Binary files /dev/null and b/public/images/educoder/competition/logo_1.jpg differ diff --git a/public/images/educoder/competition/lvmeng.png b/public/images/educoder/competition/lvmeng.png new file mode 100644 index 000000000..0fcf26b46 Binary files /dev/null and b/public/images/educoder/competition/lvmeng.png differ diff --git a/public/images/educoder/competition/noTeam.png b/public/images/educoder/competition/noTeam.png new file mode 100644 index 000000000..a012c4ca9 Binary files /dev/null and b/public/images/educoder/competition/noTeam.png differ diff --git a/public/images/educoder/competition/page-title.jpg b/public/images/educoder/competition/page-title.jpg new file mode 100644 index 000000000..32e55f4f8 Binary files /dev/null and b/public/images/educoder/competition/page-title.jpg differ diff --git a/public/images/educoder/competition/page1.jpg b/public/images/educoder/competition/page1.jpg new file mode 100644 index 000000000..7566e8b43 Binary files /dev/null and b/public/images/educoder/competition/page1.jpg differ diff --git a/public/images/educoder/competition/page2.jpg b/public/images/educoder/competition/page2.jpg new file mode 100644 index 000000000..7e0c1b9f6 Binary files /dev/null and b/public/images/educoder/competition/page2.jpg differ diff --git a/public/images/educoder/competition/page3.jpg b/public/images/educoder/competition/page3.jpg new file mode 100644 index 000000000..a59425262 Binary files /dev/null and b/public/images/educoder/competition/page3.jpg differ diff --git a/public/images/educoder/competition/page4.jpg b/public/images/educoder/competition/page4.jpg new file mode 100644 index 000000000..696a914c7 Binary files /dev/null and b/public/images/educoder/competition/page4.jpg differ diff --git a/public/images/educoder/competition/page5.jpg b/public/images/educoder/competition/page5.jpg new file mode 100644 index 000000000..11942dbf0 Binary files /dev/null and b/public/images/educoder/competition/page5.jpg differ diff --git a/public/images/educoder/competition/page6.jpg b/public/images/educoder/competition/page6.jpg new file mode 100644 index 000000000..ad329bad3 Binary files /dev/null and b/public/images/educoder/competition/page6.jpg differ diff --git a/public/images/educoder/competition/page7.jpg b/public/images/educoder/competition/page7.jpg new file mode 100644 index 000000000..e41ed35d8 Binary files /dev/null and b/public/images/educoder/competition/page7.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a1.jpg b/public/images/educoder/competition/phone_enroll/a1.jpg new file mode 100644 index 000000000..9d469883a Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a1.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a10.jpg b/public/images/educoder/competition/phone_enroll/a10.jpg new file mode 100644 index 000000000..b3086517a Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a10.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a11.jpg b/public/images/educoder/competition/phone_enroll/a11.jpg new file mode 100644 index 000000000..f480a1063 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a11.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a2.jpg b/public/images/educoder/competition/phone_enroll/a2.jpg new file mode 100644 index 000000000..0de04c26e Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a2.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a3.jpg b/public/images/educoder/competition/phone_enroll/a3.jpg new file mode 100644 index 000000000..f859fdbc7 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a3.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a4.jpg b/public/images/educoder/competition/phone_enroll/a4.jpg new file mode 100644 index 000000000..2c2d678f7 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a4.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a5.jpg b/public/images/educoder/competition/phone_enroll/a5.jpg new file mode 100644 index 000000000..12a062362 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a5.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a6.jpg b/public/images/educoder/competition/phone_enroll/a6.jpg new file mode 100644 index 000000000..23b040f4d Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a6.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a7.jpg b/public/images/educoder/competition/phone_enroll/a7.jpg new file mode 100644 index 000000000..d9d378ab9 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a7.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a8.jpg b/public/images/educoder/competition/phone_enroll/a8.jpg new file mode 100644 index 000000000..b6320bdbe Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a8.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/a9.jpg b/public/images/educoder/competition/phone_enroll/a9.jpg new file mode 100644 index 000000000..724a83999 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/a9.jpg differ diff --git a/public/images/educoder/competition/phone_enroll/person_1.png b/public/images/educoder/competition/phone_enroll/person_1.png new file mode 100644 index 000000000..795ccb967 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/person_1.png differ diff --git a/public/images/educoder/competition/phone_enroll/person_2.png b/public/images/educoder/competition/phone_enroll/person_2.png new file mode 100644 index 000000000..eb8e14bb2 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/person_2.png differ diff --git a/public/images/educoder/competition/phone_enroll/person_3.png b/public/images/educoder/competition/phone_enroll/person_3.png new file mode 100644 index 000000000..fde4c9b6b Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/person_3.png differ diff --git a/public/images/educoder/competition/phone_enroll/person_4.png b/public/images/educoder/competition/phone_enroll/person_4.png new file mode 100644 index 000000000..5c519b17f Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/person_4.png differ diff --git a/public/images/educoder/competition/phone_enroll/person_5.png b/public/images/educoder/competition/phone_enroll/person_5.png new file mode 100644 index 000000000..7bcb1a3ed Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/person_5.png differ diff --git a/public/images/educoder/competition/phone_enroll/person_6.png b/public/images/educoder/competition/phone_enroll/person_6.png new file mode 100644 index 000000000..e9de84a4d Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/person_6.png differ diff --git a/public/images/educoder/competition/phone_enroll/person_7.png b/public/images/educoder/competition/phone_enroll/person_7.png new file mode 100644 index 000000000..82f36adf5 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/person_7.png differ diff --git a/public/images/educoder/competition/phone_enroll/person_8.png b/public/images/educoder/competition/phone_enroll/person_8.png new file mode 100644 index 000000000..6b756de43 Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/person_8.png differ diff --git a/public/images/educoder/competition/phone_enroll/person_9.png b/public/images/educoder/competition/phone_enroll/person_9.png new file mode 100644 index 000000000..25db60b9d Binary files /dev/null and b/public/images/educoder/competition/phone_enroll/person_9.png differ diff --git a/public/images/educoder/competition/qg/qg-1.jpg b/public/images/educoder/competition/qg/qg-1.jpg new file mode 100644 index 000000000..151408e75 Binary files /dev/null and b/public/images/educoder/competition/qg/qg-1.jpg differ diff --git a/public/images/educoder/competition/qg/qg-2.jpg b/public/images/educoder/competition/qg/qg-2.jpg new file mode 100644 index 000000000..8b8555858 Binary files /dev/null and b/public/images/educoder/competition/qg/qg-2.jpg differ diff --git a/public/images/educoder/competition/qg/qg-3.jpg b/public/images/educoder/competition/qg/qg-3.jpg new file mode 100644 index 000000000..ca75c1822 Binary files /dev/null and b/public/images/educoder/competition/qg/qg-3.jpg differ diff --git a/public/images/educoder/competition/qg/qg-4.jpg b/public/images/educoder/competition/qg/qg-4.jpg new file mode 100644 index 000000000..4dc75adab Binary files /dev/null and b/public/images/educoder/competition/qg/qg-4.jpg differ diff --git a/public/images/educoder/competition/qg/qg-5.jpg b/public/images/educoder/competition/qg/qg-5.jpg new file mode 100644 index 000000000..057efb627 Binary files /dev/null and b/public/images/educoder/competition/qg/qg-5.jpg differ diff --git a/public/images/educoder/competition/trophy.png b/public/images/educoder/competition/trophy.png new file mode 100644 index 000000000..52d7664ad Binary files /dev/null and b/public/images/educoder/competition/trophy.png differ diff --git a/public/images/educoder/course-detail-0.jpg b/public/images/educoder/course-detail-0.jpg new file mode 100644 index 000000000..cea866a72 Binary files /dev/null and b/public/images/educoder/course-detail-0.jpg differ diff --git a/public/images/educoder/course-detail.jpg b/public/images/educoder/course-detail.jpg new file mode 100644 index 000000000..3685a0fd3 Binary files /dev/null and b/public/images/educoder/course-detail.jpg differ diff --git a/public/images/educoder/courses.jpg b/public/images/educoder/courses.jpg new file mode 100644 index 000000000..ee6a6f84f Binary files /dev/null and b/public/images/educoder/courses.jpg differ diff --git a/public/images/educoder/footNavLogo.png b/public/images/educoder/footNavLogo.png new file mode 100644 index 000000000..67b938cd9 Binary files /dev/null and b/public/images/educoder/footNavLogo.png differ diff --git a/public/images/educoder/gold-big.png b/public/images/educoder/gold-big.png new file mode 100644 index 000000000..e8929c675 Binary files /dev/null and b/public/images/educoder/gold-big.png differ diff --git a/public/images/educoder/gold1.png b/public/images/educoder/gold1.png new file mode 100644 index 000000000..6f14f22d3 Binary files /dev/null and b/public/images/educoder/gold1.png differ diff --git a/public/images/educoder/gold2.png b/public/images/educoder/gold2.png new file mode 100644 index 000000000..46fd380e9 Binary files /dev/null and b/public/images/educoder/gold2.png differ diff --git a/public/images/educoder/gold3.png b/public/images/educoder/gold3.png new file mode 100644 index 000000000..f37d36370 Binary files /dev/null and b/public/images/educoder/gold3.png differ diff --git a/public/images/educoder/guagngao.png b/public/images/educoder/guagngao.png new file mode 100644 index 000000000..0cb8c24a5 Binary files /dev/null and b/public/images/educoder/guagngao.png differ diff --git a/public/images/educoder/headNavLogo.png b/public/images/educoder/headNavLogo.png new file mode 100644 index 000000000..8df93d54d Binary files /dev/null and b/public/images/educoder/headNavLogo.png differ diff --git a/public/images/educoder/hot-h.png b/public/images/educoder/hot-h.png new file mode 100644 index 000000000..cfe444e18 Binary files /dev/null and b/public/images/educoder/hot-h.png differ diff --git a/public/images/educoder/hot-n.png b/public/images/educoder/hot-n.png new file mode 100644 index 000000000..a38d61ec0 Binary files /dev/null and b/public/images/educoder/hot-n.png differ diff --git a/public/images/educoder/huangguan-three.png b/public/images/educoder/huangguan-three.png new file mode 100644 index 000000000..f3b801c53 Binary files /dev/null and b/public/images/educoder/huangguan-three.png differ diff --git a/public/images/educoder/huangguan-two.png b/public/images/educoder/huangguan-two.png new file mode 100644 index 000000000..630f5d8e4 Binary files /dev/null and b/public/images/educoder/huangguan-two.png differ diff --git a/public/images/educoder/huangguan.png b/public/images/educoder/huangguan.png new file mode 100644 index 000000000..d0c66fe0f Binary files /dev/null and b/public/images/educoder/huangguan.png differ diff --git a/public/images/educoder/icon/QQ.svg b/public/images/educoder/icon/QQ.svg new file mode 100644 index 000000000..b7e5a42fe --- /dev/null +++ b/public/images/educoder/icon/QQ.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/add-small.svg b/public/images/educoder/icon/add-small.svg new file mode 100644 index 000000000..60c16edcd --- /dev/null +++ b/public/images/educoder/icon/add-small.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/educoder/icon/add.svg b/public/images/educoder/icon/add.svg new file mode 100644 index 000000000..ec2e99c18 --- /dev/null +++ b/public/images/educoder/icon/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/educoder/icon/addsmallgreen.svg b/public/images/educoder/icon/addsmallgreen.svg new file mode 100644 index 000000000..ed18bd02f --- /dev/null +++ b/public/images/educoder/icon/addsmallgreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/educoder/icon/addsmallwhite.svg b/public/images/educoder/icon/addsmallwhite.svg new file mode 100644 index 000000000..1fc58dd4a --- /dev/null +++ b/public/images/educoder/icon/addsmallwhite.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/public/images/educoder/icon/auto-email.svg b/public/images/educoder/icon/auto-email.svg new file mode 100644 index 000000000..870e4607e --- /dev/null +++ b/public/images/educoder/icon/auto-email.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/auto-emailed.svg b/public/images/educoder/icon/auto-emailed.svg new file mode 100644 index 000000000..d7e29e3a0 --- /dev/null +++ b/public/images/educoder/icon/auto-emailed.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/auto-identity.svg b/public/images/educoder/icon/auto-identity.svg new file mode 100644 index 000000000..cf1ad910d --- /dev/null +++ b/public/images/educoder/icon/auto-identity.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/auto-identityed.svg b/public/images/educoder/icon/auto-identityed.svg new file mode 100644 index 000000000..a5d62029a --- /dev/null +++ b/public/images/educoder/icon/auto-identityed.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/auto-phone.svg b/public/images/educoder/icon/auto-phone.svg new file mode 100644 index 000000000..bdd8bf30b --- /dev/null +++ b/public/images/educoder/icon/auto-phone.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/public/images/educoder/icon/auto-phoneed.svg b/public/images/educoder/icon/auto-phoneed.svg new file mode 100644 index 000000000..896bebb3b --- /dev/null +++ b/public/images/educoder/icon/auto-phoneed.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/public/images/educoder/icon/auto-post.svg b/public/images/educoder/icon/auto-post.svg new file mode 100644 index 000000000..effbe0885 --- /dev/null +++ b/public/images/educoder/icon/auto-post.svg @@ -0,0 +1,8 @@ + + + + + + + diff --git a/public/images/educoder/icon/auto-posted.svg b/public/images/educoder/icon/auto-posted.svg new file mode 100644 index 000000000..16ccd6e55 --- /dev/null +++ b/public/images/educoder/icon/auto-posted.svg @@ -0,0 +1,8 @@ + + + + + + + diff --git a/public/images/educoder/icon/bell.svg b/public/images/educoder/icon/bell.svg new file mode 100644 index 000000000..e073a3b8f --- /dev/null +++ b/public/images/educoder/icon/bell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/educoder/icon/branch.svg b/public/images/educoder/icon/branch.svg new file mode 100644 index 000000000..d47735d58 --- /dev/null +++ b/public/images/educoder/icon/branch.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/public/images/educoder/icon/charpter-white.svg b/public/images/educoder/icon/charpter-white.svg new file mode 100644 index 000000000..1c84c4cd2 --- /dev/null +++ b/public/images/educoder/icon/charpter-white.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/public/images/educoder/icon/charpter.svg b/public/images/educoder/icon/charpter.svg new file mode 100644 index 000000000..fedbb7c1d --- /dev/null +++ b/public/images/educoder/icon/charpter.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/public/images/educoder/icon/checked.svg b/public/images/educoder/icon/checked.svg new file mode 100644 index 000000000..a510d354f --- /dev/null +++ b/public/images/educoder/icon/checked.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/public/images/educoder/icon/choose.svg b/public/images/educoder/icon/choose.svg new file mode 100644 index 000000000..6f19458fa --- /dev/null +++ b/public/images/educoder/icon/choose.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/close.svg b/public/images/educoder/icon/close.svg new file mode 100644 index 000000000..79f804bf6 --- /dev/null +++ b/public/images/educoder/icon/close.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/public/images/educoder/icon/code.svg b/public/images/educoder/icon/code.svg new file mode 100644 index 000000000..1d5b09da3 --- /dev/null +++ b/public/images/educoder/icon/code.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/comment.svg b/public/images/educoder/icon/comment.svg new file mode 100644 index 000000000..f72de93b6 --- /dev/null +++ b/public/images/educoder/icon/comment.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/public/images/educoder/icon/commented.svg b/public/images/educoder/icon/commented.svg new file mode 100644 index 000000000..25fc1c2b9 --- /dev/null +++ b/public/images/educoder/icon/commented.svg @@ -0,0 +1,13 @@ + + + + + + + diff --git a/public/images/educoder/icon/commitRecord.svg b/public/images/educoder/icon/commitRecord.svg new file mode 100644 index 000000000..8044760d1 --- /dev/null +++ b/public/images/educoder/icon/commitRecord.svg @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/public/images/educoder/icon/copyurl.svg b/public/images/educoder/icon/copyurl.svg new file mode 100644 index 000000000..10f3db8db --- /dev/null +++ b/public/images/educoder/icon/copyurl.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/public/images/educoder/icon/del.svg b/public/images/educoder/icon/del.svg new file mode 100644 index 000000000..79e3dc8ff --- /dev/null +++ b/public/images/educoder/icon/del.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/public/images/educoder/icon/downarrow.svg b/public/images/educoder/icon/downarrow.svg new file mode 100644 index 000000000..38b5daf96 --- /dev/null +++ b/public/images/educoder/icon/downarrow.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/public/images/educoder/icon/downarrowsmall-right.svg b/public/images/educoder/icon/downarrowsmall-right.svg new file mode 100644 index 000000000..fe5bbf37e --- /dev/null +++ b/public/images/educoder/icon/downarrowsmall-right.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/public/images/educoder/icon/downarrowsmall.svg b/public/images/educoder/icon/downarrowsmall.svg new file mode 100644 index 000000000..b384243dc --- /dev/null +++ b/public/images/educoder/icon/downarrowsmall.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/public/images/educoder/icon/download.svg b/public/images/educoder/icon/download.svg new file mode 100644 index 000000000..688b4c2f6 --- /dev/null +++ b/public/images/educoder/icon/download.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/edit.svg b/public/images/educoder/icon/edit.svg new file mode 100644 index 000000000..ccb6d7c49 --- /dev/null +++ b/public/images/educoder/icon/edit.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/public/images/educoder/icon/empiric.svg b/public/images/educoder/icon/empiric.svg new file mode 100644 index 000000000..a34600db9 --- /dev/null +++ b/public/images/educoder/icon/empiric.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/educoder/icon/ewm.svg b/public/images/educoder/icon/ewm.svg new file mode 100644 index 000000000..0d0083522 --- /dev/null +++ b/public/images/educoder/icon/ewm.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/feedback.svg b/public/images/educoder/icon/feedback.svg new file mode 100644 index 000000000..1a3296767 --- /dev/null +++ b/public/images/educoder/icon/feedback.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/hint.svg b/public/images/educoder/icon/hint.svg new file mode 100644 index 000000000..824d762b3 --- /dev/null +++ b/public/images/educoder/icon/hint.svg @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/public/images/educoder/icon/hinterror.svg b/public/images/educoder/icon/hinterror.svg new file mode 100644 index 000000000..b021fb91a --- /dev/null +++ b/public/images/educoder/icon/hinterror.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/public/images/educoder/icon/homework.svg b/public/images/educoder/icon/homework.svg new file mode 100644 index 000000000..215c3a686 --- /dev/null +++ b/public/images/educoder/icon/homework.svg @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/public/images/educoder/icon/issue.svg b/public/images/educoder/icon/issue.svg new file mode 100644 index 000000000..bbe1e98cc --- /dev/null +++ b/public/images/educoder/icon/issue.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/public/images/educoder/icon/lesson.svg b/public/images/educoder/icon/lesson.svg new file mode 100644 index 000000000..4a1356dea --- /dev/null +++ b/public/images/educoder/icon/lesson.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/educoder/icon/lockclose.svg b/public/images/educoder/icon/lockclose.svg new file mode 100644 index 000000000..4f34fcde2 --- /dev/null +++ b/public/images/educoder/icon/lockclose.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/public/images/educoder/icon/lockopen.svg b/public/images/educoder/icon/lockopen.svg new file mode 100644 index 000000000..d9379b01f --- /dev/null +++ b/public/images/educoder/icon/lockopen.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/public/images/educoder/icon/look.svg b/public/images/educoder/icon/look.svg new file mode 100644 index 000000000..8f700224b --- /dev/null +++ b/public/images/educoder/icon/look.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/educoder/icon/member.svg b/public/images/educoder/icon/member.svg new file mode 100644 index 000000000..bd3dadf8b --- /dev/null +++ b/public/images/educoder/icon/member.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/message.svg b/public/images/educoder/icon/message.svg new file mode 100644 index 000000000..d2daade13 --- /dev/null +++ b/public/images/educoder/icon/message.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/movedown.svg b/public/images/educoder/icon/movedown.svg new file mode 100644 index 000000000..edddf7ca1 --- /dev/null +++ b/public/images/educoder/icon/movedown.svg @@ -0,0 +1,23 @@ + + + + + diff --git a/public/images/educoder/icon/moveup.svg b/public/images/educoder/icon/moveup.svg new file mode 100644 index 000000000..4aa25e978 --- /dev/null +++ b/public/images/educoder/icon/moveup.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/public/images/educoder/icon/narrow.svg b/public/images/educoder/icon/narrow.svg new file mode 100644 index 000000000..77d8e0f11 --- /dev/null +++ b/public/images/educoder/icon/narrow.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/public/images/educoder/icon/notice.svg b/public/images/educoder/icon/notice.svg new file mode 100644 index 000000000..cee7ea015 --- /dev/null +++ b/public/images/educoder/icon/notice.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/opencode.svg b/public/images/educoder/icon/opencode.svg new file mode 100644 index 000000000..57a9c3681 --- /dev/null +++ b/public/images/educoder/icon/opencode.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/recover.svg b/public/images/educoder/icon/recover.svg new file mode 100644 index 000000000..aa5b44a7d --- /dev/null +++ b/public/images/educoder/icon/recover.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/public/images/educoder/icon/reset.svg b/public/images/educoder/icon/reset.svg new file mode 100644 index 000000000..af395de3d --- /dev/null +++ b/public/images/educoder/icon/reset.svg @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/public/images/educoder/icon/returnc.svg b/public/images/educoder/icon/returnc.svg new file mode 100644 index 000000000..70ff4b121 --- /dev/null +++ b/public/images/educoder/icon/returnc.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/public/images/educoder/icon/revolve.svg b/public/images/educoder/icon/revolve.svg new file mode 100644 index 000000000..6311431ef --- /dev/null +++ b/public/images/educoder/icon/revolve.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/public/images/educoder/icon/ring-del.svg b/public/images/educoder/icon/ring-del.svg new file mode 100644 index 000000000..40f550970 --- /dev/null +++ b/public/images/educoder/icon/ring-del.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/ringmovedown.svg b/public/images/educoder/icon/ringmovedown.svg new file mode 100644 index 000000000..d9fef69a4 --- /dev/null +++ b/public/images/educoder/icon/ringmovedown.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/ringmoveup.svg b/public/images/educoder/icon/ringmoveup.svg new file mode 100644 index 000000000..7d50dcf18 --- /dev/null +++ b/public/images/educoder/icon/ringmoveup.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/search.svg b/public/images/educoder/icon/search.svg new file mode 100644 index 000000000..cf0e16c0c --- /dev/null +++ b/public/images/educoder/icon/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/images/educoder/icon/send.svg b/public/images/educoder/icon/send.svg new file mode 100644 index 000000000..2c6f84c2e --- /dev/null +++ b/public/images/educoder/icon/send.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/public/images/educoder/icon/sendimg.svg b/public/images/educoder/icon/sendimg.svg new file mode 100644 index 000000000..d3faf3340 --- /dev/null +++ b/public/images/educoder/icon/sendimg.svg @@ -0,0 +1,12 @@ + + + + + + + diff --git a/public/images/educoder/icon/source.svg b/public/images/educoder/icon/source.svg new file mode 100644 index 000000000..a1ba1ff75 --- /dev/null +++ b/public/images/educoder/icon/source.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/star.svg b/public/images/educoder/icon/star.svg new file mode 100644 index 000000000..978c1c046 --- /dev/null +++ b/public/images/educoder/icon/star.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/public/images/educoder/icon/test.svg b/public/images/educoder/icon/test.svg new file mode 100644 index 000000000..1f7999e43 --- /dev/null +++ b/public/images/educoder/icon/test.svg @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/public/images/educoder/icon/thousand.svg b/public/images/educoder/icon/thousand.svg new file mode 100644 index 000000000..e2399b918 --- /dev/null +++ b/public/images/educoder/icon/thousand.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/thousanded.svg b/public/images/educoder/icon/thousanded.svg new file mode 100644 index 000000000..fcd2ca62e --- /dev/null +++ b/public/images/educoder/icon/thousanded.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + diff --git a/public/images/educoder/icon/version.svg b/public/images/educoder/icon/version.svg new file mode 100644 index 000000000..849110e13 --- /dev/null +++ b/public/images/educoder/icon/version.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/public/images/educoder/index/shixun/shixun0.jpg b/public/images/educoder/index/shixun/shixun0.jpg new file mode 100644 index 000000000..92e62aca7 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun0.jpg differ diff --git a/public/images/educoder/index/shixun/shixun1.jpg b/public/images/educoder/index/shixun/shixun1.jpg new file mode 100644 index 000000000..7981f9eb0 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun1.jpg differ diff --git a/public/images/educoder/index/shixun/shixun10.jpg b/public/images/educoder/index/shixun/shixun10.jpg new file mode 100644 index 000000000..27990cefb Binary files /dev/null and b/public/images/educoder/index/shixun/shixun10.jpg differ diff --git a/public/images/educoder/index/shixun/shixun11.jpg b/public/images/educoder/index/shixun/shixun11.jpg new file mode 100644 index 000000000..4575578ca Binary files /dev/null and b/public/images/educoder/index/shixun/shixun11.jpg differ diff --git a/public/images/educoder/index/shixun/shixun12.jpg b/public/images/educoder/index/shixun/shixun12.jpg new file mode 100644 index 000000000..a6f3b776e Binary files /dev/null and b/public/images/educoder/index/shixun/shixun12.jpg differ diff --git a/public/images/educoder/index/shixun/shixun13.jpg b/public/images/educoder/index/shixun/shixun13.jpg new file mode 100644 index 000000000..a7ecc6286 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun13.jpg differ diff --git a/public/images/educoder/index/shixun/shixun14.jpg b/public/images/educoder/index/shixun/shixun14.jpg new file mode 100644 index 000000000..3da8697d1 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun14.jpg differ diff --git a/public/images/educoder/index/shixun/shixun15.jpg b/public/images/educoder/index/shixun/shixun15.jpg new file mode 100644 index 000000000..7015141c7 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun15.jpg differ diff --git a/public/images/educoder/index/shixun/shixun16.jpg b/public/images/educoder/index/shixun/shixun16.jpg new file mode 100644 index 000000000..0a6f343f4 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun16.jpg differ diff --git a/public/images/educoder/index/shixun/shixun17.jpg b/public/images/educoder/index/shixun/shixun17.jpg new file mode 100644 index 000000000..3234ee409 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun17.jpg differ diff --git a/public/images/educoder/index/shixun/shixun18.jpg b/public/images/educoder/index/shixun/shixun18.jpg new file mode 100644 index 000000000..7aaed1294 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun18.jpg differ diff --git a/public/images/educoder/index/shixun/shixun19.jpg b/public/images/educoder/index/shixun/shixun19.jpg new file mode 100644 index 000000000..13c14e45b Binary files /dev/null and b/public/images/educoder/index/shixun/shixun19.jpg differ diff --git a/public/images/educoder/index/shixun/shixun2.jpg b/public/images/educoder/index/shixun/shixun2.jpg new file mode 100644 index 000000000..6205391fa Binary files /dev/null and b/public/images/educoder/index/shixun/shixun2.jpg differ diff --git a/public/images/educoder/index/shixun/shixun20.jpg b/public/images/educoder/index/shixun/shixun20.jpg new file mode 100644 index 000000000..d038ae34d Binary files /dev/null and b/public/images/educoder/index/shixun/shixun20.jpg differ diff --git a/public/images/educoder/index/shixun/shixun21.jpg b/public/images/educoder/index/shixun/shixun21.jpg new file mode 100644 index 000000000..60ccda51e Binary files /dev/null and b/public/images/educoder/index/shixun/shixun21.jpg differ diff --git a/public/images/educoder/index/shixun/shixun22.jpg b/public/images/educoder/index/shixun/shixun22.jpg new file mode 100644 index 000000000..9f6ab9655 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun22.jpg differ diff --git a/public/images/educoder/index/shixun/shixun23.jpg b/public/images/educoder/index/shixun/shixun23.jpg new file mode 100644 index 000000000..13a729aff Binary files /dev/null and b/public/images/educoder/index/shixun/shixun23.jpg differ diff --git a/public/images/educoder/index/shixun/shixun24.jpg b/public/images/educoder/index/shixun/shixun24.jpg new file mode 100644 index 000000000..51d97e719 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun24.jpg differ diff --git a/public/images/educoder/index/shixun/shixun25.jpg b/public/images/educoder/index/shixun/shixun25.jpg new file mode 100644 index 000000000..ceb1ff60a Binary files /dev/null and b/public/images/educoder/index/shixun/shixun25.jpg differ diff --git a/public/images/educoder/index/shixun/shixun26.jpg b/public/images/educoder/index/shixun/shixun26.jpg new file mode 100644 index 000000000..6180626a4 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun26.jpg differ diff --git a/public/images/educoder/index/shixun/shixun27.jpg b/public/images/educoder/index/shixun/shixun27.jpg new file mode 100644 index 000000000..a998669c6 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun27.jpg differ diff --git a/public/images/educoder/index/shixun/shixun28.jpg b/public/images/educoder/index/shixun/shixun28.jpg new file mode 100644 index 000000000..8b9422b87 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun28.jpg differ diff --git a/public/images/educoder/index/shixun/shixun29.jpg b/public/images/educoder/index/shixun/shixun29.jpg new file mode 100644 index 000000000..e9cda9129 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun29.jpg differ diff --git a/public/images/educoder/index/shixun/shixun3.jpg b/public/images/educoder/index/shixun/shixun3.jpg new file mode 100644 index 000000000..e1e64007e Binary files /dev/null and b/public/images/educoder/index/shixun/shixun3.jpg differ diff --git a/public/images/educoder/index/shixun/shixun30.jpg b/public/images/educoder/index/shixun/shixun30.jpg new file mode 100644 index 000000000..df4df88a0 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun30.jpg differ diff --git a/public/images/educoder/index/shixun/shixun31.jpg b/public/images/educoder/index/shixun/shixun31.jpg new file mode 100644 index 000000000..131afcac2 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun31.jpg differ diff --git a/public/images/educoder/index/shixun/shixun31.jpg~HEAD b/public/images/educoder/index/shixun/shixun31.jpg~HEAD new file mode 100644 index 000000000..5d4218a45 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun31.jpg~HEAD differ diff --git a/public/images/educoder/index/shixun/shixun32.jpg b/public/images/educoder/index/shixun/shixun32.jpg new file mode 100644 index 000000000..bb4fb7d31 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun32.jpg differ diff --git a/public/images/educoder/index/shixun/shixun33.jpg b/public/images/educoder/index/shixun/shixun33.jpg new file mode 100644 index 000000000..b851ac0fc Binary files /dev/null and b/public/images/educoder/index/shixun/shixun33.jpg differ diff --git a/public/images/educoder/index/shixun/shixun34.jpg b/public/images/educoder/index/shixun/shixun34.jpg new file mode 100644 index 000000000..6eadbbe35 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun34.jpg differ diff --git a/public/images/educoder/index/shixun/shixun35.jpg b/public/images/educoder/index/shixun/shixun35.jpg new file mode 100644 index 000000000..87f8276ca Binary files /dev/null and b/public/images/educoder/index/shixun/shixun35.jpg differ diff --git a/public/images/educoder/index/shixun/shixun36.jpg b/public/images/educoder/index/shixun/shixun36.jpg new file mode 100644 index 000000000..149841c9a Binary files /dev/null and b/public/images/educoder/index/shixun/shixun36.jpg differ diff --git a/public/images/educoder/index/shixun/shixun37.jpg b/public/images/educoder/index/shixun/shixun37.jpg new file mode 100644 index 000000000..0ad960534 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun37.jpg differ diff --git a/public/images/educoder/index/shixun/shixun38.jpg b/public/images/educoder/index/shixun/shixun38.jpg new file mode 100644 index 000000000..e1e64007e Binary files /dev/null and b/public/images/educoder/index/shixun/shixun38.jpg differ diff --git a/public/images/educoder/index/shixun/shixun39.jpg b/public/images/educoder/index/shixun/shixun39.jpg new file mode 100644 index 000000000..07a00b3a6 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun39.jpg differ diff --git a/public/images/educoder/index/shixun/shixun4.jpg b/public/images/educoder/index/shixun/shixun4.jpg new file mode 100644 index 000000000..310818903 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun4.jpg differ diff --git a/public/images/educoder/index/shixun/shixun40.jpg b/public/images/educoder/index/shixun/shixun40.jpg new file mode 100644 index 000000000..d4bf2fadf Binary files /dev/null and b/public/images/educoder/index/shixun/shixun40.jpg differ diff --git a/public/images/educoder/index/shixun/shixun41.jpg b/public/images/educoder/index/shixun/shixun41.jpg new file mode 100644 index 000000000..c7a03198a Binary files /dev/null and b/public/images/educoder/index/shixun/shixun41.jpg differ diff --git a/public/images/educoder/index/shixun/shixun42.jpg b/public/images/educoder/index/shixun/shixun42.jpg new file mode 100644 index 000000000..cbccb88c6 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun42.jpg differ diff --git a/public/images/educoder/index/shixun/shixun43.jpg b/public/images/educoder/index/shixun/shixun43.jpg new file mode 100644 index 000000000..e3e3a41e2 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun43.jpg differ diff --git a/public/images/educoder/index/shixun/shixun44.jpg b/public/images/educoder/index/shixun/shixun44.jpg new file mode 100644 index 000000000..80e8b193a Binary files /dev/null and b/public/images/educoder/index/shixun/shixun44.jpg differ diff --git a/public/images/educoder/index/shixun/shixun45.jpg b/public/images/educoder/index/shixun/shixun45.jpg new file mode 100644 index 000000000..d032aed71 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun45.jpg differ diff --git a/public/images/educoder/index/shixun/shixun46.jpg b/public/images/educoder/index/shixun/shixun46.jpg new file mode 100644 index 000000000..84b7cf6e0 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun46.jpg differ diff --git a/public/images/educoder/index/shixun/shixun47.jpg b/public/images/educoder/index/shixun/shixun47.jpg new file mode 100644 index 000000000..cb99dc95d Binary files /dev/null and b/public/images/educoder/index/shixun/shixun47.jpg differ diff --git a/public/images/educoder/index/shixun/shixun48.jpg b/public/images/educoder/index/shixun/shixun48.jpg new file mode 100644 index 000000000..c619abfa6 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun48.jpg differ diff --git a/public/images/educoder/index/shixun/shixun49.jpg b/public/images/educoder/index/shixun/shixun49.jpg new file mode 100644 index 000000000..398dfa1e1 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun49.jpg differ diff --git a/public/images/educoder/index/shixun/shixun5.jpg b/public/images/educoder/index/shixun/shixun5.jpg new file mode 100644 index 000000000..07ad83150 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun5.jpg differ diff --git a/public/images/educoder/index/shixun/shixun50.jpg b/public/images/educoder/index/shixun/shixun50.jpg new file mode 100644 index 000000000..6a3a61dfd Binary files /dev/null and b/public/images/educoder/index/shixun/shixun50.jpg differ diff --git a/public/images/educoder/index/shixun/shixun51.jpg b/public/images/educoder/index/shixun/shixun51.jpg new file mode 100644 index 000000000..29262fba7 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun51.jpg differ diff --git a/public/images/educoder/index/shixun/shixun52.jpg b/public/images/educoder/index/shixun/shixun52.jpg new file mode 100644 index 000000000..766d7afd8 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun52.jpg differ diff --git a/public/images/educoder/index/shixun/shixun53.jpg b/public/images/educoder/index/shixun/shixun53.jpg new file mode 100644 index 000000000..db81f7cff Binary files /dev/null and b/public/images/educoder/index/shixun/shixun53.jpg differ diff --git a/public/images/educoder/index/shixun/shixun54.jpg b/public/images/educoder/index/shixun/shixun54.jpg new file mode 100644 index 000000000..e47fb239c Binary files /dev/null and b/public/images/educoder/index/shixun/shixun54.jpg differ diff --git a/public/images/educoder/index/shixun/shixun55.jpg b/public/images/educoder/index/shixun/shixun55.jpg new file mode 100644 index 000000000..556e59b33 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun55.jpg differ diff --git a/public/images/educoder/index/shixun/shixun56.jpg b/public/images/educoder/index/shixun/shixun56.jpg new file mode 100644 index 000000000..0048c81a5 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun56.jpg differ diff --git a/public/images/educoder/index/shixun/shixun57.jpg b/public/images/educoder/index/shixun/shixun57.jpg new file mode 100644 index 000000000..caf3ad104 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun57.jpg differ diff --git a/public/images/educoder/index/shixun/shixun58.jpg b/public/images/educoder/index/shixun/shixun58.jpg new file mode 100644 index 000000000..610199dc5 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun58.jpg differ diff --git a/public/images/educoder/index/shixun/shixun59.jpg b/public/images/educoder/index/shixun/shixun59.jpg new file mode 100644 index 000000000..973cba886 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun59.jpg differ diff --git a/public/images/educoder/index/shixun/shixun6.jpg b/public/images/educoder/index/shixun/shixun6.jpg new file mode 100644 index 000000000..82183569f Binary files /dev/null and b/public/images/educoder/index/shixun/shixun6.jpg differ diff --git a/public/images/educoder/index/shixun/shixun60.jpg b/public/images/educoder/index/shixun/shixun60.jpg new file mode 100644 index 000000000..9d13e9c61 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun60.jpg differ diff --git a/public/images/educoder/index/shixun/shixun61.jpg b/public/images/educoder/index/shixun/shixun61.jpg new file mode 100644 index 000000000..54e283cd9 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun61.jpg differ diff --git a/public/images/educoder/index/shixun/shixun62.jpg b/public/images/educoder/index/shixun/shixun62.jpg new file mode 100644 index 000000000..079c83926 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun62.jpg differ diff --git a/public/images/educoder/index/shixun/shixun7.jpg b/public/images/educoder/index/shixun/shixun7.jpg new file mode 100644 index 000000000..7a7376cd3 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun7.jpg differ diff --git a/public/images/educoder/index/shixun/shixun8.jpg b/public/images/educoder/index/shixun/shixun8.jpg new file mode 100644 index 000000000..0c82077d2 Binary files /dev/null and b/public/images/educoder/index/shixun/shixun8.jpg differ diff --git a/public/images/educoder/index/shixun/shixun9.jpg b/public/images/educoder/index/shixun/shixun9.jpg new file mode 100644 index 000000000..39362d21e Binary files /dev/null and b/public/images/educoder/index/shixun/shixun9.jpg differ diff --git a/public/images/educoder/index/subject/subject0.jpg b/public/images/educoder/index/subject/subject0.jpg new file mode 100644 index 000000000..fe81e407b Binary files /dev/null and b/public/images/educoder/index/subject/subject0.jpg differ diff --git a/public/images/educoder/index/subject/subject1.jpg b/public/images/educoder/index/subject/subject1.jpg new file mode 100644 index 000000000..3c40a2ddb Binary files /dev/null and b/public/images/educoder/index/subject/subject1.jpg differ diff --git a/public/images/educoder/index/subject/subject10.jpg b/public/images/educoder/index/subject/subject10.jpg new file mode 100644 index 000000000..ec6817cd0 Binary files /dev/null and b/public/images/educoder/index/subject/subject10.jpg differ diff --git a/public/images/educoder/index/subject/subject11.jpg b/public/images/educoder/index/subject/subject11.jpg new file mode 100644 index 000000000..a55f9a72e Binary files /dev/null and b/public/images/educoder/index/subject/subject11.jpg differ diff --git a/public/images/educoder/index/subject/subject12.jpg b/public/images/educoder/index/subject/subject12.jpg new file mode 100644 index 000000000..bedeea999 Binary files /dev/null and b/public/images/educoder/index/subject/subject12.jpg differ diff --git a/public/images/educoder/index/subject/subject13.jpg b/public/images/educoder/index/subject/subject13.jpg new file mode 100644 index 000000000..911ea20c4 Binary files /dev/null and b/public/images/educoder/index/subject/subject13.jpg differ diff --git a/public/images/educoder/index/subject/subject14.jpg b/public/images/educoder/index/subject/subject14.jpg new file mode 100644 index 000000000..18a13b0ee Binary files /dev/null and b/public/images/educoder/index/subject/subject14.jpg differ diff --git a/public/images/educoder/index/subject/subject15.jpg b/public/images/educoder/index/subject/subject15.jpg new file mode 100644 index 000000000..8db30adc1 Binary files /dev/null and b/public/images/educoder/index/subject/subject15.jpg differ diff --git a/public/images/educoder/index/subject/subject16.jpg b/public/images/educoder/index/subject/subject16.jpg new file mode 100644 index 000000000..84648d3af Binary files /dev/null and b/public/images/educoder/index/subject/subject16.jpg differ diff --git a/public/images/educoder/index/subject/subject17.jpg b/public/images/educoder/index/subject/subject17.jpg new file mode 100644 index 000000000..1df320bb0 Binary files /dev/null and b/public/images/educoder/index/subject/subject17.jpg differ diff --git a/public/images/educoder/index/subject/subject18.jpg b/public/images/educoder/index/subject/subject18.jpg new file mode 100644 index 000000000..5bcdd8e21 Binary files /dev/null and b/public/images/educoder/index/subject/subject18.jpg differ diff --git a/public/images/educoder/index/subject/subject19.jpg b/public/images/educoder/index/subject/subject19.jpg new file mode 100644 index 000000000..0c82077d2 Binary files /dev/null and b/public/images/educoder/index/subject/subject19.jpg differ diff --git a/public/images/educoder/index/subject/subject2.jpg b/public/images/educoder/index/subject/subject2.jpg new file mode 100644 index 000000000..687ef6ac5 Binary files /dev/null and b/public/images/educoder/index/subject/subject2.jpg differ diff --git a/public/images/educoder/index/subject/subject20.jpg b/public/images/educoder/index/subject/subject20.jpg new file mode 100644 index 000000000..25c3896e0 Binary files /dev/null and b/public/images/educoder/index/subject/subject20.jpg differ diff --git a/public/images/educoder/index/subject/subject21.jpg b/public/images/educoder/index/subject/subject21.jpg new file mode 100644 index 000000000..ebe3df86d Binary files /dev/null and b/public/images/educoder/index/subject/subject21.jpg differ diff --git a/public/images/educoder/index/subject/subject22.jpg b/public/images/educoder/index/subject/subject22.jpg new file mode 100644 index 000000000..b06cca4ab Binary files /dev/null and b/public/images/educoder/index/subject/subject22.jpg differ diff --git a/public/images/educoder/index/subject/subject23.jpg b/public/images/educoder/index/subject/subject23.jpg new file mode 100644 index 000000000..bd6ea450c Binary files /dev/null and b/public/images/educoder/index/subject/subject23.jpg differ diff --git a/public/images/educoder/index/subject/subject24.jpg b/public/images/educoder/index/subject/subject24.jpg new file mode 100644 index 000000000..e6fbb0ab0 Binary files /dev/null and b/public/images/educoder/index/subject/subject24.jpg differ diff --git a/public/images/educoder/index/subject/subject25.jpg b/public/images/educoder/index/subject/subject25.jpg new file mode 100644 index 000000000..bedeea999 Binary files /dev/null and b/public/images/educoder/index/subject/subject25.jpg differ diff --git a/public/images/educoder/index/subject/subject26.jpg b/public/images/educoder/index/subject/subject26.jpg new file mode 100644 index 000000000..3c8040901 Binary files /dev/null and b/public/images/educoder/index/subject/subject26.jpg differ diff --git a/public/images/educoder/index/subject/subject27.jpg b/public/images/educoder/index/subject/subject27.jpg new file mode 100644 index 000000000..59410bd62 Binary files /dev/null and b/public/images/educoder/index/subject/subject27.jpg differ diff --git a/public/images/educoder/index/subject/subject28.jpg b/public/images/educoder/index/subject/subject28.jpg new file mode 100644 index 000000000..4799d28d8 Binary files /dev/null and b/public/images/educoder/index/subject/subject28.jpg differ diff --git a/public/images/educoder/index/subject/subject29.jpg b/public/images/educoder/index/subject/subject29.jpg new file mode 100644 index 000000000..451053cf7 Binary files /dev/null and b/public/images/educoder/index/subject/subject29.jpg differ diff --git a/public/images/educoder/index/subject/subject3.jpg b/public/images/educoder/index/subject/subject3.jpg new file mode 100644 index 000000000..413bf4fcf Binary files /dev/null and b/public/images/educoder/index/subject/subject3.jpg differ diff --git a/public/images/educoder/index/subject/subject30.jpg b/public/images/educoder/index/subject/subject30.jpg new file mode 100644 index 000000000..2abd5a860 Binary files /dev/null and b/public/images/educoder/index/subject/subject30.jpg differ diff --git a/public/images/educoder/index/subject/subject31.jpg b/public/images/educoder/index/subject/subject31.jpg new file mode 100644 index 000000000..f84e0587a Binary files /dev/null and b/public/images/educoder/index/subject/subject31.jpg differ diff --git a/public/images/educoder/index/subject/subject32.jpg b/public/images/educoder/index/subject/subject32.jpg new file mode 100644 index 000000000..7ab3f038e Binary files /dev/null and b/public/images/educoder/index/subject/subject32.jpg differ diff --git a/public/images/educoder/index/subject/subject33.jpg b/public/images/educoder/index/subject/subject33.jpg new file mode 100644 index 000000000..c3f1e57db Binary files /dev/null and b/public/images/educoder/index/subject/subject33.jpg differ diff --git a/public/images/educoder/index/subject/subject34.jpg b/public/images/educoder/index/subject/subject34.jpg new file mode 100644 index 000000000..b5f4cb5f7 Binary files /dev/null and b/public/images/educoder/index/subject/subject34.jpg differ diff --git a/public/images/educoder/index/subject/subject35.jpg b/public/images/educoder/index/subject/subject35.jpg new file mode 100644 index 000000000..6a9156340 Binary files /dev/null and b/public/images/educoder/index/subject/subject35.jpg differ diff --git a/public/images/educoder/index/subject/subject36.jpg b/public/images/educoder/index/subject/subject36.jpg new file mode 100644 index 000000000..f7c8757cc Binary files /dev/null and b/public/images/educoder/index/subject/subject36.jpg differ diff --git a/public/images/educoder/index/subject/subject37.jpg b/public/images/educoder/index/subject/subject37.jpg new file mode 100644 index 000000000..b8b815f8b Binary files /dev/null and b/public/images/educoder/index/subject/subject37.jpg differ diff --git a/public/images/educoder/index/subject/subject38.jpg b/public/images/educoder/index/subject/subject38.jpg new file mode 100644 index 000000000..286a1e356 Binary files /dev/null and b/public/images/educoder/index/subject/subject38.jpg differ diff --git a/public/images/educoder/index/subject/subject39.jpg b/public/images/educoder/index/subject/subject39.jpg new file mode 100644 index 000000000..e901842c4 Binary files /dev/null and b/public/images/educoder/index/subject/subject39.jpg differ diff --git a/public/images/educoder/index/subject/subject4-o.jpg b/public/images/educoder/index/subject/subject4-o.jpg new file mode 100644 index 000000000..7c6784cf1 Binary files /dev/null and b/public/images/educoder/index/subject/subject4-o.jpg differ diff --git a/public/images/educoder/index/subject/subject4.jpg b/public/images/educoder/index/subject/subject4.jpg new file mode 100644 index 000000000..4d583cad2 Binary files /dev/null and b/public/images/educoder/index/subject/subject4.jpg differ diff --git a/public/images/educoder/index/subject/subject40.jpg b/public/images/educoder/index/subject/subject40.jpg new file mode 100644 index 000000000..ac5f581fd Binary files /dev/null and b/public/images/educoder/index/subject/subject40.jpg differ diff --git a/public/images/educoder/index/subject/subject41.jpg b/public/images/educoder/index/subject/subject41.jpg new file mode 100644 index 000000000..f968870f0 Binary files /dev/null and b/public/images/educoder/index/subject/subject41.jpg differ diff --git a/public/images/educoder/index/subject/subject42.jpg b/public/images/educoder/index/subject/subject42.jpg new file mode 100644 index 000000000..b3251b7e4 Binary files /dev/null and b/public/images/educoder/index/subject/subject42.jpg differ diff --git a/public/images/educoder/index/subject/subject43.jpg b/public/images/educoder/index/subject/subject43.jpg new file mode 100644 index 000000000..0dd42efaa Binary files /dev/null and b/public/images/educoder/index/subject/subject43.jpg differ diff --git a/public/images/educoder/index/subject/subject44.jpg b/public/images/educoder/index/subject/subject44.jpg new file mode 100644 index 000000000..21214a7d1 Binary files /dev/null and b/public/images/educoder/index/subject/subject44.jpg differ diff --git a/public/images/educoder/index/subject/subject45.jpg b/public/images/educoder/index/subject/subject45.jpg new file mode 100644 index 000000000..bd27e6ba0 Binary files /dev/null and b/public/images/educoder/index/subject/subject45.jpg differ diff --git a/public/images/educoder/index/subject/subject46.jpg b/public/images/educoder/index/subject/subject46.jpg new file mode 100644 index 000000000..3d621652b Binary files /dev/null and b/public/images/educoder/index/subject/subject46.jpg differ diff --git a/public/images/educoder/index/subject/subject47.jpg b/public/images/educoder/index/subject/subject47.jpg new file mode 100644 index 000000000..fcd318623 Binary files /dev/null and b/public/images/educoder/index/subject/subject47.jpg differ diff --git a/public/images/educoder/index/subject/subject48.jpg b/public/images/educoder/index/subject/subject48.jpg new file mode 100644 index 000000000..e7ee65970 Binary files /dev/null and b/public/images/educoder/index/subject/subject48.jpg differ diff --git a/public/images/educoder/index/subject/subject49.jpg b/public/images/educoder/index/subject/subject49.jpg new file mode 100644 index 000000000..5adf9e274 Binary files /dev/null and b/public/images/educoder/index/subject/subject49.jpg differ diff --git a/public/images/educoder/index/subject/subject5.jpg b/public/images/educoder/index/subject/subject5.jpg new file mode 100644 index 000000000..3fd883ee2 Binary files /dev/null and b/public/images/educoder/index/subject/subject5.jpg differ diff --git a/public/images/educoder/index/subject/subject50.jpg b/public/images/educoder/index/subject/subject50.jpg new file mode 100644 index 000000000..46ee0208c Binary files /dev/null and b/public/images/educoder/index/subject/subject50.jpg differ diff --git a/public/images/educoder/index/subject/subject51.jpg b/public/images/educoder/index/subject/subject51.jpg new file mode 100644 index 000000000..4c52ae48e Binary files /dev/null and b/public/images/educoder/index/subject/subject51.jpg differ diff --git a/public/images/educoder/index/subject/subject52.jpg b/public/images/educoder/index/subject/subject52.jpg new file mode 100644 index 000000000..f959d9ed7 Binary files /dev/null and b/public/images/educoder/index/subject/subject52.jpg differ diff --git a/public/images/educoder/index/subject/subject53.jpg b/public/images/educoder/index/subject/subject53.jpg new file mode 100644 index 000000000..3516fad82 Binary files /dev/null and b/public/images/educoder/index/subject/subject53.jpg differ diff --git a/public/images/educoder/index/subject/subject54.jpg b/public/images/educoder/index/subject/subject54.jpg new file mode 100644 index 000000000..d717562e7 Binary files /dev/null and b/public/images/educoder/index/subject/subject54.jpg differ diff --git a/public/images/educoder/index/subject/subject55.jpg b/public/images/educoder/index/subject/subject55.jpg new file mode 100644 index 000000000..2cc6c0173 Binary files /dev/null and b/public/images/educoder/index/subject/subject55.jpg differ diff --git a/public/images/educoder/index/subject/subject56.jpg b/public/images/educoder/index/subject/subject56.jpg new file mode 100644 index 000000000..2125dc132 Binary files /dev/null and b/public/images/educoder/index/subject/subject56.jpg differ diff --git a/public/images/educoder/index/subject/subject57.jpg b/public/images/educoder/index/subject/subject57.jpg new file mode 100644 index 000000000..eecf5b1c2 Binary files /dev/null and b/public/images/educoder/index/subject/subject57.jpg differ diff --git a/public/images/educoder/index/subject/subject58.jpg b/public/images/educoder/index/subject/subject58.jpg new file mode 100644 index 000000000..89d26b0b0 Binary files /dev/null and b/public/images/educoder/index/subject/subject58.jpg differ diff --git a/public/images/educoder/index/subject/subject6-o.jpg b/public/images/educoder/index/subject/subject6-o.jpg new file mode 100644 index 000000000..f7cda83f2 Binary files /dev/null and b/public/images/educoder/index/subject/subject6-o.jpg differ diff --git a/public/images/educoder/index/subject/subject6.jpg b/public/images/educoder/index/subject/subject6.jpg new file mode 100644 index 000000000..92e62aca7 Binary files /dev/null and b/public/images/educoder/index/subject/subject6.jpg differ diff --git a/public/images/educoder/index/subject/subject7.jpg b/public/images/educoder/index/subject/subject7.jpg new file mode 100644 index 000000000..beb9e0d5b Binary files /dev/null and b/public/images/educoder/index/subject/subject7.jpg differ diff --git a/public/images/educoder/index/subject/subject8-o.jpg b/public/images/educoder/index/subject/subject8-o.jpg new file mode 100644 index 000000000..fbeebe4ee Binary files /dev/null and b/public/images/educoder/index/subject/subject8-o.jpg differ diff --git a/public/images/educoder/index/subject/subject8.jpg b/public/images/educoder/index/subject/subject8.jpg new file mode 100644 index 000000000..c23568b00 Binary files /dev/null and b/public/images/educoder/index/subject/subject8.jpg differ diff --git a/public/images/educoder/index/subject/subject9.jpg b/public/images/educoder/index/subject/subject9.jpg new file mode 100644 index 000000000..c69dd591e Binary files /dev/null and b/public/images/educoder/index/subject/subject9.jpg differ diff --git a/public/images/educoder/logo-bg.jpg b/public/images/educoder/logo-bg.jpg new file mode 100644 index 000000000..2172ab973 Binary files /dev/null and b/public/images/educoder/logo-bg.jpg differ diff --git a/public/images/educoder/logo-o.png b/public/images/educoder/logo-o.png new file mode 100644 index 000000000..ec2161113 Binary files /dev/null and b/public/images/educoder/logo-o.png differ diff --git a/public/images/educoder/logo.png b/public/images/educoder/logo.png new file mode 100644 index 000000000..a3eb209b8 Binary files /dev/null and b/public/images/educoder/logo.png differ diff --git a/public/images/educoder/logoblack-o.png b/public/images/educoder/logoblack-o.png new file mode 100644 index 000000000..c00d7aa6f Binary files /dev/null and b/public/images/educoder/logoblack-o.png differ diff --git a/public/images/educoder/logoblack.png b/public/images/educoder/logoblack.png new file mode 100644 index 000000000..36a7123df Binary files /dev/null and b/public/images/educoder/logoblack.png differ diff --git a/public/images/educoder/logowhite-o.png b/public/images/educoder/logowhite-o.png new file mode 100644 index 000000000..c62c0a628 Binary files /dev/null and b/public/images/educoder/logowhite-o.png differ diff --git a/public/images/educoder/logowhite.png b/public/images/educoder/logowhite.png new file mode 100644 index 000000000..bc8c1601c Binary files /dev/null and b/public/images/educoder/logowhite.png differ diff --git a/public/images/educoder/nodata.png b/public/images/educoder/nodata.png new file mode 100644 index 000000000..15a9e522f Binary files /dev/null and b/public/images/educoder/nodata.png differ diff --git a/public/images/educoder/none_user.png b/public/images/educoder/none_user.png new file mode 100644 index 000000000..88cd35c37 Binary files /dev/null and b/public/images/educoder/none_user.png differ diff --git a/public/images/educoder/path-detail.jpg b/public/images/educoder/path-detail.jpg new file mode 100644 index 000000000..cea866a72 Binary files /dev/null and b/public/images/educoder/path-detail.jpg differ diff --git a/public/images/educoder/path.jpg b/public/images/educoder/path.jpg new file mode 100644 index 000000000..71e01c259 Binary files /dev/null and b/public/images/educoder/path.jpg differ diff --git a/public/images/educoder/problem.png b/public/images/educoder/problem.png new file mode 100644 index 000000000..110e9cd2a Binary files /dev/null and b/public/images/educoder/problem.png differ diff --git a/public/images/educoder/recom_1.jpg b/public/images/educoder/recom_1.jpg new file mode 100644 index 000000000..e9065b8f0 Binary files /dev/null and b/public/images/educoder/recom_1.jpg differ diff --git a/public/images/educoder/recom_2.jpg b/public/images/educoder/recom_2.jpg new file mode 100644 index 000000000..eef8af338 Binary files /dev/null and b/public/images/educoder/recom_2.jpg differ diff --git a/public/images/educoder/recom_3.jpg b/public/images/educoder/recom_3.jpg new file mode 100644 index 000000000..b1d24b635 Binary files /dev/null and b/public/images/educoder/recom_3.jpg differ diff --git a/public/images/educoder/recom_4.jpg b/public/images/educoder/recom_4.jpg new file mode 100644 index 000000000..76bf83698 Binary files /dev/null and b/public/images/educoder/recom_4.jpg differ diff --git a/public/images/educoder/recom_5.jpg b/public/images/educoder/recom_5.jpg new file mode 100644 index 000000000..ad7e7e6d2 Binary files /dev/null and b/public/images/educoder/recom_5.jpg differ diff --git a/public/images/educoder/recom_6.jpg b/public/images/educoder/recom_6.jpg new file mode 100644 index 000000000..8c13d9a8d Binary files /dev/null and b/public/images/educoder/recom_6.jpg differ diff --git a/public/images/educoder/shixun-detail.jpg b/public/images/educoder/shixun-detail.jpg new file mode 100644 index 000000000..a9af2ecdf Binary files /dev/null and b/public/images/educoder/shixun-detail.jpg differ diff --git a/public/images/educoder/shixundetail.jpg b/public/images/educoder/shixundetail.jpg new file mode 100644 index 000000000..a9af2ecdf Binary files /dev/null and b/public/images/educoder/shixundetail.jpg differ diff --git a/public/images/educoder/star-half.png b/public/images/educoder/star-half.png new file mode 100644 index 000000000..9d34954ef Binary files /dev/null and b/public/images/educoder/star-half.png differ diff --git a/public/images/educoder/star-off.png b/public/images/educoder/star-off.png new file mode 100644 index 000000000..81291f833 Binary files /dev/null and b/public/images/educoder/star-off.png differ diff --git a/public/images/educoder/star-on.png b/public/images/educoder/star-on.png new file mode 100644 index 000000000..e3c10938e Binary files /dev/null and b/public/images/educoder/star-on.png differ diff --git a/public/images/educoder/statistics.jpg b/public/images/educoder/statistics.jpg new file mode 100644 index 000000000..98459c2fe Binary files /dev/null and b/public/images/educoder/statistics.jpg differ diff --git a/public/images/educoder/subject_statistics.jpg b/public/images/educoder/subject_statistics.jpg new file mode 100644 index 000000000..7d5b8fd06 Binary files /dev/null and b/public/images/educoder/subject_statistics.jpg differ diff --git a/public/images/educoder/systemLogo.png b/public/images/educoder/systemLogo.png new file mode 100644 index 000000000..b262231ee Binary files /dev/null and b/public/images/educoder/systemLogo.png differ diff --git a/public/images/educoder/tag1.png b/public/images/educoder/tag1.png new file mode 100644 index 000000000..2fe25a0fc Binary files /dev/null and b/public/images/educoder/tag1.png differ diff --git a/public/images/educoder/tag2.png b/public/images/educoder/tag2.png new file mode 100644 index 000000000..423d2f7e3 Binary files /dev/null and b/public/images/educoder/tag2.png differ diff --git a/public/images/educoder/trainings/bannner.jpg b/public/images/educoder/trainings/bannner.jpg new file mode 100644 index 000000000..9d2af2c8c Binary files /dev/null and b/public/images/educoder/trainings/bannner.jpg differ diff --git a/public/images/educoder/tu.jpg b/public/images/educoder/tu.jpg new file mode 100644 index 000000000..f6af14691 Binary files /dev/null and b/public/images/educoder/tu.jpg differ diff --git a/public/images/educoder/upload-image.png b/public/images/educoder/upload-image.png new file mode 100644 index 000000000..517f99a50 Binary files /dev/null and b/public/images/educoder/upload-image.png differ diff --git a/public/images/educoder/user-renzheng.jpg b/public/images/educoder/user-renzheng.jpg new file mode 100644 index 000000000..507d67cd3 Binary files /dev/null and b/public/images/educoder/user-renzheng.jpg differ diff --git a/public/images/educoder/userhead.jpg b/public/images/educoder/userhead.jpg new file mode 100644 index 000000000..0be793deb Binary files /dev/null and b/public/images/educoder/userhead.jpg differ diff --git a/public/images/educoder/weibo.png b/public/images/educoder/weibo.png new file mode 100644 index 000000000..ab1f174b5 Binary files /dev/null and b/public/images/educoder/weibo.png differ diff --git a/public/images/educoder/weixin.png b/public/images/educoder/weixin.png new file mode 100644 index 000000000..37b2856a0 Binary files /dev/null and b/public/images/educoder/weixin.png differ diff --git a/public/images/educoder/welcome/shixun0.jpg b/public/images/educoder/welcome/shixun0.jpg new file mode 100644 index 000000000..7981f9eb0 Binary files /dev/null and b/public/images/educoder/welcome/shixun0.jpg differ diff --git a/public/images/educoder/welcome/shixun1.jpg b/public/images/educoder/welcome/shixun1.jpg new file mode 100644 index 000000000..4c52ae48e Binary files /dev/null and b/public/images/educoder/welcome/shixun1.jpg differ diff --git a/public/images/educoder/welcome/shixun2.jpg b/public/images/educoder/welcome/shixun2.jpg new file mode 100644 index 000000000..398dfa1e1 Binary files /dev/null and b/public/images/educoder/welcome/shixun2.jpg differ diff --git a/public/images/educoder/welcome/shixun3.jpg b/public/images/educoder/welcome/shixun3.jpg new file mode 100644 index 000000000..cbccb88c6 Binary files /dev/null and b/public/images/educoder/welcome/shixun3.jpg differ diff --git a/public/images/educoder/welcome/shixun4.jpg b/public/images/educoder/welcome/shixun4.jpg new file mode 100644 index 000000000..3516fad82 Binary files /dev/null and b/public/images/educoder/welcome/shixun4.jpg differ diff --git a/public/images/educoder/welcome/shixun5.jpg b/public/images/educoder/welcome/shixun5.jpg new file mode 100644 index 000000000..fe81e407b Binary files /dev/null and b/public/images/educoder/welcome/shixun5.jpg differ diff --git a/public/images/educoder/welcome/shixun6.jpg b/public/images/educoder/welcome/shixun6.jpg new file mode 100644 index 000000000..286a1e356 Binary files /dev/null and b/public/images/educoder/welcome/shixun6.jpg differ diff --git a/public/images/educoder/welcome/shixun7.jpg b/public/images/educoder/welcome/shixun7.jpg new file mode 100644 index 000000000..556e59b33 Binary files /dev/null and b/public/images/educoder/welcome/shixun7.jpg differ diff --git a/public/images/educoder/welcome/subject0.jpg b/public/images/educoder/welcome/subject0.jpg new file mode 100644 index 000000000..80e8b193a Binary files /dev/null and b/public/images/educoder/welcome/subject0.jpg differ diff --git a/public/images/educoder/welcome/subject1.jpg b/public/images/educoder/welcome/subject1.jpg new file mode 100644 index 000000000..e901842c4 Binary files /dev/null and b/public/images/educoder/welcome/subject1.jpg differ diff --git a/public/images/educoder/welcome/subject2.jpg b/public/images/educoder/welcome/subject2.jpg new file mode 100644 index 000000000..f968870f0 Binary files /dev/null and b/public/images/educoder/welcome/subject2.jpg differ diff --git a/public/images/educoder/welcome/subject3.jpg b/public/images/educoder/welcome/subject3.jpg new file mode 100644 index 000000000..149841c9a Binary files /dev/null and b/public/images/educoder/welcome/subject3.jpg differ diff --git a/public/images/educoder/welcome/subject4.jpg b/public/images/educoder/welcome/subject4.jpg new file mode 100644 index 000000000..bb4fb7d31 Binary files /dev/null and b/public/images/educoder/welcome/subject4.jpg differ diff --git a/public/images/educoder/welcome/subject5.jpg b/public/images/educoder/welcome/subject5.jpg new file mode 100644 index 000000000..82183569f Binary files /dev/null and b/public/images/educoder/welcome/subject5.jpg differ diff --git a/public/images/educoder/welcome/subject6.jpg b/public/images/educoder/welcome/subject6.jpg new file mode 100644 index 000000000..60ccda51e Binary files /dev/null and b/public/images/educoder/welcome/subject6.jpg differ diff --git a/public/images/educoder/welcome/subject7.jpg b/public/images/educoder/welcome/subject7.jpg new file mode 100644 index 000000000..0ad960534 Binary files /dev/null and b/public/images/educoder/welcome/subject7.jpg differ diff --git a/public/images/files/c.png b/public/images/files/c.png new file mode 100644 index 000000000..0dff8cfdf Binary files /dev/null and b/public/images/files/c.png differ diff --git a/public/images/files/csharp.png b/public/images/files/csharp.png new file mode 100644 index 000000000..093b1c5e3 Binary files /dev/null and b/public/images/files/csharp.png differ diff --git a/public/images/files/css.png b/public/images/files/css.png new file mode 100644 index 000000000..06a17cd8c Binary files /dev/null and b/public/images/files/css.png differ diff --git a/public/images/files/default.png b/public/images/files/default.png new file mode 100644 index 000000000..22996cd9d Binary files /dev/null and b/public/images/files/default.png differ diff --git a/public/images/files/html.png b/public/images/files/html.png new file mode 100644 index 000000000..6ed2490ed Binary files /dev/null and b/public/images/files/html.png differ diff --git a/public/images/files/image.png b/public/images/files/image.png new file mode 100644 index 000000000..8954d2a55 Binary files /dev/null and b/public/images/files/image.png differ diff --git a/public/images/files/java.png b/public/images/files/java.png new file mode 100644 index 000000000..0a7d6f4a6 Binary files /dev/null and b/public/images/files/java.png differ diff --git a/public/images/files/js.png b/public/images/files/js.png new file mode 100644 index 000000000..0125edfa9 Binary files /dev/null and b/public/images/files/js.png differ diff --git a/public/images/files/pdf.png b/public/images/files/pdf.png new file mode 100644 index 000000000..544e0d877 Binary files /dev/null and b/public/images/files/pdf.png differ diff --git a/public/images/files/php.png b/public/images/files/php.png new file mode 100644 index 000000000..26f2e4d7a Binary files /dev/null and b/public/images/files/php.png differ diff --git a/public/images/files/ruby.png b/public/images/files/ruby.png new file mode 100644 index 000000000..95fb3afed Binary files /dev/null and b/public/images/files/ruby.png differ diff --git a/public/images/files/text.png b/public/images/files/text.png new file mode 100644 index 000000000..b880900bf Binary files /dev/null and b/public/images/files/text.png differ diff --git a/public/images/files/xml.png b/public/images/files/xml.png new file mode 100644 index 000000000..b1b61b5fe Binary files /dev/null and b/public/images/files/xml.png differ diff --git a/public/images/files/zip.png b/public/images/files/zip.png new file mode 100644 index 000000000..914fcc402 Binary files /dev/null and b/public/images/files/zip.png differ diff --git a/public/images/folder.png b/public/images/folder.png new file mode 100644 index 000000000..e20d6823c Binary files /dev/null and b/public/images/folder.png differ diff --git a/public/images/footer_logo/BeiHang_university.png b/public/images/footer_logo/BeiHang_university.png new file mode 100644 index 000000000..f393aa3e8 Binary files /dev/null and b/public/images/footer_logo/BeiHang_university.png differ diff --git a/public/images/footer_logo/CVICSE.png b/public/images/footer_logo/CVICSE.png new file mode 100644 index 000000000..6fa4566f7 Binary files /dev/null and b/public/images/footer_logo/CVICSE.png differ diff --git a/public/images/footer_logo/ISCAS_logo.png b/public/images/footer_logo/ISCAS_logo.png new file mode 100644 index 000000000..f682f6ee0 Binary files /dev/null and b/public/images/footer_logo/ISCAS_logo.png differ diff --git a/public/images/footer_logo/PekingUniversity.png b/public/images/footer_logo/PekingUniversity.png new file mode 100644 index 000000000..533e9f7e2 Binary files /dev/null and b/public/images/footer_logo/PekingUniversity.png differ diff --git a/public/images/footer_logo/bee_logo.png b/public/images/footer_logo/bee_logo.png new file mode 100644 index 000000000..6628eee95 Binary files /dev/null and b/public/images/footer_logo/bee_logo.png differ diff --git a/public/images/footer_logo/buaa_scse.png b/public/images/footer_logo/buaa_scse.png new file mode 100644 index 000000000..c224a5668 Binary files /dev/null and b/public/images/footer_logo/buaa_scse.png differ diff --git a/public/images/footer_logo/inforbus.png b/public/images/footer_logo/inforbus.png new file mode 100644 index 000000000..f756b12d2 Binary files /dev/null and b/public/images/footer_logo/inforbus.png differ diff --git a/public/images/footer_logo/iscas.png b/public/images/footer_logo/iscas.png new file mode 100644 index 000000000..9e1be99e3 Binary files /dev/null and b/public/images/footer_logo/iscas.png differ diff --git a/public/images/footer_logo/nudt.png b/public/images/footer_logo/nudt.png new file mode 100644 index 000000000..68ff07fe0 Binary files /dev/null and b/public/images/footer_logo/nudt.png differ diff --git a/public/images/footer_logo/p-BeiHang_university.png b/public/images/footer_logo/p-BeiHang_university.png new file mode 100644 index 000000000..76e80d8dd Binary files /dev/null and b/public/images/footer_logo/p-BeiHang_university.png differ diff --git a/public/images/footer_logo/p-CVICSE.png b/public/images/footer_logo/p-CVICSE.png new file mode 100644 index 000000000..1d61a4415 Binary files /dev/null and b/public/images/footer_logo/p-CVICSE.png differ diff --git a/public/images/footer_logo/p-PekingUniversity.png b/public/images/footer_logo/p-PekingUniversity.png new file mode 100644 index 000000000..05fb64e95 Binary files /dev/null and b/public/images/footer_logo/p-PekingUniversity.png differ diff --git a/public/images/footer_logo/p-bee_logo.png b/public/images/footer_logo/p-bee_logo.png new file mode 100644 index 000000000..efc2a0b9e Binary files /dev/null and b/public/images/footer_logo/p-bee_logo.png differ diff --git a/public/images/footer_logo/p-iscas.png b/public/images/footer_logo/p-iscas.png new file mode 100644 index 000000000..4f8e874cd Binary files /dev/null and b/public/images/footer_logo/p-iscas.png differ diff --git a/public/images/footer_logo/p-nju.png b/public/images/footer_logo/p-nju.png new file mode 100644 index 000000000..94bf828d2 Binary files /dev/null and b/public/images/footer_logo/p-nju.png differ diff --git a/public/images/footer_logo/p-nudt.png b/public/images/footer_logo/p-nudt.png new file mode 100644 index 000000000..72121bfbe Binary files /dev/null and b/public/images/footer_logo/p-nudt.png differ diff --git a/public/images/footer_logo/p-ucloud.png b/public/images/footer_logo/p-ucloud.png new file mode 100644 index 000000000..7afcdf4fd Binary files /dev/null and b/public/images/footer_logo/p-ucloud.png differ diff --git a/public/images/footer_logo/p-xtdx.png b/public/images/footer_logo/p-xtdx.png new file mode 100644 index 000000000..c0cc135f7 Binary files /dev/null and b/public/images/footer_logo/p-xtdx.png differ diff --git a/public/images/footer_logo/p-xtu.png b/public/images/footer_logo/p-xtu.png new file mode 100644 index 000000000..d6afbe73a Binary files /dev/null and b/public/images/footer_logo/p-xtu.png differ diff --git a/public/images/footer_logo/p-zgkyrj.png b/public/images/footer_logo/p-zgkyrj.png new file mode 100644 index 000000000..abd08c264 Binary files /dev/null and b/public/images/footer_logo/p-zgkyrj.png differ diff --git a/public/images/footer_logo/peking_eecs.png b/public/images/footer_logo/peking_eecs.png new file mode 100644 index 000000000..6c7164f08 Binary files /dev/null and b/public/images/footer_logo/peking_eecs.png differ diff --git a/public/images/footer_logo/ucloud.png b/public/images/footer_logo/ucloud.png new file mode 100644 index 000000000..7e4f6ed9c Binary files /dev/null and b/public/images/footer_logo/ucloud.png differ diff --git a/public/images/hw/icons_hw.png b/public/images/hw/icons_hw.png new file mode 100644 index 000000000..013aa8afc Binary files /dev/null and b/public/images/hw/icons_hw.png differ diff --git a/public/images/loading.gif b/public/images/loading.gif new file mode 100644 index 000000000..085ccaeca Binary files /dev/null and b/public/images/loading.gif differ diff --git a/public/images/logo-only_med.png b/public/images/logo-only_med.png new file mode 100644 index 000000000..fa5df376b Binary files /dev/null and b/public/images/logo-only_med.png differ diff --git a/public/images/mes_icon.png b/public/images/mes_icon.png new file mode 100644 index 000000000..4a37cca0c Binary files /dev/null and b/public/images/mes_icon.png differ diff --git a/public/images/new_project/arrow.png b/public/images/new_project/arrow.png new file mode 100644 index 000000000..c4439b821 Binary files /dev/null and b/public/images/new_project/arrow.png differ diff --git a/public/images/new_project/btn.png b/public/images/new_project/btn.png new file mode 100644 index 000000000..85cea7f5c Binary files /dev/null and b/public/images/new_project/btn.png differ diff --git a/public/images/new_project/close.png b/public/images/new_project/close.png new file mode 100644 index 000000000..301ba5e85 Binary files /dev/null and b/public/images/new_project/close.png differ diff --git a/public/images/new_project/ico.png b/public/images/new_project/ico.png new file mode 100644 index 000000000..3ca78e58a Binary files /dev/null and b/public/images/new_project/ico.png differ diff --git a/public/images/new_project/icons_issue.png b/public/images/new_project/icons_issue.png new file mode 100644 index 000000000..81df5bd7c Binary files /dev/null and b/public/images/new_project/icons_issue.png differ diff --git a/public/images/new_project/icons_smile.png b/public/images/new_project/icons_smile.png new file mode 100644 index 000000000..b760d82fc Binary files /dev/null and b/public/images/new_project/icons_smile.png differ diff --git a/public/images/new_project/img_project.png b/public/images/new_project/img_project.png new file mode 100644 index 000000000..b0e5a495f Binary files /dev/null and b/public/images/new_project/img_project.png differ diff --git a/public/images/new_project/inputBg.png b/public/images/new_project/inputBg.png new file mode 100644 index 000000000..243bbf7ec Binary files /dev/null and b/public/images/new_project/inputBg.png differ diff --git a/public/images/new_project/jiantou.jpg b/public/images/new_project/jiantou.jpg new file mode 100644 index 000000000..cd2840988 Binary files /dev/null and b/public/images/new_project/jiantou.jpg differ diff --git a/public/images/new_project/jiantou1.jpg b/public/images/new_project/jiantou1.jpg new file mode 100644 index 000000000..208f44244 Binary files /dev/null and b/public/images/new_project/jiantou1.jpg differ diff --git a/public/images/new_project/logo_pro.jpg b/public/images/new_project/logo_pro.jpg new file mode 100644 index 000000000..d539de0f5 Binary files /dev/null and b/public/images/new_project/logo_pro.jpg differ diff --git a/public/images/new_project/pic_ad.png b/public/images/new_project/pic_ad.png new file mode 100644 index 000000000..d3ef56d26 Binary files /dev/null and b/public/images/new_project/pic_ad.png differ diff --git a/public/images/new_project/pic_down.png b/public/images/new_project/pic_down.png new file mode 100644 index 000000000..a2252b75d Binary files /dev/null and b/public/images/new_project/pic_down.png differ diff --git a/public/images/new_project/public_icon.png b/public/images/new_project/public_icon.png new file mode 100644 index 000000000..8ff999f9a Binary files /dev/null and b/public/images/new_project/public_icon.png differ diff --git a/public/images/public_icon.png b/public/images/public_icon.png new file mode 100644 index 000000000..8ff999f9a Binary files /dev/null and b/public/images/public_icon.png differ diff --git a/public/images/qrweixin.jpg b/public/images/qrweixin.jpg new file mode 100644 index 000000000..26555f72c Binary files /dev/null and b/public/images/qrweixin.jpg differ diff --git a/public/images/signature_edit.png b/public/images/signature_edit.png new file mode 100644 index 000000000..b9415589c Binary files /dev/null and b/public/images/signature_edit.png differ diff --git a/public/images/sy/bg_sy.jpg b/public/images/sy/bg_sy.jpg new file mode 100644 index 000000000..2a36dd530 Binary files /dev/null and b/public/images/sy/bg_sy.jpg differ diff --git a/public/images/sy/icons_smile.png b/public/images/sy/icons_smile.png new file mode 100644 index 000000000..b760d82fc Binary files /dev/null and b/public/images/sy/icons_smile.png differ diff --git a/public/images/sy/icons_sy.png b/public/images/sy/icons_sy.png new file mode 100644 index 000000000..54e4f1575 Binary files /dev/null and b/public/images/sy/icons_sy.png differ diff --git a/public/images/sy/icons_tan.png b/public/images/sy/icons_tan.png new file mode 100644 index 000000000..eaac3551b Binary files /dev/null and b/public/images/sy/icons_tan.png differ diff --git a/public/images/sy/liststyle.png b/public/images/sy/liststyle.png new file mode 100644 index 000000000..0d73a985f Binary files /dev/null and b/public/images/sy/liststyle.png differ diff --git a/public/images/sy/logo_class.jpg b/public/images/sy/logo_class.jpg new file mode 100644 index 000000000..f9b475bcf Binary files /dev/null and b/public/images/sy/logo_class.jpg differ diff --git a/public/images/sy/male.jpg b/public/images/sy/male.jpg new file mode 100644 index 000000000..46d58f26e Binary files /dev/null and b/public/images/sy/male.jpg differ diff --git a/public/images/sy/massage.jpg b/public/images/sy/massage.jpg new file mode 100644 index 000000000..6ec412180 Binary files /dev/null and b/public/images/sy/massage.jpg differ diff --git a/public/images/sy/sy_icons02.png b/public/images/sy/sy_icons02.png new file mode 100644 index 000000000..7d29ef2a9 Binary files /dev/null and b/public/images/sy/sy_icons02.png differ diff --git a/public/images/sy/sy_icons_close.png b/public/images/sy/sy_icons_close.png new file mode 100644 index 000000000..e500a2a27 Binary files /dev/null and b/public/images/sy/sy_icons_close.png differ diff --git a/public/images/sy/sy_icons_close02.png b/public/images/sy/sy_icons_close02.png new file mode 100644 index 000000000..456f2ea67 Binary files /dev/null and b/public/images/sy/sy_icons_close02.png differ diff --git a/public/images/syllabus/icons_syllabus.png b/public/images/syllabus/icons_syllabus.png new file mode 100644 index 000000000..3b81336c4 Binary files /dev/null and b/public/images/syllabus/icons_syllabus.png differ diff --git a/public/images/syllabus/sy_icons_star.png b/public/images/syllabus/sy_icons_star.png new file mode 100644 index 000000000..2256346d9 Binary files /dev/null and b/public/images/syllabus/sy_icons_star.png differ diff --git a/public/images/task/coin.png b/public/images/task/coin.png new file mode 100644 index 000000000..ef7ff002e Binary files /dev/null and b/public/images/task/coin.png differ diff --git a/public/images/task/icons-flower.png b/public/images/task/icons-flower.png new file mode 100644 index 000000000..4c58fb6f1 Binary files /dev/null and b/public/images/task/icons-flower.png differ diff --git a/public/images/task/nodata.jpg b/public/images/task/nodata.jpg new file mode 100644 index 000000000..1a77601b6 Binary files /dev/null and b/public/images/task/nodata.jpg differ diff --git a/public/images/task/task-bg-header.jpg b/public/images/task/task-bg-header.jpg new file mode 100644 index 000000000..b1bebc710 Binary files /dev/null and b/public/images/task/task-bg-header.jpg differ diff --git a/public/images/task/task-bg-header.png b/public/images/task/task-bg-header.png new file mode 100644 index 000000000..cf2e62f37 Binary files /dev/null and b/public/images/task/task-bg-header.png differ diff --git a/public/images/task/task-close.png b/public/images/task/task-close.png new file mode 100644 index 000000000..b040af1c4 Binary files /dev/null and b/public/images/task/task-close.png differ diff --git a/public/images/task/task-su-btn-jie.png b/public/images/task/task-su-btn-jie.png new file mode 100644 index 000000000..11dc7995f Binary files /dev/null and b/public/images/task/task-su-btn-jie.png differ diff --git a/public/images/task/task-su-btn.png b/public/images/task/task-su-btn.png new file mode 100644 index 000000000..0a1474783 Binary files /dev/null and b/public/images/task/task-su-btn.png differ diff --git a/public/images/task/task-success.png b/public/images/task/task-success.png new file mode 100644 index 000000000..adcfa6283 Binary files /dev/null and b/public/images/task/task-success.png differ diff --git a/public/images/task/task-success02.png b/public/images/task/task-success02.png new file mode 100644 index 000000000..c14e84fd0 Binary files /dev/null and b/public/images/task/task-success02.png differ diff --git a/public/images/twurn.com_.png b/public/images/twurn.com_.png new file mode 100644 index 000000000..8e7c6d120 Binary files /dev/null and b/public/images/twurn.com_.png differ diff --git a/public/images/vlicon/branch_icon.png b/public/images/vlicon/branch_icon.png new file mode 100644 index 000000000..c80e17134 Binary files /dev/null and b/public/images/vlicon/branch_icon.png differ diff --git a/public/images/vlicon/clone_url.png b/public/images/vlicon/clone_url.png new file mode 100644 index 000000000..a1c71862a Binary files /dev/null and b/public/images/vlicon/clone_url.png differ diff --git a/public/images/vlicon/commit_icon.png b/public/images/vlicon/commit_icon.png new file mode 100644 index 000000000..148dbcd4b Binary files /dev/null and b/public/images/vlicon/commit_icon.png differ diff --git a/public/images/vlicon/download_icon.png b/public/images/vlicon/download_icon.png new file mode 100644 index 000000000..b442730fe Binary files /dev/null and b/public/images/vlicon/download_icon.png differ diff --git a/public/images/vlicon/file.png b/public/images/vlicon/file.png new file mode 100644 index 000000000..bbfa6078d Binary files /dev/null and b/public/images/vlicon/file.png differ diff --git a/public/images/vlicon/fork_icon.png b/public/images/vlicon/fork_icon.png new file mode 100644 index 000000000..45a6b0e82 Binary files /dev/null and b/public/images/vlicon/fork_icon.png differ diff --git a/public/images/vlicon/graph.png b/public/images/vlicon/graph.png new file mode 100644 index 000000000..5f3e1c989 Binary files /dev/null and b/public/images/vlicon/graph.png differ diff --git a/public/images/warn/pic_403.jpg b/public/images/warn/pic_403.jpg new file mode 100644 index 000000000..5db2f3236 Binary files /dev/null and b/public/images/warn/pic_403.jpg differ diff --git a/public/images/warn/pic_404.jpg b/public/images/warn/pic_404.jpg new file mode 100644 index 000000000..b85751094 Binary files /dev/null and b/public/images/warn/pic_404.jpg differ diff --git a/public/images/warn/pic_500.jpg b/public/images/warn/pic_500.jpg new file mode 100644 index 000000000..f46c1c370 Binary files /dev/null and b/public/images/warn/pic_500.jpg differ diff --git a/public/images/warn/update.jpeg b/public/images/warn/update.jpeg new file mode 100644 index 000000000..ad546b37b Binary files /dev/null and b/public/images/warn/update.jpeg differ diff --git a/public/images/wechat/QR-code.jpg b/public/images/wechat/QR-code.jpg new file mode 100644 index 000000000..ba2a9e6a3 Binary files /dev/null and b/public/images/wechat/QR-code.jpg differ diff --git a/public/images/wechat/arrow.png b/public/images/wechat/arrow.png new file mode 100644 index 000000000..f9f9b18c5 Binary files /dev/null and b/public/images/wechat/arrow.png differ diff --git a/public/images/wechat/checked.png b/public/images/wechat/checked.png new file mode 100644 index 000000000..0d9713fed Binary files /dev/null and b/public/images/wechat/checked.png differ diff --git a/public/images/wechat/class.jpg b/public/images/wechat/class.jpg new file mode 100644 index 000000000..e3eebb977 Binary files /dev/null and b/public/images/wechat/class.jpg differ diff --git a/public/images/wechat/courseware.png b/public/images/wechat/courseware.png new file mode 100644 index 000000000..77d6401fd Binary files /dev/null and b/public/images/wechat/courseware.png differ diff --git a/public/images/wechat/dot.png b/public/images/wechat/dot.png new file mode 100644 index 000000000..e45863e9f Binary files /dev/null and b/public/images/wechat/dot.png differ diff --git a/public/images/wechat/dot2.png b/public/images/wechat/dot2.png new file mode 100644 index 000000000..bf1c0104e Binary files /dev/null and b/public/images/wechat/dot2.png differ diff --git a/public/images/wechat/female.jpg b/public/images/wechat/female.jpg new file mode 100644 index 000000000..219865572 Binary files /dev/null and b/public/images/wechat/female.jpg differ diff --git a/public/images/wechat/female.png b/public/images/wechat/female.png new file mode 100644 index 000000000..a13733ffc Binary files /dev/null and b/public/images/wechat/female.png differ diff --git a/public/images/wechat/homework.png b/public/images/wechat/homework.png new file mode 100644 index 000000000..836c6f38f Binary files /dev/null and b/public/images/wechat/homework.png differ diff --git a/public/images/wechat/icon.png b/public/images/wechat/icon.png new file mode 100644 index 000000000..afc7aa639 Binary files /dev/null and b/public/images/wechat/icon.png differ diff --git a/public/images/wechat/icon_list.gif b/public/images/wechat/icon_list.gif new file mode 100644 index 000000000..8b38366c6 Binary files /dev/null and b/public/images/wechat/icon_list.gif differ diff --git a/public/images/wechat/icon_list2.gif b/public/images/wechat/icon_list2.gif new file mode 100644 index 000000000..1d7dcb061 Binary files /dev/null and b/public/images/wechat/icon_list2.gif differ diff --git a/public/images/wechat/male.jpg b/public/images/wechat/male.jpg new file mode 100644 index 000000000..46d58f26e Binary files /dev/null and b/public/images/wechat/male.jpg differ diff --git a/public/images/wechat/male.png b/public/images/wechat/male.png new file mode 100644 index 000000000..9f1214a4c Binary files /dev/null and b/public/images/wechat/male.png differ diff --git a/public/images/wechat/minus.png b/public/images/wechat/minus.png new file mode 100644 index 000000000..32d82ea84 Binary files /dev/null and b/public/images/wechat/minus.png differ diff --git a/public/images/wechat/plus.png b/public/images/wechat/plus.png new file mode 100644 index 000000000..e5d83d212 Binary files /dev/null and b/public/images/wechat/plus.png differ diff --git a/public/images/wechat/post-avatar.jpg b/public/images/wechat/post-avatar.jpg new file mode 100644 index 000000000..bd2597dd2 Binary files /dev/null and b/public/images/wechat/post-avatar.jpg differ diff --git a/public/images/wechat/project.jpg b/public/images/wechat/project.jpg new file mode 100644 index 000000000..5ac1cb67c Binary files /dev/null and b/public/images/wechat/project.jpg differ diff --git a/public/images/wechat/search.png b/public/images/wechat/search.png new file mode 100644 index 000000000..a04c1496c Binary files /dev/null and b/public/images/wechat/search.png differ diff --git a/public/images/wechat/setting.png b/public/images/wechat/setting.png new file mode 100644 index 000000000..3c1159fc9 Binary files /dev/null and b/public/images/wechat/setting.png differ diff --git a/public/images/wechat/test.png b/public/images/wechat/test.png new file mode 100644 index 000000000..e67567b69 Binary files /dev/null and b/public/images/wechat/test.png differ diff --git a/public/images/wechat/tr-like.png b/public/images/wechat/tr-like.png new file mode 100644 index 000000000..9d9d38dc3 Binary files /dev/null and b/public/images/wechat/tr-like.png differ diff --git a/public/images/wechat/tr-reply.png b/public/images/wechat/tr-reply.png new file mode 100644 index 000000000..aef9cffcf Binary files /dev/null and b/public/images/wechat/tr-reply.png differ diff --git a/public/images/wechat/trustie_QR.jpg b/public/images/wechat/trustie_QR.jpg new file mode 100644 index 000000000..2b0c38f8b Binary files /dev/null and b/public/images/wechat/trustie_QR.jpg differ diff --git a/public/images/wechat/w-icons-file.png b/public/images/wechat/w-icons-file.png new file mode 100644 index 000000000..c5b8be58b Binary files /dev/null and b/public/images/wechat/w-icons-file.png differ diff --git a/public/images/wechat/w_praise.png b/public/images/wechat/w_praise.png new file mode 100644 index 000000000..6c0a5f7eb Binary files /dev/null and b/public/images/wechat/w_praise.png differ diff --git a/public/images/wechat/w_praised.png b/public/images/wechat/w_praised.png new file mode 100644 index 000000000..3b80c9c0b Binary files /dev/null and b/public/images/wechat/w_praised.png differ diff --git a/public/images/wechat/w_reply.png b/public/images/wechat/w_reply.png new file mode 100644 index 000000000..d18e19508 Binary files /dev/null and b/public/images/wechat/w_reply.png differ diff --git a/public/images/wechat/wechat_icon.gif b/public/images/wechat/wechat_icon.gif new file mode 100644 index 000000000..8d460be80 Binary files /dev/null and b/public/images/wechat/wechat_icon.gif differ diff --git a/public/images/wechat/wechat_icon.png b/public/images/wechat/wechat_icon.png new file mode 100644 index 000000000..cbc3eb565 Binary files /dev/null and b/public/images/wechat/wechat_icon.png differ diff --git a/public/images/wechat/wx_logo.jpg b/public/images/wechat/wx_logo.jpg new file mode 100644 index 000000000..8faeef27a Binary files /dev/null and b/public/images/wechat/wx_logo.jpg differ diff --git a/public/images/wx.gif b/public/images/wx.gif new file mode 100644 index 000000000..744f5ae7a Binary files /dev/null and b/public/images/wx.gif differ diff --git a/public/javascripts/educoder/edu_application.js b/public/javascripts/educoder/edu_application.js new file mode 100644 index 000000000..91e04ce80 --- /dev/null +++ b/public/javascripts/educoder/edu_application.js @@ -0,0 +1,1288 @@ +document.write(""); + +/*! + * JavaScript Cookie v2.2.0 + * https://github.com/js-cookie/js-cookie + * + * Copyright 2006, 2015 Klaus Hartl & Fagner Brack + * Released under the MIT license + */ +!function(e) { + var n; + if ("function" == typeof define && define.amd && (define(e), + n = !0), + "object" == typeof exports && (module.exports = e(), + n = !0), + !n) { + var t = window.Cookies + , o = window.Cookies = e(); + o.noConflict = function() { + return window.Cookies = t, + o + } + } +}(function() { + function e() { + for (var e = 0, n = {}; e < arguments.length; e++) { + var t = arguments[e]; + for (var o in t) + n[o] = t[o] + } + return n + } + function n(e) { + return e.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent) + } + return function t(o) { + function r() {} + function i(n, t, i) { + if ("undefined" != typeof document) { + "number" == typeof (i = e({ + path: "/" + }, r.defaults, i)).expires && (i.expires = new Date(1 * new Date + 864e5 * i.expires)), + i.expires = i.expires ? i.expires.toUTCString() : ""; + try { + var c = JSON.stringify(t); + /^[\{\[]/.test(c) && (t = c) + } catch (e) {} + t = o.write ? o.write(t, n) : encodeURIComponent(String(t)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent), + n = encodeURIComponent(String(n)).replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent).replace(/[\(\)]/g, escape); + var f = ""; + for (var u in i) + i[u] && (f += "; " + u, + !0 !== i[u] && (f += "=" + i[u].split(";")[0])); + return document.cookie = n + "=" + t + f + } + } + function c(e, t) { + if ("undefined" != typeof document) { + for (var r = {}, i = document.cookie ? document.cookie.split("; ") : [], c = 0; c < i.length; c++) { + var f = i[c].split("=") + , u = f.slice(1).join("="); + t || '"' !== u.charAt(0) || (u = u.slice(1, -1)); + try { + var a = n(f[0]); + if (u = (o.read || o)(u, a) || n(u), + t) + try { + u = JSON.parse(u) + } catch (e) {} + if (r[a] = u, + e === a) + break + } catch (e) {} + } + return e ? r[e] : r + } + } + return r.set = i, + r.get = function(e) { + return c(e, !1) + } + , + r.getJSON = function(e) { + return c(e, !0) + } + , + r.remove = function(n, t) { + i(n, "", e(t, { + expires: -1 + })) + } + , + r.defaults = {}, + r.withConverter = t, + r + }(function() {}) +}); + +$(function() { + var result = location.search.match(/\?search=(\w*)&?/i) + if (result && result[1]) { + var searchText = result[1] + $('#search-input').val(searchText) + } + // 未报名用户登录时弹框 + // console.log(Cookies.get('enroll_status')); + // if(Cookies.get('enroll_status') == 0){ + // Cookies.remove('enroll_status'); + // var html='
                                '+ + // '
                                '+ + // ''+ + // ''+ + // '立即报名'+ + // '
                                '; + // $(".newContainer").append(html); + // } +}); + +function CloseBox() { + $(".CompetitionEnrollBox").remove(); +} + +//根据页面大小决定侧边栏的位置 +$(window).resize(function() { + rightSlider(); +}); +function rightSlider() { + var poi = parseInt((parseInt($(window).width()) - 1200) / 2) - 60; + // console.log(parseInt($(window).width())+" "+poi); + if (poi > 0) { + $(".-task-sidebar").css("right", poi); + } else { + $(".-task-sidebar").css("right", "0px"); + } + $(".-task-sidebar").show(); +} +function open_course(id, allowVisit) { + if (allowVisit) { + window.open("/courses/" + id); + } +} +function open_project(id, allowVisit) { + if (allowVisit) { + window.open("/projects/" + id); + } +} + +function conver_size(limit) { + var size = ""; + if (limit < 1024) { + //如果小于1KB转化成B + size = limit.toFixed(2) + "B"; + } else if (limit < 1024 * 1024) { + //如果小于1MB转化成KB + size = (limit / 1024).toFixed(2) + "KB"; + } else if (limit < 1024 * 1024 * 1024) { + //如果小于1GB转化成MB + size = (limit / (1024 * 1024)).toFixed(2) + "MB"; + } else { + //其他转化成GB + size = (limit / (1024 * 1024 * 1024)).toFixed(2) + "GB"; + } + + var sizestr = size + ""; + var len = sizestr.indexOf("\."); + var dec = sizestr.substr(len + 1, 2); + if (dec == "00") { + //当小数点后为00时 去掉小数部分 + return sizestr.substring(0, len) + sizestr.substr(len + 3, 2); + } + return sizestr; +} + +function _initSider() { + var $descSide = $("
                                ").appendTo("body"); + $(".-task-sidebar>div").hover(function() { + //移入显示二维码 + if ($(this).hasClass("scan")) { + $(".scan_ewm").show().css({ + right: "75px", + opacity: 0 + }).stop().animate({ + right: "45px", + opacity: 1 + }) + return; + } + var $tool = $(this).attr("tooltips"); + $descSide.html($tool + "
                                "); + $descSide.data('_dom', this) + $descSide.show().css({ + left: $(this).offset().left - $descSide.width() - 30, + opacity: 0, + top: $(this).offset().top + }).stop().animate({ + left: $(this).offset().left - $descSide.width() - 5, + opacity: 1 + }, 400); + }, function() { + if ($(this).hasClass("scan")) { + $(".scan_ewm").stop().animate({ + right: "75px", + opacity: 0 + }, 200).hide(); + } + $descSide.stop().animate({ + left: $(this).offset().left - $descSide.width() - 30, + opacity: 0 + }, 200).hide(); + }); + rightSlider(); + + $(window).scroll(function() { + if ($descSide.height()) { + var hoverIcon = $descSide.data('_dom') + $descSide.css('top', $(hoverIcon).offset().top) + } + }) +} +$(function() { + loadHeader(); + _initSider(); + + $(window).scroll(function() { + if ($(".gotop").length > 0) { + if ($(document).scrollTop() > 0) { + $(".-task-sidebar .gotop").show(); + $(".gotop").click(function() { + $("html,body").scrollTop(0); + }); + } + if ($(document).scrollTop() == 0) { + $(".-task-sidebar .gotop").hide(); + } + } + }); + + // 翻页的GO + $(".page_GO").live("keydown", function(event) { + var code; + if (!event) { + event = window.event; + //针对ie浏览器 + code = event.keyCode; + } else { + code = event.keyCode; + } + if (code == 13) { + var prev = $(this).prev().find("a").html().trim(); + var page = $(this).val().trim(); + if (parseInt(prev) >= parseInt(page)) { + if (typeof ($(this).prev().children("a").attr("href")) == "undefined") { + var href = $(this).parent().find("li:first-child").children("a").attr("href"); + } else { + var href = $(this).prev().children("a").attr("href"); + } + var new_href = href.replace(/page=(\d*)/, 'page=' + page); + console.log(new_href); + $.get(new_href); + return false; + } + } + }); + + // 试用申请弹框 + $("#apply_trail_submit_btn").live('click', function() { + if ($("#apply_reason").val().trim() == "") { + $("#hint_message").show(); + } else { + $("#hint_message").hide(); + $("#apply_trail_form").submit(); + hideModal(); + } + }); + +}); + +// editor 存在了jquery对象上,应用不需要自己写md_rec_data方法了 +function md_rec_data(k, mdu, id) { + if (window.sessionStorage.getItem(k + mdu) !== null) { + editor = $("#e_tips_" + id).data('editor'); + editor.setValue(window.sessionStorage.getItem(k + mdu)); + + md_clear_data(k, mdu, id); + } +} +// markdown的自动保存 +function md_elocalStorage(editor, mdu, id) { + if (window.sessionStorage) { + var oc = window.sessionStorage.getItem('content' + mdu); + if (oc !== null) { + $("#e_tips_" + id).data('editor', editor); + var h = '您上次有已保存的数据,是否恢复 ? / 不恢复'; + $("#e_tips_" + id).html(h); + } + setInterval(function() { + 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; + $(id1).html(" 数据已于 " + h + ':' + m + ':' + s + " 保存 "); + $(id2).html(""); + } + }, 10000); + + } else { + $("#e_tip_" + id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); + } +} +// 保存数据 +function md_add_data(k, mdu, d) { + window.sessionStorage.setItem(k + mdu, d); +} +// 恢复数据 +//function md_rec_data(k,mdu,id, editor){ +// if(window.sessionStorage.getItem(k+mdu) !== null){ +// editor.setValue(window.sessionStorage.getItem(k+mdu)); +// md_clear_data(k,mdu,id); +// } +//} +// 清空保存的数据 +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(""); + } +} + +// editorMD to create +/** + * + * @param id 渲染DOM的id + * @param width 宽度 + * @param high 高度 + * @param placeholder + * @param imageUrl 上传图片的url + * @returns {*} 返回一个editorMD实例 + */ +function create_editorMD(id, width, high, placeholder, imageUrl, readonly) { + var readonly = readonly == undefined ? false : readonly; + var editorName = editormd(id, { + width: width, + height: high, + syncScrolling: "single", + //你的lib目录的路径,我这边用JSP做测试的 + path: "/editormd/lib/", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + readonly: readonly, + toolbarIcons: function() { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"] + }, + toolbarCustomIcons: { + testIcon: "
                                ", + testIcon1: "
                                " + }, + //这个配置在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 + onload: function(cMirror) { + $("#" + 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", "多行公式"); + setTimeout(function() { + editorName.resize(); + editorName.cm.refresh(); + window.new_md = editorName; + }, 300); + } + }); + return editorName; +} + +// editormd to html +/** + * + * @param id 渲染的id + * @param callback onload回調 暫時未用 + */ +function editormd_to_html(id, callback) { + editormd.loadKaTeX(function() { + editormd.markdownToHTML(id, { + htmlDecode: "style,script,iframe", + // you can filter tags decode + onload: function() { + callback && callback() + }, + taskList: true, + tex: true, + // 默认不解析 + flowChart: true, + // 默认不解析 + sequenceDiagram: true// 默认不解析 + }); + }); +} + +function loadHeader() { + //头部导航条的----------显示搜索框 + $("#search-open").on("click", function(e) { + $(this).hide(); + // $("#header-nav").animate({opacity:"0"},1000); + $(".posi-search").show() + // .animate({opacity:"1"},1000); + $("#header-nav").css("z-index", "2"); + $(".posi-search").css("z-index", "3"); + // $(".search-input").val(""); // 不清空 + $(".search-input").focus(); + $(".search-all .search-content").hide(); + e.stopPropagation(); + //阻止冒泡 + }); + $(".search-input").on("click", function(e) { + e.stopPropagation(); + //阻止冒泡 + }); + //搜索框输入内容 + $(".search-input").on("input", function(e) { + if ($(".search-input").val() == "") { + $(".search-all .search-content").hide(); + } else { + $(".search-all .search-content").show(); + } + e.stopPropagation(); + //阻止冒泡 + }); + //搜索 + $("#header_keyword_search").on("click", header_search); + $("input[name='search_keyword']").on("keydown", function(event) { + var code; + if (!event) { + event = window.event; + //针对ie浏览器 + code = event.keyCode; + } else { + code = event.keyCode; + } + if (code == 13) { + header_search(); + return false; + } + }); + $(".search-clear").click(function(e) { + e.stopPropagation(); + }); + //切换搜索条件 + $("#searchkey li").click(function(e) { + var key = $($(this).children("a")[0]).html(); + switch (key) { + case '实训': + $("#search_type").val('1'); + break; + case '课堂': + $("#search_type").val('2'); + break; + case '用户': + $("#search_type").val('3'); + break; + } + $("#searchkey").siblings(".searchkey").html(key); + // $("#searchkey").hide(); + e.stopPropagation(); + //阻止冒泡 + }); + //切换选择导航条 + $("#header-nav li").click(function() { + $("#header-nav li").removeClass("active"); + $(this).addClass("active"); + }); + //点击页面其它(与搜索框无关的地方)都会将搜索框隐藏,所以与搜索框有关的地方需要阻止冒泡 + $("body").on("click", function() { + closeSearch(); + }); + + $(".search_history").on("click", function() { + $("input[name='search_keyword']").val($(this).html()); + header_search(); + }); +} + +function header_search() { + var keyword = $("input[name='search_keyword']").val(); + // 搜索关键字 + var index = $("#search_type").val(); + // 搜索课程/项目 + keyword = encodeURIComponent(keyword); + // $.get('/users/search_shixuns_or_course', + // { search: keyword, + // index: index}); + window.location.href = "/users/search_shixuns_or_courses" + "?search=" + keyword + "&index=" + index; + //e.stopPropagation();//阻止冒泡 +} + +//头部导航条的隐藏 +function closeSearch() { + $('#posi-search').hide(); + $("#search-open").show(); + // $(".posi-search").animate({opacity:"0"},800); + $("#header-nav").animate({ + opacity: "1" + }, 1000); + $(".posi-search").css("z-index", "2"); + $("#header-nav").css("z-index", "3"); +} +(function($) { + $.fn.drag = function(options) { + var x, drag = this, isMove = false, defaults = {}; + var options = $.extend(defaults, options); + //添加背景,文字,滑块 + var html = '
                                ' + '
                                请拖住滑块,拖动到最右边
                                ' + '
                                '; + this.append(html); + + var handler = drag.find('.handler'); + var drag_bg = drag.find('.drag_bg'); + var text = drag.find('.drag_text'); + var maxWidth = text.width() - handler.width(); + //能滑动的最大间距 + //鼠标按下时候的x轴的位置 + handler.mousedown(function(e) { + isMove = true; + x = e.pageX - parseInt(handler.css('left'), 10); + }); + + //鼠标指针在上下文移动时,移动距离大于0小于最大间距,滑块x轴位置等于鼠标移动距离 + $(document).mousemove(function(e) { + var _x = e.pageX - x; + var handler_offset = handler.offset(); + var lastX = e.clientX - x; + lastX = Math.max(0, Math.min(maxWidth, lastX)); + if (isMove) { + if (_x > 0 && _x <= maxWidth) { + handler.css({ + 'left': lastX + }); + drag_bg.css({ + 'width': lastX + }); + } else if (lastX > maxWidth - 5 && lastX < maxWidth + 5) { + //鼠标指针移动距离达到最大时清空事件 + dragOk(); + } + } + }); + handler.mouseup(function(e) { + isMove = false; + var _x = e.pageX - x; + if (_x < maxWidth) { + //鼠标松开时,如果没有达到最大距离位置,滑块就返回初始位置 + handler.css({ + 'left': 0 + }); + drag_bg.css({ + 'width': 0 + }); + } + }); + + //清空事件 + function dragOk() { + var kuaiwidth = drag.width() - handler.width(); + handler.removeClass('handler_bg').addClass('handler_ok_bg'); + handler.css({ + 'left': kuaiwidth + 'px' + }) + text.css({ + 'width': kuaiwidth + 'px' + }); + text.text('验证通过'); + drag.css({ + 'color': '#fff' + }); + drag_bg.css({ + 'width': kuaiwidth + 'px' + }) + handler.unbind('mousedown'); + $(document).unbind('mousemove'); + $(document).unbind('mouseup'); + handler.parent().next().find("p").html("").hide(); + } + } + ; +} +)(jQuery); + +//判断是手机端还是电脑端 +function IsPC() { + var userAgentInfo = navigator.userAgent; + var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; + var flag = true; + for (var v = 0; v < Agents.length; v++) { + if (userAgentInfo.indexOf(Agents[v]) > 0) { + flag = false; + break; + } + } + return flag; +} + +//Dom:绑定事件的节点对象,ChangeDOM:操作的相关节点, +function LeaveTitle(Dom, ChangeDom) { + ChangeDom.html("").hide(); + ChangeDom.parent().css({ + opacity: 0, + left: 0, + top: 0 + }).hide(); +} + +$(function() { + //平台tip的样式优化js + var $desc = $("
                                " + "
                                " + "
                                " + "
                                " + "
                                " + "
                                ").appendTo("body"); + //Dom:绑定事件的节点对象,ChangeDOM:操作的相关节点, + function LeaveTitle(Dom, ChangeDom) { + Dom.live("mouseleave", function() { + ChangeDom.html("").hide(); + $desc.css({ + opacity: 0, + left: 0, + top: 0 + }).hide(); + }) + } + LeaveTitle($("[data-tip-top]"), $(".data-tip-top")); + LeaveTitle($("[data-tip-down]"), $(".data-tip-down")); + LeaveTitle($("[data-tip-right]"), $(".data-tip-left")); + LeaveTitle($("[data-tip-left]"), $(".data-tip-right")); + $("[data-tip-top]").live("mouseenter", function() { + var $tool = $(this).attr("data-tip-top"); + if ($tool != "") { + $(".data-tip-top").show().html($tool); + $desc.show().css({ + left: $(this).offset().left - ($desc.width() - $(this).outerWidth()) / 2, + opacity: 1, + top: $(this).offset().top - 30 + }); + } + }); + $("[data-tip-down]").live("mouseenter", function() { + var $tool = $(this).attr("data-tip-down"); + if ($tool != "") { + $(".data-tip-down").show().html($tool); + $desc.show().css({ + left: $(this).offset().left - ($desc.width() - $(this).outerWidth()) / 2, + opacity: 1, + top: $(this).offset().top + $(this).height() + 6 + }); + } + }); + $("[data-tip-right]").live("mouseenter", function() { + var $tool = $(this).attr("data-tip-right"); + if ($tool != "") { + console.log($(this).offset().left + " " + $(this).width()); + $(".data-tip-left").show().html($tool); + $desc.show().css({ + left: $(this).offset().left + $(this).outerWidth() + 6, + opacity: 1, + top: $(this).offset().top - ($desc.height() - $(this).height()) / 2 + }); + } + }); + $("[data-tip-left]").live("mouseenter", function() { + var $tool = $(this).attr("data-tip-left"); + if ($tool != "") { + $(".data-tip-right").show().html($tool); + $desc.show().css({ + left: $(this).offset().left - $desc.width() - 6, + opacity: 1, + top: $(this).offset().top - ($desc.height() - $(this).height()) / 2 + }); + } + }); + unitDownOption(); +}); + +function unitDownOption() { + //下拉框 + $("[select-for]").append(""); + $("[select-for]").hover(function() { + $(this).find(".down-select").show(); + }, function() { + $(this).find(".down-select").hide(); + }) + $("[select-for] .down-select p").bind("click", function() { + //alert($(this).attr("data-shixun-value")); + if ($(this).attr("id") == "diy_script") { + return; + // 实训新建-选择自定义脚本diy + } + $(this).parents(".down-select").siblings("input[type=hidden]").attr("value", $(this).attr("data-shixun-value")); + + $(this).parents(".down-select").siblings("input[type=text]").val($(this).html().trim()); + $(this).parents(".down-select").hide(); + }) +} + +//初始化省份 +function showprovince(id) { + var arrary = ["北京", "上海", "广东", "江苏", "浙江", "重庆", "安徽", "福建", "甘肃", "广西", "贵州", "海南", "河北", "黑龙江", "河南", "湖北", "湖南", "江西", "吉林", "辽宁", "内蒙古", "宁夏", "青海", "山东", "山西", "陕西", "四川", "天津", "新疆", "西藏", "云南", "香港特别行政区", "澳门特别行政区", "台湾", "海外"]; + var html = "" + for (var i = 0; i < arrary.length; i++) { + var item = arrary[i]; + html += ""; + } + $("#" + id).html(html); +} + +//省市下拉框 +function showcity(province, cityField) { + switch (province) { + case "北京": + var cityOptions = new Array("东城","西城","朝阳","丰台","石景山","海淀","门头沟","房山","通州","顺义","昌平","大兴","平谷","怀柔","密云","延庆"); + break; + case "上海": + var cityOptions = new Array("崇明","黄浦","卢湾","徐汇","长宁","静安","普陀","闸北","虹口","杨浦","闵行","宝山","嘉定","浦东","金山","松江","青浦","南汇","奉贤"); + break; + case "广东": + var cityOptions = new Array("广州","深圳","珠海","东莞","中山","佛山","惠州","河源","潮州","江门","揭阳","茂名","梅州","清远","汕头","汕尾","韶关","顺德","阳江","云浮","湛江","肇庆"); + break; + case "江苏": + var cityOptions = new Array("南京","常熟","常州","海门","淮安","江都","江阴","昆山","连云港","南通","启东","沭阳","宿迁","苏州","太仓","泰州","同里","无锡","徐州","盐城","扬州","宜兴","仪征","张家港","镇江","周庄"); + break; + case "重庆": + var cityOptions = new Array("万州","涪陵","渝中","大渡口","江北","沙坪坝","九龙坡","南岸","北碚","万盛","双挢","渝北","巴南","黔江","长寿","綦江","潼南","铜梁","大足","荣昌","壁山","梁平","城口","丰都","垫江","武隆","忠县","开县","云阳","奉节","巫山","巫溪","石柱","秀山","酉阳","彭水","江津","合川","永川","南川"); + break; + case "安徽": + var cityOptions = new Array("合肥","安庆","蚌埠","亳州","巢湖","滁州","阜阳","贵池","淮北","淮化","淮南","黄山","九华山","六安","马鞍山","宿州","铜陵","屯溪","芜湖","宣城"); + break; + case "福建": + var cityOptions = new Array("福州","厦门","泉州","漳州","龙岩","南平","宁德","莆田","三明"); + break; + case "甘肃": + var cityOptions = new Array("兰州","白银","定西","敦煌","甘南","金昌","酒泉","临夏","平凉","天水","武都","武威","西峰","张掖"); + break; + case "广西": + var cityOptions = new Array("南宁","百色","北海","桂林","防城港","贵港","河池","贺州","柳州","钦州","梧州","玉林"); + break; + case "贵州": + var cityOptions = new Array("贵阳","安顺","毕节","都匀","凯里","六盘水","铜仁","兴义","玉屏","遵义"); + break; + case "海南": + var cityOptions = new Array("海口","儋县","陵水","琼海","三亚","通什","万宁"); + break; + case "河北": + var cityOptions = new Array("石家庄","保定","北戴河","沧州","承德","丰润","邯郸","衡水","廊坊","南戴河","秦皇岛","唐山","新城","邢台","张家口"); + break; + case "黑龙江": + var cityOptions = new Array("哈尔滨","北安","大庆","大兴安岭","鹤岗","黑河","佳木斯","鸡西","牡丹江","齐齐哈尔","七台河","双鸭山","绥化","伊春"); + break; + case "河南": + var cityOptions = new Array("郑州","安阳","鹤壁","潢川","焦作","济源","开封","漯河","洛阳","南阳","平顶山","濮阳","三门峡","商丘","新乡","信阳","许昌","周口","驻马店"); + break; + case "香港": + var cityOptions = new Array("香港","九龙","新界"); + break; + case "湖北": + var cityOptions = new Array("武汉","恩施","鄂州","黄冈","黄石","荆门","荆州","潜江","十堰","随州","武穴","仙桃","咸宁","襄阳","襄樊","孝感","宜昌"); + break; + case "湖南": + var cityOptions = new Array("长沙","常德","郴州","衡阳","怀化","吉首","娄底","邵阳","湘潭","益阳","岳阳","永州","张家界","株洲"); + break; + case "江西": + var cityOptions = new Array("南昌","抚州","赣州","吉安","景德镇","井冈山","九江","庐山","萍乡","上饶","新余","宜春","鹰潭"); + break; + case "吉林": + var cityOptions = new Array("长春","吉林","白城","白山","珲春","辽源","梅河","四平","松原","通化","延吉"); + break; + case "辽宁": + var cityOptions = new Array("沈阳","鞍山","本溪","朝阳","大连","丹东","抚顺","阜新","葫芦岛","锦州","辽阳","盘锦","铁岭","营口"); + break; + case "澳门": + var cityOptions = new Array("澳门"); + break; + case "内蒙古": + var cityOptions = new Array("呼和浩特","阿拉善盟","包头","赤峰","东胜","海拉尔","集宁","临河","通辽","乌海","乌兰浩特","锡林浩特"); + break; + case "宁夏": + var cityOptions = new Array("银川","固源","石嘴山","吴忠"); + break; + case "青海": + var cityOptions = new Array("西宁","德令哈","格尔木","共和","海东","海晏","玛沁","同仁","玉树"); + break; + case "山东": + var cityOptions = new Array("济南","滨州","兖州","德州","东营","菏泽","济宁","莱芜","聊城","临沂","蓬莱","青岛","曲阜","日照","泰安","潍坊","威海","烟台","枣庄","淄博"); + break; + case "山西": + var cityOptions = new Array("太原","长治","大同","候马","晋城","离石","临汾","宁武","朔州","忻州","阳泉","榆次","运城"); + break; + case "陕西": + var cityOptions = new Array("西安","安康","宝鸡","汉中","渭南","商州","绥德","铜川","咸阳","延安","榆林"); + break; + case "四川": + var cityOptions = new Array("成都","巴中","达川","德阳","都江堰","峨眉山","涪陵","广安","广元","九寨沟","康定","乐山","泸州","马尔康","绵阳","眉山","南充","内江","攀枝花","遂宁","汶川","西昌","雅安","宜宾","自贡","资阳"); + break; + case "台湾": + var cityOptions = new Array("台北","基隆","台南","台中","高雄","屏东","南投","云林","新竹","彰化","苗栗","嘉义","花莲","桃园","宜兰","台东","金门","马祖","澎湖"); + break; + case "天津": + var cityOptions = new Array("天津","和平","东丽","河东","西青","河西","津南","南开","北辰","河北","武清","红挢","塘沽","汉沽","大港","宁河","静海","宝坻","蓟县"); + break; + case "新疆": + var cityOptions = new Array("乌鲁木齐","阿克苏","阿勒泰","阿图什","博乐","昌吉","东山","哈密","和田","喀什","克拉玛依","库车","库尔勒","奎屯","石河子","塔城","吐鲁番","伊宁"); + break; + case "西藏": + var cityOptions = new Array("拉萨","阿里","昌都","林芝","那曲","日喀则","山南"); + break; + case "云南": + var cityOptions = new Array("昆明","大理","保山","楚雄","大理","东川","个旧","景洪","开远","临沧","丽江","六库","潞西","曲靖","思茅","文山","西双版纳","玉溪","中甸","昭通"); + break; + case "浙江": + var cityOptions = new Array("杭州","安吉","慈溪","定海","奉化","海盐","黄岩","湖州","嘉兴","金华","临安","临海","丽水","宁波","瓯海","平湖","千岛湖","衢州","江山","瑞安","绍兴","嵊州","台州","温岭","温州","余姚","舟山"); + break; + case "海外": + var cityOptions = new Array("美国","日本","英国","法国","德国","其他"); + break; + default: + var cityOptions = new Array("请选择所在城市"); + break; + } + + cityField.options.length = 0; + for (var i = 0; i < cityOptions.length; i++) { + cityField.options[i] = new Option(cityOptions[i],cityOptions[i]); + /* + if (cityField.options[i].value==city) + { + //alert("here put City ok!"); + document.oblogform["city"].selectedIndex = i; + }*/ + } +} + +/*弹框*/ +// 公共弹框样式 +// 建议左右栏的:Width:460,Height:190 +// 建议宽屏对应值:Width:760,Height:500 +function pop_box_new(value, Width, Height, close) { + + if ($("#popupAll").length > 0) { + $("#popupAll").remove(); + } + w = ($(window).width() - Width) / 2; + h = ($(window).height() - Height) / 2; + var html = "
                                "; + if (close) { + value = "" + value; + } + $(document.body).append(html); + $("#popupWrap").html(value); + $('#popupWrap').css({ + "top": h + "px", + "left": w + "px", + "padding": "0", + "border": "none", + "position": "fixed", + "z-index": "99999", + "background-color": "#fff", + "border-radius": "10px" + }); + if (close) { + $('#closeIcon').css({ + "top": "-26px", + "left": Width + "px", + "z-index": "100000" + }); + } + + $("#popupWrap").parent().parent().show(); + $('#popupAll').find("#closeIcon").click(function() { + $("#popupAll").hide(); + }); + $('#popupAll').find("a[class*='pop_close']").click(function() { + $("#popupAll").hide(); + }); + // w = ($(window).width() - Width)/2; + // h = ($(window).height() - Height)/2; + // $("#ajax-modal").html(value); + // showModal('ajax-modal', Width + 'px'); + // $('#ajax-modal').siblings().remove(); + // $('#ajax-modal').parent().css({"top": h+"px","left": w+"px","padding":"0","border":"none","position":"fixed"}); + // $('#ajax-modal').parent().removeClass("resourceUploadPopup popbox_polls popbox"); + // $('#ajax-modal').css({"padding":"0","overflow":"hidden"}); + // $('#ajax-modal').parent().attr("id","popupWrap"); + + //拖拽 + function Drag(id) { + this.div = document.getElementById(id); + if (this.div) { + this.div.style.cursor = "move"; + this.div.style.position = "fixed"; + } + this.disX = 0; + this.disY = 0; + var _this = this; + this.div.onmousedown = function(evt) { + _this.getDistance(evt); + document.onmousemove = function(evt) { + _this.setPosition(evt); + } + ; + _this.div.onmouseup = function() { + _this.clearEvent(); + } + } + } + Drag.prototype.getDistance = function(evt) { + var oEvent = evt || event; + this.disX = oEvent.clientX - this.div.offsetLeft; + this.disY = oEvent.clientY - this.div.offsetTop; + } + ; + Drag.prototype.setPosition = function(evt) { + var oEvent = evt || event; + var l = oEvent.clientX - this.disX; + var t = oEvent.clientY - this.disY; + if (l <= 0) { + l = 0; + } else if (l >= document.documentElement.clientWidth - this.div.offsetWidth) { + l = document.documentElement.clientWidth - this.div.offsetWidth; + } + if (t <= 0) { + t = 0; + } else if (t >= document.documentElement.clientHeight - this.div.offsetHeight) { + t = document.documentElement.clientHeight - this.div.offsetHeight; + } + this.div.style.left = l + "px"; + this.div.style.top = t + "px"; + } + ; + Drag.prototype.clearEvent = function() { + this.div.onmouseup = null; + document.onmousemove = null; + } + ; + + new Drag("popupWrap"); + + $("#popupAll input, #popupAll textarea, #popupAll select, #popupAll ul, #popupAll a,#shixun_search_form_div").mousedown(function(event) { + event.stopPropagation(); + new Drag("popupWrap"); + }); + +} + +function hideModal(el) { + if ($("#popupAll").length > 0) { + $("#popupAll").remove(); + } else { + var modal; + if (el) { + modal = $(el).parents('.ui-dialog-content'); + } else { + modal = $('#ajax-modal'); + } + modal.dialog("close"); + } +} + +//提示框:只有一个确定按钮,点击跳转 +// +function notice_box_redirect(url, str) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                ' + '确定
                                '; + pop_box_new(htmlvalue, 480, 160); +} +//按钮内容自定义(自定义按钮需要remote=true,且有取消按钮) +function notice_operation_box(url, str, btnstr) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                '; + pop_box_new(htmlvalue, 480, 160); +} +//点击删除时的确认弹框: 不走destroy方法 +function delete_confirm_box(url, str) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                '; + pop_box_new(htmlvalue, 480, 160); +} +//点击删除时的确认弹框: 走destroy方法,remote为true +function delete_confirm_box_2(url, str) { + var htmlvalue = '
                                提示
                                ' + '
                                ' + str + '
                                '; + pop_box_new(htmlvalue, 480, 160); +} + +// 点击确定的时候ajax请求,两个按钮 点击确认跳转, 提示信息可以多行 +function op_confirm_box_remote(url, str) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                '; + pop_box_new(htmlvalue, 578, 205); +} + +//点击删除时的确认弹框: post,remote为true +function post_confirm_box(url, str) { + var htmlvalue = '

                                提示

                                ' + '

                                ' + str + '

                                '; + pop_box_new(htmlvalue, 480, 160); +} + +//提示框:只有一个确定按钮,点击关闭弹框 +// +function notice_box(str) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                ' + '确定
                                '; + pop_box_new(htmlvalue, 480, 160); +} + +//点击删除时的确认弹框: 走destroy方法 +function delete_confirm_box_3(url, str) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                '; + pop_box_new(htmlvalue, 480, 160); +} + +//取消和确定,确定会调用自定义方法 +function op_confirm_tip(str, func) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                '; + pop_box_new(htmlvalue, 500, 205); +} + +//取消和确定,确定会调用自定义方法(带参数) +function op_confirm_tip_1(str, func) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                '; + pop_box_new(htmlvalue, 500, 205); +} + +function op_confirm_box_loading(url, str) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                '; + pop_box_new(htmlvalue, 578, 205); +} + +// 两个按钮 点击确认跳转, 提示信息有两行 +function s_op_confirm_box(url, str) { + var htmlvalue = '
                                提示
                                ' + '

                                ' + str + '

                                '; + pop_box_new(htmlvalue, 480, 205); +} + +function suofang() { + var html = '

                                可能会影响某些功能的正常使用

                                  ' + '
                                • 1.请尝试调整浏览器缩放比例为100%(快捷键ctrl+0)
                                • ' + '
                                • 2.请尝试调整系统显示比例为100%(控制面板/显示 设置)
                                • ' + '
                                '; + sure_confirm_box("页面缩放比例不正确", 600, 310, html); +} + +//一个“知道了”按钮,title和宽度都作为参数 +function sure_confirm_box(title, width, height, str) { + var htmlvalue = '
                                ' + title + '
                                ' + '
                                ' + str + '
                                '; + pop_box_new(htmlvalue, width, height); +} + +function throttle(method, context, e) { + clearTimeout(method.tId); + method.tId = setTimeout(function() { + method.call(context, e); + }, 500); +} + +function apply_publish_shixun(url) { + if ($("#apply_publish_shixun").attr("data-option") == '1') { + $("#apply_publish_shixun").attr("data-option", 0); + $("#apply_publish_shixun").addClass("disabled-grey-bg"); + $.ajax({ + url: url, + type: 'get' + }); + } +} + +var autoTextarea = function(elem, extra, maxHeight) { + extra = extra || 0; + var isFirefox = !!document.getBoxObjectFor || 'mozInnerScreenX'in window + , isOpera = !!window.opera && !!window.opera.toString().indexOf('Opera') + , addEvent = function(type, callback) { + elem.addEventListener ? elem.addEventListener(type, callback, false) : elem.attachEvent('on' + type, callback); + } + , getStyle = elem.currentStyle ? function(name) { + var val = elem.currentStyle[name]; + + if (name === 'height' && val.search(/px/i) !== 1) { + var rect = elem.getBoundingClientRect(); + return rect.bottom - rect.top - parseFloat(getStyle('paddingTop')) - parseFloat(getStyle('paddingBottom')) + 'px'; + } + ; + return val; + } + : function(name) { + return getComputedStyle(elem, null)[name]; + } + , minHeight = parseFloat(getStyle('height')); + + elem.style.resize = 'none'; + + var change = function() { + var scrollTop, height, padding = 0, style = elem.style; + + if (elem._length === elem.value.length) + return; + elem._length = elem.value.length; + + if (!isFirefox && !isOpera) { + padding = parseInt(getStyle('paddingTop')) + parseInt(getStyle('paddingBottom')); + } + ;scrollTop = document.body.scrollTop || document.documentElement.scrollTop; + + elem.style.height = minHeight + 'px'; + if (elem.scrollHeight > minHeight) { + if (maxHeight && elem.scrollHeight > maxHeight) { + height = maxHeight - padding; + style.overflowY = 'auto'; + } else { + height = elem.scrollHeight - padding + 10; + style.overflowY = 'hidden'; + } + ;style.height = height + extra + 'px'; + scrollTop += parseInt(style.height) - elem.currHeight; + //document.body.scrollTop = scrollTop; + //document.documentElement.scrollTop = scrollTop; + elem.currHeight = parseInt(style.height); + } + ; + }; + + addEvent('propertychange', change); + addEvent('input', change); + addEvent('focus', change); + change(); +}; + +// 点击按钮复制功能 +function jsCopy() { + var e = document.getElementById("copy_rep_content"); + e.select(); + document.execCommand("Copy"); +} + +// 使用resize事件监听窗口的zoom,如果zoom变化了,弹框提示;初始化时也检查zoom是否是100%。 +function _initZoomCheck() { + if (!IsPC()) { + // 手机端不需要提示 + return; + } + var isNormalZoom = Math.round(window.devicePixelRatio * 100) === 100 + if (!isNormalZoom) { + suofang(); + } + + $(window).resize(function() { + var isNormalZoom = Math.round(window.devicePixelRatio * 100) === 100 + if (!isNormalZoom) { + suofang(); + } else { + $('.task-btn.task-btn-orange:visible').click() + } + }) + +} + +var win_resize = function() { + var _w = $(window).width() - 1200; + if (_w < 0) { + $('.newHeader>.educontent').width('auto') + } else { + $('.newHeader>.educontent').width('1200px') + } +}; + +function initWindowResize() { + if (location.pathname === '/login') { + // 登录页不需要 + return; + } + + $(function() { + setTimeout(function() { + win_resize(); + }, 1000) + }) + + $(window).resize(function() { + win_resize() + }) +} +initWindowResize(); + +// 登录刷新 https://stackoverflow.com/questions/28230845/communication-between-tabs-or-windows +if (window['BroadcastChannel']) { + var bc = new BroadcastChannel('ec_reload'); + bc.onmessage = function(ev) { + if (window['ec_reload_msg_send_window']) { + window['ec_reload_msg_send_window'] = false; + } else { + location.reload(); + } + } +} +function _sendReloadMsg() { + var bc = new BroadcastChannel('ec_reload'); + window['ec_reload_msg_send_window'] = true; + // 消息发出的窗口,不需要处理该消息 + bc.postMessage('ec_reload'); + /* send */ +} +// IE11 没有 startsWith +if (!String.prototype.startsWith) { + String.prototype.startsWith = function(searchString, position) { + position = position || 0; + return this.substr(position, searchString.length) === searchString; + } + ; + String.prototype.endsWith = function(search, this_len) { + if (this_len === undefined || this_len > this.length) { + this_len = this.length; + } + return this.substring(this_len - search.length, this_len) === search; + } + ; +} + +function clickNewsubscript() { + $(".newsubscript").hide(); + $(".newedbox").addClass("newminheight"); + $(".newedbox").removeClass("newedboxheight"); +} + +/** tpm实训开启按钮,不允许多次点击 START */ +//点击模拟实战或者开启实战等,按钮变灰内容变成“开启中” +var operationItem = null; +var operationButtonOldValue = null; +function opClickString(item) { + var value = $(item).html(); + $(item).css({ + 'background': 'gray', + 'border': '1px solid grey', + 'pointer-events': 'none' + }); + $(item).html('开启中'); + + operationButtonOldValue = value + operationItem = item + // setTimeout(function(){ $(item).css('background', '#4CACFF');$(item).html(value); }, 4000) +} +// +// var isOperationSending = false; +$(document).bind('ajaxStop', function(event, xhr, settings) { + if (settings && settings.url && (settings.url.match(/operation\?/))) { + if (operationItem) { + $(operationItem).css('background', '#4CACFF').css('pointer-events', 'inherit'); + $(operationItem).html(operationButtonOldValue); + } + } +}); +$(document).bind('ajaxError', function(event, xhr, settings) { + if (settings && settings.url && (settings.url.match(/operation\?/))) { + if (operationItem) { + $(operationItem).css('background', '#4CACFF').css('pointer-events', 'inherit'); + $(operationItem).html(operationButtonOldValue); + } + } +}); +/** tpm实训开启按钮,不允许多次点击 END */ diff --git a/public/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js b/public/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js new file mode 100644 index 000000000..7f3701c87 --- /dev/null +++ b/public/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js @@ -0,0 +1,11 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
                                a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
                                t
                                ",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
                                ",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
                                ",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

                                ",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
                                ","
                                "],thead:[1,"","
                                "],tr:[2,"","
                                "],td:[3,"","
                                "],col:[2,"","
                                "],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
                                ","
                                "]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
                                ").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); + +/*! jQuery UI - v1.9.2 - 2012-12-26 + * http://jqueryui.com + * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js + * Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */ +(function(e,t){function i(t,n){var r,i,o,u=t.nodeName.toLowerCase();return"area"===u?(r=t.parentNode,i=r.name,!t.href||!i||r.nodeName.toLowerCase()!=="map"?!1:(o=e("img[usemap=#"+i+"]")[0],!!o&&s(o))):(/input|select|textarea|button|object/.test(u)?!t.disabled:"a"===u?t.href||n:n)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().andSelf().filter(function(){return e.css(this,"visibility")==="hidden"}).length}var n=0,r=/^ui-id-\d+$/;e.ui=e.ui||{};if(e.ui.version)return;e.extend(e.ui,{version:"1.9.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({_focus:e.fn.focus,focus:function(t,n){return typeof t=="number"?this.each(function(){var r=this;setTimeout(function(){e(r).focus(),n&&n.call(r)},t)}):this._focus.apply(this,arguments)},scrollParent:function(){var t;return e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?t=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):t=this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(n){if(n!==t)return this.css("zIndex",n);if(this.length){var r=e(this[0]),i,s;while(r.length&&r[0]!==document){i=r.css("position");if(i==="absolute"||i==="relative"||i==="fixed"){s=parseInt(r.css("zIndex"),10);if(!isNaN(s)&&s!==0)return s}r=r.parent()}}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++n)})},removeUniqueId:function(){return this.each(function(){r.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(n){return!!e.data(n,t)}}):function(t,n,r){return!!e.data(t,r[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var n=e.attr(t,"tabindex"),r=isNaN(n);return(r||n>=0)&&i(t,!r)}}),e(function(){var t=document.body,n=t.appendChild(n=document.createElement("div"));n.offsetHeight,e.extend(n.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),e.support.minHeight=n.offsetHeight===100,e.support.selectstart="onselectstart"in n,t.removeChild(n).style.display="none"}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(n,r){function u(t,n,r,s){return e.each(i,function(){n-=parseFloat(e.css(t,"padding"+this))||0,r&&(n-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(n-=parseFloat(e.css(t,"margin"+this))||0)}),n}var i=r==="Width"?["Left","Right"]:["Top","Bottom"],s=r.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+r]=function(n){return n===t?o["inner"+r].call(this):this.each(function(){e(this).css(s,u(this,n)+"px")})},e.fn["outer"+r]=function(t,n){return typeof t!="number"?o["outer"+r].call(this,t):this.each(function(){e(this).css(s,u(this,t,!0,n)+"px")})}}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(n){return arguments.length?t.call(this,e.camelCase(n)):t.call(this)}}(e.fn.removeData)),function(){var t=/msie ([\w.]+)/.exec(navigator.userAgent.toLowerCase())||[];e.ui.ie=t.length?!0:!1,e.ui.ie6=parseFloat(t[1],10)===6}(),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,n,r){var i,s=e.ui[t].prototype;for(i in r)s.plugins[i]=s.plugins[i]||[],s.plugins[i].push([n,r[i]])},call:function(e,t,n){var r,i=e.plugins[t];if(!i||!e.element[0].parentNode||e.element[0].parentNode.nodeType===11)return;for(r=0;r0?!0:(t[r]=1,i=t[r]>0,t[r]=0,i)},isOverAxis:function(e,t,n){return e>t&&e",options:{disabled:!1,create:null},_createWidget:function(t,r){r=e(r||this.defaultElement||this)[0],this.element=e(r),this.uuid=n++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),r!==this&&(e.data(r,this.widgetName,this),e.data(r,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===r&&this.destroy()}}),this.document=e(r.style?r.ownerDocument:r.document||r),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(n,r){var i=n,s,o,u;if(arguments.length===0)return e.widget.extend({},this.options);if(typeof n=="string"){i={},s=n.split("."),n=s.shift();if(s.length){o=i[n]=e.widget.extend({},this.options[n]);for(u=0;u=9||!!t.button?this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted):this._mouseUp(t)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(e){return this.mouseDelayMet},_mouseStart:function(e){},_mouseDrag:function(e){},_mouseStop:function(e){},_mouseCapture:function(e){return!0}})})(jQuery);(function(e,t){function h(e,t,n){return[parseInt(e[0],10)*(l.test(e[0])?t/100:1),parseInt(e[1],10)*(l.test(e[1])?n/100:1)]}function p(t,n){return parseInt(e.css(t,n),10)||0}e.ui=e.ui||{};var n,r=Math.max,i=Math.abs,s=Math.round,o=/left|center|right/,u=/top|center|bottom/,a=/[\+\-]\d+%?/,f=/^\w+/,l=/%$/,c=e.fn.position;e.position={scrollbarWidth:function(){if(n!==t)return n;var r,i,s=e("
                                "),o=s.children()[0];return e("body").append(s),r=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,r===i&&(i=s[0].clientWidth),s.remove(),n=r-i},getScrollInfo:function(t){var n=t.isWindow?"":t.element.css("overflow-x"),r=t.isWindow?"":t.element.css("overflow-y"),i=n==="scroll"||n==="auto"&&t.width0?"right":"center",vertical:u<0?"top":o>0?"bottom":"middle"};lr(i(o),i(u))?h.important="horizontal":h.important="vertical",t.using.call(this,e,h)}),a.offset(e.extend(C,{using:u}))})},e.ui.position={fit:{left:function(e,t){var n=t.within,i=n.isWindow?n.scrollLeft:n.offset.left,s=n.width,o=e.left-t.collisionPosition.marginLeft,u=i-o,a=o+t.collisionWidth-s-i,f;t.collisionWidth>s?u>0&&a<=0?(f=e.left+u+t.collisionWidth-s-i,e.left+=u-f):a>0&&u<=0?e.left=i:u>a?e.left=i+s-t.collisionWidth:e.left=i:u>0?e.left+=u:a>0?e.left-=a:e.left=r(e.left-o,e.left)},top:function(e,t){var n=t.within,i=n.isWindow?n.scrollTop:n.offset.top,s=t.within.height,o=e.top-t.collisionPosition.marginTop,u=i-o,a=o+t.collisionHeight-s-i,f;t.collisionHeight>s?u>0&&a<=0?(f=e.top+u+t.collisionHeight-s-i,e.top+=u-f):a>0&&u<=0?e.top=i:u>a?e.top=i+s-t.collisionHeight:e.top=i:u>0?e.top+=u:a>0?e.top-=a:e.top=r(e.top-o,e.top)}},flip:{left:function(e,t){var n=t.within,r=n.offset.left+n.scrollLeft,s=n.width,o=n.isWindow?n.scrollLeft:n.offset.left,u=e.left-t.collisionPosition.marginLeft,a=u-o,f=u+t.collisionWidth-s-o,l=t.my[0]==="left"?-t.elemWidth:t.my[0]==="right"?t.elemWidth:0,c=t.at[0]==="left"?t.targetWidth:t.at[0]==="right"?-t.targetWidth:0,h=-2*t.offset[0],p,d;if(a<0){p=e.left+l+c+h+t.collisionWidth-s-r;if(p<0||p0){d=e.left-t.collisionPosition.marginLeft+l+c+h-o;if(d>0||i(d)a&&(v<0||v0&&(d=e.top-t.collisionPosition.marginTop+c+h+p-o,e.top+c+h+p>f&&(d>0||i(d)10&&i<11,t.innerHTML="",n.removeChild(t)}(),e.uiBackCompat!==!1&&function(e){var n=e.fn.position;e.fn.position=function(r){if(!r||!r.offset)return n.call(this,r);var i=r.offset.split(" "),s=r.at.split(" ");return i.length===1&&(i[1]=i[0]),/^\d/.test(i[0])&&(i[0]="+"+i[0]),/^\d/.test(i[1])&&(i[1]="+"+i[1]),s.length===1&&(/left|center|right/.test(s[0])?s[1]="center":(s[1]=s[0],s[0]="center")),n.call(this,e.extend(r,{at:s[0]+i[0]+" "+s[1]+i[1],offset:t}))}}(jQuery)})(jQuery);(function(e,t){e.widget("ui.draggable",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(t){var n=this.options;return this.helper||n.disabled||e(t.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(t),this.handle?(e(n.iframeFix===!0?"iframe":n.iframeFix).each(function(){e('
                                ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(t){var n=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,n.cursorAt&&this._adjustOffsetFromHelper(n.cursorAt),n.containment&&this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!n.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_mouseDrag:function(t,n){this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute");if(!n){var r=this._uiHash();if(this._trigger("drag",t,r)===!1)return this._mouseUp({}),!1;this.position=r.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var n=!1;e.ui.ddmanager&&!this.options.dropBehaviour&&(n=e.ui.ddmanager.drop(this,t)),this.dropped&&(n=this.dropped,this.dropped=!1);var r=this.element[0],i=!1;while(r&&(r=r.parentNode))r==document&&(i=!0);if(!i&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!n||this.options.revert=="valid"&&n||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,n)){var s=this;e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){s._trigger("stop",t)!==!1&&s._clear()})}else this._trigger("stop",t)!==!1&&this._clear();return!1},_mouseUp:function(t){return e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){var n=!this.options.handle||!e(this.options.handle,this.element).length?!0:!1;return e(this.options.handle,this.element).find("*").andSelf().each(function(){this==t.target&&(n=!0)}),n},_createHelper:function(t){var n=this.options,r=e.isFunction(n.helper)?e(n.helper.apply(this.element[0],[t])):n.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return r.parents("body").length||r.appendTo(n.appendTo=="parent"?this.element[0].parentNode:n.appendTo),r[0]!=this.element[0]&&!/(fixed|absolute)/.test(r.css("position"))&&r.css("position","absolute"),r},_adjustOffsetFromHelper:function(t){typeof t=="string"&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&e.ui.ie)t={top:0,left:0};return{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var e=this.element.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t=this.options;t.containment=="parent"&&(t.containment=this.helper[0].parentNode);if(t.containment=="document"||t.containment=="window")this.containment=[t.containment=="document"?0:e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t.containment=="document"?0:e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(t.containment=="document"?0:e(window).scrollLeft())+e(t.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(t.containment=="document"?0:e(window).scrollTop())+(e(t.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(t.containment)&&t.containment.constructor!=Array){var n=e(t.containment),r=n[0];if(!r)return;var i=n.offset(),s=e(r).css("overflow")!="hidden";this.containment=[(parseInt(e(r).css("borderLeftWidth"),10)||0)+(parseInt(e(r).css("paddingLeft"),10)||0),(parseInt(e(r).css("borderTopWidth"),10)||0)+(parseInt(e(r).css("paddingTop"),10)||0),(s?Math.max(r.scrollWidth,r.offsetWidth):r.offsetWidth)-(parseInt(e(r).css("borderLeftWidth"),10)||0)-(parseInt(e(r).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(s?Math.max(r.scrollHeight,r.offsetHeight):r.offsetHeight)-(parseInt(e(r).css("borderTopWidth"),10)||0)-(parseInt(e(r).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=n}else t.containment.constructor==Array&&(this.containment=t.containment)},_convertPositionTo:function(t,n){n||(n=this.position);var r=t=="absolute"?1:-1,i=this.options,s=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(s[0].tagName);return{top:n.top+this.offset.relative.top*r+this.offset.parent.top*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():o?0:s.scrollTop())*r,left:n.left+this.offset.relative.left*r+this.offset.parent.left*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():o?0:s.scrollLeft())*r}},_generatePosition:function(t){var n=this.options,r=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,i=/(html|body)/i.test(r[0].tagName),s=t.pageX,o=t.pageY;if(this.originalPosition){var u;if(this.containment){if(this.relative_container){var a=this.relative_container.offset();u=[this.containment[0]+a.left,this.containment[1]+a.top,this.containment[2]+a.left,this.containment[3]+a.top]}else u=this.containment;t.pageX-this.offset.click.leftu[2]&&(s=u[2]+this.offset.click.left),t.pageY-this.offset.click.top>u[3]&&(o=u[3]+this.offset.click.top)}if(n.grid){var f=n.grid[1]?this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1]:this.originalPageY;o=u?f-this.offset.click.topu[3]?f-this.offset.click.topu[2]?l-this.offset.click.left=0;l--){var c=r.snapElements[l].left,h=c+r.snapElements[l].width,p=r.snapElements[l].top,d=p+r.snapElements[l].height;if(!(c-s=l&&o<=c||u>=l&&u<=c||oc)&&(i>=a&&i<=f||s>=a&&s<=f||if);default:return!1}},e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,n){var r=e.ui.ddmanager.droppables[t.options.scope]||[],i=n?n.type:null,s=(t.currentItem||t.element).find(":data(droppable)").andSelf();e:for(var o=0;o
                                ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=n.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var r=this.handles.split(",");this.handles={};for(var i=0;i');u.css({zIndex:n.zIndex}),"se"==s&&u.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(u)}}this._renderAxis=function(t){t=t||this.element;for(var n in this.handles){this.handles[n].constructor==String&&(this.handles[n]=e(this.handles[n],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var r=e(this.handles[n],this.element),i=0;i=/sw|ne|nw|se|n|s/.test(n)?r.outerHeight():r.outerWidth();var s=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");t.css(s,i),this._proportionallyResize()}if(!e(this.handles[n]).length)continue}},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!t.resizing){if(this.className)var e=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);t.axis=e&&e[1]?e[1]:"se"}}),n.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){if(n.disabled)return;e(this).removeClass("ui-resizable-autohide"),t._handles.show()}).mouseleave(function(){if(n.disabled)return;t.resizing||(e(this).addClass("ui-resizable-autohide"),t._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){t(this.element);var n=this.element;this.originalElement.css({position:n.css("position"),width:n.outerWidth(),height:n.outerHeight(),top:n.css("top"),left:n.css("left")}).insertAfter(n),n.remove()}return this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_mouseCapture:function(t){var n=!1;for(var r in this.handles)e(this.handles[r])[0]==t.target&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(t){var r=this.options,i=this.element.position(),s=this.element;this.resizing=!0,this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()},(s.is(".ui-draggable")||/absolute/.test(s.css("position")))&&s.css({position:"absolute",top:i.top,left:i.left}),this._renderProxy();var o=n(this.helper.css("left")),u=n(this.helper.css("top"));r.containment&&(o+=e(r.containment).scrollLeft()||0,u+=e(r.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:o,top:u},this.size=this._helper?{width:s.outerWidth(),height:s.outerHeight()}:{width:s.width(),height:s.height()},this.originalSize=this._helper?{width:s.outerWidth(),height:s.outerHeight()}:{width:s.width(),height:s.height()},this.originalPosition={left:o,top:u},this.sizeDiff={width:s.outerWidth()-s.width(),height:s.outerHeight()-s.height()},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio=typeof r.aspectRatio=="number"?r.aspectRatio:this.originalSize.width/this.originalSize.height||1;var a=e(".ui-resizable-"+this.axis).css("cursor");return e("body").css("cursor",a=="auto"?this.axis+"-resize":a),s.addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(e){var t=this.helper,n=this.options,r={},i=this,s=this.originalMousePosition,o=this.axis,u=e.pageX-s.left||0,a=e.pageY-s.top||0,f=this._change[o];if(!f)return!1;var l=f.apply(this,[e,u,a]);this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey)l=this._updateRatio(l,e);return l=this._respectSize(l,e),this._propagate("resize",e),t.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",e,this.ui()),!1},_mouseStop:function(t){this.resizing=!1;var n=this.options,r=this;if(this._helper){var i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),o=s&&e.ui.hasScroll(i[0],"left")?0:r.sizeDiff.height,u=s?0:r.sizeDiff.width,a={width:r.helper.width()-u,height:r.helper.height()-o},f=parseInt(r.element.css("left"),10)+(r.position.left-r.originalPosition.left)||null,l=parseInt(r.element.css("top"),10)+(r.position.top-r.originalPosition.top)||null;n.animate||this.element.css(e.extend(a,{top:l,left:f})),r.helper.height(r.size.height),r.helper.width(r.size.width),this._helper&&!n.animate&&this._proportionallyResize()}return e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(e){var t=this.options,n,i,s,o,u;u={minWidth:r(t.minWidth)?t.minWidth:0,maxWidth:r(t.maxWidth)?t.maxWidth:Infinity,minHeight:r(t.minHeight)?t.minHeight:0,maxHeight:r(t.maxHeight)?t.maxHeight:Infinity};if(this._aspectRatio||e)n=u.minHeight*this.aspectRatio,s=u.minWidth/this.aspectRatio,i=u.maxHeight*this.aspectRatio,o=u.maxWidth/this.aspectRatio,n>u.minWidth&&(u.minWidth=n),s>u.minHeight&&(u.minHeight=s),ie.width,l=r(e.height)&&i.minHeight&&i.minHeight>e.height;f&&(e.width=i.minWidth),l&&(e.height=i.minHeight),u&&(e.width=i.maxWidth),a&&(e.height=i.maxHeight);var c=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,p=/sw|nw|w/.test(o),d=/nw|ne|n/.test(o);f&&p&&(e.left=c-i.minWidth),u&&p&&(e.left=c-i.maxWidth),l&&d&&(e.top=h-i.minHeight),a&&d&&(e.top=h-i.maxHeight);var v=!e.width&&!e.height;return v&&!e.left&&e.top?e.top=null:v&&!e.top&&e.left&&(e.left=null),e},_proportionallyResize:function(){var t=this.options;if(!this._proportionallyResizeElements.length)return;var n=this.helper||this.element;for(var r=0;r');var r=e.ui.ie6?1:0,i=e.ui.ie6?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+i,height:this.element.outerHeight()+i,position:"absolute",left:this.elementOffset.left-r+"px",top:this.elementOffset.top-r+"px",zIndex:++n.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(e,t,n){return{width:this.originalSize.width+t}},w:function(e,t,n){var r=this.options,i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,n){var r=this.options,i=this.originalSize,s=this.originalPosition;return{top:s.top+n,height:i.height-n}},s:function(e,t,n){return{height:this.originalSize.height+n}},se:function(t,n,r){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,n,r]))},sw:function(t,n,r){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,n,r]))},ne:function(t,n,r){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,n,r]))},nw:function(t,n,r){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,n,r]))}},_propagate:function(t,n){e.ui.plugin.call(this,t,[n,this.ui()]),t!="resize"&&this._trigger(t,n,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","alsoResize",{start:function(t,n){var r=e(this).data("resizable"),i=r.options,s=function(t){e(t).each(function(){var t=e(this);t.data("resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};typeof i.alsoResize=="object"&&!i.alsoResize.parentNode?i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)}):s(i.alsoResize)},resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.originalSize,o=r.originalPosition,u={height:r.size.height-s.height||0,width:r.size.width-s.width||0,top:r.position.top-o.top||0,left:r.position.left-o.left||0},a=function(t,r){e(t).each(function(){var t=e(this),i=e(this).data("resizable-alsoresize"),s={},o=r&&r.length?r:t.parents(n.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var n=(i[t]||0)+(u[t]||0);n&&n>=0&&(s[t]=n||null)}),t.css(s)})};typeof i.alsoResize=="object"&&!i.alsoResize.nodeType?e.each(i.alsoResize,function(e,t){a(e,t)}):a(i.alsoResize)},stop:function(t,n){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","animate",{stop:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r._proportionallyResizeElements,o=s.length&&/textarea/i.test(s[0].nodeName),u=o&&e.ui.hasScroll(s[0],"left")?0:r.sizeDiff.height,a=o?0:r.sizeDiff.width,f={width:r.size.width-a,height:r.size.height-u},l=parseInt(r.element.css("left"),10)+(r.position.left-r.originalPosition.left)||null,c=parseInt(r.element.css("top"),10)+(r.position.top-r.originalPosition.top)||null;r.element.animate(e.extend(f,c&&l?{top:c,left:l}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var n={width:parseInt(r.element.css("width"),10),height:parseInt(r.element.css("height"),10),top:parseInt(r.element.css("top"),10),left:parseInt(r.element.css("left"),10)};s&&s.length&&e(s[0]).css({width:n.width,height:n.height}),r._updateCache(n),r._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(t,r){var i=e(this).data("resizable"),s=i.options,o=i.element,u=s.containment,a=u instanceof e?u.get(0):/parent/.test(u)?o.parent().get(0):u;if(!a)return;i.containerElement=e(a);if(/document/.test(u)||u==document)i.containerOffset={left:0,top:0},i.containerPosition={left:0,top:0},i.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight};else{var f=e(a),l=[];e(["Top","Right","Left","Bottom"]).each(function(e,t){l[e]=n(f.css("padding"+t))}),i.containerOffset=f.offset(),i.containerPosition=f.position(),i.containerSize={height:f.innerHeight()-l[3],width:f.innerWidth()-l[1]};var c=i.containerOffset,h=i.containerSize.height,p=i.containerSize.width,d=e.ui.hasScroll(a,"left")?a.scrollWidth:p,v=e.ui.hasScroll(a)?a.scrollHeight:h;i.parentData={element:a,left:c.left,top:c.top,width:d,height:v}}},resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.containerSize,o=r.containerOffset,u=r.size,a=r.position,f=r._aspectRatio||t.shiftKey,l={top:0,left:0},c=r.containerElement;c[0]!=document&&/static/.test(c.css("position"))&&(l=o),a.left<(r._helper?o.left:0)&&(r.size.width=r.size.width+(r._helper?r.position.left-o.left:r.position.left-l.left),f&&(r.size.height=r.size.width/r.aspectRatio),r.position.left=i.helper?o.left:0),a.top<(r._helper?o.top:0)&&(r.size.height=r.size.height+(r._helper?r.position.top-o.top:r.position.top),f&&(r.size.width=r.size.height*r.aspectRatio),r.position.top=r._helper?o.top:0),r.offset.left=r.parentData.left+r.position.left,r.offset.top=r.parentData.top+r.position.top;var h=Math.abs((r._helper?r.offset.left-l.left:r.offset.left-l.left)+r.sizeDiff.width),p=Math.abs((r._helper?r.offset.top-l.top:r.offset.top-o.top)+r.sizeDiff.height),d=r.containerElement.get(0)==r.element.parent().get(0),v=/relative|absolute/.test(r.containerElement.css("position"));d&&v&&(h-=r.parentData.left),h+r.size.width>=r.parentData.width&&(r.size.width=r.parentData.width-h,f&&(r.size.height=r.size.width/r.aspectRatio)),p+r.size.height>=r.parentData.height&&(r.size.height=r.parentData.height-p,f&&(r.size.width=r.size.height*r.aspectRatio))},stop:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.position,o=r.containerOffset,u=r.containerPosition,a=r.containerElement,f=e(r.helper),l=f.offset(),c=f.outerWidth()-r.sizeDiff.width,h=f.outerHeight()-r.sizeDiff.height;r._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:l.left-u.left-o.left,width:c,height:h}),r._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:l.left-u.left-o.left,width:c,height:h})}}),e.ui.plugin.add("resizable","ghost",{start:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.size;r.ghost=r.originalElement.clone(),r.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:""),r.ghost.appendTo(r.helper)},resize:function(t,n){var r=e(this).data("resizable"),i=r.options;r.ghost&&r.ghost.css({position:"relative",height:r.size.height,width:r.size.width})},stop:function(t,n){var r=e(this).data("resizable"),i=r.options;r.ghost&&r.helper&&r.helper.get(0).removeChild(r.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.size,o=r.originalSize,u=r.originalPosition,a=r.axis,f=i._aspectRatio||t.shiftKey;i.grid=typeof i.grid=="number"?[i.grid,i.grid]:i.grid;var l=Math.round((s.width-o.width)/(i.grid[0]||1))*(i.grid[0]||1),c=Math.round((s.height-o.height)/(i.grid[1]||1))*(i.grid[1]||1);/^(se|s|e)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c):/^(ne)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c,r.position.top=u.top-c):/^(sw)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c,r.position.left=u.left-l):(r.size.width=o.width+l,r.size.height=o.height+c,r.position.top=u.top-c,r.position.left=u.left-l)}});var n=function(e){return parseInt(e,10)||0},r=function(e){return!isNaN(parseInt(e,10))}})(jQuery);(function(e,t){e.widget("ui.selectable",e.ui.mouse,{version:"1.9.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var t=this;this.element.addClass("ui-selectable"),this.dragged=!1;var n;this.refresh=function(){n=e(t.options.filter,t.element[0]),n.addClass("ui-selectee"),n.each(function(){var t=e(this),n=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:n.left,top:n.top,right:n.left+t.outerWidth(),bottom:n.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=n.addClass("ui-selectee"),this._mouseInit(),this.helper=e("
                                ")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var n=this;this.opos=[t.pageX,t.pageY];if(this.options.disabled)return;var r=this.options;this.selectees=e(r.filter,this.element[0]),this._trigger("start",t),e(r.appendTo).append(this.helper),this.helper.css({left:t.clientX,top:t.clientY,width:0,height:0}),r.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var r=e.data(this,"selectable-item");r.startselected=!0,!t.metaKey&&!t.ctrlKey&&(r.$element.removeClass("ui-selected"),r.selected=!1,r.$element.addClass("ui-unselecting"),r.unselecting=!0,n._trigger("unselecting",t,{unselecting:r.element}))}),e(t.target).parents().andSelf().each(function(){var r=e.data(this,"selectable-item");if(r){var i=!t.metaKey&&!t.ctrlKey||!r.$element.hasClass("ui-selected");return r.$element.removeClass(i?"ui-unselecting":"ui-selected").addClass(i?"ui-selecting":"ui-unselecting"),r.unselecting=!i,r.selecting=i,r.selected=i,i?n._trigger("selecting",t,{selecting:r.element}):n._trigger("unselecting",t,{unselecting:r.element}),!1}})},_mouseDrag:function(t){var n=this;this.dragged=!0;if(this.options.disabled)return;var r=this.options,i=this.opos[0],s=this.opos[1],o=t.pageX,u=t.pageY;if(i>o){var a=o;o=i,i=a}if(s>u){var a=u;u=s,s=a}return this.helper.css({left:i,top:s,width:o-i,height:u-s}),this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!a||a.element==n.element[0])return;var f=!1;r.tolerance=="touch"?f=!(a.left>o||a.rightu||a.bottomi&&a.rights&&a.bottom *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var e=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?e.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_setOption:function(t,n){t==="disabled"?(this.options[t]=n,this.widget().toggleClass("ui-sortable-disabled",!!n)):e.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(t,n){var r=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(t);var i=null,s=e(t.target).parents().each(function(){if(e.data(this,r.widgetName+"-item")==r)return i=e(this),!1});e.data(t.target,r.widgetName+"-item")==r&&(i=e(t.target));if(!i)return!1;if(this.options.handle&&!n){var o=!1;e(this.options.handle,i).find("*").andSelf().each(function(){this==t.target&&(o=!0)});if(!o)return!1}return this.currentItem=i,this._removeCurrentsFromItems(),!0},_mouseStart:function(t,n,r){var i=this.options;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),i.containment&&this._setContainment(),i.cursor&&(e("body").css("cursor")&&(this._storedCursor=e("body").css("cursor")),e("body").css("cursor",i.cursor)),i.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",i.opacity)),i.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",i.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!r)for(var s=this.containers.length-1;s>=0;s--)this.containers[s]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var n=this.options,r=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY=0;i--){var s=this.items[i],o=s.item[0],u=this._intersectsWithPointer(s);if(!u)continue;if(s.instance!==this.currentContainer)continue;if(o!=this.currentItem[0]&&this.placeholder[u==1?"next":"prev"]()[0]!=o&&!e.contains(this.placeholder[0],o)&&(this.options.type=="semi-dynamic"?!e.contains(this.element[0],o):!0)){this.direction=u==1?"down":"up";if(this.options.tolerance!="pointer"&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,n){if(!t)return;e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t);if(this.options.revert){var r=this,i=this.placeholder.offset();this.reverting=!0,e(this.helper).animate({left:i.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:i.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){r._clear(t)})}else this._clear(t,n);return!1},cancel:function(){if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var n=this._getItemsAsjQuery(t&&t.connected),r=[];return t=t||{},e(n).each(function(){var n=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[-=_](.+)/);n&&r.push((t.key||n[1]+"[]")+"="+(t.key&&t.expression?n[1]:n[2]))}),!r.length&&t.key&&r.push(t.key+"="),r.join("&")},toArray:function(t){var n=this._getItemsAsjQuery(t&&t.connected),r=[];return t=t||{},n.each(function(){r.push(e(t.item||this).attr(t.attribute||"id")||"")}),r},_intersectsWith:function(e){var t=this.positionAbs.left,n=t+this.helperProportions.width,r=this.positionAbs.top,i=r+this.helperProportions.height,s=e.left,o=s+e.width,u=e.top,a=u+e.height,f=this.offset.click.top,l=this.offset.click.left,c=r+f>u&&r+fs&&t+le[this.floating?"width":"height"]?c:s0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return e!=0&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor==String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){var n=[],r=[],i=this._connectWith();if(i&&t)for(var s=i.length-1;s>=0;s--){var o=e(i[s]);for(var u=o.length-1;u>=0;u--){var a=e.data(o[u],this.widgetName);a&&a!=this&&!a.options.disabled&&r.push([e.isFunction(a.options.items)?a.options.items.call(a.element):e(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a])}}r.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var s=r.length-1;s>=0;s--)r[s][0].each(function(){n.push(this)});return e(n)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var n=0;n=0;s--){var o=e(i[s]);for(var u=o.length-1;u>=0;u--){var a=e.data(o[u],this.widgetName);a&&a!=this&&!a.options.disabled&&(r.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a))}}for(var s=r.length-1;s>=0;s--){var f=r[s][1],l=r[s][0];for(var u=0,c=l.length;u=0;n--){var r=this.items[n];if(r.instance!=this.currentContainer&&this.currentContainer&&r.item[0]!=this.currentItem[0])continue;var i=this.options.toleranceElement?e(this.options.toleranceElement,r.item):r.item;t||(r.width=i.outerWidth(),r.height=i.outerHeight());var s=i.offset();r.left=s.left,r.top=s.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var n=this.containers.length-1;n>=0;n--){var s=this.containers[n].element.offset();this.containers[n].containerCache.left=s.left,this.containers[n].containerCache.top=s.top,this.containers[n].containerCache.width=this.containers[n].element.outerWidth(),this.containers[n].containerCache.height=this.containers[n].element.outerHeight()}return this},_createPlaceholder:function(t){t=t||this;var n=t.options;if(!n.placeholder||n.placeholder.constructor==String){var r=n.placeholder;n.placeholder={element:function(){var n=e(document.createElement(t.currentItem[0].nodeName)).addClass(r||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return r||(n.style.visibility="hidden"),n},update:function(e,i){if(r&&!n.forcePlaceholderSize)return;i.height()||i.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),i.width()||i.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10))}}}t.placeholder=e(n.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),n.placeholder.update(t,t.placeholder)},_contactContainers:function(t){var n=null,r=null;for(var i=this.containers.length-1;i>=0;i--){if(e.contains(this.currentItem[0],this.containers[i].element[0]))continue;if(this._intersectsWith(this.containers[i].containerCache)){if(n&&e.contains(this.containers[i].element[0],n.element[0]))continue;n=this.containers[i],r=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0)}if(!n)return;if(this.containers.length===1)this.containers[r]._trigger("over",t,this._uiHash(this)),this.containers[r].containerCache.over=1;else{var s=1e4,o=null,u=this.containers[r].floating?"left":"top",a=this.containers[r].floating?"width":"height",f=this.positionAbs[u]+this.offset.click[u];for(var l=this.items.length-1;l>=0;l--){if(!e.contains(this.containers[r].element[0],this.items[l].item[0]))continue;if(this.items[l].item[0]==this.currentItem[0])continue;var c=this.items[l].item.offset()[u],h=!1;Math.abs(c-f)>Math.abs(c+this.items[l][a]-f)&&(h=!0,c+=this.items[l][a]),Math.abs(c-f)this.containment[2]&&(s=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top));if(n.grid){var u=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1];o=this.containment?u-this.offset.click.topthis.containment[3]?u-this.offset.click.topthis.containment[2]?a-this.offset.click.left=0;i--)n||r.push(function(e){return function(t){e._trigger("deactivate",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(r.push(function(e){return function(t){e._trigger("out",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);this._storedCursor&&e("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!n){this._trigger("beforeStop",t,this._uiHash());for(var i=0;i li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var t=this.accordionId="ui-accordion-"+(this.element.attr("id")||++n),r=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset"),this.headers=this.element.find(r.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this._hoverable(this.headers),this._focusable(this.headers),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").hide(),!r.collapsible&&(r.active===!1||r.active==null)&&(r.active=0),r.active<0&&(r.active+=this.headers.length),this.active=this._findActive(r.active).addClass("ui-accordion-header-active ui-state-active").toggleClass("ui-corner-all ui-corner-top"),this.active.next().addClass("ui-accordion-content-active").show(),this._createIcons(),this.refresh(),this.element.attr("role","tablist"),this.headers.attr("role","tab").each(function(n){var r=e(this),i=r.attr("id"),s=r.next(),o=s.attr("id");i||(i=t+"-header-"+n,r.attr("id",i)),o||(o=t+"-panel-"+n,s.attr("id",o)),r.attr("aria-controls",o),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._on(this.headers,{keydown:"_keydown"}),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._setupEvents(r.event)},_getCreateEventData:function(){return{header:this.active,content:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),e=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this.options.heightStyle!=="content"&&e.css("height","")},_setOption:function(e,t){if(e==="active"){this._activate(t);return}e==="event"&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),e==="collapsible"&&!t&&this.options.active===!1&&this._activate(0),e==="icons"&&(this._destroyIcons(),t&&this._createIcons()),e==="disabled"&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)},_keydown:function(t){if(t.altKey||t.ctrlKey)return;var n=e.ui.keyCode,r=this.headers.length,i=this.headers.index(t.target),s=!1;switch(t.keyCode){case n.RIGHT:case n.DOWN:s=this.headers[(i+1)%r];break;case n.LEFT:case n.UP:s=this.headers[(i-1+r)%r];break;case n.SPACE:case n.ENTER:this._eventHandler(t);break;case n.HOME:s=this.headers[0];break;case n.END:s=this.headers[r-1]}s&&(e(t.target).attr("tabIndex",-1),e(s).attr("tabIndex",0),s.focus(),t.preventDefault())},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t,n,r=this.options.heightStyle,i=this.element.parent();r==="fill"?(e.support.minHeight||(n=i.css("overflow"),i.css("overflow","hidden")),t=i.height(),this.element.siblings(":visible").each(function(){var n=e(this),r=n.css("position");if(r==="absolute"||r==="fixed")return;t-=n.outerHeight(!0)}),n&&i.css("overflow",n),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):r==="auto"&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var n=this._findActive(t)[0];if(n===this.active[0])return;n=n||this.active[0],this._eventHandler({target:n,currentTarget:n,preventDefault:e.noop})},_findActive:function(t){return typeof t=="number"?this.headers.eq(t):e()},_setupEvents:function(t){var n={};if(!t)return;e.each(t.split(" "),function(e,t){n[t]="_eventHandler"}),this._on(this.headers,n)},_eventHandler:function(t){var n=this.options,r=this.active,i=e(t.currentTarget),s=i[0]===r[0],o=s&&n.collapsible,u=o?e():i.next(),a=r.next(),f={oldHeader:r,oldPanel:a,newHeader:o?e():i,newPanel:u};t.preventDefault();if(s&&!n.collapsible||this._trigger("beforeActivate",t,f)===!1)return;n.active=o?!1:this.headers.index(i),this.active=s?e():i,this._toggle(f),r.removeClass("ui-accordion-header-active ui-state-active"),n.icons&&r.children(".ui-accordion-header-icon").removeClass(n.icons.activeHeader).addClass(n.icons.header),s||(i.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),n.icons&&i.children(".ui-accordion-header-icon").removeClass(n.icons.header).addClass(n.icons.activeHeader),i.next().addClass("ui-accordion-content-active"))},_toggle:function(t){var n=t.newPanel,r=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=n,this.prevHide=r,this.options.animate?this._animate(n,r,t):(r.hide(),n.show(),this._toggleComplete(t)),r.attr({"aria-expanded":"false","aria-hidden":"true"}),r.prev().attr("aria-selected","false"),n.length&&r.length?r.prev().attr("tabIndex",-1):n.length&&this.headers.filter(function(){return e(this).attr("tabIndex")===0}).attr("tabIndex",-1),n.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(e,t,n){var s,o,u,a=this,f=0,l=e.length&&(!t.length||e.index()",options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var t,n,r;this.isMultiLine=this._isMultiLine(),this.valueMethod=this.element[this.element.is("input,textarea")?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(i){if(this.element.prop("readOnly")){t=!0,r=!0,n=!0;return}t=!1,r=!1,n=!1;var s=e.ui.keyCode;switch(i.keyCode){case s.PAGE_UP:t=!0,this._move("previousPage",i);break;case s.PAGE_DOWN:t=!0,this._move("nextPage",i);break;case s.UP:t=!0,this._keyEvent("previous",i);break;case s.DOWN:t=!0,this._keyEvent("next",i);break;case s.ENTER:case s.NUMPAD_ENTER:this.menu.active&&(t=!0,i.preventDefault(),this.menu.select(i));break;case s.TAB:this.menu.active&&this.menu.select(i);break;case s.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(i),i.preventDefault());break;default:n=!0,this._searchTimeout(i)}},keypress:function(r){if(t){t=!1,r.preventDefault();return}if(n)return;var i=e.ui.keyCode;switch(r.keyCode){case i.PAGE_UP:this._move("previousPage",r);break;case i.PAGE_DOWN:this._move("nextPage",r);break;case i.UP:this._keyEvent("previous",r);break;case i.DOWN:this._keyEvent("next",r)}},input:function(e){if(r){r=!1,e.preventDefault();return}this._searchTimeout(e)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){if(this.cancelBlur){delete this.cancelBlur;return}clearTimeout(this.searching),this.close(e),this._change(e)}}),this._initSource(),this.menu=e("
                                '+"";var z=N?'":"";for(var W=0;W<7;W++){var X=(W+T)%7;z+="=5?' class="ui-datepicker-week-end"':"")+">"+''+L[X]+""}U+=z+"";var V=this._getDaysInMonth(d,p);d==e.selectedYear&&p==e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,V));var J=(this._getFirstDayOfMonth(d,p)-T+7)%7,K=Math.ceil((J+V)/7),Q=f?this.maxRows>K?this.maxRows:K:K;this.maxRows=Q;var G=this._daylightSavingAdjust(new Date(d,p,1-J));for(var Y=0;Y";var Z=N?'":"";for(var W=0;W<7;W++){var et=M?M.apply(e.input?e.input[0]:null,[G]):[!0,""],tt=G.getMonth()!=p,nt=tt&&!D||!et[0]||c&&Gh;Z+='",G.setDate(G.getDate()+1),G=this._daylightSavingAdjust(G)}U+=Z+""}p++,p>11&&(p=0,d++),U+="
                                '+this._get(e,"weekHeader")+"
                                '+this._get(e,"calculateWeek")(G)+""+(tt&&!_?" ":nt?''+G.getDate()+"":''+G.getDate()+"")+"
                                "+(f?""+(o[0]>0&&I==o[1]-1?'
                                ':""):""),F+=U}B+=F}return B+=x+($.ui.ie6&&!e.inline?'':""),e._keyEvent=!1,B},_generateMonthYearHeader:function(e,t,n,r,i,s,o,u){var a=this._get(e,"changeMonth"),f=this._get(e,"changeYear"),l=this._get(e,"showMonthAfterYear"),c='
                                ',h="";if(s||!a)h+=''+o[t]+"";else{var p=r&&r.getFullYear()==n,d=i&&i.getFullYear()==n;h+='"}l||(c+=h+(s||!a||!f?" ":""));if(!e.yearshtml){e.yearshtml="";if(s||!f)c+=''+n+"";else{var m=this._get(e,"yearRange").split(":"),g=(new Date).getFullYear(),y=function(e){var t=e.match(/c[+-].*/)?n+parseInt(e.substring(1),10):e.match(/[+-].*/)?g+parseInt(e,10):parseInt(e,10);return isNaN(t)?g:t},b=y(m[0]),w=Math.max(b,y(m[1]||""));b=r?Math.max(b,r.getFullYear()):b,w=i?Math.min(w,i.getFullYear()):w,e.yearshtml+='",c+=e.yearshtml,e.yearshtml=null}}return c+=this._get(e,"yearSuffix"),l&&(c+=(s||!a||!f?" ":"")+h),c+="
                                ",c},_adjustInstDate:function(e,t,n){var r=e.drawYear+(n=="Y"?t:0),i=e.drawMonth+(n=="M"?t:0),s=Math.min(e.selectedDay,this._getDaysInMonth(r,i))+(n=="D"?t:0),o=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(r,i,s)));e.selectedDay=o.getDate(),e.drawMonth=e.selectedMonth=o.getMonth(),e.drawYear=e.selectedYear=o.getFullYear(),(n=="M"||n=="Y")&&this._notifyChange(e)},_restrictMinMax:function(e,t){var n=this._getMinMaxDate(e,"min"),r=this._getMinMaxDate(e,"max"),i=n&&tr?r:i,i},_notifyChange:function(e){var t=this._get(e,"onChangeMonthYear");t&&t.apply(e.input?e.input[0]:null,[e.selectedYear,e.selectedMonth+1,e])},_getNumberOfMonths:function(e){var t=this._get(e,"numberOfMonths");return t==null?[1,1]:typeof t=="number"?[1,t]:t},_getMinMaxDate:function(e,t){return this._determineDate(e,this._get(e,t+"Date"),null)},_getDaysInMonth:function(e,t){return 32-this._daylightSavingAdjust(new Date(e,t,32)).getDate()},_getFirstDayOfMonth:function(e,t){return(new Date(e,t,1)).getDay()},_canAdjustMonth:function(e,t,n,r){var i=this._getNumberOfMonths(e),s=this._daylightSavingAdjust(new Date(n,r+(t<0?t:i[0]*i[1]),1));return t<0&&s.setDate(this._getDaysInMonth(s.getFullYear(),s.getMonth())),this._isInRange(e,s)},_isInRange:function(e,t){var n=this._getMinMaxDate(e,"min"),r=this._getMinMaxDate(e,"max");return(!n||t.getTime()>=n.getTime())&&(!r||t.getTime()<=r.getTime())},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return t=typeof t!="string"?t:(new Date).getFullYear()%100+parseInt(t,10),{shortYearCutoff:t,dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,n,r){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);var i=t?typeof t=="object"?t:this._daylightSavingAdjust(new Date(r,n,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),i,this._getFormatConfig(e))}}),$.fn.datepicker=function(e){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find(document.body).append($.datepicker.dpDiv),$.datepicker.initialized=!0);var t=Array.prototype.slice.call(arguments,1);return typeof e!="string"||e!="isDisabled"&&e!="getDate"&&e!="widget"?e=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this[0]].concat(t)):this.each(function(){typeof e=="string"?$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this].concat(t)):$.datepicker._attachDatepicker(this,e)}):$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this[0]].concat(t))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.9.2",window["DP_jQuery_"+dpuuid]=$})(jQuery);(function(e,t){var n="ui-dialog ui-widget ui-widget-content ui-corner-all ",r={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};e.widget("ui.dialog",{version:"1.9.2",options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(t){var n=e(this).css(t).offset().top;n<0&&e(this).css("top",t.top-n)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.oldPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.options.title=this.options.title||this.originalTitle;var t=this,r=this.options,i=r.title||" ",s,o,u,a,f;s=(this.uiDialog=e("
                                ")).addClass(n+r.dialogClass).css({display:"none",outline:0,zIndex:r.zIndex}).attr("tabIndex",-1).keydown(function(n){r.closeOnEscape&&!n.isDefaultPrevented()&&n.keyCode&&n.keyCode===e.ui.keyCode.ESCAPE&&(t.close(n),n.preventDefault())}).mousedown(function(e){t.moveToTop(!1,e)}).appendTo("body"),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(s),o=(this.uiDialogTitlebar=e("
                                ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").bind("mousedown",function(){s.focus()}).prependTo(s),u=e("").addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").click(function(e){e.preventDefault(),t.close(e)}).appendTo(o),(this.uiDialogTitlebarCloseText=e("")).addClass("ui-icon ui-icon-closethick").text(r.closeText).appendTo(u),a=e("").uniqueId().addClass("ui-dialog-title").html(i).prependTo(o),f=(this.uiDialogButtonPane=e("
                                ")).addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),(this.uiButtonSet=e("
                                ")).addClass("ui-dialog-buttonset").appendTo(f),s.attr({role:"dialog","aria-labelledby":a.attr("id")}),o.find("*").add(o).disableSelection(),this._hoverable(u),this._focusable(u),r.draggable&&e.fn.draggable&&this._makeDraggable(),r.resizable&&e.fn.resizable&&this._makeResizable(),this._createButtons(r.buttons),this._isOpen=!1,e.fn.bgiframe&&s.bgiframe(),this._on(s,{keydown:function(t){if(!r.modal||t.keyCode!==e.ui.keyCode.TAB)return;var n=e(":tabbable",s),i=n.filter(":first"),o=n.filter(":last");if(t.target===o[0]&&!t.shiftKey)return i.focus(1),!1;if(t.target===i[0]&&t.shiftKey)return o.focus(1),!1}})},_init:function(){this.options.autoOpen&&this.open()},_destroy:function(){var e,t=this.oldPosition;this.overlay&&this.overlay.destroy(),this.uiDialog.hide(),this.element.removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),e=t.parent.children().eq(t.index),e.length&&e[0]!==this.element[0]?e.before(this.element):t.parent.append(this.element)},widget:function(){return this.uiDialog},close:function(t){var n=this,r,i;if(!this._isOpen)return;if(!1===this._trigger("beforeClose",t))return;return this._isOpen=!1,this.overlay&&this.overlay.destroy(),this.options.hide?this._hide(this.uiDialog,this.options.hide,function(){n._trigger("close",t)}):(this.uiDialog.hide(),this._trigger("close",t)),e.ui.dialog.overlay.resize(),this.options.modal&&(r=0,e(".ui-dialog").each(function(){this!==n.uiDialog[0]&&(i=e(this).css("z-index"),isNaN(i)||(r=Math.max(r,i)))}),e.ui.dialog.maxZ=r),this},isOpen:function(){return this._isOpen},moveToTop:function(t,n){var r=this.options,i;return r.modal&&!t||!r.stack&&!r.modal?this._trigger("focus",n):(r.zIndex>e.ui.dialog.maxZ&&(e.ui.dialog.maxZ=r.zIndex),this.overlay&&(e.ui.dialog.maxZ+=1,e.ui.dialog.overlay.maxZ=e.ui.dialog.maxZ,this.overlay.$el.css("z-index",e.ui.dialog.overlay.maxZ)),i={scrollTop:this.element.scrollTop(),scrollLeft:this.element.scrollLeft()},e.ui.dialog.maxZ+=1,this.uiDialog.css("z-index",e.ui.dialog.maxZ),this.element.attr(i),this._trigger("focus",n),this)},open:function(){if(this._isOpen)return;var t,n=this.options,r=this.uiDialog;return this._size(),this._position(n.position),r.show(n.show),this.overlay=n.modal?new e.ui.dialog.overlay(this):null,this.moveToTop(!0),t=this.element.find(":tabbable"),t.length||(t=this.uiDialogButtonPane.find(":tabbable"),t.length||(t=r)),t.eq(0).focus(),this._isOpen=!0,this._trigger("open"),this},_createButtons:function(t){var n=this,r=!1;this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),typeof t=="object"&&t!==null&&e.each(t,function(){return!(r=!0)}),r?(e.each(t,function(t,r){var i,s;r=e.isFunction(r)?{click:r,text:t}:r,r=e.extend({type:"button"},r),s=r.click,r.click=function(){s.apply(n.element[0],arguments)},i=e("",r).appendTo(n.uiButtonSet),e.fn.button&&i.button()}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog)):this.uiDialog.removeClass("ui-dialog-buttons")},_makeDraggable:function(){function r(e){return{position:e.position,offset:e.offset}}var t=this,n=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(n,i){e(this).addClass("ui-dialog-dragging"),t._trigger("dragStart",n,r(i))},drag:function(e,n){t._trigger("drag",e,r(n))},stop:function(i,s){n.position=[s.position.left-t.document.scrollLeft(),s.position.top-t.document.scrollTop()],e(this).removeClass("ui-dialog-dragging"),t._trigger("dragStop",i,r(s)),e.ui.dialog.overlay.resize()}})},_makeResizable:function(n){function u(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}n=n===t?this.options.resizable:n;var r=this,i=this.options,s=this.uiDialog.css("position"),o=typeof n=="string"?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:i.maxWidth,maxHeight:i.maxHeight,minWidth:i.minWidth,minHeight:this._minHeight(),handles:o,start:function(t,n){e(this).addClass("ui-dialog-resizing"),r._trigger("resizeStart",t,u(n))},resize:function(e,t){r._trigger("resize",e,u(t))},stop:function(t,n){e(this).removeClass("ui-dialog-resizing"),i.height=e(this).height(),i.width=e(this).width(),r._trigger("resizeStop",t,u(n)),e.ui.dialog.overlay.resize()}}).css("position",s).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var e=this.options;return e.height==="auto"?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(t){var n=[],r=[0,0],i;if(t){if(typeof t=="string"||typeof t=="object"&&"0"in t)n=t.split?t.split(" "):[t[0],t[1]],n.length===1&&(n[1]=n[0]),e.each(["left","top"],function(e,t){+n[e]===n[e]&&(r[e]=n[e],n[e]=t)}),t={my:n[0]+(r[0]<0?r[0]:"+"+r[0])+" "+n[1]+(r[1]<0?r[1]:"+"+r[1]),at:n.join(" ")};t=e.extend({},e.ui.dialog.prototype.options.position,t)}else t=e.ui.dialog.prototype.options.position;i=this.uiDialog.is(":visible"),i||this.uiDialog.show(),this.uiDialog.position(t),i||this.uiDialog.hide()},_setOptions:function(t){var n=this,s={},o=!1;e.each(t,function(e,t){n._setOption(e,t),e in r&&(o=!0),e in i&&(s[e]=t)}),o&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",s)},_setOption:function(t,r){var i,s,o=this.uiDialog;switch(t){case"buttons":this._createButtons(r);break;case"closeText":this.uiDialogTitlebarCloseText.text(""+r);break;case"dialogClass":o.removeClass(this.options.dialogClass).addClass(n+r);break;case"disabled":r?o.addClass("ui-dialog-disabled"):o.removeClass("ui-dialog-disabled");break;case"draggable":i=o.is(":data(draggable)"),i&&!r&&o.draggable("destroy"),!i&&r&&this._makeDraggable();break;case"position":this._position(r);break;case"resizable":s=o.is(":data(resizable)"),s&&!r&&o.resizable("destroy"),s&&typeof r=="string"&&o.resizable("option","handles",r),!s&&r!==!1&&this._makeResizable(r);break;case"title":e(".ui-dialog-title",this.uiDialogTitlebar).html(""+(r||" "))}this._super(t,r)},_size:function(){var t,n,r,i=this.options,s=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),i.minWidth>i.width&&(i.width=i.minWidth),t=this.uiDialog.css({height:"auto",width:i.width}).outerHeight(),n=Math.max(0,i.minHeight-t),i.height==="auto"?e.support.minHeight?this.element.css({minHeight:n,height:"auto"}):(this.uiDialog.show(),r=this.element.css("height","auto").height(),s||this.uiDialog.hide(),this.element.height(Math.max(r,n))):this.element.height(Math.max(i.height-t,0)),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),e.extend(e.ui.dialog,{uuid:0,maxZ:0,getTitleId:function(e){var t=e.attr("id");return t||(this.uuid+=1,t=this.uuid),"ui-dialog-title-"+t},overlay:function(t){this.$el=e.ui.dialog.overlay.create(t)}}),e.extend(e.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:e.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(e){return e+".dialog-overlay"}).join(" "),create:function(t){this.instances.length===0&&(setTimeout(function(){e.ui.dialog.overlay.instances.length&&e(document).bind(e.ui.dialog.overlay.events,function(t){if(e(t.target).zIndex()").addClass("ui-widget-overlay");return e(document).bind("keydown.dialog-overlay",function(r){var i=e.ui.dialog.overlay.instances;i.length!==0&&i[i.length-1]===n&&t.options.closeOnEscape&&!r.isDefaultPrevented()&&r.keyCode&&r.keyCode===e.ui.keyCode.ESCAPE&&(t.close(r),r.preventDefault())}),n.appendTo(document.body).css({width:this.width(),height:this.height()}),e.fn.bgiframe&&n.bgiframe(),this.instances.push(n),n},destroy:function(t){var n=e.inArray(t,this.instances),r=0;n!==-1&&this.oldInstances.push(this.instances.splice(n,1)[0]),this.instances.length===0&&e([document,window]).unbind(".dialog-overlay"),t.height(0).width(0).remove(),e.each(this.instances,function(){r=Math.max(r,this.css("z-index"))}),this.maxZ=r},height:function(){var t,n;return e.ui.ie?(t=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),n=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),t",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,e.proxy(function(e){this.options.disabled&&e.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(e){e.preventDefault()},"click .ui-state-disabled > a":function(e){e.preventDefault()},"click .ui-menu-item:has(a)":function(t){var r=e(t.target).closest(".ui-menu-item");!n&&r.not(".ui-state-disabled").length&&(n=!0,this.select(t),r.has(".ui-menu").length?this.expand(t):this.element.is(":focus")||(this.element.trigger("focus",[!0]),this.active&&this.active.parents(".ui-menu").length===1&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){var n=e(t.currentTarget);n.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(t,n)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var n=this.active||this.element.children(".ui-menu-item").eq(0);t||this.focus(e,n)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){e(t.target).closest(".ui-menu").length||this.collapseAll(t),n=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").andSelf().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){function a(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var n,r,i,s,o,u=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:u=!1,r=this.previousFilter||"",i=String.fromCharCode(t.keyCode),s=!1,clearTimeout(this.filterTimer),i===r?s=!0:i=r+i,o=new RegExp("^"+a(i),"i"),n=this.activeMenu.children(".ui-menu-item").filter(function(){return o.test(e(this).children("a").text())}),n=s&&n.index(this.active.next())!==-1?this.active.nextAll(".ui-menu-item"):n,n.length||(i=String.fromCharCode(t.keyCode),o=new RegExp("^"+a(i),"i"),n=this.activeMenu.children(".ui-menu-item").filter(function(){return o.test(e(this).children("a").text())})),n.length?(this.focus(t,n),n.length>1?(this.previousFilter=i,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}u&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(e):this.select(e))},refresh:function(){var t,n=this.options.icons.submenu,r=this.element.find(this.options.menus);r.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),r=t.prev("a"),i=e("").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);r.attr("aria-haspopup","true").prepend(i),t.attr("aria-labelledby",r.attr("id"))}),t=r.add(this.element),t.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),t.children(":not(.ui-menu-item)").each(function(){var t=e(this);/[^\-—–\s]/.test(t.text())||t.addClass("ui-widget-content ui-menu-divider")}),t.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},focus:function(e,t){var n,r;this.blur(e,e&&e.type==="focus"),this._scrollIntoView(t),this.active=t.first(),r=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",r.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),e&&e.type==="keydown"?this._close():this.timer=this._delay(function(){this._close()},this.delay),n=t.children(".ui-menu"),n.length&&/^mouse/.test(e.type)&&this._startOpening(n),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var n,r,i,s,o,u;this._hasScroll()&&(n=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,r=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,i=t.offset().top-this.activeMenu.offset().top-n-r,s=this.activeMenu.scrollTop(),o=this.activeMenu.height(),u=t.height(),i<0?this.activeMenu.scrollTop(s+i):i+u>o&&this.activeMenu.scrollTop(s+i-o+u))},blur:function(e,t){t||clearTimeout(this.timer);if(!this.active)return;this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active})},_startOpening:function(e){clearTimeout(this.timer);if(e.attr("aria-hidden")!=="true")return;this.timer=this._delay(function(){this._close(),this._open(e)},this.delay)},_open:function(t){var n=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(n)},collapseAll:function(t,n){clearTimeout(this.timer),this.timer=this._delay(function(){var r=n?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));r.length||(r=this.element),this._close(r),this.blur(t),this.activeMenu=r},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,n){var r;this.active&&(e==="first"||e==="last"?r=this.active[e==="first"?"prevAll":"nextAll"](".ui-menu-item").eq(-1):r=this.active[e+"All"](".ui-menu-item").eq(0));if(!r||!r.length||!this.active)r=this.activeMenu.children(".ui-menu-item")[t]();this.focus(n,r)},nextPage:function(t){var n,r,i;if(!this.active){this.next(t);return}if(this.isLastItem())return;this._hasScroll()?(r=this.active.offset().top,i=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return n=e(this),n.offset().top-r-i<0}),this.focus(t,n)):this.focus(t,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())},previousPage:function(t){var n,r,i;if(!this.active){this.next(t);return}if(this.isFirstItem())return;this._hasScroll()?(r=this.active.offset().top,i=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return n=e(this),n.offset().top-r+i>0}),this.focus(t,n)):this.focus(t,this.activeMenu.children(".ui-menu-item").first())},_hasScroll:function(){return this.element.outerHeight()
                                ").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(e){return e===t?this._value():(this._setOption("value",e),this)},_setOption:function(e,t){e==="value"&&(this.options.value=t,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),this._super(e,t)},_value:function(){var e=this.options.value;return typeof e!="number"&&(e=0),Math.min(this.options.max,Math.max(this.min,e))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var e=this.value(),t=this._percentage();this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),this.valueDiv.toggle(e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(t.toFixed(0)+"%"),this.element.attr("aria-valuenow",e)}})})(jQuery);(function(e,t){var n=5;e.widget("ui.slider",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var t,r,i=this.options,s=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),o="",u=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(i.disabled?" ui-slider-disabled ui-disabled":"")),this.range=e([]),i.range&&(i.range===!0&&(i.values||(i.values=[this._valueMin(),this._valueMin()]),i.values.length&&i.values.length!==2&&(i.values=[i.values[0],i.values[0]])),this.range=e("
                                ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(i.range==="min"||i.range==="max"?" ui-slider-range-"+i.range:""))),r=i.values&&i.values.length||1;for(t=s.length;tn&&(i=n,s=e(this),o=t)}),c.range===!0&&this.values(1)===c.min&&(o+=1,s=e(this.handles[o])),u=this._start(t,o),u===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,s.addClass("ui-state-active").focus(),a=s.offset(),f=!e(t.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=f?{left:0,top:0}:{left:t.pageX-a.left-s.width()/2,top:t.pageY-a.top-s.height()/2-(parseInt(s.css("borderTopWidth"),10)||0)-(parseInt(s.css("borderBottomWidth"),10)||0)+(parseInt(s.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(t,o,r),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(e){var t={x:e.pageX,y:e.pageY},n=this._normValueFromMouse(t);return this._slide(e,this._handleIndex,n),!1},_mouseStop:function(e){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(e,this._handleIndex),this._change(e,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(e){var t,n,r,i,s;return this.orientation==="horizontal"?(t=this.elementSize.width,n=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(t=this.elementSize.height,n=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),r=n/t,r>1&&(r=1),r<0&&(r=0),this.orientation==="vertical"&&(r=1-r),i=this._valueMax()-this._valueMin(),s=this._valueMin()+r*i,this._trimAlignValue(s)},_start:function(e,t){var n={handle:this.handles[t],value:this.value()};return this.options.values&&this.options.values.length&&(n.value=this.values(t),n.values=this.values()),this._trigger("start",e,n)},_slide:function(e,t,n){var r,i,s;this.options.values&&this.options.values.length?(r=this.values(t?0:1),this.options.values.length===2&&this.options.range===!0&&(t===0&&n>r||t===1&&n1){this.options.values[t]=this._trimAlignValue(n),this._refreshValue(),this._change(null,t);return}if(!arguments.length)return this._values();if(!e.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(t):this.value();r=this.options.values,i=arguments[0];for(s=0;s=this._valueMax())return this._valueMax();var t=this.options.step>0?this.options.step:1,n=(e-this._valueMin())%t,r=e-n;return Math.abs(n)*2>=t&&(r+=n>0?t:-t),parseFloat(r.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var t,n,r,i,s,o=this.options.range,u=this.options,a=this,f=this._animateOff?!1:u.animate,l={};this.options.values&&this.options.values.length?this.handles.each(function(r){n=(a.values(r)-a._valueMin())/(a._valueMax()-a._valueMin())*100,l[a.orientation==="horizontal"?"left":"bottom"]=n+"%",e(this).stop(1,1)[f?"animate":"css"](l,u.animate),a.options.range===!0&&(a.orientation==="horizontal"?(r===0&&a.range.stop(1,1)[f?"animate":"css"]({left:n+"%"},u.animate),r===1&&a.range[f?"animate":"css"]({width:n-t+"%"},{queue:!1,duration:u.animate})):(r===0&&a.range.stop(1,1)[f?"animate":"css"]({bottom:n+"%"},u.animate),r===1&&a.range[f?"animate":"css"]({height:n-t+"%"},{queue:!1,duration:u.animate}))),t=n}):(r=this.value(),i=this._valueMin(),s=this._valueMax(),n=s!==i?(r-i)/(s-i)*100:0,l[this.orientation==="horizontal"?"left":"bottom"]=n+"%",this.handle.stop(1,1)[f?"animate":"css"](l,u.animate),o==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[f?"animate":"css"]({width:n+"%"},u.animate),o==="max"&&this.orientation==="horizontal"&&this.range[f?"animate":"css"]({width:100-n+"%"},{queue:!1,duration:u.animate}),o==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[f?"animate":"css"]({height:n+"%"},u.animate),o==="max"&&this.orientation==="vertical"&&this.range[f?"animate":"css"]({height:100-n+"%"},{queue:!1,duration:u.animate}))}})})(jQuery);(function(e){function t(e){return function(){var t=this.element.val();e.apply(this,arguments),this._refresh(),t!==this.element.val()&&this._trigger("change")}}e.widget("ui.spinner",{version:"1.9.2",defaultElement:"",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var t={},n=this.element;return e.each(["min","max","step"],function(e,r){var i=n.attr(r);i!==undefined&&i.length&&(t[r]=i)}),t},_events:{keydown:function(e){this._start(e)&&this._keydown(e)&&e.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(e){if(this.cancelBlur){delete this.cancelBlur;return}this._refresh(),this.previous!==this.element.val()&&this._trigger("change",e)},mousewheel:function(e,t){if(!t)return;if(!this.spinning&&!this._start(e))return!1;this._spin((t>0?1:-1)*this.options.step,e),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(e)},100),e.preventDefault()},"mousedown .ui-spinner-button":function(t){function r(){var e=this.element[0]===this.document[0].activeElement;e||(this.element.focus(),this.previous=n,this._delay(function(){this.previous=n}))}var n;n=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),t.preventDefault(),r.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,r.call(this)});if(this._start(t)===!1)return;this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(t){if(!e(t.currentTarget).hasClass("ui-state-active"))return;if(this._start(t)===!1)return!1;this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var e=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=e.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(e.height()*.5)&&e.height()>0&&e.height(e.height()),this.options.disabled&&this.disable()},_keydown:function(t){var n=this.options,r=e.ui.keyCode;switch(t.keyCode){case r.UP:return this._repeat(null,1,t),!0;case r.DOWN:return this._repeat(null,-1,t),!0;case r.PAGE_UP:return this._repeat(null,n.page,t),!0;case r.PAGE_DOWN:return this._repeat(null,-n.page,t),!0}return!1},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""+""+""+""+""},_start:function(e){return!this.spinning&&this._trigger("start",e)===!1?!1:(this.counter||(this.counter=1),this.spinning=!0,!0)},_repeat:function(e,t,n){e=e||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,t,n)},e),this._spin(t*this.options.step,n)},_spin:function(e,t){var n=this.value()||0;this.counter||(this.counter=1),n=this._adjustValue(n+e*this._increment(this.counter));if(!this.spinning||this._trigger("spin",t,{value:n})!==!1)this._value(n),this.counter++},_increment:function(t){var n=this.options.incremental;return n?e.isFunction(n)?n(t):Math.floor(t*t*t/5e4-t*t/500+17*t/200+1):1},_precision:function(){var e=this._precisionOf(this.options.step);return this.options.min!==null&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=e.toString(),n=t.indexOf(".");return n===-1?0:t.length-n-1},_adjustValue:function(e){var t,n,r=this.options;return t=r.min!==null?r.min:0,n=e-t,n=Math.round(n/r.step)*r.step,e=t+n,e=parseFloat(e.toFixed(this._precision())),r.max!==null&&e>r.max?r.max:r.min!==null&&e1&&e.href.replace(r,"")===location.href.replace(r,"").replace(/\s/g,"%20")}var n=0,r=/#.*$/;e.widget("ui.tabs",{version:"1.9.2",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var t=this,n=this.options,r=n.active,i=location.hash.substring(1);this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",n.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(t){e(this).is(".ui-state-disabled")&&t.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){e(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs();if(r===null){i&&this.tabs.each(function(t,n){if(e(n).attr("aria-controls")===i)return r=t,!1}),r===null&&(r=this.tabs.index(this.tabs.filter(".ui-tabs-active")));if(r===null||r===-1)r=this.tabs.length?0:!1}r!==!1&&(r=this.tabs.index(this.tabs.eq(r)),r===-1&&(r=n.collapsible?!1:0)),n.active=r,!n.collapsible&&n.active===!1&&this.anchors.length&&(n.active=0),e.isArray(n.disabled)&&(n.disabled=e.unique(n.disabled.concat(e.map(this.tabs.filter(".ui-state-disabled"),function(e){return t.tabs.index(e)}))).sort()),this.options.active!==!1&&this.anchors.length?this.active=this._findActive(this.options.active):this.active=e(),this._refresh(),this.active.length&&this.load(n.active)},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):e()}},_tabKeydown:function(t){var n=e(this.document[0].activeElement).closest("li"),r=this.tabs.index(n),i=!0;if(this._handlePageNav(t))return;switch(t.keyCode){case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:r++;break;case e.ui.keyCode.UP:case e.ui.keyCode.LEFT:i=!1,r--;break;case e.ui.keyCode.END:r=this.anchors.length-1;break;case e.ui.keyCode.HOME:r=0;break;case e.ui.keyCode.SPACE:t.preventDefault(),clearTimeout(this.activating),this._activate(r);return;case e.ui.keyCode.ENTER:t.preventDefault(),clearTimeout(this.activating),this._activate(r===this.options.active?!1:r);return;default:return}t.preventDefault(),clearTimeout(this.activating),r=this._focusNextTab(r,i),t.ctrlKey||(n.attr("aria-selected","false"),this.tabs.eq(r).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",r)},this.delay))},_panelKeydown:function(t){if(this._handlePageNav(t))return;t.ctrlKey&&t.keyCode===e.ui.keyCode.UP&&(t.preventDefault(),this.active.focus())},_handlePageNav:function(t){if(t.altKey&&t.keyCode===e.ui.keyCode.PAGE_UP)return this._activate(this._focusNextTab(this.options.active-1,!1)),!0;if(t.altKey&&t.keyCode===e.ui.keyCode.PAGE_DOWN)return this._activate(this._focusNextTab(this.options.active+1,!0)),!0},_findNextTab:function(t,n){function i(){return t>r&&(t=0),t<0&&(t=r),t}var r=this.tabs.length-1;while(e.inArray(i(),this.options.disabled)!==-1)t=n?t+1:t-1;return t},_focusNextTab:function(e,t){return e=this._findNextTab(e,t),this.tabs.eq(e).focus(),e},_setOption:function(e,t){if(e==="active"){this._activate(t);return}if(e==="disabled"){this._setupDisabled(t);return}this._super(e,t),e==="collapsible"&&(this.element.toggleClass("ui-tabs-collapsible",t),!t&&this.options.active===!1&&this._activate(0)),e==="event"&&this._setupEvents(t),e==="heightStyle"&&this._setupHeightStyle(t)},_tabId:function(e){return e.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(e){return e?e.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,n=this.tablist.children(":has(a[href])");t.disabled=e.map(n.filter(".ui-state-disabled"),function(e){return n.index(e)}),this._processTabs(),t.active===!1||!this.anchors.length?(t.active=!1,this.active=e()):this.active.length&&!e.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=e()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var t=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return e("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=e(),this.anchors.each(function(n,r){var i,o,u,a=e(r).uniqueId().attr("id"),f=e(r).closest("li"),l=f.attr("aria-controls");s(r)?(i=r.hash,o=t.element.find(t._sanitizeSelector(i))):(u=t._tabId(f),i="#"+u,o=t.element.find(i),o.length||(o=t._createPanel(u),o.insertAfter(t.panels[n-1]||t.tablist)),o.attr("aria-live","polite")),o.length&&(t.panels=t.panels.add(o)),l&&f.data("ui-tabs-aria-controls",l),f.attr({"aria-controls":i.substring(1),"aria-labelledby":a}),o.attr("aria-labelledby",a)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(t){return e("
                                ").attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(t){e.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1);for(var n=0,r;r=this.tabs[n];n++)t===!0||e.inArray(n,t)!==-1?e(r).addClass("ui-state-disabled").attr("aria-disabled","true"):e(r).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=t},_setupEvents:function(t){var n={click:function(e){e.preventDefault()}};t&&e.each(t.split(" "),function(e,t){n[t]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,n),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var n,r,i=this.element.parent();t==="fill"?(e.support.minHeight||(r=i.css("overflow"),i.css("overflow","hidden")),n=i.height(),this.element.siblings(":visible").each(function(){var t=e(this),r=t.css("position");if(r==="absolute"||r==="fixed")return;n-=t.outerHeight(!0)}),r&&i.css("overflow",r),this.element.children().not(this.panels).each(function(){n-=e(this).outerHeight(!0)}),this.panels.each(function(){e(this).height(Math.max(0,n-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):t==="auto"&&(n=0,this.panels.each(function(){n=Math.max(n,e(this).height("").height())}).height(n))},_eventHandler:function(t){var n=this.options,r=this.active,i=e(t.currentTarget),s=i.closest("li"),o=s[0]===r[0],u=o&&n.collapsible,a=u?e():this._getPanelForTab(s),f=r.length?this._getPanelForTab(r):e(),l={oldTab:r,oldPanel:f,newTab:u?e():s,newPanel:a};t.preventDefault();if(s.hasClass("ui-state-disabled")||s.hasClass("ui-tabs-loading")||this.running||o&&!n.collapsible||this._trigger("beforeActivate",t,l)===!1)return;n.active=u?!1:this.tabs.index(s),this.active=o?e():s,this.xhr&&this.xhr.abort(),!f.length&&!a.length&&e.error("jQuery UI Tabs: Mismatching fragment identifier."),a.length&&this.load(this.tabs.index(s),t),this._toggle(t,l)},_toggle:function(t,n){function o(){r.running=!1,r._trigger("activate",t,n)}function u(){n.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),i.length&&r.options.show?r._show(i,r.options.show,o):(i.show(),o())}var r=this,i=n.newPanel,s=n.oldPanel;this.running=!0,s.length&&this.options.hide?this._hide(s,this.options.hide,function(){n.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),u()}):(n.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),s.hide(),u()),s.attr({"aria-expanded":"false","aria-hidden":"true"}),n.oldTab.attr("aria-selected","false"),i.length&&s.length?n.oldTab.attr("tabIndex",-1):i.length&&this.tabs.filter(function(){return e(this).attr("tabIndex")===0}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}),n.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(t){var n,r=this._findActive(t);if(r[0]===this.active[0])return;r.length||(r=this.active),n=r.find(".ui-tabs-anchor")[0],this._eventHandler({target:n,currentTarget:n,preventDefault:e.noop})},_findActive:function(t){return t===!1?e():this.tabs.eq(t)},_getIndex:function(e){return typeof e=="string"&&(e=this.anchors.index(this.anchors.filter("[href$='"+e+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeData("href.tabs").removeData("load.tabs").removeUniqueId(),this.tabs.add(this.panels).each(function(){e.data(this,"ui-tabs-destroy")?e(this).remove():e(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var t=e(this),n=t.data("ui-tabs-aria-controls");n?t.attr("aria-controls",n):t.removeAttr("aria-controls")}),this.panels.show(),this.options.heightStyle!=="content"&&this.panels.css("height","")},enable:function(n){var r=this.options.disabled;if(r===!1)return;n===t?r=!1:(n=this._getIndex(n),e.isArray(r)?r=e.map(r,function(e){return e!==n?e:null}):r=e.map(this.tabs,function(e,t){return t!==n?t:null})),this._setupDisabled(r)},disable:function(n){var r=this.options.disabled;if(r===!0)return;if(n===t)r=!0;else{n=this._getIndex(n);if(e.inArray(n,r)!==-1)return;e.isArray(r)?r=e.merge([n],r).sort():r=[n]}this._setupDisabled(r)},load:function(t,n){t=this._getIndex(t);var r=this,i=this.tabs.eq(t),o=i.find(".ui-tabs-anchor"),u=this._getPanelForTab(i),a={tab:i,panel:u};if(s(o[0]))return;this.xhr=e.ajax(this._ajaxSettings(o,n,a)),this.xhr&&this.xhr.statusText!=="canceled"&&(i.addClass("ui-tabs-loading"),u.attr("aria-busy","true"),this.xhr.success(function(e){setTimeout(function(){u.html(e),r._trigger("load",n,a)},1)}).complete(function(e,t){setTimeout(function(){t==="abort"&&r.panels.stop(!1,!0),i.removeClass("ui-tabs-loading"),u.removeAttr("aria-busy"),e===r.xhr&&delete r.xhr},1)}))},_ajaxSettings:function(t,n,r){var i=this;return{url:t.attr("href"),beforeSend:function(t,s){return i._trigger("beforeLoad",n,e.extend({jqXHR:t,ajaxSettings:s},r))}}},_getPanelForTab:function(t){var n=e(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+n))}}),e.uiBackCompat!==!1&&(e.ui.tabs.prototype._ui=function(e,t){return{tab:e,panel:t,index:this.anchors.index(e)}},e.widget("ui.tabs",e.ui.tabs,{url:function(e,t){this.anchors.eq(e).attr("href",t)}}),e.widget("ui.tabs",e.ui.tabs,{options:{ajaxOptions:null,cache:!1},_create:function(){this._super();var t=this;this._on({tabsbeforeload:function(n,r){if(e.data(r.tab[0],"cache.tabs")){n.preventDefault();return}r.jqXHR.success(function(){t.options.cache&&e.data(r.tab[0],"cache.tabs",!0)})}})},_ajaxSettings:function(t,n,r){var i=this.options.ajaxOptions;return e.extend({},i,{error:function(e,t){try{i.error(e,t,r.tab.closest("li").index(),r.tab[0])}catch(n){}}},this._superApply(arguments))},_setOption:function(e,t){e==="cache"&&t===!1&&this.anchors.removeData("cache.tabs"),this._super(e,t)},_destroy:function(){this.anchors.removeData("cache.tabs"),this._super()},url:function(e){this.anchors.eq(e).removeData("cache.tabs"),this._superApply(arguments)}}),e.widget("ui.tabs",e.ui.tabs,{abort:function(){this.xhr&&this.xhr.abort()}}),e.widget("ui.tabs",e.ui.tabs,{options:{spinner:"Loading…"},_create:function(){this._super(),this._on({tabsbeforeload:function(e,t){if(e.target!==this.element[0]||!this.options.spinner)return;var n=t.tab.find("span"),r=n.html();n.html(this.options.spinner),t.jqXHR.complete(function(){n.html(r)})}})}}),e.widget("ui.tabs",e.ui.tabs,{options:{enable:null,disable:null},enable:function(t){var n=this.options,r;if(t&&n.disabled===!0||e.isArray(n.disabled)&&e.inArray(t,n.disabled)!==-1)r=!0;this._superApply(arguments),r&&this._trigger("enable",null,this._ui(this.anchors[t],this.panels[t]))},disable:function(t){var n=this.options,r;if(t&&n.disabled===!1||e.isArray(n.disabled)&&e.inArray(t,n.disabled)===-1)r=!0;this._superApply(arguments),r&&this._trigger("disable",null,this._ui(this.anchors[t],this.panels[t]))}}),e.widget("ui.tabs",e.ui.tabs,{options:{add:null,remove:null,tabTemplate:"
                              2. #{label}
                              3. "},add:function(n,r,i){i===t&&(i=this.anchors.length);var s,o,u=this.options,a=e(u.tabTemplate.replace(/#\{href\}/g,n).replace(/#\{label\}/g,r)),f=n.indexOf("#")?this._tabId(a):n.replace("#","");return a.addClass("ui-state-default ui-corner-top").data("ui-tabs-destroy",!0),a.attr("aria-controls",f),s=i>=this.tabs.length,o=this.element.find("#"+f),o.length||(o=this._createPanel(f),s?i>0?o.insertAfter(this.panels.eq(-1)):o.appendTo(this.element):o.insertBefore(this.panels[i])),o.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").hide(),s?a.appendTo(this.tablist):a.insertBefore(this.tabs[i]),u.disabled=e.map(u.disabled,function(e){return e>=i?++e:e}),this.refresh(),this.tabs.length===1&&u.active===!1&&this.option("active",0),this._trigger("add",null,this._ui(this.anchors[i],this.panels[i])),this},remove:function(t){t=this._getIndex(t);var n=this.options,r=this.tabs.eq(t).remove(),i=this._getPanelForTab(r).remove();return r.hasClass("ui-tabs-active")&&this.anchors.length>2&&this._activate(t+(t+1=t?--e:e}),this.refresh(),this._trigger("remove",null,this._ui(r.find("a")[0],i[0])),this}}),e.widget("ui.tabs",e.ui.tabs,{length:function(){return this.anchors.length}}),e.widget("ui.tabs",e.ui.tabs,{options:{idPrefix:"ui-tabs-"},_tabId:function(t){var n=t.is("li")?t.find("a[href]"):t;return n=n[0],e(n).closest("li").attr("aria-controls")||n.title&&n.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF\-]/g,"")||this.options.idPrefix+i()}}),e.widget("ui.tabs",e.ui.tabs,{options:{panelTemplate:"
                                "},_createPanel:function(t){return e(this.options.panelTemplate).attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)}}),e.widget("ui.tabs",e.ui.tabs,{_create:function(){var e=this.options;e.active===null&&e.selected!==t&&(e.active=e.selected===-1?!1:e.selected),this._super(),e.selected=e.active,e.selected===!1&&(e.selected=-1)},_setOption:function(e,t){if(e!=="selected")return this._super(e,t);var n=this.options;this._super("active",t===-1?!1:t),n.selected=n.active,n.selected===!1&&(n.selected=-1)},_eventHandler:function(){this._superApply(arguments),this.options.selected=this.options.active,this.options.selected===!1&&(this.options.selected=-1)}}),e.widget("ui.tabs",e.ui.tabs,{options:{show:null,select:null},_create:function(){this._super(),this.options.active!==!1&&this._trigger("show",null,this._ui(this.active.find(".ui-tabs-anchor")[0],this._getPanelForTab(this.active)[0]))},_trigger:function(e,t,n){var r,i,s=this._superApply(arguments);return s?(e==="beforeActivate"?(r=n.newTab.length?n.newTab:n.oldTab,i=n.newPanel.length?n.newPanel:n.oldPanel,s=this._super("select",t,{tab:r.find(".ui-tabs-anchor")[0],panel:i[0],index:r.closest("li").index()})):e==="activate"&&n.newTab.length&&(s=this._super("show",t,{tab:n.newTab.find(".ui-tabs-anchor")[0],panel:n.newPanel[0],index:n.newTab.closest("li").index()})),s):!1}}),e.widget("ui.tabs",e.ui.tabs,{select:function(e){e=this._getIndex(e);if(e===-1){if(!this.options.collapsible||this.options.selected===-1)return;e=this.options.selected}this.anchors.eq(e).trigger(this.options.event+this.eventNamespace)}}),function(){var t=0;e.widget("ui.tabs",e.ui.tabs,{options:{cookie:null},_create:function(){var e=this.options,t;e.active==null&&e.cookie&&(t=parseInt(this._cookie(),10),t===-1&&(t=!1),e.active=t),this._super()},_cookie:function(n){var r=[this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+ ++t)];return arguments.length&&(r.push(n===!1?-1:n),r.push(this.options.cookie)),e.cookie.apply(null,r)},_refresh:function(){this._super(),this.options.cookie&&this._cookie(this.options.active,this.options.cookie)},_eventHandler:function(){this._superApply(arguments),this.options.cookie&&this._cookie(this.options.active,this.options.cookie)},_destroy:function(){this._super(),this.options.cookie&&this._cookie(null,this.options.cookie)}})}(),e.widget("ui.tabs",e.ui.tabs,{_trigger:function(t,n,r){var i=e.extend({},r);return t==="load"&&(i.panel=i.panel[0],i.tab=i.tab.find(".ui-tabs-anchor")[0]),this._super(t,n,i)}}),e.widget("ui.tabs",e.ui.tabs,{options:{fx:null},_getFx:function(){var t,n,r=this.options.fx;return r&&(e.isArray(r)?(t=r[0],n=r[1]):t=n=r),r?{show:n,hide:t}:null},_toggle:function(e,t){function o(){n.running=!1,n._trigger("activate",e,t)}function u(){t.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),r.length&&s.show?r.animate(s.show,s.show.duration,function(){o()}):(r.show(),o())}var n=this,r=t.newPanel,i=t.oldPanel,s=this._getFx();if(!s)return this._super(e,t);n.running=!0,i.length&&s.hide?i.animate(s.hide,s.hide.duration,function(){t.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),u()}):(t.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),i.hide(),u())}}))})(jQuery);(function(e){function n(t,n){var r=(t.attr("aria-describedby")||"").split(/\s+/);r.push(n),t.data("ui-tooltip-id",n).attr("aria-describedby",e.trim(r.join(" ")))}function r(t){var n=t.data("ui-tooltip-id"),r=(t.attr("aria-describedby")||"").split(/\s+/),i=e.inArray(n,r);i!==-1&&r.splice(i,1),t.removeData("ui-tooltip-id"),r=e.trim(r.join(" ")),r?t.attr("aria-describedby",r):t.removeAttr("aria-describedby")}var t=0;e.widget("ui.tooltip",{version:"1.9.2",options:{content:function(){return e(this).attr("title")},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(t,n){var r=this;if(t==="disabled"){this[n?"_disable":"_enable"](),this.options[t]=n;return}this._super(t,n),t==="content"&&e.each(this.tooltips,function(e,t){r._updateContent(t)})},_disable:function(){var t=this;e.each(this.tooltips,function(n,r){var i=e.Event("blur");i.target=i.currentTarget=r[0],t.close(i,!0)}),this.element.find(this.options.items).andSelf().each(function(){var t=e(this);t.is("[title]")&&t.data("ui-tooltip-title",t.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).andSelf().each(function(){var t=e(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))})},open:function(t){var n=this,r=e(t?t.target:this.element).closest(this.options.items);if(!r.length||r.data("ui-tooltip-id"))return;r.attr("title")&&r.data("ui-tooltip-title",r.attr("title")),r.data("ui-tooltip-open",!0),t&&t.type==="mouseover"&&r.parents().each(function(){var t=e(this),r;t.data("ui-tooltip-open")&&(r=e.Event("blur"),r.target=r.currentTarget=this,n.close(r,!0)),t.attr("title")&&(t.uniqueId(),n.parents[this.id]={element:this,title:t.attr("title")},t.attr("title",""))}),this._updateContent(r,t)},_updateContent:function(e,t){var n,r=this.options.content,i=this,s=t?t.type:null;if(typeof r=="string")return this._open(t,e,r);n=r.call(e[0],function(n){if(!e.data("ui-tooltip-open"))return;i._delay(function(){t&&(t.type=s),this._open(t,e,n)})}),n&&this._open(t,e,n)},_open:function(t,r,i){function f(e){a.of=e;if(s.is(":hidden"))return;s.position(a)}var s,o,u,a=e.extend({},this.options.position);if(!i)return;s=this._find(r);if(s.length){s.find(".ui-tooltip-content").html(i);return}r.is("[title]")&&(t&&t.type==="mouseover"?r.attr("title",""):r.removeAttr("title")),s=this._tooltip(r),n(r,s.attr("id")),s.find(".ui-tooltip-content").html(i),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:f}),f(t)):s.position(e.extend({of:r},this.options.position)),s.hide(),this._show(s,this.options.show),this.options.show&&this.options.show.delay&&(u=setInterval(function(){s.is(":visible")&&(f(a.of),clearInterval(u))},e.fx.interval)),this._trigger("open",t,{tooltip:s}),o={keyup:function(t){if(t.keyCode===e.ui.keyCode.ESCAPE){var n=e.Event(t);n.currentTarget=r[0],this.close(n,!0)}},remove:function(){this._removeTooltip(s)}};if(!t||t.type==="mouseover")o.mouseleave="close";if(!t||t.type==="focusin")o.focusout="close";this._on(!0,r,o)},close:function(t){var n=this,i=e(t?t.currentTarget:this.element),s=this._find(i);if(this.closing)return;i.data("ui-tooltip-title")&&i.attr("title",i.data("ui-tooltip-title")),r(i),s.stop(!0),this._hide(s,this.options.hide,function(){n._removeTooltip(e(this))}),i.removeData("ui-tooltip-open"),this._off(i,"mouseleave focusout keyup"),i[0]!==this.element[0]&&this._off(i,"remove"),this._off(this.document,"mousemove"),t&&t.type==="mouseleave"&&e.each(this.parents,function(t,r){e(r.element).attr("title",r.title),delete n.parents[t]}),this.closing=!0,this._trigger("close",t,{tooltip:s}),this.closing=!1},_tooltip:function(n){var r="ui-tooltip-"+t++,i=e("
                                ").attr({id:r,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return e("
                                ").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),e.fn.bgiframe&&i.bgiframe(),this.tooltips[r]=n,i},_find:function(t){var n=t.data("ui-tooltip-id");return n?e("#"+n):e()},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(n,r){var i=e.Event("blur");i.target=i.currentTarget=r[0],t.close(i,!0),e("#"+n).remove(),r.data("ui-tooltip-title")&&(r.attr("title",r.data("ui-tooltip-title")),r.removeData("ui-tooltip-title"))})}})})(jQuery);jQuery.effects||function(e,t){var n=e.uiBackCompat!==!1,r="ui-effects-";e.effects={effect:{}},function(t,n){function p(e,t,n){var r=a[t.type]||{};return e==null?n||!t.def?null:t.def:(e=r.floor?~~e:parseFloat(e),isNaN(e)?t.def:r.mod?(e+r.mod)%r.mod:0>e?0:r.max")[0],c,h=t.each;l.style.cssText="background-color:rgba(1,1,1,.5)",f.rgba=l.style.backgroundColor.indexOf("rgba")>-1,h(u,function(e,t){t.cache="_"+e,t.props.alpha={idx:3,type:"percent",def:1}}),o.fn=t.extend(o.prototype,{parse:function(r,i,s,a){if(r===n)return this._rgba=[null,null,null,null],this;if(r.jquery||r.nodeType)r=t(r).css(i),i=n;var f=this,l=t.type(r),v=this._rgba=[];i!==n&&(r=[r,i,s,a],l="array");if(l==="string")return this.parse(d(r)||c._default);if(l==="array")return h(u.rgba.props,function(e,t){v[t.idx]=p(r[t.idx],t)}),this;if(l==="object")return r instanceof o?h(u,function(e,t){r[t.cache]&&(f[t.cache]=r[t.cache].slice())}):h(u,function(t,n){var i=n.cache;h(n.props,function(e,t){if(!f[i]&&n.to){if(e==="alpha"||r[e]==null)return;f[i]=n.to(f._rgba)}f[i][t.idx]=p(r[e],t,!0)}),f[i]&&e.inArray(null,f[i].slice(0,3))<0&&(f[i][3]=1,n.from&&(f._rgba=n.from(f[i])))}),this},is:function(e){var t=o(e),n=!0,r=this;return h(u,function(e,i){var s,o=t[i.cache];return o&&(s=r[i.cache]||i.to&&i.to(r._rgba)||[],h(i.props,function(e,t){if(o[t.idx]!=null)return n=o[t.idx]===s[t.idx],n})),n}),n},_space:function(){var e=[],t=this;return h(u,function(n,r){t[r.cache]&&e.push(n)}),e.pop()},transition:function(e,t){var n=o(e),r=n._space(),i=u[r],s=this.alpha()===0?o("transparent"):this,f=s[i.cache]||i.to(s._rgba),l=f.slice();return n=n[i.cache],h(i.props,function(e,r){var i=r.idx,s=f[i],o=n[i],u=a[r.type]||{};if(o===null)return;s===null?l[i]=o:(u.mod&&(o-s>u.mod/2?s+=u.mod:s-o>u.mod/2&&(s-=u.mod)),l[i]=p((o-s)*t+s,r))}),this[r](l)},blend:function(e){if(this._rgba[3]===1)return this;var n=this._rgba.slice(),r=n.pop(),i=o(e)._rgba;return o(t.map(n,function(e,t){return(1-r)*i[t]+r*e}))},toRgbaString:function(){var e="rgba(",n=t.map(this._rgba,function(e,t){return e==null?t>2?1:0:e});return n[3]===1&&(n.pop(),e="rgb("),e+n.join()+")"},toHslaString:function(){var e="hsla(",n=t.map(this.hsla(),function(e,t){return e==null&&(e=t>2?1:0),t&&t<3&&(e=Math.round(e*100)+"%"),e});return n[3]===1&&(n.pop(),e="hsl("),e+n.join()+")"},toHexString:function(e){var n=this._rgba.slice(),r=n.pop();return e&&n.push(~~(r*255)),"#"+t.map(n,function(e){return e=(e||0).toString(16),e.length===1?"0"+e:e}).join("")},toString:function(){return this._rgba[3]===0?"transparent":this.toRgbaString()}}),o.fn.parse.prototype=o.fn,u.hsla.to=function(e){if(e[0]==null||e[1]==null||e[2]==null)return[null,null,null,e[3]];var t=e[0]/255,n=e[1]/255,r=e[2]/255,i=e[3],s=Math.max(t,n,r),o=Math.min(t,n,r),u=s-o,a=s+o,f=a*.5,l,c;return o===s?l=0:t===s?l=60*(n-r)/u+360:n===s?l=60*(r-t)/u+120:l=60*(t-n)/u+240,f===0||f===1?c=f:f<=.5?c=u/a:c=u/(2-a),[Math.round(l)%360,c,f,i==null?1:i]},u.hsla.from=function(e){if(e[0]==null||e[1]==null||e[2]==null)return[null,null,null,e[3]];var t=e[0]/360,n=e[1],r=e[2],i=e[3],s=r<=.5?r*(1+n):r+n-r*n,o=2*r-s;return[Math.round(v(o,s,t+1/3)*255),Math.round(v(o,s,t)*255),Math.round(v(o,s,t-1/3)*255),i]},h(u,function(e,r){var s=r.props,u=r.cache,a=r.to,f=r.from;o.fn[e]=function(e){a&&!this[u]&&(this[u]=a(this._rgba));if(e===n)return this[u].slice();var r,i=t.type(e),l=i==="array"||i==="object"?e:arguments,c=this[u].slice();return h(s,function(e,t){var n=l[i==="object"?e:t.idx];n==null&&(n=c[t.idx]),c[t.idx]=p(n,t)}),f?(r=o(f(c)),r[u]=c,r):o(c)},h(s,function(n,r){if(o.fn[n])return;o.fn[n]=function(s){var o=t.type(s),u=n==="alpha"?this._hsla?"hsla":"rgba":e,a=this[u](),f=a[r.idx],l;return o==="undefined"?f:(o==="function"&&(s=s.call(this,f),o=t.type(s)),s==null&&r.empty?this:(o==="string"&&(l=i.exec(s),l&&(s=f+parseFloat(l[2])*(l[1]==="+"?1:-1))),a[r.idx]=s,this[u](a)))}})}),h(r,function(e,n){t.cssHooks[n]={set:function(e,r){var i,s,u="";if(t.type(r)!=="string"||(i=d(r))){r=o(i||r);if(!f.rgba&&r._rgba[3]!==1){s=n==="backgroundColor"?e.parentNode:e;while((u===""||u==="transparent")&&s&&s.style)try{u=t.css(s,"backgroundColor"),s=s.parentNode}catch(a){}r=r.blend(u&&u!=="transparent"?u:"_default")}r=r.toRgbaString()}try{e.style[n]=r}catch(l){}}},t.fx.step[n]=function(e){e.colorInit||(e.start=o(e.elem,n),e.end=o(e.end),e.colorInit=!0),t.cssHooks[n].set(e.elem,e.start.transition(e.end,e.pos))}}),t.cssHooks.borderColor={expand:function(e){var t={};return h(["Top","Right","Bottom","Left"],function(n,r){t["border"+r+"Color"]=e}),t}},c=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(){var t=this.ownerDocument.defaultView?this.ownerDocument.defaultView.getComputedStyle(this,null):this.currentStyle,n={},r,i;if(t&&t.length&&t[0]&&t[t[0]]){i=t.length;while(i--)r=t[i],typeof t[r]=="string"&&(n[e.camelCase(r)]=t[r])}else for(r in t)typeof t[r]=="string"&&(n[r]=t[r]);return n}function s(t,n){var i={},s,o;for(s in n)o=n[s],t[s]!==o&&!r[s]&&(e.fx.step[s]||!isNaN(parseFloat(o)))&&(i[s]=o);return i}var n=["add","remove","toggle"],r={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};e.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(t,n){e.fx.step[n]=function(e){if(e.end!=="none"&&!e.setAttr||e.pos===1&&!e.setAttr)jQuery.style(e.elem,n,e.end),e.setAttr=!0}}),e.effects.animateClass=function(t,r,o,u){var a=e.speed(r,o,u);return this.queue(function(){var r=e(this),o=r.attr("class")||"",u,f=a.children?r.find("*").andSelf():r;f=f.map(function(){var t=e(this);return{el:t,start:i.call(this)}}),u=function(){e.each(n,function(e,n){t[n]&&r[n+"Class"](t[n])})},u(),f=f.map(function(){return this.end=i.call(this.el[0]),this.diff=s(this.start,this.end),this}),r.attr("class",o),f=f.map(function(){var t=this,n=e.Deferred(),r=jQuery.extend({},a,{queue:!1,complete:function(){n.resolve(t)}});return this.el.animate(this.diff,r),n.promise()}),e.when.apply(e,f.get()).done(function(){u(),e.each(arguments,function(){var t=this.el;e.each(this.diff,function(e){t.css(e,"")})}),a.complete.call(r[0])})})},e.fn.extend({_addClass:e.fn.addClass,addClass:function(t,n,r,i){return n?e.effects.animateClass.call(this,{add:t},n,r,i):this._addClass(t)},_removeClass:e.fn.removeClass,removeClass:function(t,n,r,i){return n?e.effects.animateClass.call(this,{remove:t},n,r,i):this._removeClass(t)},_toggleClass:e.fn.toggleClass,toggleClass:function(n,r,i,s,o){return typeof r=="boolean"||r===t?i?e.effects.animateClass.call(this,r?{add:n}:{remove:n},i,s,o):this._toggleClass(n,r):e.effects.animateClass.call(this,{toggle:n},r,i,s)},switchClass:function(t,n,r,i,s){return e.effects.animateClass.call(this,{add:n,remove:t},r,i,s)}})}(),function(){function i(t,n,r,i){e.isPlainObject(t)&&(n=t,t=t.effect),t={effect:t},n==null&&(n={}),e.isFunction(n)&&(i=n,r=null,n={});if(typeof n=="number"||e.fx.speeds[n])i=r,r=n,n={};return e.isFunction(r)&&(i=r,r=null),n&&e.extend(t,n),r=r||n.duration,t.duration=e.fx.off?0:typeof r=="number"?r:r in e.fx.speeds?e.fx.speeds[r]:e.fx.speeds._default,t.complete=i||n.complete,t}function s(t){return!t||typeof t=="number"||e.fx.speeds[t]?!0:typeof t=="string"&&!e.effects.effect[t]?n&&e.effects[t]?!1:!0:!1}e.extend(e.effects,{version:"1.9.2",save:function(e,t){for(var n=0;n
                                ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),i={width:t.width(),height:t.height()},s=document.activeElement;try{s.id}catch(o){s=document.body}return t.wrap(r),(t[0]===s||e.contains(t[0],s))&&e(s).focus(),r=t.parent(),t.css("position")==="static"?(r.css({position:"relative"}),t.css({position:"relative"})):(e.extend(n,{position:t.css("position"),zIndex:t.css("z-index")}),e.each(["top","left","bottom","right"],function(e,r){n[r]=t.css(r),isNaN(parseInt(n[r],10))&&(n[r]="auto")}),t.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),t.css(i),r.css(n).show()},removeWrapper:function(t){var n=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===n||e.contains(t[0],n))&&e(n).focus()),t},setTransition:function(t,n,r,i){return i=i||{},e.each(n,function(e,n){var s=t.cssUnit(n);s[0]>0&&(i[n]=s[0]*r+s[1])}),i}}),e.fn.extend({effect:function(){function a(n){function u(){e.isFunction(i)&&i.call(r[0]),e.isFunction(n)&&n()}var r=e(this),i=t.complete,s=t.mode;(r.is(":hidden")?s==="hide":s==="show")?u():o.call(r[0],t,u)}var t=i.apply(this,arguments),r=t.mode,s=t.queue,o=e.effects.effect[t.effect],u=!o&&n&&e.effects[t.effect];return e.fx.off||!o&&!u?r?this[r](t.duration,t.complete):this.each(function(){t.complete&&t.complete.call(this)}):o?s===!1?this.each(a):this.queue(s||"fx",a):u.call(this,{options:t,duration:t.duration,callback:t.complete,mode:t.mode})},_show:e.fn.show,show:function(e){if(s(e))return this._show.apply(this,arguments);var t=i.apply(this,arguments);return t.mode="show",this.effect.call(this,t)},_hide:e.fn.hide,hide:function(e){if(s(e))return this._hide.apply(this,arguments);var t=i.apply(this,arguments);return t.mode="hide",this.effect.call(this,t)},__toggle:e.fn.toggle,toggle:function(t){if(s(t)||typeof t=="boolean"||e.isFunction(t))return this.__toggle.apply(this,arguments);var n=i.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)},cssUnit:function(t){var n=this.css(t),r=[];return e.each(["em","px","%","pt"],function(e,t){n.indexOf(t)>0&&(r=[parseFloat(n),t])}),r}})}(),function(){var t={};e.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,n){t[n]=function(t){return Math.pow(t,e+2)}}),e.extend(t,{Sine:function(e){return 1-Math.cos(e*Math.PI/2)},Circ:function(e){return 1-Math.sqrt(1-e*e)},Elastic:function(e){return e===0||e===1?e:-Math.pow(2,8*(e-1))*Math.sin(((e-1)*80-7.5)*Math.PI/15)},Back:function(e){return e*e*(3*e-2)},Bounce:function(e){var t,n=4;while(e<((t=Math.pow(2,--n))-1)/11);return 1/Math.pow(4,3-n)-7.5625*Math.pow((t*3-2)/22-e,2)}}),e.each(t,function(t,n){e.easing["easeIn"+t]=n,e.easing["easeOut"+t]=function(e){return 1-n(1-e)},e.easing["easeInOut"+t]=function(e){return e<.5?n(e*2)/2:1-n(e*-2+2)/2}})}()}(jQuery);(function(e,t){var n=/up|down|vertical/,r=/up|left|vertical|horizontal/;e.effects.effect.blind=function(t,i){var s=e(this),o=["position","top","bottom","left","right","height","width"],u=e.effects.setMode(s,t.mode||"hide"),a=t.direction||"up",f=n.test(a),l=f?"height":"width",c=f?"top":"left",h=r.test(a),p={},d=u==="show",v,m,g;s.parent().is(".ui-effects-wrapper")?e.effects.save(s.parent(),o):e.effects.save(s,o),s.show(),v=e.effects.createWrapper(s).css({overflow:"hidden"}),m=v[l](),g=parseFloat(v.css(c))||0,p[l]=d?m:0,h||(s.css(f?"bottom":"right",0).css(f?"top":"left","auto").css({position:"absolute"}),p[c]=d?g:m+g),d&&(v.css(l,0),h||v.css(c,g+m)),v.animate(p,{duration:t.duration,easing:t.easing,queue:!1,complete:function(){u==="hide"&&s.hide(),e.effects.restore(s,o),e.effects.removeWrapper(s),i()}})}})(jQuery);(function(e,t){e.effects.effect.bounce=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"effect"),o=s==="hide",u=s==="show",a=t.direction||"up",f=t.distance,l=t.times||5,c=l*2+(u||o?1:0),h=t.duration/c,p=t.easing,d=a==="up"||a==="down"?"top":"left",v=a==="up"||a==="left",m,g,y,b=r.queue(),w=b.length;(u||o)&&i.push("opacity"),e.effects.save(r,i),r.show(),e.effects.createWrapper(r),f||(f=r[d==="top"?"outerHeight":"outerWidth"]()/3),u&&(y={opacity:1},y[d]=0,r.css("opacity",0).css(d,v?-f*2:f*2).animate(y,h,p)),o&&(f/=Math.pow(2,l-1)),y={},y[d]=0;for(m=0;m1&&b.splice.apply(b,[1,0].concat(b.splice(w,c+1))),r.dequeue()}})(jQuery);(function(e,t){e.effects.effect.clip=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=t.direction||"vertical",a=u==="vertical",f=a?"height":"width",l=a?"top":"left",c={},h,p,d;e.effects.save(r,i),r.show(),h=e.effects.createWrapper(r).css({overflow:"hidden"}),p=r[0].tagName==="IMG"?h:r,d=p[f](),o&&(p.css(f,0),p.css(l,d/2)),c[f]=o?d:0,c[l]=o?0:d/2,p.animate(c,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){o||r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}})(jQuery);(function(e,t){e.effects.effect.drop=function(t,n){var r=e(this),i=["position","top","bottom","left","right","opacity","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=t.direction||"left",a=u==="up"||u==="down"?"top":"left",f=u==="up"||u==="left"?"pos":"neg",l={opacity:o?1:0},c;e.effects.save(r,i),r.show(),e.effects.createWrapper(r),c=t.distance||r[a==="top"?"outerHeight":"outerWidth"](!0)/2,o&&r.css("opacity",0).css(a,f==="pos"?-c:c),l[a]=(o?f==="pos"?"+=":"-=":f==="pos"?"-=":"+=")+c,r.animate(l,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}})(jQuery);(function(e,t){e.effects.effect.explode=function(t,n){function y(){c.push(this),c.length===r*i&&b()}function b(){s.css({visibility:"visible"}),e(c).remove(),u||s.hide(),n()}var r=t.pieces?Math.round(Math.sqrt(t.pieces)):3,i=r,s=e(this),o=e.effects.setMode(s,t.mode||"hide"),u=o==="show",a=s.show().css("visibility","hidden").offset(),f=Math.ceil(s.outerWidth()/i),l=Math.ceil(s.outerHeight()/r),c=[],h,p,d,v,m,g;for(h=0;h
                                ").css({position:"absolute",visibility:"visible",left:-p*f,top:-h*l}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:f,height:l,left:d+(u?m*f:0),top:v+(u?g*l:0),opacity:u?0:1}).animate({left:d+(u?0:m*f),top:v+(u?0:g*l),opacity:u?1:0},t.duration||500,t.easing,y)}}})(jQuery);(function(e,t){e.effects.effect.fade=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"toggle");r.animate({opacity:i},{queue:!1,duration:t.duration,easing:t.easing,complete:n})}})(jQuery);(function(e,t){e.effects.effect.fold=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=s==="hide",a=t.size||15,f=/([0-9]+)%/.exec(a),l=!!t.horizFirst,c=o!==l,h=c?["width","height"]:["height","width"],p=t.duration/2,d,v,m={},g={};e.effects.save(r,i),r.show(),d=e.effects.createWrapper(r).css({overflow:"hidden"}),v=c?[d.width(),d.height()]:[d.height(),d.width()],f&&(a=parseInt(f[1],10)/100*v[u?0:1]),o&&d.css(l?{height:0,width:a}:{height:a,width:0}),m[h[0]]=o?v[0]:a,g[h[1]]=o?v[1]:0,d.animate(m,p,t.easing).animate(g,p,t.easing,function(){u&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()})}})(jQuery);(function(e,t){e.effects.effect.highlight=function(t,n){var r=e(this),i=["backgroundImage","backgroundColor","opacity"],s=e.effects.setMode(r,t.mode||"show"),o={backgroundColor:r.css("backgroundColor")};s==="hide"&&(o.opacity=0),e.effects.save(r,i),r.show().css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(o,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),n()}})}})(jQuery);(function(e,t){e.effects.effect.pulsate=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"show"),s=i==="show",o=i==="hide",u=s||i==="hide",a=(t.times||5)*2+(u?1:0),f=t.duration/a,l=0,c=r.queue(),h=c.length,p;if(s||!r.is(":visible"))r.css("opacity",0).show(),l=1;for(p=1;p1&&c.splice.apply(c,[1,0].concat(c.splice(h,a+1))),r.dequeue()}})(jQuery);(function(e,t){e.effects.effect.puff=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"hide"),s=i==="hide",o=parseInt(t.percent,10)||150,u=o/100,a={height:r.height(),width:r.width(),outerHeight:r.outerHeight(),outerWidth:r.outerWidth()};e.extend(t,{effect:"scale",queue:!1,fade:!0,mode:i,complete:n,percent:s?o:100,from:s?a:{height:a.height*u,width:a.width*u,outerHeight:a.outerHeight*u,outerWidth:a.outerWidth*u}}),r.effect(t)},e.effects.effect.scale=function(t,n){var r=e(this),i=e.extend(!0,{},t),s=e.effects.setMode(r,t.mode||"effect"),o=parseInt(t.percent,10)||(parseInt(t.percent,10)===0?0:s==="hide"?0:100),u=t.direction||"both",a=t.origin,f={height:r.height(),width:r.width(),outerHeight:r.outerHeight(),outerWidth:r.outerWidth()},l={y:u!=="horizontal"?o/100:1,x:u!=="vertical"?o/100:1};i.effect="size",i.queue=!1,i.complete=n,s!=="effect"&&(i.origin=a||["middle","center"],i.restore=!0),i.from=t.from||(s==="show"?{height:0,width:0,outerHeight:0,outerWidth:0}:f),i.to={height:f.height*l.y,width:f.width*l.x,outerHeight:f.outerHeight*l.y,outerWidth:f.outerWidth*l.x},i.fade&&(s==="show"&&(i.from.opacity=0,i.to.opacity=1),s==="hide"&&(i.from.opacity=1,i.to.opacity=0)),r.effect(i)},e.effects.effect.size=function(t,n){var r,i,s,o=e(this),u=["position","top","bottom","left","right","width","height","overflow","opacity"],a=["position","top","bottom","left","right","overflow","opacity"],f=["width","height","overflow"],l=["fontSize"],c=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],h=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=e.effects.setMode(o,t.mode||"effect"),d=t.restore||p!=="effect",v=t.scale||"both",m=t.origin||["middle","center"],g=o.css("position"),y=d?u:a,b={height:0,width:0,outerHeight:0,outerWidth:0};p==="show"&&o.show(),r={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},t.mode==="toggle"&&p==="show"?(o.from=t.to||b,o.to=t.from||r):(o.from=t.from||(p==="show"?b:r),o.to=t.to||(p==="hide"?b:r)),s={from:{y:o.from.height/r.height,x:o.from.width/r.width},to:{y:o.to.height/r.height,x:o.to.width/r.width}};if(v==="box"||v==="both")s.from.y!==s.to.y&&(y=y.concat(c),o.from=e.effects.setTransition(o,c,s.from.y,o.from),o.to=e.effects.setTransition(o,c,s.to.y,o.to)),s.from.x!==s.to.x&&(y=y.concat(h),o.from=e.effects.setTransition(o,h,s.from.x,o.from),o.to=e.effects.setTransition(o,h,s.to.x,o.to));(v==="content"||v==="both")&&s.from.y!==s.to.y&&(y=y.concat(l).concat(f),o.from=e.effects.setTransition(o,l,s.from.y,o.from),o.to=e.effects.setTransition(o,l,s.to.y,o.to)),e.effects.save(o,y),o.show(),e.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),m&&(i=e.effects.getBaseline(m,r),o.from.top=(r.outerHeight-o.outerHeight())*i.y,o.from.left=(r.outerWidth-o.outerWidth())*i.x,o.to.top=(r.outerHeight-o.to.outerHeight)*i.y,o.to.left=(r.outerWidth-o.to.outerWidth)*i.x),o.css(o.from);if(v==="content"||v==="both")c=c.concat(["marginTop","marginBottom"]).concat(l),h=h.concat(["marginLeft","marginRight"]),f=u.concat(c).concat(h),o.find("*[width]").each(function(){var n=e(this),r={height:n.height(),width:n.width(),outerHeight:n.outerHeight(),outerWidth:n.outerWidth()};d&&e.effects.save(n,f),n.from={height:r.height*s.from.y,width:r.width*s.from.x,outerHeight:r.outerHeight*s.from.y,outerWidth:r.outerWidth*s.from.x},n.to={height:r.height*s.to.y,width:r.width*s.to.x,outerHeight:r.height*s.to.y,outerWidth:r.width*s.to.x},s.from.y!==s.to.y&&(n.from=e.effects.setTransition(n,c,s.from.y,n.from),n.to=e.effects.setTransition(n,c,s.to.y,n.to)),s.from.x!==s.to.x&&(n.from=e.effects.setTransition(n,h,s.from.x,n.from),n.to=e.effects.setTransition(n,h,s.to.x,n.to)),n.css(n.from),n.animate(n.to,t.duration,t.easing,function(){d&&e.effects.restore(n,f)})});o.animate(o.to,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){o.to.opacity===0&&o.css("opacity",o.from.opacity),p==="hide"&&o.hide(),e.effects.restore(o,y),d||(g==="static"?o.css({position:"relative",top:o.to.top,left:o.to.left}):e.each(["top","left"],function(e,t){o.css(t,function(t,n){var r=parseInt(n,10),i=e?o.to.left:o.to.top;return n==="auto"?i+"px":r+i+"px"})})),e.effects.removeWrapper(o),n()}})}})(jQuery);(function(e,t){e.effects.effect.shake=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"effect"),o=t.direction||"left",u=t.distance||20,a=t.times||3,f=a*2+1,l=Math.round(t.duration/f),c=o==="up"||o==="down"?"top":"left",h=o==="up"||o==="left",p={},d={},v={},m,g=r.queue(),y=g.length;e.effects.save(r,i),r.show(),e.effects.createWrapper(r),p[c]=(h?"-=":"+=")+u,d[c]=(h?"+=":"-=")+u*2,v[c]=(h?"-=":"+=")+u*2,r.animate(p,l,t.easing);for(m=1;m1&&g.splice.apply(g,[1,0].concat(g.splice(y,f+1))),r.dequeue()}})(jQuery);(function(e,t){e.effects.effect.slide=function(t,n){var r=e(this),i=["position","top","bottom","left","right","width","height"],s=e.effects.setMode(r,t.mode||"show"),o=s==="show",u=t.direction||"left",a=u==="up"||u==="down"?"top":"left",f=u==="up"||u==="left",l,c={};e.effects.save(r,i),r.show(),l=t.distance||r[a==="top"?"outerHeight":"outerWidth"](!0),e.effects.createWrapper(r).css({overflow:"hidden"}),o&&r.css(a,f?isNaN(l)?"-"+l:-l:l),c[a]=(o?f?"+=":"-=":f?"-=":"+=")+l,r.animate(c,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}})(jQuery);(function(e,t){e.effects.effect.transfer=function(t,n){var r=e(this),i=e(t.to),s=i.css("position")==="fixed",o=e("body"),u=s?o.scrollTop():0,a=s?o.scrollLeft():0,f=i.offset(),l={top:f.top-u,left:f.left-a,height:i.innerHeight(),width:i.innerWidth()},c=r.offset(),h=e('
                                ').appendTo(document.body).addClass(t.className).css({top:c.top-u,left:c.left-a,height:r.innerHeight(),width:r.innerWidth(),position:s?"fixed":"absolute"}).animate(l,t.duration,t.easing,function(){h.remove(),n()})}})(jQuery); + +/* JQuery UJS 2.0.3 */ +(function(a,b){var c=function(){var b=a(document).data("events");return b&&b.click&&a.grep(b.click,function(a){return a.namespace==="rails"}).length};if(c()){a.error("jquery-ujs has already been loaded!")}var d;a.rails=d={linkClickSelector:"a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]",inputChangeSelector:"select[data-remote], input[data-remote], textarea[data-remote]",formSubmitSelector:"form",formInputClickSelector:"form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])",disableSelector:"input[data-disable-with], button[data-disable-with], textarea[data-disable-with]",enableSelector:"input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled",requiredInputSelector:"input[name][required]:not([disabled]),textarea[name][required]:not([disabled])",fileInputSelector:"input:file",linkDisableSelector:"a[data-disable-with]",CSRFProtection:function(b){var c=a('meta[name="csrf-token"]').attr("content");if(c)b.setRequestHeader("X-CSRF-Token",c)},fire:function(b,c,d){var e=a.Event(c);b.trigger(e,d);return e.result!==false},confirm:function(a){return confirm(a)},ajax:function(b){return a.ajax(b)},href:function(a){return a.attr("href")},handleRemote:function(c){var e,f,g,h,i,j,k,l;if(d.fire(c,"ajax:before")){h=c.data("cross-domain");i=h===b?null:h;j=c.data("with-credentials")||null;k=c.data("type")||a.ajaxSettings&&a.ajaxSettings.dataType;if(c.is("form")){e=c.attr("method");f=c.attr("action");g=c.serializeArray();var m=c.data("ujs:submit-button");if(m){g.push(m);c.data("ujs:submit-button",null)}}else if(c.is(d.inputChangeSelector)){e=c.data("method");f=c.data("url");g=c.serialize();if(c.data("params"))g=g+"&"+c.data("params")}else{e=c.data("method");f=d.href(c);g=c.data("params")||null}l={type:e||"GET",data:g,dataType:k,beforeSend:function(a,e){if(e.dataType===b){a.setRequestHeader("accept","*/*;q=0.5, "+e.accepts.script)}return d.fire(c,"ajax:beforeSend",[a,e])},success:function(a,b,d){c.trigger("ajax:success",[a,b,d])},complete:function(a,b){c.trigger("ajax:complete",[a,b])},error:function(a,b,d){c.trigger("ajax:error",[a,b,d])},xhrFields:{withCredentials:j},crossDomain:i};if(f){l.url=f}var n=d.ajax(l);c.trigger("ajax:send",n);return n}else{return false}},handleMethod:function(c){var e=d.href(c),f=c.data("method"),g=c.attr("target"),h=a("meta[name=csrf-token]").attr("content"),i=a("meta[name=csrf-param]").attr("content"),j=a('
                                '),k='';if(i!==b&&h!==b){k+=''}if(g){j.attr("target",g)}j.hide().append(k).appendTo("body");j.submit()},disableFormElements:function(b){b.find(d.disableSelector).each(function(){var b=a(this),c=b.is("button")?"html":"val";b.data("ujs:enable-with",b[c]());b[c](b.data("disable-with"));b.prop("disabled",true)})},enableFormElements:function(b){b.find(d.enableSelector).each(function(){var b=a(this),c=b.is("button")?"html":"val";if(b.data("ujs:enable-with"))b[c](b.data("ujs:enable-with"));b.prop("disabled",false)})},allowAction:function(a){var b=a.data("confirm"),c=false,e;if(!b){return true}if(d.fire(a,"confirm")){c=d.confirm(b);e=d.fire(a,"confirm:complete",[c])}return c&&e},blankInputs:function(b,c,d){var e=a(),f,g,h=c||"input,textarea";b.find(h).each(function(){f=a(this);g=f.is(":checkbox,:radio")?f.is(":checked"):f.val();if(g==!!d){e=e.add(f)}});return e.length?e:false},nonBlankInputs:function(a,b){return d.blankInputs(a,b,true)},stopEverything:function(b){a(b.target).trigger("ujs:everythingStopped");b.stopImmediatePropagation();return false},callFormSubmitBindings:function(c,d){var e=c.data("events"),f=true;if(e!==b&&e["submit"]!==b){a.each(e["submit"],function(a,b){if(typeof b.handler==="function")return f=b.handler(d)})}return f},disableElement:function(a){a.data("ujs:enable-with",a.html());a.html(a.data("disable-with"));a.bind("click.railsDisable",function(a){return d.stopEverything(a)})},enableElement:function(a){if(a.data("ujs:enable-with")!==b){a.html(a.data("ujs:enable-with"));a.data("ujs:enable-with",false)}a.unbind("click.railsDisable")}};if(d.fire(a(document),"rails:attachBindings")){a.ajaxPrefilter(function(a,b,c){if(!a.crossDomain){d.CSRFProtection(c)}});a(document).delegate(d.linkDisableSelector,"ajax:complete",function(){d.enableElement(a(this))});a(document).delegate(d.linkClickSelector,"click.rails",function(c){var e=a(this),f=e.data("method"),g=e.data("params");if(!d.allowAction(e))return d.stopEverything(c);if(e.is(d.linkDisableSelector))d.disableElement(e);if(e.data("remote")!==b){if((c.metaKey||c.ctrlKey)&&(!f||f==="GET")&&!g){return true}if(d.handleRemote(e)===false){d.enableElement(e)}return false}else if(e.data("method")){d.handleMethod(e);return false}});a(document).delegate(d.inputChangeSelector,"change.rails",function(b){var c=a(this);if(!d.allowAction(c))return d.stopEverything(b);d.handleRemote(c);return false});a(document).delegate(d.formSubmitSelector,"submit.rails",function(c){var e=a(this),f=e.data("remote")!==b,g=d.blankInputs(e,d.requiredInputSelector),h=d.nonBlankInputs(e,d.fileInputSelector);if(!d.allowAction(e))return d.stopEverything(c);if(g&&e.attr("novalidate")==b&&d.fire(e,"ajax:aborted:required",[g])){return d.stopEverything(c)}if(f){if(h){setTimeout(function(){d.disableFormElements(e)},13);return d.fire(e,"ajax:aborted:file",[h])}if(!a.support.submitBubbles&&a().jquery<"1.7"&&d.callFormSubmitBindings(e,c)===false)return d.stopEverything(c);d.handleRemote(e);return false}else{setTimeout(function(){d.disableFormElements(e)},13)}});a(document).delegate(d.formInputClickSelector,"click.rails",function(b){var c=a(this);if(!d.allowAction(c))return d.stopEverything(b);var e=c.attr("name"),f=e?{name:e,value:c.val()}:null;c.closest("form").data("ujs:submit-button",f)});a(document).delegate(d.formSubmitSelector,"ajax:beforeSend.rails",function(b){if(this==b.target)d.disableFormElements(a(this))});a(document).delegate(d.formSubmitSelector,"ajax:complete.rails",function(b){if(this==b.target)d.enableFormElements(a(this))});a(function(){csrf_token=a("meta[name=csrf-token]").attr("content");csrf_param=a("meta[name=csrf-param]").attr("content");a('form input[name="'+csrf_param+'"]').val(csrf_token)})}})(jQuery) diff --git a/public/katex/README.md b/public/katex/README.md new file mode 100644 index 000000000..e839f4c2b --- /dev/null +++ b/public/katex/README.md @@ -0,0 +1,68 @@ +# [KaTeX](https://khan.github.io/KaTeX/) [![Build Status](https://travis-ci.org/Khan/KaTeX.svg?branch=master)](https://travis-ci.org/Khan/KaTeX) + +[![Join the chat at https://gitter.im/Khan/KaTeX](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Khan/KaTeX?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web. + + * **Fast:** KaTeX renders its math synchronously and doesn't need to reflow the page. See how it compares to a competitor in [this speed test](http://jsperf.com/katex-vs-mathjax/). + * **Print quality:** KaTeX’s layout is based on Donald Knuth’s TeX, the gold standard for math typesetting. + * **Self contained:** KaTeX has no dependencies and can easily be bundled with your website resources. + * **Server side rendering:** KaTeX produces the same output regardless of browser or environment, so you can pre-render expressions using Node.js and send them as plain HTML. + +KaTeX supports all major browsers, including Chrome, Safari, Firefox, Opera, and IE 8 - IE 11. A list of supported commands can be on the [wiki](https://github.com/Khan/KaTeX/wiki/Function-Support-in-KaTeX). + +## Usage + +You can [download KaTeX](https://github.com/khan/katex/releases) and host it on your server or include the `katex.min.js` and `katex.min.css` files on your page directly from a CDN: + +```html + + +``` + +#### In-browser rendering + +Call `katex.render` with a TeX expression and a DOM element to render into: + +```js +katex.render("c = \\pm\\sqrt{a^2 + b^2}", element); +``` + +If KaTeX can't parse the expression, it throws a `katex.ParseError` error. + +#### Server side rendering or rendering to a string + +To generate HTML on the server or to generate an HTML string of the rendered math, you can use `katex.renderToString`: + +```js +var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}"); +// '...' +``` + +Make sure to include the CSS and font files, but there is no need to include the JavaScript. Like `render`, `renderToString` throws if it can't parse the expression. + +#### Rendering options + +You can provide an object of options as the last argument to `katex.render` and `katex.renderToString`. Available options are: + +- `displayMode`: `boolean`. If `true` the math will be rendered in display mode, which will put the math in display style (so `\int` and `\sum` are large, for example), and will center the math on the page on its own line. If `false` the math will be rendered in inline mode. (default: `false`) +- `throwOnError`: `boolean`. If `true`, KaTeX will throw a `ParseError` when it encounters an unsupported command. If `false`, KaTeX will render the unsupported command as text in the color given by `errorColor`. (default: `true`) +- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color which unsupported commands are rendered in. (default: `#cc0000`) + +For example: + +```js +katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { displayMode: true }); +``` + +#### Automatic rendering of math on a page + +Math on the page can be automatically rendered using the auto-render extension. See [the Auto-render README](contrib/auto-render/README.md) for more information. + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) + +## License + +KaTeX is licensed under the [MIT License](http://opensource.org/licenses/MIT). diff --git a/public/katex/contrib/auto-render.min.js b/public/katex/contrib/auto-render.min.js new file mode 100644 index 000000000..ba2fef1f4 --- /dev/null +++ b/public/katex/contrib/auto-render.min.js @@ -0,0 +1 @@ +(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.renderMathInElement=e()}})(function(){var e,t,r;return function n(e,t,r){function a(o,l){if(!t[o]){if(!e[o]){var f=typeof require=="function"&&require;if(!l&&f)return f(o,!0);if(i)return i(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var s=t[o]={exports:{}};e[o][0].call(s.exports,function(t){var r=e[o][1][t];return a(r?r:t)},s,s.exports,n,e,t,r)}return t[o].exports}var i=typeof require=="function"&&require;for(var o=0;o .katex { + display: inline-block; + text-align: initial; +} +.katex { + font: normal 1.21em KaTeX_Main, Times New Roman, serif; + line-height: 1.2; + white-space: nowrap; + text-indent: 0; +} +.katex .katex-html { + display: inline-block; +} +.katex .katex-mathml { + position: absolute; + clip: rect(1px, 1px, 1px, 1px); + padding: 0; + border: 0; + height: 1px; + width: 1px; + overflow: hidden; +} +.katex .base { + display: inline-block; +} +.katex .strut { + display: inline-block; +} +.katex .mathrm { + font-style: normal; +} +.katex .textit { + font-style: italic; +} +.katex .mathit { + font-family: KaTeX_Math; + font-style: italic; +} +.katex .mathbf { + font-family: KaTeX_Main; + font-weight: bold; +} +.katex .amsrm { + font-family: KaTeX_AMS; +} +.katex .mathbb { + font-family: KaTeX_AMS; +} +.katex .mathcal { + font-family: KaTeX_Caligraphic; +} +.katex .mathfrak { + font-family: KaTeX_Fraktur; +} +.katex .mathtt { + font-family: KaTeX_Typewriter; +} +.katex .mathscr { + font-family: KaTeX_Script; +} +.katex .mathsf { + font-family: KaTeX_SansSerif; +} +.katex .mainit { + font-family: KaTeX_Main; + font-style: italic; +} +.katex .mord + .mop { + margin-left: 0.16667em; +} +.katex .mord + .mbin { + margin-left: 0.22222em; +} +.katex .mord + .mrel { + margin-left: 0.27778em; +} +.katex .mord + .minner { + margin-left: 0.16667em; +} +.katex .mop + .mord { + margin-left: 0.16667em; +} +.katex .mop + .mop { + margin-left: 0.16667em; +} +.katex .mop + .mrel { + margin-left: 0.27778em; +} +.katex .mop + .minner { + margin-left: 0.16667em; +} +.katex .mbin + .mord { + margin-left: 0.22222em; +} +.katex .mbin + .mop { + margin-left: 0.22222em; +} +.katex .mbin + .mopen { + margin-left: 0.22222em; +} +.katex .mbin + .minner { + margin-left: 0.22222em; +} +.katex .mrel + .mord { + margin-left: 0.27778em; +} +.katex .mrel + .mop { + margin-left: 0.27778em; +} +.katex .mrel + .mopen { + margin-left: 0.27778em; +} +.katex .mrel + .minner { + margin-left: 0.27778em; +} +.katex .mclose + .mop { + margin-left: 0.16667em; +} +.katex .mclose + .mbin { + margin-left: 0.22222em; +} +.katex .mclose + .mrel { + margin-left: 0.27778em; +} +.katex .mclose + .minner { + margin-left: 0.16667em; +} +.katex .mpunct + .mord { + margin-left: 0.16667em; +} +.katex .mpunct + .mop { + margin-left: 0.16667em; +} +.katex .mpunct + .mrel { + margin-left: 0.16667em; +} +.katex .mpunct + .mopen { + margin-left: 0.16667em; +} +.katex .mpunct + .mclose { + margin-left: 0.16667em; +} +.katex .mpunct + .mpunct { + margin-left: 0.16667em; +} +.katex .mpunct + .minner { + margin-left: 0.16667em; +} +.katex .minner + .mord { + margin-left: 0.16667em; +} +.katex .minner + .mop { + margin-left: 0.16667em; +} +.katex .minner + .mbin { + margin-left: 0.22222em; +} +.katex .minner + .mrel { + margin-left: 0.27778em; +} +.katex .minner + .mopen { + margin-left: 0.16667em; +} +.katex .minner + .mpunct { + margin-left: 0.16667em; +} +.katex .minner + .minner { + margin-left: 0.16667em; +} +.katex .mord.mtight { + margin-left: 0; +} +.katex .mop.mtight { + margin-left: 0; +} +.katex .mbin.mtight { + margin-left: 0; +} +.katex .mrel.mtight { + margin-left: 0; +} +.katex .mopen.mtight { + margin-left: 0; +} +.katex .mclose.mtight { + margin-left: 0; +} +.katex .mpunct.mtight { + margin-left: 0; +} +.katex .minner.mtight { + margin-left: 0; +} +.katex .mord + .mop.mtight { + margin-left: 0.16667em; +} +.katex .mop + .mord.mtight { + margin-left: 0.16667em; +} +.katex .mop + .mop.mtight { + margin-left: 0.16667em; +} +.katex .mclose + .mop.mtight { + margin-left: 0.16667em; +} +.katex .minner + .mop.mtight { + margin-left: 0.16667em; +} +.katex .reset-textstyle.textstyle { + font-size: 1em; +} +.katex .reset-textstyle.scriptstyle { + font-size: 0.7em; +} +.katex .reset-textstyle.scriptscriptstyle { + font-size: 0.5em; +} +.katex .reset-scriptstyle.textstyle { + font-size: 1.42857em; +} +.katex .reset-scriptstyle.scriptstyle { + font-size: 1em; +} +.katex .reset-scriptstyle.scriptscriptstyle { + font-size: 0.71429em; +} +.katex .reset-scriptscriptstyle.textstyle { + font-size: 2em; +} +.katex .reset-scriptscriptstyle.scriptstyle { + font-size: 1.4em; +} +.katex .reset-scriptscriptstyle.scriptscriptstyle { + font-size: 1em; +} +.katex .style-wrap { + position: relative; +} +.katex .vlist { + display: inline-block; +} +.katex .vlist > span { + display: block; + height: 0; + position: relative; +} +.katex .vlist > span > span { + display: inline-block; +} +.katex .vlist .baseline-fix { + display: inline-table; + table-layout: fixed; +} +.katex .msupsub { + text-align: left; +} +.katex .mfrac > span > span { + text-align: center; +} +.katex .mfrac .frac-line { + width: 100%; +} +.katex .mfrac .frac-line:before { + border-bottom-style: solid; + border-bottom-width: 1px; + content: ""; + display: block; +} +.katex .mfrac .frac-line:after { + border-bottom-style: solid; + border-bottom-width: 0.04em; + content: ""; + display: block; + margin-top: -1px; +} +.katex .mspace { + display: inline-block; +} +.katex .mspace.negativethinspace { + margin-left: -0.16667em; +} +.katex .mspace.thinspace { + width: 0.16667em; +} +.katex .mspace.negativemediumspace { + margin-left: -0.22222em; +} +.katex .mspace.mediumspace { + width: 0.22222em; +} +.katex .mspace.thickspace { + width: 0.27778em; +} +.katex .mspace.sixmuspace { + width: 0.333333em; +} +.katex .mspace.eightmuspace { + width: 0.444444em; +} +.katex .mspace.enspace { + width: 0.5em; +} +.katex .mspace.twelvemuspace { + width: 0.666667em; +} +.katex .mspace.quad { + width: 1em; +} +.katex .mspace.qquad { + width: 2em; +} +.katex .llap, +.katex .rlap { + width: 0; + position: relative; +} +.katex .llap > .inner, +.katex .rlap > .inner { + position: absolute; +} +.katex .llap > .fix, +.katex .rlap > .fix { + display: inline-block; +} +.katex .llap > .inner { + right: 0; +} +.katex .rlap > .inner { + left: 0; +} +.katex .katex-logo .a { + font-size: 0.75em; + margin-left: -0.32em; + position: relative; + top: -0.2em; +} +.katex .katex-logo .t { + margin-left: -0.23em; +} +.katex .katex-logo .e { + margin-left: -0.1667em; + position: relative; + top: 0.2155em; +} +.katex .katex-logo .x { + margin-left: -0.125em; +} +.katex .rule { + display: inline-block; + border: solid 0; + position: relative; +} +.katex .overline .overline-line, +.katex .underline .underline-line { + width: 100%; +} +.katex .overline .overline-line:before, +.katex .underline .underline-line:before { + border-bottom-style: solid; + border-bottom-width: 1px; + content: ""; + display: block; +} +.katex .overline .overline-line:after, +.katex .underline .underline-line:after { + border-bottom-style: solid; + border-bottom-width: 0.04em; + content: ""; + display: block; + margin-top: -1px; +} +.katex .sqrt > .sqrt-sign { + position: relative; +} +.katex .sqrt .sqrt-line { + width: 100%; +} +.katex .sqrt .sqrt-line:before { + border-bottom-style: solid; + border-bottom-width: 1px; + content: ""; + display: block; +} +.katex .sqrt .sqrt-line:after { + border-bottom-style: solid; + border-bottom-width: 0.04em; + content: ""; + display: block; + margin-top: -1px; +} +.katex .sqrt > .root { + margin-left: 0.27777778em; + margin-right: -0.55555556em; +} +.katex .sizing, +.katex .fontsize-ensurer { + display: inline-block; +} +.katex .sizing.reset-size1.size1, +.katex .fontsize-ensurer.reset-size1.size1 { + font-size: 1em; +} +.katex .sizing.reset-size1.size2, +.katex .fontsize-ensurer.reset-size1.size2 { + font-size: 1.4em; +} +.katex .sizing.reset-size1.size3, +.katex .fontsize-ensurer.reset-size1.size3 { + font-size: 1.6em; +} +.katex .sizing.reset-size1.size4, +.katex .fontsize-ensurer.reset-size1.size4 { + font-size: 1.8em; +} +.katex .sizing.reset-size1.size5, +.katex .fontsize-ensurer.reset-size1.size5 { + font-size: 2em; +} +.katex .sizing.reset-size1.size6, +.katex .fontsize-ensurer.reset-size1.size6 { + font-size: 2.4em; +} +.katex .sizing.reset-size1.size7, +.katex .fontsize-ensurer.reset-size1.size7 { + font-size: 2.88em; +} +.katex .sizing.reset-size1.size8, +.katex .fontsize-ensurer.reset-size1.size8 { + font-size: 3.46em; +} +.katex .sizing.reset-size1.size9, +.katex .fontsize-ensurer.reset-size1.size9 { + font-size: 4.14em; +} +.katex .sizing.reset-size1.size10, +.katex .fontsize-ensurer.reset-size1.size10 { + font-size: 4.98em; +} +.katex .sizing.reset-size2.size1, +.katex .fontsize-ensurer.reset-size2.size1 { + font-size: 0.71428571em; +} +.katex .sizing.reset-size2.size2, +.katex .fontsize-ensurer.reset-size2.size2 { + font-size: 1em; +} +.katex .sizing.reset-size2.size3, +.katex .fontsize-ensurer.reset-size2.size3 { + font-size: 1.14285714em; +} +.katex .sizing.reset-size2.size4, +.katex .fontsize-ensurer.reset-size2.size4 { + font-size: 1.28571429em; +} +.katex .sizing.reset-size2.size5, +.katex .fontsize-ensurer.reset-size2.size5 { + font-size: 1.42857143em; +} +.katex .sizing.reset-size2.size6, +.katex .fontsize-ensurer.reset-size2.size6 { + font-size: 1.71428571em; +} +.katex .sizing.reset-size2.size7, +.katex .fontsize-ensurer.reset-size2.size7 { + font-size: 2.05714286em; +} +.katex .sizing.reset-size2.size8, +.katex .fontsize-ensurer.reset-size2.size8 { + font-size: 2.47142857em; +} +.katex .sizing.reset-size2.size9, +.katex .fontsize-ensurer.reset-size2.size9 { + font-size: 2.95714286em; +} +.katex .sizing.reset-size2.size10, +.katex .fontsize-ensurer.reset-size2.size10 { + font-size: 3.55714286em; +} +.katex .sizing.reset-size3.size1, +.katex .fontsize-ensurer.reset-size3.size1 { + font-size: 0.625em; +} +.katex .sizing.reset-size3.size2, +.katex .fontsize-ensurer.reset-size3.size2 { + font-size: 0.875em; +} +.katex .sizing.reset-size3.size3, +.katex .fontsize-ensurer.reset-size3.size3 { + font-size: 1em; +} +.katex .sizing.reset-size3.size4, +.katex .fontsize-ensurer.reset-size3.size4 { + font-size: 1.125em; +} +.katex .sizing.reset-size3.size5, +.katex .fontsize-ensurer.reset-size3.size5 { + font-size: 1.25em; +} +.katex .sizing.reset-size3.size6, +.katex .fontsize-ensurer.reset-size3.size6 { + font-size: 1.5em; +} +.katex .sizing.reset-size3.size7, +.katex .fontsize-ensurer.reset-size3.size7 { + font-size: 1.8em; +} +.katex .sizing.reset-size3.size8, +.katex .fontsize-ensurer.reset-size3.size8 { + font-size: 2.1625em; +} +.katex .sizing.reset-size3.size9, +.katex .fontsize-ensurer.reset-size3.size9 { + font-size: 2.5875em; +} +.katex .sizing.reset-size3.size10, +.katex .fontsize-ensurer.reset-size3.size10 { + font-size: 3.1125em; +} +.katex .sizing.reset-size4.size1, +.katex .fontsize-ensurer.reset-size4.size1 { + font-size: 0.55555556em; +} +.katex .sizing.reset-size4.size2, +.katex .fontsize-ensurer.reset-size4.size2 { + font-size: 0.77777778em; +} +.katex .sizing.reset-size4.size3, +.katex .fontsize-ensurer.reset-size4.size3 { + font-size: 0.88888889em; +} +.katex .sizing.reset-size4.size4, +.katex .fontsize-ensurer.reset-size4.size4 { + font-size: 1em; +} +.katex .sizing.reset-size4.size5, +.katex .fontsize-ensurer.reset-size4.size5 { + font-size: 1.11111111em; +} +.katex .sizing.reset-size4.size6, +.katex .fontsize-ensurer.reset-size4.size6 { + font-size: 1.33333333em; +} +.katex .sizing.reset-size4.size7, +.katex .fontsize-ensurer.reset-size4.size7 { + font-size: 1.6em; +} +.katex .sizing.reset-size4.size8, +.katex .fontsize-ensurer.reset-size4.size8 { + font-size: 1.92222222em; +} +.katex .sizing.reset-size4.size9, +.katex .fontsize-ensurer.reset-size4.size9 { + font-size: 2.3em; +} +.katex .sizing.reset-size4.size10, +.katex .fontsize-ensurer.reset-size4.size10 { + font-size: 2.76666667em; +} +.katex .sizing.reset-size5.size1, +.katex .fontsize-ensurer.reset-size5.size1 { + font-size: 0.5em; +} +.katex .sizing.reset-size5.size2, +.katex .fontsize-ensurer.reset-size5.size2 { + font-size: 0.7em; +} +.katex .sizing.reset-size5.size3, +.katex .fontsize-ensurer.reset-size5.size3 { + font-size: 0.8em; +} +.katex .sizing.reset-size5.size4, +.katex .fontsize-ensurer.reset-size5.size4 { + font-size: 0.9em; +} +.katex .sizing.reset-size5.size5, +.katex .fontsize-ensurer.reset-size5.size5 { + font-size: 1em; +} +.katex .sizing.reset-size5.size6, +.katex .fontsize-ensurer.reset-size5.size6 { + font-size: 1.2em; +} +.katex .sizing.reset-size5.size7, +.katex .fontsize-ensurer.reset-size5.size7 { + font-size: 1.44em; +} +.katex .sizing.reset-size5.size8, +.katex .fontsize-ensurer.reset-size5.size8 { + font-size: 1.73em; +} +.katex .sizing.reset-size5.size9, +.katex .fontsize-ensurer.reset-size5.size9 { + font-size: 2.07em; +} +.katex .sizing.reset-size5.size10, +.katex .fontsize-ensurer.reset-size5.size10 { + font-size: 2.49em; +} +.katex .sizing.reset-size6.size1, +.katex .fontsize-ensurer.reset-size6.size1 { + font-size: 0.41666667em; +} +.katex .sizing.reset-size6.size2, +.katex .fontsize-ensurer.reset-size6.size2 { + font-size: 0.58333333em; +} +.katex .sizing.reset-size6.size3, +.katex .fontsize-ensurer.reset-size6.size3 { + font-size: 0.66666667em; +} +.katex .sizing.reset-size6.size4, +.katex .fontsize-ensurer.reset-size6.size4 { + font-size: 0.75em; +} +.katex .sizing.reset-size6.size5, +.katex .fontsize-ensurer.reset-size6.size5 { + font-size: 0.83333333em; +} +.katex .sizing.reset-size6.size6, +.katex .fontsize-ensurer.reset-size6.size6 { + font-size: 1em; +} +.katex .sizing.reset-size6.size7, +.katex .fontsize-ensurer.reset-size6.size7 { + font-size: 1.2em; +} +.katex .sizing.reset-size6.size8, +.katex .fontsize-ensurer.reset-size6.size8 { + font-size: 1.44166667em; +} +.katex .sizing.reset-size6.size9, +.katex .fontsize-ensurer.reset-size6.size9 { + font-size: 1.725em; +} +.katex .sizing.reset-size6.size10, +.katex .fontsize-ensurer.reset-size6.size10 { + font-size: 2.075em; +} +.katex .sizing.reset-size7.size1, +.katex .fontsize-ensurer.reset-size7.size1 { + font-size: 0.34722222em; +} +.katex .sizing.reset-size7.size2, +.katex .fontsize-ensurer.reset-size7.size2 { + font-size: 0.48611111em; +} +.katex .sizing.reset-size7.size3, +.katex .fontsize-ensurer.reset-size7.size3 { + font-size: 0.55555556em; +} +.katex .sizing.reset-size7.size4, +.katex .fontsize-ensurer.reset-size7.size4 { + font-size: 0.625em; +} +.katex .sizing.reset-size7.size5, +.katex .fontsize-ensurer.reset-size7.size5 { + font-size: 0.69444444em; +} +.katex .sizing.reset-size7.size6, +.katex .fontsize-ensurer.reset-size7.size6 { + font-size: 0.83333333em; +} +.katex .sizing.reset-size7.size7, +.katex .fontsize-ensurer.reset-size7.size7 { + font-size: 1em; +} +.katex .sizing.reset-size7.size8, +.katex .fontsize-ensurer.reset-size7.size8 { + font-size: 1.20138889em; +} +.katex .sizing.reset-size7.size9, +.katex .fontsize-ensurer.reset-size7.size9 { + font-size: 1.4375em; +} +.katex .sizing.reset-size7.size10, +.katex .fontsize-ensurer.reset-size7.size10 { + font-size: 1.72916667em; +} +.katex .sizing.reset-size8.size1, +.katex .fontsize-ensurer.reset-size8.size1 { + font-size: 0.28901734em; +} +.katex .sizing.reset-size8.size2, +.katex .fontsize-ensurer.reset-size8.size2 { + font-size: 0.40462428em; +} +.katex .sizing.reset-size8.size3, +.katex .fontsize-ensurer.reset-size8.size3 { + font-size: 0.46242775em; +} +.katex .sizing.reset-size8.size4, +.katex .fontsize-ensurer.reset-size8.size4 { + font-size: 0.52023121em; +} +.katex .sizing.reset-size8.size5, +.katex .fontsize-ensurer.reset-size8.size5 { + font-size: 0.57803468em; +} +.katex .sizing.reset-size8.size6, +.katex .fontsize-ensurer.reset-size8.size6 { + font-size: 0.69364162em; +} +.katex .sizing.reset-size8.size7, +.katex .fontsize-ensurer.reset-size8.size7 { + font-size: 0.83236994em; +} +.katex .sizing.reset-size8.size8, +.katex .fontsize-ensurer.reset-size8.size8 { + font-size: 1em; +} +.katex .sizing.reset-size8.size9, +.katex .fontsize-ensurer.reset-size8.size9 { + font-size: 1.19653179em; +} +.katex .sizing.reset-size8.size10, +.katex .fontsize-ensurer.reset-size8.size10 { + font-size: 1.43930636em; +} +.katex .sizing.reset-size9.size1, +.katex .fontsize-ensurer.reset-size9.size1 { + font-size: 0.24154589em; +} +.katex .sizing.reset-size9.size2, +.katex .fontsize-ensurer.reset-size9.size2 { + font-size: 0.33816425em; +} +.katex .sizing.reset-size9.size3, +.katex .fontsize-ensurer.reset-size9.size3 { + font-size: 0.38647343em; +} +.katex .sizing.reset-size9.size4, +.katex .fontsize-ensurer.reset-size9.size4 { + font-size: 0.43478261em; +} +.katex .sizing.reset-size9.size5, +.katex .fontsize-ensurer.reset-size9.size5 { + font-size: 0.48309179em; +} +.katex .sizing.reset-size9.size6, +.katex .fontsize-ensurer.reset-size9.size6 { + font-size: 0.57971014em; +} +.katex .sizing.reset-size9.size7, +.katex .fontsize-ensurer.reset-size9.size7 { + font-size: 0.69565217em; +} +.katex .sizing.reset-size9.size8, +.katex .fontsize-ensurer.reset-size9.size8 { + font-size: 0.83574879em; +} +.katex .sizing.reset-size9.size9, +.katex .fontsize-ensurer.reset-size9.size9 { + font-size: 1em; +} +.katex .sizing.reset-size9.size10, +.katex .fontsize-ensurer.reset-size9.size10 { + font-size: 1.20289855em; +} +.katex .sizing.reset-size10.size1, +.katex .fontsize-ensurer.reset-size10.size1 { + font-size: 0.20080321em; +} +.katex .sizing.reset-size10.size2, +.katex .fontsize-ensurer.reset-size10.size2 { + font-size: 0.2811245em; +} +.katex .sizing.reset-size10.size3, +.katex .fontsize-ensurer.reset-size10.size3 { + font-size: 0.32128514em; +} +.katex .sizing.reset-size10.size4, +.katex .fontsize-ensurer.reset-size10.size4 { + font-size: 0.36144578em; +} +.katex .sizing.reset-size10.size5, +.katex .fontsize-ensurer.reset-size10.size5 { + font-size: 0.40160643em; +} +.katex .sizing.reset-size10.size6, +.katex .fontsize-ensurer.reset-size10.size6 { + font-size: 0.48192771em; +} +.katex .sizing.reset-size10.size7, +.katex .fontsize-ensurer.reset-size10.size7 { + font-size: 0.57831325em; +} +.katex .sizing.reset-size10.size8, +.katex .fontsize-ensurer.reset-size10.size8 { + font-size: 0.69477912em; +} +.katex .sizing.reset-size10.size9, +.katex .fontsize-ensurer.reset-size10.size9 { + font-size: 0.8313253em; +} +.katex .sizing.reset-size10.size10, +.katex .fontsize-ensurer.reset-size10.size10 { + font-size: 1em; +} +.katex .delimsizing.size1 { + font-family: KaTeX_Size1; +} +.katex .delimsizing.size2 { + font-family: KaTeX_Size2; +} +.katex .delimsizing.size3 { + font-family: KaTeX_Size3; +} +.katex .delimsizing.size4 { + font-family: KaTeX_Size4; +} +.katex .delimsizing.mult .delim-size1 > span { + font-family: KaTeX_Size1; +} +.katex .delimsizing.mult .delim-size4 > span { + font-family: KaTeX_Size4; +} +.katex .nulldelimiter { + display: inline-block; + width: 0.12em; +} +.katex .op-symbol { + position: relative; +} +.katex .op-symbol.small-op { + font-family: KaTeX_Size1; +} +.katex .op-symbol.large-op { + font-family: KaTeX_Size2; +} +.katex .op-limits > .vlist > span { + text-align: center; +} +.katex .accent > .vlist > span { + text-align: center; +} +.katex .accent .accent-body > span { + width: 0; +} +.katex .accent .accent-body.accent-vec > span { + position: relative; + left: 0.326em; +} +.katex .mtable .vertical-separator { + display: inline-block; + margin: 0 -0.025em; + border-right: 0.05em solid black; +} +.katex .mtable .arraycolsep { + display: inline-block; +} +.katex .mtable .col-align-c > .vlist { + text-align: center; +} +.katex .mtable .col-align-l > .vlist { + text-align: left; +} +.katex .mtable .col-align-r > .vlist { + text-align: right; +} diff --git a/public/katex/katex.js b/public/katex/katex.js new file mode 100644 index 000000000..63d50d457 --- /dev/null +++ b/public/katex/katex.js @@ -0,0 +1,9075 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.katex = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 15) { + left = "…" + input.slice(start - 15, start); + } else { + left = input.slice(0, start); + } + var right; + if (end + 15 < input.length) { + right = input.slice(end, end + 15) + "…"; + } else { + right = input.slice(end); + } + error += left + underlined + right; + } + + // Some hackery to make ParseError a prototype of Error + // See http://stackoverflow.com/a/8460753 + var self = new Error(error); + self.name = "ParseError"; + self.__proto__ = ParseError.prototype; + + self.position = start; + return self; +} + +// More hackery +ParseError.prototype.__proto__ = Error.prototype; + +module.exports = ParseError; + +},{}],7:[function(require,module,exports){ +/* eslint no-constant-condition:0 */ +var functions = require("./functions"); +var environments = require("./environments"); +var MacroExpander = require("./MacroExpander"); +var symbols = require("./symbols"); +var utils = require("./utils"); +var cjkRegex = require("./unicodeRegexes").cjkRegex; + +var parseData = require("./parseData"); +var ParseError = require("./ParseError"); + +/** + * This file contains the parser used to parse out a TeX expression from the + * input. Since TeX isn't context-free, standard parsers don't work particularly + * well. + * + * The strategy of this parser is as such: + * + * The main functions (the `.parse...` ones) take a position in the current + * parse string to parse tokens from. The lexer (found in Lexer.js, stored at + * this.lexer) also supports pulling out tokens at arbitrary places. When + * individual tokens are needed at a position, the lexer is called to pull out a + * token, which is then used. + * + * The parser has a property called "mode" indicating the mode that + * the parser is currently in. Currently it has to be one of "math" or + * "text", which denotes whether the current environment is a math-y + * one or a text-y one (e.g. inside \text). Currently, this serves to + * limit the functions which can be used in text mode. + * + * The main functions then return an object which contains the useful data that + * was parsed at its given point, and a new position at the end of the parsed + * data. The main functions can call each other and continue the parsing by + * using the returned position as a new starting point. + * + * There are also extra `.handle...` functions, which pull out some reused + * functionality into self-contained functions. + * + * The earlier functions return ParseNodes. + * The later functions (which are called deeper in the parse) sometimes return + * ParseFuncOrArgument, which contain a ParseNode as well as some data about + * whether the parsed object is a function which is missing some arguments, or a + * standalone object which can be used as an argument to another function. + */ + +/** + * Main Parser class + */ +function Parser(input, settings) { + // Create a new macro expander (gullet) and (indirectly via that) also a + // new lexer (mouth) for this parser (stomach, in the language of TeX) + this.gullet = new MacroExpander(input, settings.macros); + // Store the settings for use in parsing + this.settings = settings; + // Count leftright depth (for \middle errors) + this.leftrightDepth = 0; +} + +var ParseNode = parseData.ParseNode; + +/** + * An initial function (without its arguments), or an argument to a function. + * The `result` argument should be a ParseNode. + */ +function ParseFuncOrArgument(result, isFunction, token) { + this.result = result; + // Is this a function (i.e. is it something defined in functions.js)? + this.isFunction = isFunction; + this.token = token; +} + +/** + * Checks a result to make sure it has the right type, and throws an + * appropriate error otherwise. + * + * @param {boolean=} consume whether to consume the expected token, + * defaults to true + */ +Parser.prototype.expect = function(text, consume) { + if (this.nextToken.text !== text) { + throw new ParseError( + "Expected '" + text + "', got '" + this.nextToken.text + "'", + this.nextToken + ); + } + if (consume !== false) { + this.consume(); + } +}; + +/** + * Considers the current look ahead token as consumed, + * and fetches the one after that as the new look ahead. + */ +Parser.prototype.consume = function() { + this.nextToken = this.gullet.get(this.mode === "math"); +}; + +Parser.prototype.switchMode = function(newMode) { + this.gullet.unget(this.nextToken); + this.mode = newMode; + this.consume(); +}; + +/** + * Main parsing function, which parses an entire input. + * + * @return {?Array.} + */ +Parser.prototype.parse = function() { + // Try to parse the input + this.mode = "math"; + this.consume(); + var parse = this.parseInput(); + return parse; +}; + +/** + * Parses an entire input tree. + */ +Parser.prototype.parseInput = function() { + // Parse an expression + var expression = this.parseExpression(false); + // If we succeeded, make sure there's an EOF at the end + this.expect("EOF", false); + return expression; +}; + +var endOfExpression = ["}", "\\end", "\\right", "&", "\\\\", "\\cr"]; + +/** + * Parses an "expression", which is a list of atoms. + * + * @param {boolean} breakOnInfix Should the parsing stop when we hit infix + * nodes? This happens when functions have higher precendence + * than infix nodes in implicit parses. + * + * @param {?string} breakOnTokenText The text of the token that the expression + * should end with, or `null` if something else should end the + * expression. + * + * @return {ParseNode} + */ +Parser.prototype.parseExpression = function(breakOnInfix, breakOnTokenText) { + var body = []; + // Keep adding atoms to the body until we can't parse any more atoms (either + // we reached the end, a }, or a \right) + while (true) { + var lex = this.nextToken; + if (endOfExpression.indexOf(lex.text) !== -1) { + break; + } + if (breakOnTokenText && lex.text === breakOnTokenText) { + break; + } + if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) { + break; + } + var atom = this.parseAtom(); + if (!atom) { + if (!this.settings.throwOnError && lex.text[0] === "\\") { + var errorNode = this.handleUnsupportedCmd(); + body.push(errorNode); + continue; + } + + break; + } + body.push(atom); + } + return this.handleInfixNodes(body); +}; + +/** + * Rewrites infix operators such as \over with corresponding commands such + * as \frac. + * + * There can only be one infix operator per group. If there's more than one + * then the expression is ambiguous. This can be resolved by adding {}. + * + * @returns {Array} + */ +Parser.prototype.handleInfixNodes = function(body) { + var overIndex = -1; + var funcName; + + for (var i = 0; i < body.length; i++) { + var node = body[i]; + if (node.type === "infix") { + if (overIndex !== -1) { + throw new ParseError( + "only one infix operator per group", + node.value.token); + } + overIndex = i; + funcName = node.value.replaceWith; + } + } + + if (overIndex !== -1) { + var numerNode; + var denomNode; + + var numerBody = body.slice(0, overIndex); + var denomBody = body.slice(overIndex + 1); + + if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { + numerNode = numerBody[0]; + } else { + numerNode = new ParseNode("ordgroup", numerBody, this.mode); + } + + if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { + denomNode = denomBody[0]; + } else { + denomNode = new ParseNode("ordgroup", denomBody, this.mode); + } + + var value = this.callFunction( + funcName, [numerNode, denomNode], null); + return [new ParseNode(value.type, value, this.mode)]; + } else { + return body; + } +}; + +// The greediness of a superscript or subscript +var SUPSUB_GREEDINESS = 1; + +/** + * Handle a subscript or superscript with nice errors. + */ +Parser.prototype.handleSupSubscript = function(name) { + var symbolToken = this.nextToken; + var symbol = symbolToken.text; + this.consume(); + var group = this.parseGroup(); + + if (!group) { + if (!this.settings.throwOnError && this.nextToken.text[0] === "\\") { + return this.handleUnsupportedCmd(); + } else { + throw new ParseError( + "Expected group after '" + symbol + "'", + symbolToken + ); + } + } else if (group.isFunction) { + // ^ and _ have a greediness, so handle interactions with functions' + // greediness + var funcGreediness = functions[group.result].greediness; + if (funcGreediness > SUPSUB_GREEDINESS) { + return this.parseFunction(group); + } else { + throw new ParseError( + "Got function '" + group.result + "' with no arguments " + + "as " + name, symbolToken); + } + } else { + return group.result; + } +}; + +/** + * Converts the textual input of an unsupported command into a text node + * contained within a color node whose color is determined by errorColor + */ +Parser.prototype.handleUnsupportedCmd = function() { + var text = this.nextToken.text; + var textordArray = []; + + for (var i = 0; i < text.length; i++) { + textordArray.push(new ParseNode("textord", text[i], "text")); + } + + var textNode = new ParseNode( + "text", + { + body: textordArray, + type: "text" + }, + this.mode); + + var colorNode = new ParseNode( + "color", + { + color: this.settings.errorColor, + value: [textNode], + type: "color" + }, + this.mode); + + this.consume(); + return colorNode; +}; + +/** + * Parses a group with optional super/subscripts. + * + * @return {?ParseNode} + */ +Parser.prototype.parseAtom = function() { + // The body of an atom is an implicit group, so that things like + // \left(x\right)^2 work correctly. + var base = this.parseImplicitGroup(); + + // In text mode, we don't have superscripts or subscripts + if (this.mode === "text") { + return base; + } + + // Note that base may be empty (i.e. null) at this point. + + var superscript; + var subscript; + while (true) { + // Lex the first token + var lex = this.nextToken; + + if (lex.text === "\\limits" || lex.text === "\\nolimits") { + // We got a limit control + if (!base || base.type !== "op") { + throw new ParseError( + "Limit controls must follow a math operator", + lex); + } else { + var limits = lex.text === "\\limits"; + base.value.limits = limits; + base.value.alwaysHandleSupSub = true; + } + this.consume(); + } else if (lex.text === "^") { + // We got a superscript start + if (superscript) { + throw new ParseError("Double superscript", lex); + } + superscript = this.handleSupSubscript("superscript"); + } else if (lex.text === "_") { + // We got a subscript start + if (subscript) { + throw new ParseError("Double subscript", lex); + } + subscript = this.handleSupSubscript("subscript"); + } else if (lex.text === "'") { + // We got a prime + var prime = new ParseNode("textord", "\\prime", this.mode); + + // Many primes can be grouped together, so we handle this here + var primes = [prime]; + this.consume(); + // Keep lexing tokens until we get something that's not a prime + while (this.nextToken.text === "'") { + // For each one, add another prime to the list + primes.push(prime); + this.consume(); + } + // Put them into an ordgroup as the superscript + superscript = new ParseNode("ordgroup", primes, this.mode); + } else { + // If it wasn't ^, _, or ', stop parsing super/subscripts + break; + } + } + + if (superscript || subscript) { + // If we got either a superscript or subscript, create a supsub + return new ParseNode("supsub", { + base: base, + sup: superscript, + sub: subscript + }, this.mode); + } else { + // Otherwise return the original body + return base; + } +}; + +// A list of the size-changing functions, for use in parseImplicitGroup +var sizeFuncs = [ + "\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize", + "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge" +]; + +// A list of the style-changing functions, for use in parseImplicitGroup +var styleFuncs = [ + "\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle" +]; + +/** + * Parses an implicit group, which is a group that starts at the end of a + * specified, and ends right before a higher explicit group ends, or at EOL. It + * is used for functions that appear to affect the current style, like \Large or + * \textrm, where instead of keeping a style we just pretend that there is an + * implicit grouping after it until the end of the group. E.g. + * small text {\Large large text} small text again + * It is also used for \left and \right to get the correct grouping. + * + * @return {?ParseNode} + */ +Parser.prototype.parseImplicitGroup = function() { + var start = this.parseSymbol(); + + if (start == null) { + // If we didn't get anything we handle, fall back to parseFunction + return this.parseFunction(); + } + + var func = start.result; + var body; + + if (func === "\\left") { + // If we see a left: + // Parse the entire left function (including the delimiter) + var left = this.parseFunction(start); + // Parse out the implicit body + ++this.leftrightDepth; + body = this.parseExpression(false); + --this.leftrightDepth; + // Check the next token + this.expect("\\right", false); + var right = this.parseFunction(); + return new ParseNode("leftright", { + body: body, + left: left.value.value, + right: right.value.value + }, this.mode); + } else if (func === "\\begin") { + // begin...end is similar to left...right + var begin = this.parseFunction(start); + var envName = begin.value.name; + if (!environments.hasOwnProperty(envName)) { + throw new ParseError( + "No such environment: " + envName, begin.value.nameGroup); + } + // Build the environment object. Arguments and other information will + // be made available to the begin and end methods using properties. + var env = environments[envName]; + var args = this.parseArguments("\\begin{" + envName + "}", env); + var context = { + mode: this.mode, + envName: envName, + parser: this, + positions: args.pop() + }; + var result = env.handler(context, args); + this.expect("\\end", false); + var endNameToken = this.nextToken; + var end = this.parseFunction(); + if (end.value.name !== envName) { + throw new ParseError( + "Mismatch: \\begin{" + envName + "} matched " + + "by \\end{" + end.value.name + "}", + endNameToken); + } + result.position = end.position; + return result; + } else if (utils.contains(sizeFuncs, func)) { + // If we see a sizing function, parse out the implict body + body = this.parseExpression(false); + return new ParseNode("sizing", { + // Figure out what size to use based on the list of functions above + size: "size" + (utils.indexOf(sizeFuncs, func) + 1), + value: body + }, this.mode); + } else if (utils.contains(styleFuncs, func)) { + // If we see a styling function, parse out the implict body + body = this.parseExpression(true); + return new ParseNode("styling", { + // Figure out what style to use by pulling out the style from + // the function name + style: func.slice(1, func.length - 5), + value: body + }, this.mode); + } else { + // Defer to parseFunction if it's not a function we handle + return this.parseFunction(start); + } +}; + +/** + * Parses an entire function, including its base and all of its arguments. + * The base might either have been parsed already, in which case + * it is provided as an argument, or it's the next group in the input. + * + * @param {ParseFuncOrArgument=} baseGroup optional as described above + * @return {?ParseNode} + */ +Parser.prototype.parseFunction = function(baseGroup) { + if (!baseGroup) { + baseGroup = this.parseGroup(); + } + + if (baseGroup) { + if (baseGroup.isFunction) { + var func = baseGroup.result; + var funcData = functions[func]; + if (this.mode === "text" && !funcData.allowedInText) { + throw new ParseError( + "Can't use function '" + func + "' in text mode", + baseGroup.token); + } + + var args = this.parseArguments(func, funcData); + var token = baseGroup.token; + var result = this.callFunction(func, args, args.pop(), token); + return new ParseNode(result.type, result, this.mode); + } else { + return baseGroup.result; + } + } else { + return null; + } +}; + +/** + * Call a function handler with a suitable context and arguments. + */ +Parser.prototype.callFunction = function(name, args, positions, token) { + var context = { + funcName: name, + parser: this, + positions: positions, + token: token + }; + return functions[name].handler(context, args); +}; + +/** + * Parses the arguments of a function or environment + * + * @param {string} func "\name" or "\begin{name}" + * @param {{numArgs:number,numOptionalArgs:number|undefined}} funcData + * @return the array of arguments, with the list of positions as last element + */ +Parser.prototype.parseArguments = function(func, funcData) { + var totalArgs = funcData.numArgs + funcData.numOptionalArgs; + if (totalArgs === 0) { + return [[this.pos]]; + } + + var baseGreediness = funcData.greediness; + var positions = [this.pos]; + var args = []; + + for (var i = 0; i < totalArgs; i++) { + var nextToken = this.nextToken; + var argType = funcData.argTypes && funcData.argTypes[i]; + var arg; + if (i < funcData.numOptionalArgs) { + if (argType) { + arg = this.parseGroupOfType(argType, true); + } else { + arg = this.parseGroup(true); + } + if (!arg) { + args.push(null); + positions.push(this.pos); + continue; + } + } else { + if (argType) { + arg = this.parseGroupOfType(argType); + } else { + arg = this.parseGroup(); + } + if (!arg) { + if (!this.settings.throwOnError && + this.nextToken.text[0] === "\\") { + arg = new ParseFuncOrArgument( + this.handleUnsupportedCmd(this.nextToken.text), + false); + } else { + throw new ParseError( + "Expected group after '" + func + "'", nextToken); + } + } + } + var argNode; + if (arg.isFunction) { + var argGreediness = + functions[arg.result].greediness; + if (argGreediness > baseGreediness) { + argNode = this.parseFunction(arg); + } else { + throw new ParseError( + "Got function '" + arg.result + "' as " + + "argument to '" + func + "'", nextToken); + } + } else { + argNode = arg.result; + } + args.push(argNode); + positions.push(this.pos); + } + + args.push(positions); + + return args; +}; + + +/** + * Parses a group when the mode is changing. + * + * @return {?ParseFuncOrArgument} + */ +Parser.prototype.parseGroupOfType = function(innerMode, optional) { + var outerMode = this.mode; + // Handle `original` argTypes + if (innerMode === "original") { + innerMode = outerMode; + } + + if (innerMode === "color") { + return this.parseColorGroup(optional); + } + if (innerMode === "size") { + return this.parseSizeGroup(optional); + } + + this.switchMode(innerMode); + if (innerMode === "text") { + // text mode is special because it should ignore the whitespace before + // it + while (this.nextToken.text === " ") { + this.consume(); + } + } + // By the time we get here, innerMode is one of "text" or "math". + // We switch the mode of the parser, recurse, then restore the old mode. + var res = this.parseGroup(optional); + this.switchMode(outerMode); + return res; +}; + +/** + * Parses a group, essentially returning the string formed by the + * brace-enclosed tokens plus some position information. + * + * @param {string} modeName Used to describe the mode in error messages + * @param {boolean=} optional Whether the group is optional or required + */ +Parser.prototype.parseStringGroup = function(modeName, optional) { + if (optional && this.nextToken.text !== "[") { + return null; + } + var outerMode = this.mode; + this.mode = "text"; + this.expect(optional ? "[" : "{"); + var str = ""; + var firstToken = this.nextToken; + var lastToken = firstToken; + while (this.nextToken.text !== (optional ? "]" : "}")) { + if (this.nextToken.text === "EOF") { + throw new ParseError( + "Unexpected end of input in " + modeName, + firstToken.range(this.nextToken, str)); + } + lastToken = this.nextToken; + str += lastToken.text; + this.consume(); + } + this.mode = outerMode; + this.expect(optional ? "]" : "}"); + return firstToken.range(lastToken, str); +}; + +/** + * Parses a regex-delimited group: the largest sequence of tokens + * whose concatenated strings match `regex`. Returns the string + * formed by the tokens plus some position information. + * + * @param {RegExp} regex + * @param {string} modeName Used to describe the mode in error messages + */ +Parser.prototype.parseRegexGroup = function(regex, modeName) { + var outerMode = this.mode; + this.mode = "text"; + var firstToken = this.nextToken; + var lastToken = firstToken; + var str = ""; + while (this.nextToken.text !== "EOF" + && regex.test(str + this.nextToken.text)) { + lastToken = this.nextToken; + str += lastToken.text; + this.consume(); + } + if (str === "") { + throw new ParseError( + "Invalid " + modeName + ": '" + firstToken.text + "'", + firstToken); + } + this.mode = outerMode; + return firstToken.range(lastToken, str); +}; + +/** + * Parses a color description. + */ +Parser.prototype.parseColorGroup = function(optional) { + var res = this.parseStringGroup("color", optional); + if (!res) { + return null; + } + var match = (/^(#[a-z0-9]+|[a-z]+)$/i).exec(res.text); + if (!match) { + throw new ParseError("Invalid color: '" + res.text + "'", res); + } + return new ParseFuncOrArgument( + new ParseNode("color", match[0], this.mode), + false); +}; + +/** + * Parses a size specification, consisting of magnitude and unit. + */ +Parser.prototype.parseSizeGroup = function(optional) { + var res; + if (!optional && this.nextToken.text !== "{") { + res = this.parseRegexGroup( + /^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2}$/, "size"); + } else { + res = this.parseStringGroup("size", optional); + } + if (!res) { + return null; + } + var match = (/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/).exec(res.text); + if (!match) { + throw new ParseError("Invalid size: '" + res.text + "'", res); + } + var data = { + number: +(match[1] + match[2]), // sign + magnitude, cast to number + unit: match[3] + }; + if (data.unit !== "em" && data.unit !== "ex" && data.unit !== "mu") { + throw new ParseError("Invalid unit: '" + data.unit + "'", res); + } + return new ParseFuncOrArgument( + new ParseNode("color", data, this.mode), + false); +}; + +/** + * If the argument is false or absent, this parses an ordinary group, + * which is either a single nucleus (like "x") or an expression + * in braces (like "{x+y}"). + * If the argument is true, it parses either a bracket-delimited expression + * (like "[x+y]") or returns null to indicate the absence of a + * bracket-enclosed group. + * + * @param {boolean=} optional Whether the group is optional or required + * @return {?ParseFuncOrArgument} + */ +Parser.prototype.parseGroup = function(optional) { + var firstToken = this.nextToken; + // Try to parse an open brace + if (this.nextToken.text === (optional ? "[" : "{")) { + // If we get a brace, parse an expression + this.consume(); + var expression = this.parseExpression(false, optional ? "]" : null); + var lastToken = this.nextToken; + // Make sure we get a close brace + this.expect(optional ? "]" : "}"); + if (this.mode === "text") { + this.formLigatures(expression); + } + return new ParseFuncOrArgument( + new ParseNode("ordgroup", expression, this.mode, + firstToken, lastToken), + false); + } else { + // Otherwise, just return a nucleus, or nothing for an optional group + return optional ? null : this.parseSymbol(); + } +}; + +/** + * Form ligature-like combinations of characters for text mode. + * This includes inputs like "--", "---", "``" and "''". + * The result will simply replace multiple textord nodes with a single + * character in each value by a single textord node having multiple + * characters in its value. The representation is still ASCII source. + * + * @param {Array.} group the nodes of this group, + * list will be moified in place + */ +Parser.prototype.formLigatures = function(group) { + var i; + var n = group.length - 1; + for (i = 0; i < n; ++i) { + var a = group[i]; + var v = a.value; + if (v === "-" && group[i + 1].value === "-") { + if (i + 1 < n && group[i + 2].value === "-") { + group.splice(i, 3, new ParseNode( + "textord", "---", "text", a, group[i + 2])); + n -= 2; + } else { + group.splice(i, 2, new ParseNode( + "textord", "--", "text", a, group[i + 1])); + n -= 1; + } + } + if ((v === "'" || v === "`") && group[i + 1].value === v) { + group.splice(i, 2, new ParseNode( + "textord", v + v, "text", a, group[i + 1])); + n -= 1; + } + } +}; + +/** + * Parse a single symbol out of the string. Here, we handle both the functions + * we have defined, as well as the single character symbols + * + * @return {?ParseFuncOrArgument} + */ +Parser.prototype.parseSymbol = function() { + var nucleus = this.nextToken; + + if (functions[nucleus.text]) { + this.consume(); + // If there exists a function with this name, we return the function and + // say that it is a function. + return new ParseFuncOrArgument( + nucleus.text, + true, nucleus); + } else if (symbols[this.mode][nucleus.text]) { + this.consume(); + // Otherwise if this is a no-argument function, find the type it + // corresponds to in the symbols map + return new ParseFuncOrArgument( + new ParseNode(symbols[this.mode][nucleus.text].group, + nucleus.text, this.mode, nucleus), + false, nucleus); + } else if (this.mode === "text" && cjkRegex.test(nucleus.text)) { + this.consume(); + return new ParseFuncOrArgument( + new ParseNode("textord", nucleus.text, this.mode, nucleus), + false, nucleus); + } else { + return null; + } +}; + +Parser.prototype.ParseNode = ParseNode; + +module.exports = Parser; + +},{"./MacroExpander":4,"./ParseError":6,"./environments":16,"./functions":19,"./parseData":21,"./symbols":23,"./unicodeRegexes":24,"./utils":25}],8:[function(require,module,exports){ +/** + * This is a module for storing settings passed into KaTeX. It correctly handles + * default settings. + */ + +/** + * Helper function for getting a default value if the value is undefined + */ +function get(option, defaultValue) { + return option === undefined ? defaultValue : option; +} + +/** + * The main Settings object + * + * The current options stored are: + * - displayMode: Whether the expression should be typeset by default in + * textstyle or displaystyle (default false) + */ +function Settings(options) { + // allow null options + options = options || {}; + this.displayMode = get(options.displayMode, false); + this.throwOnError = get(options.throwOnError, true); + this.errorColor = get(options.errorColor, "#cc0000"); + this.macros = options.macros || {}; +} + +module.exports = Settings; + +},{}],9:[function(require,module,exports){ +/** + * This file contains information and classes for the various kinds of styles + * used in TeX. It provides a generic `Style` class, which holds information + * about a specific style. It then provides instances of all the different kinds + * of styles possible, and provides functions to move between them and get + * information about them. + */ + +var sigmas = require("./fontMetrics.js").sigmas; + +var metrics = [{}, {}, {}]; +var i; +for (var key in sigmas) { + if (sigmas.hasOwnProperty(key)) { + for (i = 0; i < 3; i++) { + metrics[i][key] = sigmas[key][i]; + } + } +} +for (i = 0; i < 3; i++) { + metrics[i].emPerEx = sigmas.xHeight[i] / sigmas.quad[i]; +} + +/** + * The main style class. Contains a unique id for the style, a size (which is + * the same for cramped and uncramped version of a style), a cramped flag, and a + * size multiplier, which gives the size difference between a style and + * textstyle. + */ +function Style(id, size, multiplier, cramped) { + this.id = id; + this.size = size; + this.cramped = cramped; + this.sizeMultiplier = multiplier; + this.metrics = metrics[size > 0 ? size - 1 : 0]; +} + +/** + * Get the style of a superscript given a base in the current style. + */ +Style.prototype.sup = function() { + return styles[sup[this.id]]; +}; + +/** + * Get the style of a subscript given a base in the current style. + */ +Style.prototype.sub = function() { + return styles[sub[this.id]]; +}; + +/** + * Get the style of a fraction numerator given the fraction in the current + * style. + */ +Style.prototype.fracNum = function() { + return styles[fracNum[this.id]]; +}; + +/** + * Get the style of a fraction denominator given the fraction in the current + * style. + */ +Style.prototype.fracDen = function() { + return styles[fracDen[this.id]]; +}; + +/** + * Get the cramped version of a style (in particular, cramping a cramped style + * doesn't change the style). + */ +Style.prototype.cramp = function() { + return styles[cramp[this.id]]; +}; + +/** + * HTML class name, like "displaystyle cramped" + */ +Style.prototype.cls = function() { + return sizeNames[this.size] + (this.cramped ? " cramped" : " uncramped"); +}; + +/** + * HTML Reset class name, like "reset-textstyle" + */ +Style.prototype.reset = function() { + return resetNames[this.size]; +}; + +/** + * Return if this style is tightly spaced (scriptstyle/scriptscriptstyle) + */ +Style.prototype.isTight = function() { + return this.size >= 2; +}; + +// IDs of the different styles +var D = 0; +var Dc = 1; +var T = 2; +var Tc = 3; +var S = 4; +var Sc = 5; +var SS = 6; +var SSc = 7; + +// String names for the different sizes +var sizeNames = [ + "displaystyle textstyle", + "textstyle", + "scriptstyle", + "scriptscriptstyle" +]; + +// Reset names for the different sizes +var resetNames = [ + "reset-textstyle", + "reset-textstyle", + "reset-scriptstyle", + "reset-scriptscriptstyle" +]; + +// Instances of the different styles +var styles = [ + new Style(D, 0, 1.0, false), + new Style(Dc, 0, 1.0, true), + new Style(T, 1, 1.0, false), + new Style(Tc, 1, 1.0, true), + new Style(S, 2, 0.7, false), + new Style(Sc, 2, 0.7, true), + new Style(SS, 3, 0.5, false), + new Style(SSc, 3, 0.5, true) +]; + +// Lookup tables for switching from one style to another +var sup = [S, Sc, S, Sc, SS, SSc, SS, SSc]; +var sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc]; +var fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc]; +var fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc]; +var cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc]; + +// We only export some of the styles. Also, we don't export the `Style` class so +// no more styles can be generated. +module.exports = { + DISPLAY: styles[D], + TEXT: styles[T], + SCRIPT: styles[S], + SCRIPTSCRIPT: styles[SS] +}; + +},{"./fontMetrics.js":17}],10:[function(require,module,exports){ +/* eslint no-console:0 */ +/** + * This module contains general functions that can be used for building + * different kinds of domTree nodes in a consistent manner. + */ + +var domTree = require("./domTree"); +var fontMetrics = require("./fontMetrics"); +var symbols = require("./symbols"); +var utils = require("./utils"); + +var greekCapitals = [ + "\\Gamma", + "\\Delta", + "\\Theta", + "\\Lambda", + "\\Xi", + "\\Pi", + "\\Sigma", + "\\Upsilon", + "\\Phi", + "\\Psi", + "\\Omega" +]; + +// The following have to be loaded from Main-Italic font, using class mainit +var mainitLetters = [ + "\u0131", // dotless i, \imath + "\u0237", // dotless j, \jmath + "\u00a3" // \pounds +]; + +/** + * Makes a symbolNode after translation via the list of symbols in symbols.js. + * Correctly pulls out metrics for the character, and optionally takes a list of + * classes to be attached to the node. + * + * TODO: make argument order closer to makeSpan + * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which + * should if present come first in `classes`. + */ +var makeSymbol = function(value, fontFamily, mode, options, classes) { + // Replace the value with its replaced value from symbol.js + if (symbols[mode][value] && symbols[mode][value].replace) { + value = symbols[mode][value].replace; + } + + var metrics = fontMetrics.getCharacterMetrics(value, fontFamily); + + var symbolNode; + if (metrics) { + var italic = metrics.italic; + if (mode === "text") { + italic = 0; + } + symbolNode = new domTree.symbolNode( + value, metrics.height, metrics.depth, italic, metrics.skew, + classes); + } else { + // TODO(emily): Figure out a good way to only print this in development + typeof console !== "undefined" && console.warn( + "No character metrics for '" + value + "' in style '" + + fontFamily + "'"); + symbolNode = new domTree.symbolNode(value, 0, 0, 0, 0, classes); + } + + if (options) { + if (options.style.isTight()) { + symbolNode.classes.push("mtight"); + } + if (options.getColor()) { + symbolNode.style.color = options.getColor(); + } + } + + return symbolNode; +}; + +/** + * Makes a symbol in Main-Regular or AMS-Regular. + * Used for rel, bin, open, close, inner, and punct. + */ +var mathsym = function(value, mode, options, classes) { + // Decide what font to render the symbol in by its entry in the symbols + // table. + // Have a special case for when the value = \ because the \ is used as a + // textord in unsupported command errors but cannot be parsed as a regular + // text ordinal and is therefore not present as a symbol in the symbols + // table for text + if (value === "\\" || symbols[mode][value].font === "main") { + return makeSymbol(value, "Main-Regular", mode, options, classes); + } else { + return makeSymbol( + value, "AMS-Regular", mode, options, classes.concat(["amsrm"])); + } +}; + +/** + * Makes a symbol in the default font for mathords and textords. + */ +var mathDefault = function(value, mode, options, classes, type) { + if (type === "mathord") { + return mathit(value, mode, options, classes); + } else if (type === "textord") { + return makeSymbol( + value, "Main-Regular", mode, options, classes.concat(["mathrm"])); + } else { + throw new Error("unexpected type: " + type + " in mathDefault"); + } +}; + +/** + * Makes a symbol in the italic math font. + */ +var mathit = function(value, mode, options, classes) { + if (/[0-9]/.test(value.charAt(0)) || + // glyphs for \imath and \jmath do not exist in Math-Italic so we + // need to use Main-Italic instead + utils.contains(mainitLetters, value) || + utils.contains(greekCapitals, value)) { + return makeSymbol( + value, "Main-Italic", mode, options, classes.concat(["mainit"])); + } else { + return makeSymbol( + value, "Math-Italic", mode, options, classes.concat(["mathit"])); + } +}; + +/** + * Makes either a mathord or textord in the correct font and color. + */ +var makeOrd = function(group, options, type) { + var mode = group.mode; + var value = group.value; + if (symbols[mode][value] && symbols[mode][value].replace) { + value = symbols[mode][value].replace; + } + + var classes = ["mord"]; + + var font = options.font; + if (font) { + if (font === "mathit" || utils.contains(mainitLetters, value)) { + return mathit(value, mode, options, classes); + } else { + var fontName = fontMap[font].fontName; + if (fontMetrics.getCharacterMetrics(value, fontName)) { + return makeSymbol( + value, fontName, mode, options, classes.concat([font])); + } else { + return mathDefault(value, mode, options, classes, type); + } + } + } else { + return mathDefault(value, mode, options, classes, type); + } +}; + +/** + * Calculate the height, depth, and maxFontSize of an element based on its + * children. + */ +var sizeElementFromChildren = function(elem) { + var height = 0; + var depth = 0; + var maxFontSize = 0; + + if (elem.children) { + for (var i = 0; i < elem.children.length; i++) { + if (elem.children[i].height > height) { + height = elem.children[i].height; + } + if (elem.children[i].depth > depth) { + depth = elem.children[i].depth; + } + if (elem.children[i].maxFontSize > maxFontSize) { + maxFontSize = elem.children[i].maxFontSize; + } + } + } + + elem.height = height; + elem.depth = depth; + elem.maxFontSize = maxFontSize; +}; + +/** + * Makes a span with the given list of classes, list of children, and options. + * + * TODO: Ensure that `options` is always provided (currently some call sites + * don't pass it). + * TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which + * should if present come first in `classes`. + */ +var makeSpan = function(classes, children, options) { + var span = new domTree.span(classes, children, options); + + sizeElementFromChildren(span); + + return span; +}; + +/** + * Prepends the given children to the given span, updating height, depth, and + * maxFontSize. + */ +var prependChildren = function(span, children) { + span.children = children.concat(span.children); + + sizeElementFromChildren(span); +}; + +/** + * Makes a document fragment with the given list of children. + */ +var makeFragment = function(children) { + var fragment = new domTree.documentFragment(children); + + sizeElementFromChildren(fragment); + + return fragment; +}; + +/** + * Makes an element placed in each of the vlist elements to ensure that each + * element has the same max font size. To do this, we create a zero-width space + * with the correct font size. + */ +var makeFontSizer = function(options, fontSize) { + var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]); + fontSizeInner.style.fontSize = + (fontSize / options.style.sizeMultiplier) + "em"; + + var fontSizer = makeSpan( + ["fontsize-ensurer", "reset-" + options.size, "size5"], + [fontSizeInner]); + + return fontSizer; +}; + +/** + * Makes a vertical list by stacking elements and kerns on top of each other. + * Allows for many different ways of specifying the positioning method. + * + * Arguments: + * - children: A list of child or kern nodes to be stacked on top of each other + * (i.e. the first element will be at the bottom, and the last at + * the top). Element nodes are specified as + * {type: "elem", elem: node} + * while kern nodes are specified as + * {type: "kern", size: size} + * - positionType: The method by which the vlist should be positioned. Valid + * values are: + * - "individualShift": The children list only contains elem + * nodes, and each node contains an extra + * "shift" value of how much it should be + * shifted (note that shifting is always + * moving downwards). positionData is + * ignored. + * - "top": The positionData specifies the topmost point of + * the vlist (note this is expected to be a height, + * so positive values move up) + * - "bottom": The positionData specifies the bottommost point + * of the vlist (note this is expected to be a + * depth, so positive values move down + * - "shift": The vlist will be positioned such that its + * baseline is positionData away from the baseline + * of the first child. Positive values move + * downwards. + * - "firstBaseline": The vlist will be positioned such that + * its baseline is aligned with the + * baseline of the first child. + * positionData is ignored. (this is + * equivalent to "shift" with + * positionData=0) + * - positionData: Data used in different ways depending on positionType + * - options: An Options object + * + */ +var makeVList = function(children, positionType, positionData, options) { + var depth; + var currPos; + var i; + if (positionType === "individualShift") { + var oldChildren = children; + children = [oldChildren[0]]; + + // Add in kerns to the list of children to get each element to be + // shifted to the correct specified shift + depth = -oldChildren[0].shift - oldChildren[0].elem.depth; + currPos = depth; + for (i = 1; i < oldChildren.length; i++) { + var diff = -oldChildren[i].shift - currPos - + oldChildren[i].elem.depth; + var size = diff - + (oldChildren[i - 1].elem.height + + oldChildren[i - 1].elem.depth); + + currPos = currPos + diff; + + children.push({type: "kern", size: size}); + children.push(oldChildren[i]); + } + } else if (positionType === "top") { + // We always start at the bottom, so calculate the bottom by adding up + // all the sizes + var bottom = positionData; + for (i = 0; i < children.length; i++) { + if (children[i].type === "kern") { + bottom -= children[i].size; + } else { + bottom -= children[i].elem.height + children[i].elem.depth; + } + } + depth = bottom; + } else if (positionType === "bottom") { + depth = -positionData; + } else if (positionType === "shift") { + depth = -children[0].elem.depth - positionData; + } else if (positionType === "firstBaseline") { + depth = -children[0].elem.depth; + } else { + depth = 0; + } + + // Make the fontSizer + var maxFontSize = 0; + for (i = 0; i < children.length; i++) { + if (children[i].type === "elem") { + maxFontSize = Math.max(maxFontSize, children[i].elem.maxFontSize); + } + } + var fontSizer = makeFontSizer(options, maxFontSize); + + // Create a new list of actual children at the correct offsets + var realChildren = []; + currPos = depth; + for (i = 0; i < children.length; i++) { + if (children[i].type === "kern") { + currPos += children[i].size; + } else { + var child = children[i].elem; + + var shift = -child.depth - currPos; + currPos += child.height + child.depth; + + var childWrap = makeSpan([], [fontSizer, child]); + childWrap.height -= shift; + childWrap.depth += shift; + childWrap.style.top = shift + "em"; + + realChildren.push(childWrap); + } + } + + // Add in an element at the end with no offset to fix the calculation of + // baselines in some browsers (namely IE, sometimes safari) + var baselineFix = makeSpan( + ["baseline-fix"], [fontSizer, new domTree.symbolNode("\u200b")]); + realChildren.push(baselineFix); + + var vlist = makeSpan(["vlist"], realChildren); + // Fix the final height and depth, in case there were kerns at the ends + // since the makeSpan calculation won't take that in to account. + vlist.height = Math.max(currPos, vlist.height); + vlist.depth = Math.max(-depth, vlist.depth); + return vlist; +}; + +// A table of size -> font size for the different sizing functions +var sizingMultiplier = { + size1: 0.5, + size2: 0.7, + size3: 0.8, + size4: 0.9, + size5: 1.0, + size6: 1.2, + size7: 1.44, + size8: 1.73, + size9: 2.07, + size10: 2.49 +}; + +// A map of spacing functions to their attributes, like size and corresponding +// CSS class +var spacingFunctions = { + "\\qquad": { + size: "2em", + className: "qquad" + }, + "\\quad": { + size: "1em", + className: "quad" + }, + "\\enspace": { + size: "0.5em", + className: "enspace" + }, + "\\;": { + size: "0.277778em", + className: "thickspace" + }, + "\\:": { + size: "0.22222em", + className: "mediumspace" + }, + "\\,": { + size: "0.16667em", + className: "thinspace" + }, + "\\!": { + size: "-0.16667em", + className: "negativethinspace" + } +}; + +/** + * Maps TeX font commands to objects containing: + * - variant: string used for "mathvariant" attribute in buildMathML.js + * - fontName: the "style" parameter to fontMetrics.getCharacterMetrics + */ +// A map between tex font commands an MathML mathvariant attribute values +var fontMap = { + // styles + "mathbf": { + variant: "bold", + fontName: "Main-Bold" + }, + "mathrm": { + variant: "normal", + fontName: "Main-Regular" + }, + "textit": { + variant: "italic", + fontName: "Main-Italic" + }, + + // "mathit" is missing because it requires the use of two fonts: Main-Italic + // and Math-Italic. This is handled by a special case in makeOrd which ends + // up calling mathit. + + // families + "mathbb": { + variant: "double-struck", + fontName: "AMS-Regular" + }, + "mathcal": { + variant: "script", + fontName: "Caligraphic-Regular" + }, + "mathfrak": { + variant: "fraktur", + fontName: "Fraktur-Regular" + }, + "mathscr": { + variant: "script", + fontName: "Script-Regular" + }, + "mathsf": { + variant: "sans-serif", + fontName: "SansSerif-Regular" + }, + "mathtt": { + variant: "monospace", + fontName: "Typewriter-Regular" + } +}; + +module.exports = { + fontMap: fontMap, + makeSymbol: makeSymbol, + mathsym: mathsym, + makeSpan: makeSpan, + makeFragment: makeFragment, + makeVList: makeVList, + makeOrd: makeOrd, + prependChildren: prependChildren, + sizingMultiplier: sizingMultiplier, + spacingFunctions: spacingFunctions +}; + +},{"./domTree":15,"./fontMetrics":17,"./symbols":23,"./utils":25}],11:[function(require,module,exports){ +/* eslint no-console:0 */ +/** + * This file does the main work of building a domTree structure from a parse + * tree. The entry point is the `buildHTML` function, which takes a parse tree. + * Then, the buildExpression, buildGroup, and various groupTypes functions are + * called, to produce a final HTML tree. + */ + +var ParseError = require("./ParseError"); +var Style = require("./Style"); + +var buildCommon = require("./buildCommon"); +var delimiter = require("./delimiter"); +var domTree = require("./domTree"); +var fontMetrics = require("./fontMetrics"); +var utils = require("./utils"); + +var makeSpan = buildCommon.makeSpan; + +var isSpace = function(node) { + return node instanceof domTree.span && node.classes[0] === "mspace"; +}; + +// Binary atoms (first class `mbin`) change into ordinary atoms (`mord`) +// depending on their surroundings. See TeXbook pg. 442-446, Rules 5 and 6, +// and the text before Rule 19. + +var isBin = function(node) { + return node && node.classes[0] === "mbin"; +}; + +var isBinLeftCanceller = function(node, isRealGroup) { + // TODO: This code assumes that a node's math class is the first element + // of its `classes` array. A later cleanup should ensure this, for + // instance by changing the signature of `makeSpan`. + if (node) { + return utils.contains(["mbin", "mopen", "mrel", "mop", "mpunct"], + node.classes[0]); + } else { + return isRealGroup; + } +}; + +var isBinRightCanceller = function(node, isRealGroup) { + if (node) { + return utils.contains(["mrel", "mclose", "mpunct"], node.classes[0]); + } else { + return isRealGroup; + } +}; + +/** + * Take a list of nodes, build them in order, and return a list of the built + * nodes. documentFragments are flattened into their contents, so the + * returned list contains no fragments. `isRealGroup` is true if `expression` + * is a real group (no atoms will be added on either side), as opposed to + * a partial group (e.g. one created by \color). + */ +var buildExpression = function(expression, options, isRealGroup) { + // Parse expressions into `groups`. + var groups = []; + for (var i = 0; i < expression.length; i++) { + var group = expression[i]; + var output = buildGroup(group, options); + if (output instanceof domTree.documentFragment) { + Array.prototype.push.apply(groups, output.children); + } else { + groups.push(output); + } + } + // At this point `groups` consists entirely of `symbolNode`s and `span`s. + + // Explicit spaces (e.g., \;, \,) should be ignored with respect to atom + // spacing (e.g., "add thick space between mord and mrel"). Since CSS + // adjacency rules implement atom spacing, spaces should be invisible to + // CSS. So we splice them out of `groups` and into the atoms themselves. + var spaces = null; + for (i = 0; i < groups.length; i++) { + if (isSpace(groups[i])) { + spaces = spaces || []; + spaces.push(groups[i]); + groups.splice(i, 1); + i--; + } else if (spaces) { + if (groups[i] instanceof domTree.symbolNode) { + groups[i] = makeSpan([].concat(groups[i].classes), [groups[i]]); + } + buildCommon.prependChildren(groups[i], spaces); + spaces = null; + } + } + if (spaces) { + Array.prototype.push.apply(groups, spaces); + } + + // Binary operators change to ordinary symbols in some contexts. + for (i = 0; i < groups.length; i++) { + if (isBin(groups[i]) + && (isBinLeftCanceller(groups[i - 1], isRealGroup) + || isBinRightCanceller(groups[i + 1], isRealGroup))) { + groups[i].classes[0] = "mord"; + } + } + + return groups; +}; + +// Return math atom class (mclass) of a domTree. +var getTypeOfDomTree = function(node) { + if (node instanceof domTree.documentFragment) { + if (node.children.length) { + return getTypeOfDomTree( + node.children[node.children.length - 1]); + } + } else { + if (utils.contains(["mord", "mop", "mbin", "mrel", "mopen", "mclose", + "mpunct", "minner"], node.classes[0])) { + return node.classes[0]; + } + } + return null; +}; + +/** + * Sometimes, groups perform special rules when they have superscripts or + * subscripts attached to them. This function lets the `supsub` group know that + * its inner element should handle the superscripts and subscripts instead of + * handling them itself. + */ +var shouldHandleSupSub = function(group, options) { + if (!group) { + return false; + } else if (group.type === "op") { + // Operators handle supsubs differently when they have limits + // (e.g. `\displaystyle\sum_2^3`) + return group.value.limits && + (options.style.size === Style.DISPLAY.size || + group.value.alwaysHandleSupSub); + } else if (group.type === "accent") { + return isCharacterBox(group.value.base); + } else { + return null; + } +}; + +/** + * Sometimes we want to pull out the innermost element of a group. In most + * cases, this will just be the group itself, but when ordgroups and colors have + * a single element, we want to pull that out. + */ +var getBaseElem = function(group) { + if (!group) { + return false; + } else if (group.type === "ordgroup") { + if (group.value.length === 1) { + return getBaseElem(group.value[0]); + } else { + return group; + } + } else if (group.type === "color") { + if (group.value.value.length === 1) { + return getBaseElem(group.value.value[0]); + } else { + return group; + } + } else if (group.type === "font") { + return getBaseElem(group.value.body); + } else { + return group; + } +}; + +/** + * TeXbook algorithms often reference "character boxes", which are simply groups + * with a single character in them. To decide if something is a character box, + * we find its innermost group, and see if it is a single character. + */ +var isCharacterBox = function(group) { + var baseElem = getBaseElem(group); + + // These are all they types of groups which hold single characters + return baseElem.type === "mathord" || + baseElem.type === "textord" || + baseElem.type === "bin" || + baseElem.type === "rel" || + baseElem.type === "inner" || + baseElem.type === "open" || + baseElem.type === "close" || + baseElem.type === "punct"; +}; + +var makeNullDelimiter = function(options, classes) { + return makeSpan(classes.concat([ + "sizing", "reset-" + options.size, "size5", + options.style.reset(), Style.TEXT.cls(), + "nulldelimiter"])); +}; + +/** + * This is a map of group types to the function used to handle that type. + * Simpler types come at the beginning, while complicated types come afterwards. + */ +var groupTypes = {}; + +groupTypes.mathord = function(group, options) { + return buildCommon.makeOrd(group, options, "mathord"); +}; + +groupTypes.textord = function(group, options) { + return buildCommon.makeOrd(group, options, "textord"); +}; + +groupTypes.bin = function(group, options) { + return buildCommon.mathsym( + group.value, group.mode, options, ["mbin"]); +}; + +groupTypes.rel = function(group, options) { + return buildCommon.mathsym( + group.value, group.mode, options, ["mrel"]); +}; + +groupTypes.open = function(group, options) { + return buildCommon.mathsym( + group.value, group.mode, options, ["mopen"]); +}; + +groupTypes.close = function(group, options) { + return buildCommon.mathsym( + group.value, group.mode, options, ["mclose"]); +}; + +groupTypes.inner = function(group, options) { + return buildCommon.mathsym( + group.value, group.mode, options, ["minner"]); +}; + +groupTypes.punct = function(group, options) { + return buildCommon.mathsym( + group.value, group.mode, options, ["mpunct"]); +}; + +groupTypes.ordgroup = function(group, options) { + return makeSpan( + ["mord", options.style.cls()], + buildExpression(group.value, options.reset(), true), + options + ); +}; + +groupTypes.text = function(group, options) { + var newOptions = options.withFont(group.value.style); + var inner = buildExpression(group.value.body, newOptions, true); + for (var i = 0; i < inner.length - 1; i++) { + if (inner[i].tryCombine(inner[i + 1])) { + inner.splice(i + 1, 1); + i--; + } + } + return makeSpan(["mord", "text", newOptions.style.cls()], + inner, newOptions); +}; + +groupTypes.color = function(group, options) { + var elements = buildExpression( + group.value.value, + options.withColor(group.value.color), + false + ); + + // \color isn't supposed to affect the type of the elements it contains. + // To accomplish this, we wrap the results in a fragment, so the inner + // elements will be able to directly interact with their neighbors. For + // example, `\color{red}{2 +} 3` has the same spacing as `2 + 3` + return new buildCommon.makeFragment(elements); +}; + +groupTypes.supsub = function(group, options) { + // Superscript and subscripts are handled in the TeXbook on page + // 445-446, rules 18(a-f). + + // Here is where we defer to the inner group if it should handle + // superscripts and subscripts itself. + if (shouldHandleSupSub(group.value.base, options)) { + return groupTypes[group.value.base.type](group, options); + } + + var base = buildGroup(group.value.base, options.reset()); + var supmid; + var submid; + var sup; + var sub; + + var style = options.style; + var newOptions; + + if (group.value.sup) { + newOptions = options.withStyle(style.sup()); + sup = buildGroup(group.value.sup, newOptions); + supmid = makeSpan([style.reset(), style.sup().cls()], + [sup], newOptions); + } + + if (group.value.sub) { + newOptions = options.withStyle(style.sub()); + sub = buildGroup(group.value.sub, newOptions); + submid = makeSpan([style.reset(), style.sub().cls()], + [sub], newOptions); + } + + // Rule 18a + var supShift; + var subShift; + if (isCharacterBox(group.value.base)) { + supShift = 0; + subShift = 0; + } else { + supShift = base.height - style.metrics.supDrop; + subShift = base.depth + style.metrics.subDrop; + } + + // Rule 18c + var minSupShift; + if (style === Style.DISPLAY) { + minSupShift = style.metrics.sup1; + } else if (style.cramped) { + minSupShift = style.metrics.sup3; + } else { + minSupShift = style.metrics.sup2; + } + + // scriptspace is a font-size-independent size, so scale it + // appropriately + var multiplier = Style.TEXT.sizeMultiplier * + style.sizeMultiplier; + var scriptspace = + (0.5 / fontMetrics.metrics.ptPerEm) / multiplier + "em"; + + var supsub; + if (!group.value.sup) { + // Rule 18b + subShift = Math.max( + subShift, style.metrics.sub1, + sub.height - 0.8 * style.metrics.xHeight); + + supsub = buildCommon.makeVList([ + {type: "elem", elem: submid} + ], "shift", subShift, options); + + supsub.children[0].style.marginRight = scriptspace; + + // Subscripts shouldn't be shifted by the base's italic correction. + // Account for that by shifting the subscript back the appropriate + // amount. Note we only do this when the base is a single symbol. + if (base instanceof domTree.symbolNode) { + supsub.children[0].style.marginLeft = -base.italic + "em"; + } + } else if (!group.value.sub) { + // Rule 18c, d + supShift = Math.max(supShift, minSupShift, + sup.depth + 0.25 * style.metrics.xHeight); + + supsub = buildCommon.makeVList([ + {type: "elem", elem: supmid} + ], "shift", -supShift, options); + + supsub.children[0].style.marginRight = scriptspace; + } else { + supShift = Math.max( + supShift, minSupShift, sup.depth + 0.25 * style.metrics.xHeight); + subShift = Math.max(subShift, style.metrics.sub2); + + var ruleWidth = fontMetrics.metrics.defaultRuleThickness; + + // Rule 18e + if ((supShift - sup.depth) - (sub.height - subShift) < + 4 * ruleWidth) { + subShift = 4 * ruleWidth - (supShift - sup.depth) + sub.height; + var psi = 0.8 * style.metrics.xHeight - (supShift - sup.depth); + if (psi > 0) { + supShift += psi; + subShift -= psi; + } + } + + supsub = buildCommon.makeVList([ + {type: "elem", elem: submid, shift: subShift}, + {type: "elem", elem: supmid, shift: -supShift} + ], "individualShift", null, options); + + // See comment above about subscripts not being shifted + if (base instanceof domTree.symbolNode) { + supsub.children[0].style.marginLeft = -base.italic + "em"; + } + + supsub.children[0].style.marginRight = scriptspace; + supsub.children[1].style.marginRight = scriptspace; + } + + // We ensure to wrap the supsub vlist in a span.msupsub to reset text-align + var mclass = getTypeOfDomTree(base) || "mord"; + return makeSpan([mclass], + [base, makeSpan(["msupsub"], [supsub])], + options); +}; + +groupTypes.genfrac = function(group, options) { + // Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e). + // Figure out what style this fraction should be in based on the + // function used + var style = options.style; + if (group.value.size === "display") { + style = Style.DISPLAY; + } else if (group.value.size === "text") { + style = Style.TEXT; + } + + var nstyle = style.fracNum(); + var dstyle = style.fracDen(); + var newOptions; + + newOptions = options.withStyle(nstyle); + var numer = buildGroup(group.value.numer, newOptions); + var numerreset = makeSpan([style.reset(), nstyle.cls()], + [numer], newOptions); + + newOptions = options.withStyle(dstyle); + var denom = buildGroup(group.value.denom, newOptions); + var denomreset = makeSpan([style.reset(), dstyle.cls()], + [denom], newOptions); + + var ruleWidth; + if (group.value.hasBarLine) { + ruleWidth = fontMetrics.metrics.defaultRuleThickness / + options.style.sizeMultiplier; + } else { + ruleWidth = 0; + } + + // Rule 15b + var numShift; + var clearance; + var denomShift; + if (style.size === Style.DISPLAY.size) { + numShift = style.metrics.num1; + if (ruleWidth > 0) { + clearance = 3 * ruleWidth; + } else { + clearance = 7 * fontMetrics.metrics.defaultRuleThickness; + } + denomShift = style.metrics.denom1; + } else { + if (ruleWidth > 0) { + numShift = style.metrics.num2; + clearance = ruleWidth; + } else { + numShift = style.metrics.num3; + clearance = 3 * fontMetrics.metrics.defaultRuleThickness; + } + denomShift = style.metrics.denom2; + } + + var frac; + if (ruleWidth === 0) { + // Rule 15c + var candidateClearance = + (numShift - numer.depth) - (denom.height - denomShift); + if (candidateClearance < clearance) { + numShift += 0.5 * (clearance - candidateClearance); + denomShift += 0.5 * (clearance - candidateClearance); + } + + frac = buildCommon.makeVList([ + {type: "elem", elem: denomreset, shift: denomShift}, + {type: "elem", elem: numerreset, shift: -numShift} + ], "individualShift", null, options); + } else { + // Rule 15d + var axisHeight = style.metrics.axisHeight; + + if ((numShift - numer.depth) - (axisHeight + 0.5 * ruleWidth) < + clearance) { + numShift += + clearance - ((numShift - numer.depth) - + (axisHeight + 0.5 * ruleWidth)); + } + + if ((axisHeight - 0.5 * ruleWidth) - (denom.height - denomShift) < + clearance) { + denomShift += + clearance - ((axisHeight - 0.5 * ruleWidth) - + (denom.height - denomShift)); + } + + var mid = makeSpan( + [options.style.reset(), Style.TEXT.cls(), "frac-line"]); + // Manually set the height of the line because its height is + // created in CSS + mid.height = ruleWidth; + + var midShift = -(axisHeight - 0.5 * ruleWidth); + + frac = buildCommon.makeVList([ + {type: "elem", elem: denomreset, shift: denomShift}, + {type: "elem", elem: mid, shift: midShift}, + {type: "elem", elem: numerreset, shift: -numShift} + ], "individualShift", null, options); + } + + // Since we manually change the style sometimes (with \dfrac or \tfrac), + // account for the possible size change here. + frac.height *= style.sizeMultiplier / options.style.sizeMultiplier; + frac.depth *= style.sizeMultiplier / options.style.sizeMultiplier; + + // Rule 15e + var delimSize; + if (style.size === Style.DISPLAY.size) { + delimSize = style.metrics.delim1; + } else { + delimSize = style.metrics.delim2; + } + + var leftDelim; + var rightDelim; + if (group.value.leftDelim == null) { + leftDelim = makeNullDelimiter(options, ["mopen"]); + } else { + leftDelim = delimiter.customSizedDelim( + group.value.leftDelim, delimSize, true, + options.withStyle(style), group.mode, ["mopen"]); + } + if (group.value.rightDelim == null) { + rightDelim = makeNullDelimiter(options, ["mclose"]); + } else { + rightDelim = delimiter.customSizedDelim( + group.value.rightDelim, delimSize, true, + options.withStyle(style), group.mode, ["mclose"]); + } + + return makeSpan( + ["mord", options.style.reset(), style.cls()], + [leftDelim, makeSpan(["mfrac"], [frac]), rightDelim], + options); +}; + +var calculateSize = function(sizeValue, style) { + var x = sizeValue.number; + if (sizeValue.unit === "ex") { + x *= style.metrics.emPerEx; + } else if (sizeValue.unit === "mu") { + x /= 18; + } + return x; +}; + +groupTypes.array = function(group, options) { + var r; + var c; + var nr = group.value.body.length; + var nc = 0; + var body = new Array(nr); + + var style = options.style; + + // Horizontal spacing + var pt = 1 / fontMetrics.metrics.ptPerEm; + var arraycolsep = 5 * pt; // \arraycolsep in article.cls + + // Vertical spacing + var baselineskip = 12 * pt; // see size10.clo + // Default \arraystretch from lttab.dtx + // TODO(gagern): may get redefined once we have user-defined macros + var arraystretch = utils.deflt(group.value.arraystretch, 1); + var arrayskip = arraystretch * baselineskip; + var arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and + var arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx + + var totalHeight = 0; + for (r = 0; r < group.value.body.length; ++r) { + var inrow = group.value.body[r]; + var height = arstrutHeight; // \@array adds an \@arstrut + var depth = arstrutDepth; // to each tow (via the template) + + if (nc < inrow.length) { + nc = inrow.length; + } + + var outrow = new Array(inrow.length); + for (c = 0; c < inrow.length; ++c) { + var elt = buildGroup(inrow[c], options); + if (depth < elt.depth) { + depth = elt.depth; + } + if (height < elt.height) { + height = elt.height; + } + outrow[c] = elt; + } + + var gap = 0; + if (group.value.rowGaps[r]) { + gap = calculateSize(group.value.rowGaps[r].value, style); + if (gap > 0) { // \@argarraycr + gap += arstrutDepth; + if (depth < gap) { + depth = gap; // \@xargarraycr + } + gap = 0; + } + } + + outrow.height = height; + outrow.depth = depth; + totalHeight += height; + outrow.pos = totalHeight; + totalHeight += depth + gap; // \@yargarraycr + body[r] = outrow; + } + + var offset = totalHeight / 2 + style.metrics.axisHeight; + var colDescriptions = group.value.cols || []; + var cols = []; + var colSep; + var colDescrNum; + for (c = 0, colDescrNum = 0; + // Continue while either there are more columns or more column + // descriptions, so trailing separators don't get lost. + c < nc || colDescrNum < colDescriptions.length; + ++c, ++colDescrNum) { + + var colDescr = colDescriptions[colDescrNum] || {}; + + var firstSeparator = true; + while (colDescr.type === "separator") { + // If there is more than one separator in a row, add a space + // between them. + if (!firstSeparator) { + colSep = makeSpan(["arraycolsep"], []); + colSep.style.width = + fontMetrics.metrics.doubleRuleSep + "em"; + cols.push(colSep); + } + + if (colDescr.separator === "|") { + var separator = makeSpan( + ["vertical-separator"], + []); + separator.style.height = totalHeight + "em"; + separator.style.verticalAlign = + -(totalHeight - offset) + "em"; + + cols.push(separator); + } else { + throw new ParseError( + "Invalid separator type: " + colDescr.separator); + } + + colDescrNum++; + colDescr = colDescriptions[colDescrNum] || {}; + firstSeparator = false; + } + + if (c >= nc) { + continue; + } + + var sepwidth; + if (c > 0 || group.value.hskipBeforeAndAfter) { + sepwidth = utils.deflt(colDescr.pregap, arraycolsep); + if (sepwidth !== 0) { + colSep = makeSpan(["arraycolsep"], []); + colSep.style.width = sepwidth + "em"; + cols.push(colSep); + } + } + + var col = []; + for (r = 0; r < nr; ++r) { + var row = body[r]; + var elem = row[c]; + if (!elem) { + continue; + } + var shift = row.pos - offset; + elem.depth = row.depth; + elem.height = row.height; + col.push({type: "elem", elem: elem, shift: shift}); + } + + col = buildCommon.makeVList(col, "individualShift", null, options); + col = makeSpan( + ["col-align-" + (colDescr.align || "c")], + [col]); + cols.push(col); + + if (c < nc - 1 || group.value.hskipBeforeAndAfter) { + sepwidth = utils.deflt(colDescr.postgap, arraycolsep); + if (sepwidth !== 0) { + colSep = makeSpan(["arraycolsep"], []); + colSep.style.width = sepwidth + "em"; + cols.push(colSep); + } + } + } + body = makeSpan(["mtable"], cols); + return makeSpan(["mord"], [body], options); +}; + +groupTypes.spacing = function(group, options) { + if (group.value === "\\ " || group.value === "\\space" || + group.value === " " || group.value === "~") { + // Spaces are generated by adding an actual space. Each of these + // things has an entry in the symbols table, so these will be turned + // into appropriate outputs. + if (group.mode === "text") { + return buildCommon.makeOrd(group, options, "textord"); + } else { + return makeSpan(["mspace"], + [buildCommon.mathsym(group.value, group.mode, options)], + options); + } + } else { + // Other kinds of spaces are of arbitrary width. We use CSS to + // generate these. + return makeSpan( + ["mspace", + buildCommon.spacingFunctions[group.value].className], + [], options); + } +}; + +groupTypes.llap = function(group, options) { + var inner = makeSpan( + ["inner"], [buildGroup(group.value.body, options.reset())]); + var fix = makeSpan(["fix"], []); + return makeSpan( + ["mord", "llap", options.style.cls()], [inner, fix], options); +}; + +groupTypes.rlap = function(group, options) { + var inner = makeSpan( + ["inner"], [buildGroup(group.value.body, options.reset())]); + var fix = makeSpan(["fix"], []); + return makeSpan( + ["mord", "rlap", options.style.cls()], [inner, fix], options); +}; + +groupTypes.op = function(group, options) { + // Operators are handled in the TeXbook pg. 443-444, rule 13(a). + var supGroup; + var subGroup; + var hasLimits = false; + if (group.type === "supsub") { + // If we have limits, supsub will pass us its group to handle. Pull + // out the superscript and subscript and set the group to the op in + // its base. + supGroup = group.value.sup; + subGroup = group.value.sub; + group = group.value.base; + hasLimits = true; + } + + var style = options.style; + + // Most operators have a large successor symbol, but these don't. + var noSuccessor = [ + "\\smallint" + ]; + + var large = false; + if (style.size === Style.DISPLAY.size && + group.value.symbol && + !utils.contains(noSuccessor, group.value.body)) { + + // Most symbol operators get larger in displaystyle (rule 13) + large = true; + } + + var base; + var baseShift = 0; + var slant = 0; + if (group.value.symbol) { + // If this is a symbol, create the symbol. + var fontName = large ? "Size2-Regular" : "Size1-Regular"; + base = buildCommon.makeSymbol( + group.value.body, fontName, "math", options, + ["mop", "op-symbol", large ? "large-op" : "small-op"]); + + // Shift the symbol so its center lies on the axis (rule 13). It + // appears that our fonts have the centers of the symbols already + // almost on the axis, so these numbers are very small. Note we + // don't actually apply this here, but instead it is used either in + // the vlist creation or separately when there are no limits. + baseShift = (base.height - base.depth) / 2 - + style.metrics.axisHeight * style.sizeMultiplier; + + // The slant of the symbol is just its italic correction. + slant = base.italic; + } else if (group.value.value) { + // If this is a list, compose that list. + var inner = buildExpression(group.value.value, options, true); + + base = makeSpan(["mop"], inner, options); + } else { + // Otherwise, this is a text operator. Build the text from the + // operator's name. + // TODO(emily): Add a space in the middle of some of these + // operators, like \limsup + var output = []; + for (var i = 1; i < group.value.body.length; i++) { + output.push(buildCommon.mathsym(group.value.body[i], group.mode)); + } + base = makeSpan(["mop"], output, options); + } + + if (hasLimits) { + // IE 8 clips \int if it is in a display: inline-block. We wrap it + // in a new span so it is an inline, and works. + base = makeSpan([], [base]); + + var supmid; + var supKern; + var submid; + var subKern; + var newOptions; + // We manually have to handle the superscripts and subscripts. This, + // aside from the kern calculations, is copied from supsub. + if (supGroup) { + newOptions = options.withStyle(style.sup()); + var sup = buildGroup(supGroup, newOptions); + supmid = makeSpan([style.reset(), style.sup().cls()], + [sup], newOptions); + + supKern = Math.max( + fontMetrics.metrics.bigOpSpacing1, + fontMetrics.metrics.bigOpSpacing3 - sup.depth); + } + + if (subGroup) { + newOptions = options.withStyle(style.sub()); + var sub = buildGroup(subGroup, newOptions); + submid = makeSpan([style.reset(), style.sub().cls()], + [sub], newOptions); + + subKern = Math.max( + fontMetrics.metrics.bigOpSpacing2, + fontMetrics.metrics.bigOpSpacing4 - sub.height); + } + + // Build the final group as a vlist of the possible subscript, base, + // and possible superscript. + var finalGroup; + var top; + var bottom; + if (!supGroup) { + top = base.height - baseShift; + + finalGroup = buildCommon.makeVList([ + {type: "kern", size: fontMetrics.metrics.bigOpSpacing5}, + {type: "elem", elem: submid}, + {type: "kern", size: subKern}, + {type: "elem", elem: base} + ], "top", top, options); + + // Here, we shift the limits by the slant of the symbol. Note + // that we are supposed to shift the limits by 1/2 of the slant, + // but since we are centering the limits adding a full slant of + // margin will shift by 1/2 that. + finalGroup.children[0].style.marginLeft = -slant + "em"; + } else if (!subGroup) { + bottom = base.depth + baseShift; + + finalGroup = buildCommon.makeVList([ + {type: "elem", elem: base}, + {type: "kern", size: supKern}, + {type: "elem", elem: supmid}, + {type: "kern", size: fontMetrics.metrics.bigOpSpacing5} + ], "bottom", bottom, options); + + // See comment above about slants + finalGroup.children[1].style.marginLeft = slant + "em"; + } else if (!supGroup && !subGroup) { + // This case probably shouldn't occur (this would mean the + // supsub was sending us a group with no superscript or + // subscript) but be safe. + return base; + } else { + bottom = fontMetrics.metrics.bigOpSpacing5 + + submid.height + submid.depth + + subKern + + base.depth + baseShift; + + finalGroup = buildCommon.makeVList([ + {type: "kern", size: fontMetrics.metrics.bigOpSpacing5}, + {type: "elem", elem: submid}, + {type: "kern", size: subKern}, + {type: "elem", elem: base}, + {type: "kern", size: supKern}, + {type: "elem", elem: supmid}, + {type: "kern", size: fontMetrics.metrics.bigOpSpacing5} + ], "bottom", bottom, options); + + // See comment above about slants + finalGroup.children[0].style.marginLeft = -slant + "em"; + finalGroup.children[2].style.marginLeft = slant + "em"; + } + + return makeSpan(["mop", "op-limits"], [finalGroup], options); + } else { + if (group.value.symbol) { + base.style.top = baseShift + "em"; + } + + return base; + } +}; + +groupTypes.mod = function(group, options) { + var inner = []; + + if (group.value.modType === "bmod") { + // “\nonscript\mskip-\medmuskip\mkern5mu” + if (!options.style.isTight()) { + inner.push(makeSpan( + ["mspace", "negativemediumspace"], [], options)); + } + inner.push(makeSpan(["mspace", "thickspace"], [], options)); + } else if (options.style.size === Style.DISPLAY.size) { + inner.push(makeSpan(["mspace", "quad"], [], options)); + } else if (group.value.modType === "mod") { + inner.push(makeSpan(["mspace", "twelvemuspace"], [], options)); + } else { + inner.push(makeSpan(["mspace", "eightmuspace"], [], options)); + } + + if (group.value.modType === "pod" || group.value.modType === "pmod") { + inner.push(buildCommon.mathsym("(", group.mode)); + } + + if (group.value.modType !== "pod") { + var modInner = [ + buildCommon.mathsym("m", group.mode), + buildCommon.mathsym("o", group.mode), + buildCommon.mathsym("d", group.mode)]; + if (group.value.modType === "bmod") { + inner.push(makeSpan(["mbin"], modInner, options)); + // “\mkern5mu\nonscript\mskip-\medmuskip” + inner.push(makeSpan(["mspace", "thickspace"], [], options)); + if (!options.style.isTight()) { + inner.push(makeSpan( + ["mspace", "negativemediumspace"], [], options)); + } + } else { + Array.prototype.push.apply(inner, modInner); + inner.push(makeSpan(["mspace", "sixmuspace"], [], options)); + } + } + + if (group.value.value) { + Array.prototype.push.apply(inner, + buildExpression(group.value.value, options, false)); + } + + if (group.value.modType === "pod" || group.value.modType === "pmod") { + inner.push(buildCommon.mathsym(")", group.mode)); + } + + return buildCommon.makeFragment(inner); +}; + +groupTypes.katex = function(group, options) { + // The KaTeX logo. The offsets for the K and a were chosen to look + // good, but the offsets for the T, E, and X were taken from the + // definition of \TeX in TeX (see TeXbook pg. 356) + var k = makeSpan( + ["k"], [buildCommon.mathsym("K", group.mode)], options); + var a = makeSpan( + ["a"], [buildCommon.mathsym("A", group.mode)], options); + + a.height = (a.height + 0.2) * 0.75; + a.depth = (a.height - 0.2) * 0.75; + + var t = makeSpan( + ["t"], [buildCommon.mathsym("T", group.mode)], options); + var e = makeSpan( + ["e"], [buildCommon.mathsym("E", group.mode)], options); + + e.height = (e.height - 0.2155); + e.depth = (e.depth + 0.2155); + + var x = makeSpan( + ["x"], [buildCommon.mathsym("X", group.mode)], options); + + return makeSpan( + ["mord", "katex-logo"], [k, a, t, e, x], options); +}; + +groupTypes.overline = function(group, options) { + // Overlines are handled in the TeXbook pg 443, Rule 9. + var style = options.style; + + // Build the inner group in the cramped style. + var innerGroup = buildGroup(group.value.body, + options.withStyle(style.cramp())); + + var ruleWidth = fontMetrics.metrics.defaultRuleThickness / + style.sizeMultiplier; + + // Create the line above the body + var line = makeSpan( + [style.reset(), Style.TEXT.cls(), "overline-line"]); + line.height = ruleWidth; + line.maxFontSize = 1.0; + + // Generate the vlist, with the appropriate kerns + var vlist = buildCommon.makeVList([ + {type: "elem", elem: innerGroup}, + {type: "kern", size: 3 * ruleWidth}, + {type: "elem", elem: line}, + {type: "kern", size: ruleWidth} + ], "firstBaseline", null, options); + + return makeSpan(["mord", "overline"], [vlist], options); +}; + +groupTypes.underline = function(group, options) { + // Underlines are handled in the TeXbook pg 443, Rule 10. + var style = options.style; + + // Build the inner group. + var innerGroup = buildGroup(group.value.body, options); + + var ruleWidth = fontMetrics.metrics.defaultRuleThickness / + style.sizeMultiplier; + + // Create the line above the body + var line = makeSpan([style.reset(), Style.TEXT.cls(), "underline-line"]); + line.height = ruleWidth; + line.maxFontSize = 1.0; + + // Generate the vlist, with the appropriate kerns + var vlist = buildCommon.makeVList([ + {type: "kern", size: ruleWidth}, + {type: "elem", elem: line}, + {type: "kern", size: 3 * ruleWidth}, + {type: "elem", elem: innerGroup} + ], "top", innerGroup.height, options); + + return makeSpan(["mord", "underline"], [vlist], options); +}; + +groupTypes.sqrt = function(group, options) { + // Square roots are handled in the TeXbook pg. 443, Rule 11. + var style = options.style; + + // First, we do the same steps as in overline to build the inner group + // and line + var inner = buildGroup(group.value.body, options.withStyle(style.cramp())); + + var ruleWidth = fontMetrics.metrics.defaultRuleThickness / + style.sizeMultiplier; + + var line = makeSpan( + [style.reset(), Style.TEXT.cls(), "sqrt-line"], [], + options); + line.height = ruleWidth; + line.maxFontSize = 1.0; + + var phi = ruleWidth; + if (style.id < Style.TEXT.id) { + phi = style.metrics.xHeight; + } + + // Calculate the clearance between the body and line + var lineClearance = ruleWidth + phi / 4; + + var innerHeight = (inner.height + inner.depth) * style.sizeMultiplier; + var minDelimiterHeight = innerHeight + lineClearance + ruleWidth; + + // Create a \surd delimiter of the required minimum size + var delim = makeSpan(["sqrt-sign"], [ + delimiter.customSizedDelim("\\surd", minDelimiterHeight, + false, options, group.mode)], + options); + + var delimDepth = (delim.height + delim.depth) - ruleWidth; + + // Adjust the clearance based on the delimiter size + if (delimDepth > inner.height + inner.depth + lineClearance) { + lineClearance = + (lineClearance + delimDepth - inner.height - inner.depth) / 2; + } + + // Shift the delimiter so that its top lines up with the top of the line + var delimShift = -(inner.height + lineClearance + ruleWidth) + delim.height; + delim.style.top = delimShift + "em"; + delim.height -= delimShift; + delim.depth += delimShift; + + // We add a special case here, because even when `inner` is empty, we + // still get a line. So, we use a simple heuristic to decide if we + // should omit the body entirely. (note this doesn't work for something + // like `\sqrt{\rlap{x}}`, but if someone is doing that they deserve for + // it not to work. + var body; + if (inner.height === 0 && inner.depth === 0) { + body = makeSpan(); + } else { + body = buildCommon.makeVList([ + {type: "elem", elem: inner}, + {type: "kern", size: lineClearance}, + {type: "elem", elem: line}, + {type: "kern", size: ruleWidth} + ], "firstBaseline", null, options); + } + + if (!group.value.index) { + return makeSpan(["mord", "sqrt"], [delim, body], options); + } else { + // Handle the optional root index + + // The index is always in scriptscript style + var newOptions = options.withStyle(Style.SCRIPTSCRIPT); + var root = buildGroup(group.value.index, newOptions); + var rootWrap = makeSpan( + [style.reset(), Style.SCRIPTSCRIPT.cls()], + [root], + newOptions); + + // Figure out the height and depth of the inner part + var innerRootHeight = Math.max(delim.height, body.height); + var innerRootDepth = Math.max(delim.depth, body.depth); + + // The amount the index is shifted by. This is taken from the TeX + // source, in the definition of `\r@@t`. + var toShift = 0.6 * (innerRootHeight - innerRootDepth); + + // Build a VList with the superscript shifted up correctly + var rootVList = buildCommon.makeVList( + [{type: "elem", elem: rootWrap}], + "shift", -toShift, options); + // Add a class surrounding it so we can add on the appropriate + // kerning + var rootVListWrap = makeSpan(["root"], [rootVList]); + + return makeSpan(["mord", "sqrt"], + [rootVListWrap, delim, body], options); + } +}; + +groupTypes.sizing = function(group, options) { + // Handle sizing operators like \Huge. Real TeX doesn't actually allow + // these functions inside of math expressions, so we do some special + // handling. + var inner = buildExpression(group.value.value, + options.withSize(group.value.size), false); + + // Compute the correct maxFontSize. + var style = options.style; + var fontSize = buildCommon.sizingMultiplier[group.value.size]; + fontSize = fontSize * style.sizeMultiplier; + + // Add size-resetting classes to the inner list and set maxFontSize + // manually. Handle nested size changes. + for (var i = 0; i < inner.length; i++) { + var pos = utils.indexOf(inner[i].classes, "sizing"); + if (pos < 0) { + inner[i].classes.push("sizing", "reset-" + options.size, + group.value.size, style.cls()); + inner[i].maxFontSize = fontSize; + } else if (inner[i].classes[pos + 1] === "reset-" + group.value.size) { + // This is a nested size change: e.g., inner[i] is the "b" in + // `\Huge a \small b`. Override the old size (the `reset-` class) + // but not the new size. + inner[i].classes[pos + 1] = "reset-" + options.size; + } + } + + return buildCommon.makeFragment(inner); +}; + +groupTypes.styling = function(group, options) { + // Style changes are handled in the TeXbook on pg. 442, Rule 3. + + // Figure out what style we're changing to. + var styleMap = { + "display": Style.DISPLAY, + "text": Style.TEXT, + "script": Style.SCRIPT, + "scriptscript": Style.SCRIPTSCRIPT + }; + + var newStyle = styleMap[group.value.style]; + var newOptions = options.withStyle(newStyle); + + // Build the inner expression in the new style. + var inner = buildExpression( + group.value.value, newOptions, false); + + // Add style-resetting classes to the inner list. Handle nested changes. + for (var i = 0; i < inner.length; i++) { + var pos = utils.indexOf(inner[i].classes, newStyle.reset()); + if (pos < 0) { + inner[i].classes.push(options.style.reset(), newStyle.cls()); + } else { + // This is a nested style change, as `\textstyle a\scriptstyle b`. + // Only override the old style (the reset class). + inner[i].classes[pos] = options.style.reset(); + } + } + + return new buildCommon.makeFragment(inner); +}; + +groupTypes.font = function(group, options) { + var font = group.value.font; + return buildGroup(group.value.body, options.withFont(font)); +}; + +groupTypes.delimsizing = function(group, options) { + var delim = group.value.value; + + if (delim === ".") { + // Empty delimiters still count as elements, even though they don't + // show anything. + return makeSpan([group.value.mclass]); + } + + // Use delimiter.sizedDelim to generate the delimiter. + return delimiter.sizedDelim( + delim, group.value.size, options, group.mode, + [group.value.mclass]); +}; + +groupTypes.leftright = function(group, options) { + // Build the inner expression + var inner = buildExpression(group.value.body, options.reset(), true); + + var innerHeight = 0; + var innerDepth = 0; + var hadMiddle = false; + + // Calculate its height and depth + for (var i = 0; i < inner.length; i++) { + if (inner[i].isMiddle) { + hadMiddle = true; + } else { + innerHeight = Math.max(inner[i].height, innerHeight); + innerDepth = Math.max(inner[i].depth, innerDepth); + } + } + + var style = options.style; + + // The size of delimiters is the same, regardless of what style we are + // in. Thus, to correctly calculate the size of delimiter we need around + // a group, we scale down the inner size based on the size. + innerHeight *= style.sizeMultiplier; + innerDepth *= style.sizeMultiplier; + + var leftDelim; + if (group.value.left === ".") { + // Empty delimiters in \left and \right make null delimiter spaces. + leftDelim = makeNullDelimiter(options, ["mopen"]); + } else { + // Otherwise, use leftRightDelim to generate the correct sized + // delimiter. + leftDelim = delimiter.leftRightDelim( + group.value.left, innerHeight, innerDepth, options, + group.mode, ["mopen"]); + } + // Add it to the beginning of the expression + inner.unshift(leftDelim); + + // Handle middle delimiters + if (hadMiddle) { + for (i = 1; i < inner.length; i++) { + if (inner[i].isMiddle) { + // Apply the options that were active when \middle was called + inner[i] = delimiter.leftRightDelim( + inner[i].isMiddle.value, innerHeight, innerDepth, + inner[i].isMiddle.options, group.mode, []); + } + } + } + + var rightDelim; + // Same for the right delimiter + if (group.value.right === ".") { + rightDelim = makeNullDelimiter(options, ["mclose"]); + } else { + rightDelim = delimiter.leftRightDelim( + group.value.right, innerHeight, innerDepth, options, + group.mode, ["mclose"]); + } + // Add it to the end of the expression. + inner.push(rightDelim); + + return makeSpan( + ["minner", style.cls()], inner, options); +}; + +groupTypes.middle = function(group, options) { + var middleDelim; + if (group.value.value === ".") { + middleDelim = makeNullDelimiter(options, []); + } else { + middleDelim = delimiter.sizedDelim( + group.value.value, 1, options, + group.mode, []); + middleDelim.isMiddle = {value: group.value.value, options: options}; + } + return middleDelim; +}; + +groupTypes.rule = function(group, options) { + // Make an empty span for the rule + var rule = makeSpan(["mord", "rule"], [], options); + var style = options.style; + + // Calculate the shift, width, and height of the rule, and account for units + var shift = 0; + if (group.value.shift) { + shift = calculateSize(group.value.shift, style); + } + + var width = calculateSize(group.value.width, style); + var height = calculateSize(group.value.height, style); + + // The sizes of rules are absolute, so make it larger if we are in a + // smaller style. + shift /= style.sizeMultiplier; + width /= style.sizeMultiplier; + height /= style.sizeMultiplier; + + // Style the rule to the right size + rule.style.borderRightWidth = width + "em"; + rule.style.borderTopWidth = height + "em"; + rule.style.bottom = shift + "em"; + + // Record the height and width + rule.width = width; + rule.height = height + shift; + rule.depth = -shift; + + return rule; +}; + +groupTypes.kern = function(group, options) { + // Make an empty span for the rule + var rule = makeSpan(["mord", "rule"], [], options); + var style = options.style; + + var dimension = 0; + if (group.value.dimension) { + dimension = calculateSize(group.value.dimension, style); + } + + dimension /= style.sizeMultiplier; + + rule.style.marginLeft = dimension + "em"; + + return rule; +}; + +groupTypes.accent = function(group, options) { + // Accents are handled in the TeXbook pg. 443, rule 12. + var base = group.value.base; + var style = options.style; + + var supsubGroup; + if (group.type === "supsub") { + // If our base is a character box, and we have superscripts and + // subscripts, the supsub will defer to us. In particular, we want + // to attach the superscripts and subscripts to the inner body (so + // that the position of the superscripts and subscripts won't be + // affected by the height of the accent). We accomplish this by + // sticking the base of the accent into the base of the supsub, and + // rendering that, while keeping track of where the accent is. + + // The supsub group is the group that was passed in + var supsub = group; + // The real accent group is the base of the supsub group + group = supsub.value.base; + // The character box is the base of the accent group + base = group.value.base; + // Stick the character box into the base of the supsub group + supsub.value.base = base; + + // Rerender the supsub group with its new base, and store that + // result. + supsubGroup = buildGroup( + supsub, options.reset()); + } + + // Build the base group + var body = buildGroup( + base, options.withStyle(style.cramp())); + + // Calculate the skew of the accent. This is based on the line "If the + // nucleus is not a single character, let s = 0; otherwise set s to the + // kern amount for the nucleus followed by the \skewchar of its font." + // Note that our skew metrics are just the kern between each character + // and the skewchar. + var skew; + if (isCharacterBox(base)) { + // If the base is a character box, then we want the skew of the + // innermost character. To do that, we find the innermost character: + var baseChar = getBaseElem(base); + // Then, we render its group to get the symbol inside it + var baseGroup = buildGroup( + baseChar, options.withStyle(style.cramp())); + // Finally, we pull the skew off of the symbol. + skew = baseGroup.skew; + // Note that we now throw away baseGroup, because the layers we + // removed with getBaseElem might contain things like \color which + // we can't get rid of. + // TODO(emily): Find a better way to get the skew + } else { + skew = 0; + } + + // calculate the amount of space between the body and the accent + var clearance = Math.min( + body.height, + style.metrics.xHeight); + + // Build the accent + var accent = buildCommon.makeSymbol( + group.value.accent, "Main-Regular", "math", options); + // Remove the italic correction of the accent, because it only serves to + // shift the accent over to a place we don't want. + accent.italic = 0; + + // The \vec character that the fonts use is a combining character, and + // thus shows up much too far to the left. To account for this, we add a + // specific class which shifts the accent over to where we want it. + // TODO(emily): Fix this in a better way, like by changing the font + var vecClass = group.value.accent === "\\vec" ? "accent-vec" : null; + + var accentBody = makeSpan(["accent-body", vecClass], [ + makeSpan([], [accent])]); + + accentBody = buildCommon.makeVList([ + {type: "elem", elem: body}, + {type: "kern", size: -clearance}, + {type: "elem", elem: accentBody} + ], "firstBaseline", null, options); + + // Shift the accent over by the skew. Note we shift by twice the skew + // because we are centering the accent, so by adding 2*skew to the left, + // we shift it to the right by 1*skew. + accentBody.children[1].style.marginLeft = 2 * skew + "em"; + + var accentWrap = makeSpan(["mord", "accent"], [accentBody], options); + + if (supsubGroup) { + // Here, we replace the "base" child of the supsub with our newly + // generated accent. + supsubGroup.children[0] = accentWrap; + + // Since we don't rerun the height calculation after replacing the + // accent, we manually recalculate height. + supsubGroup.height = Math.max(accentWrap.height, supsubGroup.height); + + // Accents should always be ords, even when their innards are not. + supsubGroup.classes[0] = "mord"; + + return supsubGroup; + } else { + return accentWrap; + } +}; + +groupTypes.phantom = function(group, options) { + var elements = buildExpression( + group.value.value, + options.withPhantom(), + false + ); + + // \phantom isn't supposed to affect the elements it contains. + // See "color" for more details. + return new buildCommon.makeFragment(elements); +}; + +groupTypes.mclass = function(group, options) { + var elements = buildExpression(group.value.value, options, true); + + return makeSpan([group.value.mclass], elements, options); +}; + +/** + * buildGroup is the function that takes a group and calls the correct groupType + * function for it. It also handles the interaction of size and style changes + * between parents and children. + */ +var buildGroup = function(group, options) { + if (!group) { + return makeSpan(); + } + + if (groupTypes[group.type]) { + // Call the groupTypes function + var groupNode = groupTypes[group.type](group, options); + var multiplier; + + // If the style changed between the parent and the current group, + // account for the size difference + if (options.style !== options.parentStyle) { + multiplier = options.style.sizeMultiplier / + options.parentStyle.sizeMultiplier; + + groupNode.height *= multiplier; + groupNode.depth *= multiplier; + } + + // If the size changed between the parent and the current group, account + // for that size difference. + if (options.size !== options.parentSize) { + multiplier = buildCommon.sizingMultiplier[options.size] / + buildCommon.sizingMultiplier[options.parentSize]; + + groupNode.height *= multiplier; + groupNode.depth *= multiplier; + } + + return groupNode; + } else { + throw new ParseError( + "Got group of unknown type: '" + group.type + "'"); + } +}; + +/** + * Take an entire parse tree, and build it into an appropriate set of HTML + * nodes. + */ +var buildHTML = function(tree, options) { + // buildExpression is destructive, so we need to make a clone + // of the incoming tree so that it isn't accidentally changed + tree = JSON.parse(JSON.stringify(tree)); + + // Build the expression contained in the tree + var expression = buildExpression(tree, options, true); + var body = makeSpan(["base", options.style.cls()], expression, options); + + // Add struts, which ensure that the top of the HTML element falls at the + // height of the expression, and the bottom of the HTML element falls at the + // depth of the expression. + var topStrut = makeSpan(["strut"]); + var bottomStrut = makeSpan(["strut", "bottom"]); + + topStrut.style.height = body.height + "em"; + bottomStrut.style.height = (body.height + body.depth) + "em"; + // We'd like to use `vertical-align: top` but in IE 9 this lowers the + // baseline of the box to the bottom of this strut (instead staying in the + // normal place) so we use an absolute value for vertical-align instead + bottomStrut.style.verticalAlign = -body.depth + "em"; + + // Wrap the struts and body together + var htmlNode = makeSpan(["katex-html"], [topStrut, bottomStrut, body]); + + htmlNode.setAttribute("aria-hidden", "true"); + + return htmlNode; +}; + +module.exports = buildHTML; + +},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./delimiter":14,"./domTree":15,"./fontMetrics":17,"./utils":25}],12:[function(require,module,exports){ +/** + * This file converts a parse tree into a cooresponding MathML tree. The main + * entry point is the `buildMathML` function, which takes a parse tree from the + * parser. + */ + +var buildCommon = require("./buildCommon"); +var fontMetrics = require("./fontMetrics"); +var mathMLTree = require("./mathMLTree"); +var ParseError = require("./ParseError"); +var symbols = require("./symbols"); +var utils = require("./utils"); + +var makeSpan = buildCommon.makeSpan; +var fontMap = buildCommon.fontMap; + +/** + * Takes a symbol and converts it into a MathML text node after performing + * optional replacement from symbols.js. + */ +var makeText = function(text, mode) { + if (symbols[mode][text] && symbols[mode][text].replace) { + text = symbols[mode][text].replace; + } + + return new mathMLTree.TextNode(text); +}; + +/** + * Returns the math variant as a string or null if none is required. + */ +var getVariant = function(group, options) { + var font = options.font; + if (!font) { + return null; + } + + var mode = group.mode; + if (font === "mathit") { + return "italic"; + } + + var value = group.value; + if (utils.contains(["\\imath", "\\jmath"], value)) { + return null; + } + + if (symbols[mode][value] && symbols[mode][value].replace) { + value = symbols[mode][value].replace; + } + + var fontName = fontMap[font].fontName; + if (fontMetrics.getCharacterMetrics(value, fontName)) { + return fontMap[options.font].variant; + } + + return null; +}; + +/** + * Functions for handling the different types of groups found in the parse + * tree. Each function should take a parse group and return a MathML node. + */ +var groupTypes = {}; + +groupTypes.mathord = function(group, options) { + var node = new mathMLTree.MathNode( + "mi", + [makeText(group.value, group.mode)]); + + var variant = getVariant(group, options); + if (variant) { + node.setAttribute("mathvariant", variant); + } + return node; +}; + +groupTypes.textord = function(group, options) { + var text = makeText(group.value, group.mode); + + var variant = getVariant(group, options) || "normal"; + + var node; + if (/[0-9]/.test(group.value)) { + // TODO(kevinb) merge adjacent nodes + // do it as a post processing step + node = new mathMLTree.MathNode("mn", [text]); + if (options.font) { + node.setAttribute("mathvariant", variant); + } + } else { + node = new mathMLTree.MathNode("mi", [text]); + node.setAttribute("mathvariant", variant); + } + + return node; +}; + +groupTypes.bin = function(group) { + var node = new mathMLTree.MathNode( + "mo", [makeText(group.value, group.mode)]); + + return node; +}; + +groupTypes.rel = function(group) { + var node = new mathMLTree.MathNode( + "mo", [makeText(group.value, group.mode)]); + + return node; +}; + +groupTypes.open = function(group) { + var node = new mathMLTree.MathNode( + "mo", [makeText(group.value, group.mode)]); + + return node; +}; + +groupTypes.close = function(group) { + var node = new mathMLTree.MathNode( + "mo", [makeText(group.value, group.mode)]); + + return node; +}; + +groupTypes.inner = function(group) { + var node = new mathMLTree.MathNode( + "mo", [makeText(group.value, group.mode)]); + + return node; +}; + +groupTypes.punct = function(group) { + var node = new mathMLTree.MathNode( + "mo", [makeText(group.value, group.mode)]); + + node.setAttribute("separator", "true"); + + return node; +}; + +groupTypes.ordgroup = function(group, options) { + var inner = buildExpression(group.value, options); + + var node = new mathMLTree.MathNode("mrow", inner); + + return node; +}; + +groupTypes.text = function(group, options) { + var inner = buildExpression(group.value.body, options); + + var node = new mathMLTree.MathNode("mtext", inner); + + return node; +}; + +groupTypes.color = function(group, options) { + var inner = buildExpression(group.value.value, options); + + var node = new mathMLTree.MathNode("mstyle", inner); + + node.setAttribute("mathcolor", group.value.color); + + return node; +}; + +groupTypes.supsub = function(group, options) { + var children = [buildGroup(group.value.base, options)]; + + if (group.value.sub) { + children.push(buildGroup(group.value.sub, options)); + } + + if (group.value.sup) { + children.push(buildGroup(group.value.sup, options)); + } + + var nodeType; + if (!group.value.sub) { + nodeType = "msup"; + } else if (!group.value.sup) { + nodeType = "msub"; + } else { + nodeType = "msubsup"; + } + + var node = new mathMLTree.MathNode(nodeType, children); + + return node; +}; + +groupTypes.genfrac = function(group, options) { + var node = new mathMLTree.MathNode( + "mfrac", + [buildGroup(group.value.numer, options), + buildGroup(group.value.denom, options)]); + + if (!group.value.hasBarLine) { + node.setAttribute("linethickness", "0px"); + } + + if (group.value.leftDelim != null || group.value.rightDelim != null) { + var withDelims = []; + + if (group.value.leftDelim != null) { + var leftOp = new mathMLTree.MathNode( + "mo", [new mathMLTree.TextNode(group.value.leftDelim)]); + + leftOp.setAttribute("fence", "true"); + + withDelims.push(leftOp); + } + + withDelims.push(node); + + if (group.value.rightDelim != null) { + var rightOp = new mathMLTree.MathNode( + "mo", [new mathMLTree.TextNode(group.value.rightDelim)]); + + rightOp.setAttribute("fence", "true"); + + withDelims.push(rightOp); + } + + var outerNode = new mathMLTree.MathNode("mrow", withDelims); + + return outerNode; + } + + return node; +}; + +groupTypes.array = function(group, options) { + return new mathMLTree.MathNode( + "mtable", group.value.body.map(function(row) { + return new mathMLTree.MathNode( + "mtr", row.map(function(cell) { + return new mathMLTree.MathNode( + "mtd", [buildGroup(cell, options)]); + })); + })); +}; + +groupTypes.sqrt = function(group, options) { + var node; + if (group.value.index) { + node = new mathMLTree.MathNode( + "mroot", [ + buildGroup(group.value.body, options), + buildGroup(group.value.index, options) + ]); + } else { + node = new mathMLTree.MathNode( + "msqrt", [buildGroup(group.value.body, options)]); + } + + return node; +}; + +groupTypes.leftright = function(group, options) { + var inner = buildExpression(group.value.body, options); + + if (group.value.left !== ".") { + var leftNode = new mathMLTree.MathNode( + "mo", [makeText(group.value.left, group.mode)]); + + leftNode.setAttribute("fence", "true"); + + inner.unshift(leftNode); + } + + if (group.value.right !== ".") { + var rightNode = new mathMLTree.MathNode( + "mo", [makeText(group.value.right, group.mode)]); + + rightNode.setAttribute("fence", "true"); + + inner.push(rightNode); + } + + var outerNode = new mathMLTree.MathNode("mrow", inner); + + return outerNode; +}; + +groupTypes.middle = function(group, options) { + var middleNode = new mathMLTree.MathNode( + "mo", [makeText(group.value.middle, group.mode)]); + middleNode.setAttribute("fence", "true"); + return middleNode; +}; + +groupTypes.accent = function(group, options) { + var accentNode = new mathMLTree.MathNode( + "mo", [makeText(group.value.accent, group.mode)]); + + var node = new mathMLTree.MathNode( + "mover", + [buildGroup(group.value.base, options), + accentNode]); + + node.setAttribute("accent", "true"); + + return node; +}; + +groupTypes.spacing = function(group) { + var node; + + if (group.value === "\\ " || group.value === "\\space" || + group.value === " " || group.value === "~") { + node = new mathMLTree.MathNode( + "mtext", [new mathMLTree.TextNode("\u00a0")]); + } else { + node = new mathMLTree.MathNode("mspace"); + + node.setAttribute( + "width", buildCommon.spacingFunctions[group.value].size); + } + + return node; +}; + +groupTypes.op = function(group, options) { + var node; + + // TODO(emily): handle big operators using the `largeop` attribute + + if (group.value.symbol) { + // This is a symbol. Just add the symbol. + node = new mathMLTree.MathNode( + "mo", [makeText(group.value.body, group.mode)]); + } else if (group.value.value) { + // This is an operator with children. Add them. + node = new mathMLTree.MathNode( + "mo", buildExpression(group.value.value, options)); + } else { + // This is a text operator. Add all of the characters from the + // operator's name. + // TODO(emily): Add a space in the middle of some of these + // operators, like \limsup. + node = new mathMLTree.MathNode( + "mi", [new mathMLTree.TextNode(group.value.body.slice(1))]); + } + + return node; +}; + +groupTypes.mod = function(group, options) { + var inner = []; + + if (group.value.modType === "pod" || group.value.modType === "pmod") { + inner.push(new mathMLTree.MathNode( + "mo", [makeText("(", group.mode)])); + } + if (group.value.modType !== "pod") { + inner.push(new mathMLTree.MathNode( + "mo", [makeText("mod", group.mode)])); + } + if (group.value.value) { + var space = new mathMLTree.MathNode("mspace"); + space.setAttribute("width", "0.333333em"); + inner.push(space); + inner = inner.concat(buildExpression(group.value.value, options)); + } + if (group.value.modType === "pod" || group.value.modType === "pmod") { + inner.push(new mathMLTree.MathNode( + "mo", [makeText(")", group.mode)])); + } + + return new mathMLTree.MathNode("mo", inner); +}; + +groupTypes.katex = function(group) { + var node = new mathMLTree.MathNode( + "mtext", [new mathMLTree.TextNode("KaTeX")]); + + return node; +}; + +groupTypes.font = function(group, options) { + var font = group.value.font; + return buildGroup(group.value.body, options.withFont(font)); +}; + +groupTypes.delimsizing = function(group) { + var children = []; + + if (group.value.value !== ".") { + children.push(makeText(group.value.value, group.mode)); + } + + var node = new mathMLTree.MathNode("mo", children); + + if (group.value.mclass === "mopen" || + group.value.mclass === "mclose") { + // Only some of the delimsizing functions act as fences, and they + // return "mopen" or "mclose" mclass. + node.setAttribute("fence", "true"); + } else { + // Explicitly disable fencing if it's not a fence, to override the + // defaults. + node.setAttribute("fence", "false"); + } + + return node; +}; + +groupTypes.styling = function(group, options) { + var inner = buildExpression(group.value.value, options); + + var node = new mathMLTree.MathNode("mstyle", inner); + + var styleAttributes = { + "display": ["0", "true"], + "text": ["0", "false"], + "script": ["1", "false"], + "scriptscript": ["2", "false"] + }; + + var attr = styleAttributes[group.value.style]; + + node.setAttribute("scriptlevel", attr[0]); + node.setAttribute("displaystyle", attr[1]); + + return node; +}; + +groupTypes.sizing = function(group, options) { + var inner = buildExpression(group.value.value, options); + + var node = new mathMLTree.MathNode("mstyle", inner); + + // TODO(emily): This doesn't produce the correct size for nested size + // changes, because we don't keep state of what style we're currently + // in, so we can't reset the size to normal before changing it. Now + // that we're passing an options parameter we should be able to fix + // this. + node.setAttribute( + "mathsize", buildCommon.sizingMultiplier[group.value.size] + "em"); + + return node; +}; + +groupTypes.overline = function(group, options) { + var operator = new mathMLTree.MathNode( + "mo", [new mathMLTree.TextNode("\u203e")]); + operator.setAttribute("stretchy", "true"); + + var node = new mathMLTree.MathNode( + "mover", + [buildGroup(group.value.body, options), + operator]); + node.setAttribute("accent", "true"); + + return node; +}; + +groupTypes.underline = function(group, options) { + var operator = new mathMLTree.MathNode( + "mo", [new mathMLTree.TextNode("\u203e")]); + operator.setAttribute("stretchy", "true"); + + var node = new mathMLTree.MathNode( + "munder", + [buildGroup(group.value.body, options), + operator]); + node.setAttribute("accentunder", "true"); + + return node; +}; + +groupTypes.rule = function(group) { + // TODO(emily): Figure out if there's an actual way to draw black boxes + // in MathML. + var node = new mathMLTree.MathNode("mrow"); + + return node; +}; + +groupTypes.kern = function(group) { + // TODO(kevin): Figure out if there's a way to add space in MathML + var node = new mathMLTree.MathNode("mrow"); + + return node; +}; + +groupTypes.llap = function(group, options) { + var node = new mathMLTree.MathNode( + "mpadded", [buildGroup(group.value.body, options)]); + + node.setAttribute("lspace", "-1width"); + node.setAttribute("width", "0px"); + + return node; +}; + +groupTypes.rlap = function(group, options) { + var node = new mathMLTree.MathNode( + "mpadded", [buildGroup(group.value.body, options)]); + + node.setAttribute("width", "0px"); + + return node; +}; + +groupTypes.phantom = function(group, options) { + var inner = buildExpression(group.value.value, options); + return new mathMLTree.MathNode("mphantom", inner); +}; + +groupTypes.mclass = function(group, options) { + var inner = buildExpression(group.value.value, options); + return new mathMLTree.MathNode("mstyle", inner); +}; + +/** + * Takes a list of nodes, builds them, and returns a list of the generated + * MathML nodes. A little simpler than the HTML version because we don't do any + * previous-node handling. + */ +var buildExpression = function(expression, options) { + var groups = []; + for (var i = 0; i < expression.length; i++) { + var group = expression[i]; + groups.push(buildGroup(group, options)); + } + return groups; +}; + +/** + * Takes a group from the parser and calls the appropriate groupTypes function + * on it to produce a MathML node. + */ +var buildGroup = function(group, options) { + if (!group) { + return new mathMLTree.MathNode("mrow"); + } + + if (groupTypes[group.type]) { + // Call the groupTypes function + return groupTypes[group.type](group, options); + } else { + throw new ParseError( + "Got group of unknown type: '" + group.type + "'"); + } +}; + +/** + * Takes a full parse tree and settings and builds a MathML representation of + * it. In particular, we put the elements from building the parse tree into a + * tag so we can also include that TeX source as an annotation. + * + * Note that we actually return a domTree element with a `` inside it so + * we can do appropriate styling. + */ +var buildMathML = function(tree, texExpression, options) { + var expression = buildExpression(tree, options); + + // Wrap up the expression in an mrow so it is presented in the semantics + // tag correctly. + var wrapper = new mathMLTree.MathNode("mrow", expression); + + // Build a TeX annotation of the source + var annotation = new mathMLTree.MathNode( + "annotation", [new mathMLTree.TextNode(texExpression)]); + + annotation.setAttribute("encoding", "application/x-tex"); + + var semantics = new mathMLTree.MathNode( + "semantics", [wrapper, annotation]); + + var math = new mathMLTree.MathNode("math", [semantics]); + + // You can't style nodes, so we wrap the node in a span. + return makeSpan(["katex-mathml"], [math]); +}; + +module.exports = buildMathML; + +},{"./ParseError":6,"./buildCommon":10,"./fontMetrics":17,"./mathMLTree":20,"./symbols":23,"./utils":25}],13:[function(require,module,exports){ +var buildHTML = require("./buildHTML"); +var buildMathML = require("./buildMathML"); +var buildCommon = require("./buildCommon"); +var Options = require("./Options"); +var Settings = require("./Settings"); +var Style = require("./Style"); + +var makeSpan = buildCommon.makeSpan; + +var buildTree = function(tree, expression, settings) { + settings = settings || new Settings({}); + + var startStyle = Style.TEXT; + if (settings.displayMode) { + startStyle = Style.DISPLAY; + } + + // Setup the default options + var options = new Options({ + style: startStyle, + size: "size5" + }); + + // `buildHTML` sometimes messes with the parse tree (like turning bins -> + // ords), so we build the MathML version first. + var mathMLNode = buildMathML(tree, expression, options); + var htmlNode = buildHTML(tree, options); + + var katexNode = makeSpan(["katex"], [ + mathMLNode, htmlNode + ]); + + if (settings.displayMode) { + return makeSpan(["katex-display"], [katexNode]); + } else { + return katexNode; + } +}; + +module.exports = buildTree; + +},{"./Options":5,"./Settings":8,"./Style":9,"./buildCommon":10,"./buildHTML":11,"./buildMathML":12}],14:[function(require,module,exports){ +/** + * This file deals with creating delimiters of various sizes. The TeXbook + * discusses these routines on page 441-442, in the "Another subroutine sets box + * x to a specified variable delimiter" paragraph. + * + * There are three main routines here. `makeSmallDelim` makes a delimiter in the + * normal font, but in either text, script, or scriptscript style. + * `makeLargeDelim` makes a delimiter in textstyle, but in one of the Size1, + * Size2, Size3, or Size4 fonts. `makeStackedDelim` makes a delimiter out of + * smaller pieces that are stacked on top of one another. + * + * The functions take a parameter `center`, which determines if the delimiter + * should be centered around the axis. + * + * Then, there are three exposed functions. `sizedDelim` makes a delimiter in + * one of the given sizes. This is used for things like `\bigl`. + * `customSizedDelim` makes a delimiter with a given total height+depth. It is + * called in places like `\sqrt`. `leftRightDelim` makes an appropriate + * delimiter which surrounds an expression of a given height an depth. It is + * used in `\left` and `\right`. + */ + +var ParseError = require("./ParseError"); +var Style = require("./Style"); + +var buildCommon = require("./buildCommon"); +var fontMetrics = require("./fontMetrics"); +var symbols = require("./symbols"); +var utils = require("./utils"); + +var makeSpan = buildCommon.makeSpan; + +/** + * Get the metrics for a given symbol and font, after transformation (i.e. + * after following replacement from symbols.js) + */ +var getMetrics = function(symbol, font) { + if (symbols.math[symbol] && symbols.math[symbol].replace) { + return fontMetrics.getCharacterMetrics( + symbols.math[symbol].replace, font); + } else { + return fontMetrics.getCharacterMetrics( + symbol, font); + } +}; + +/** + * Builds a symbol in the given font size (note size is an integer) + */ +var mathrmSize = function(value, size, mode, options) { + return buildCommon.makeSymbol(value, "Size" + size + "-Regular", + mode, options); +}; + +/** + * Puts a delimiter span in a given style, and adds appropriate height, depth, + * and maxFontSizes. + */ +var styleWrap = function(delim, toStyle, options, classes) { + classes = classes || []; + var span = makeSpan( + classes.concat(["style-wrap", options.style.reset(), toStyle.cls()]), + [delim], options); + + var multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier; + + span.height *= multiplier; + span.depth *= multiplier; + span.maxFontSize = toStyle.sizeMultiplier; + + return span; +}; + +/** + * Makes a small delimiter. This is a delimiter that comes in the Main-Regular + * font, but is restyled to either be in textstyle, scriptstyle, or + * scriptscriptstyle. + */ +var makeSmallDelim = function(delim, style, center, options, mode, classes) { + var text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options); + + var span = styleWrap(text, style, options, classes); + + if (center) { + var shift = + (1 - options.style.sizeMultiplier / style.sizeMultiplier) * + options.style.metrics.axisHeight; + + span.style.top = shift + "em"; + span.height -= shift; + span.depth += shift; + } + + return span; +}; + +/** + * Makes a large delimiter. This is a delimiter that comes in the Size1, Size2, + * Size3, or Size4 fonts. It is always rendered in textstyle. + */ +var makeLargeDelim = function(delim, size, center, options, mode, classes) { + var inner = mathrmSize(delim, size, mode, options); + + var span = styleWrap( + makeSpan(["delimsizing", "size" + size], [inner], options), + Style.TEXT, options, classes); + + if (center) { + var shift = (1 - options.style.sizeMultiplier) * + options.style.metrics.axisHeight; + + span.style.top = shift + "em"; + span.height -= shift; + span.depth += shift; + } + + return span; +}; + +/** + * Make an inner span with the given offset and in the given font. This is used + * in `makeStackedDelim` to make the stacking pieces for the delimiter. + */ +var makeInner = function(symbol, font, mode) { + var sizeClass; + // Apply the correct CSS class to choose the right font. + if (font === "Size1-Regular") { + sizeClass = "delim-size1"; + } else if (font === "Size4-Regular") { + sizeClass = "delim-size4"; + } + + var inner = makeSpan( + ["delimsizinginner", sizeClass], + [makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]); + + // Since this will be passed into `makeVList` in the end, wrap the element + // in the appropriate tag that VList uses. + return {type: "elem", elem: inner}; +}; + +/** + * Make a stacked delimiter out of a given delimiter, with the total height at + * least `heightTotal`. This routine is mentioned on page 442 of the TeXbook. + */ +var makeStackedDelim = function(delim, heightTotal, center, options, mode, + classes) { + // There are four parts, the top, an optional middle, a repeated part, and a + // bottom. + var top; + var middle; + var repeat; + var bottom; + top = repeat = bottom = delim; + middle = null; + // Also keep track of what font the delimiters are in + var font = "Size1-Regular"; + + // We set the parts and font based on the symbol. Note that we use + // '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the + // repeats of the arrows + if (delim === "\\uparrow") { + repeat = bottom = "\u23d0"; + } else if (delim === "\\Uparrow") { + repeat = bottom = "\u2016"; + } else if (delim === "\\downarrow") { + top = repeat = "\u23d0"; + } else if (delim === "\\Downarrow") { + top = repeat = "\u2016"; + } else if (delim === "\\updownarrow") { + top = "\\uparrow"; + repeat = "\u23d0"; + bottom = "\\downarrow"; + } else if (delim === "\\Updownarrow") { + top = "\\Uparrow"; + repeat = "\u2016"; + bottom = "\\Downarrow"; + } else if (delim === "[" || delim === "\\lbrack") { + top = "\u23a1"; + repeat = "\u23a2"; + bottom = "\u23a3"; + font = "Size4-Regular"; + } else if (delim === "]" || delim === "\\rbrack") { + top = "\u23a4"; + repeat = "\u23a5"; + bottom = "\u23a6"; + font = "Size4-Regular"; + } else if (delim === "\\lfloor") { + repeat = top = "\u23a2"; + bottom = "\u23a3"; + font = "Size4-Regular"; + } else if (delim === "\\lceil") { + top = "\u23a1"; + repeat = bottom = "\u23a2"; + font = "Size4-Regular"; + } else if (delim === "\\rfloor") { + repeat = top = "\u23a5"; + bottom = "\u23a6"; + font = "Size4-Regular"; + } else if (delim === "\\rceil") { + top = "\u23a4"; + repeat = bottom = "\u23a5"; + font = "Size4-Regular"; + } else if (delim === "(") { + top = "\u239b"; + repeat = "\u239c"; + bottom = "\u239d"; + font = "Size4-Regular"; + } else if (delim === ")") { + top = "\u239e"; + repeat = "\u239f"; + bottom = "\u23a0"; + font = "Size4-Regular"; + } else if (delim === "\\{" || delim === "\\lbrace") { + top = "\u23a7"; + middle = "\u23a8"; + bottom = "\u23a9"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\}" || delim === "\\rbrace") { + top = "\u23ab"; + middle = "\u23ac"; + bottom = "\u23ad"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\lgroup") { + top = "\u23a7"; + bottom = "\u23a9"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\rgroup") { + top = "\u23ab"; + bottom = "\u23ad"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\lmoustache") { + top = "\u23a7"; + bottom = "\u23ad"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\rmoustache") { + top = "\u23ab"; + bottom = "\u23a9"; + repeat = "\u23aa"; + font = "Size4-Regular"; + } else if (delim === "\\surd") { + top = "\ue001"; + bottom = "\u23b7"; + repeat = "\ue000"; + font = "Size4-Regular"; + } + + // Get the metrics of the four sections + var topMetrics = getMetrics(top, font); + var topHeightTotal = topMetrics.height + topMetrics.depth; + var repeatMetrics = getMetrics(repeat, font); + var repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth; + var bottomMetrics = getMetrics(bottom, font); + var bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth; + var middleHeightTotal = 0; + var middleFactor = 1; + if (middle !== null) { + var middleMetrics = getMetrics(middle, font); + middleHeightTotal = middleMetrics.height + middleMetrics.depth; + middleFactor = 2; // repeat symmetrically above and below middle + } + + // Calcuate the minimal height that the delimiter can have. + // It is at least the size of the top, bottom, and optional middle combined. + var minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal; + + // Compute the number of copies of the repeat symbol we will need + var repeatCount = Math.ceil( + (heightTotal - minHeight) / (middleFactor * repeatHeightTotal)); + + // Compute the total height of the delimiter including all the symbols + var realHeightTotal = + minHeight + repeatCount * middleFactor * repeatHeightTotal; + + // The center of the delimiter is placed at the center of the axis. Note + // that in this context, "center" means that the delimiter should be + // centered around the axis in the current style, while normally it is + // centered around the axis in textstyle. + var axisHeight = options.style.metrics.axisHeight; + if (center) { + axisHeight *= options.style.sizeMultiplier; + } + // Calculate the depth + var depth = realHeightTotal / 2 - axisHeight; + + // Now, we start building the pieces that will go into the vlist + + // Keep a list of the inner pieces + var inners = []; + + // Add the bottom symbol + inners.push(makeInner(bottom, font, mode)); + + var i; + if (middle === null) { + // Add that many symbols + for (i = 0; i < repeatCount; i++) { + inners.push(makeInner(repeat, font, mode)); + } + } else { + // When there is a middle bit, we need the middle part and two repeated + // sections + for (i = 0; i < repeatCount; i++) { + inners.push(makeInner(repeat, font, mode)); + } + inners.push(makeInner(middle, font, mode)); + for (i = 0; i < repeatCount; i++) { + inners.push(makeInner(repeat, font, mode)); + } + } + + // Add the top symbol + inners.push(makeInner(top, font, mode)); + + // Finally, build the vlist + var inner = buildCommon.makeVList(inners, "bottom", depth, options); + + return styleWrap( + makeSpan(["delimsizing", "mult"], [inner], options), + Style.TEXT, options, classes); +}; + +// There are three kinds of delimiters, delimiters that stack when they become +// too large +var stackLargeDelimiters = [ + "(", ")", "[", "\\lbrack", "]", "\\rbrack", + "\\{", "\\lbrace", "\\}", "\\rbrace", + "\\lfloor", "\\rfloor", "\\lceil", "\\rceil", + "\\surd" +]; + +// delimiters that always stack +var stackAlwaysDelimiters = [ + "\\uparrow", "\\downarrow", "\\updownarrow", + "\\Uparrow", "\\Downarrow", "\\Updownarrow", + "|", "\\|", "\\vert", "\\Vert", + "\\lvert", "\\rvert", "\\lVert", "\\rVert", + "\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache" +]; + +// and delimiters that never stack +var stackNeverDelimiters = [ + "<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt" +]; + +// Metrics of the different sizes. Found by looking at TeX's output of +// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ +// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. +var sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; + +/** + * Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4. + */ +var makeSizedDelim = function(delim, size, options, mode, classes) { + // < and > turn into \langle and \rangle in delimiters + if (delim === "<" || delim === "\\lt") { + delim = "\\langle"; + } else if (delim === ">" || delim === "\\gt") { + delim = "\\rangle"; + } + + // Sized delimiters are never centered. + if (utils.contains(stackLargeDelimiters, delim) || + utils.contains(stackNeverDelimiters, delim)) { + return makeLargeDelim(delim, size, false, options, mode, classes); + } else if (utils.contains(stackAlwaysDelimiters, delim)) { + return makeStackedDelim( + delim, sizeToMaxHeight[size], false, options, mode, classes); + } else { + throw new ParseError("Illegal delimiter: '" + delim + "'"); + } +}; + +/** + * There are three different sequences of delimiter sizes that the delimiters + * follow depending on the kind of delimiter. This is used when creating custom + * sized delimiters to decide whether to create a small, large, or stacked + * delimiter. + * + * In real TeX, these sequences aren't explicitly defined, but are instead + * defined inside the font metrics. Since there are only three sequences that + * are possible for the delimiters that TeX defines, it is easier to just encode + * them explicitly here. + */ + +// Delimiters that never stack try small delimiters and large delimiters only +var stackNeverDelimiterSequence = [ + {type: "small", style: Style.SCRIPTSCRIPT}, + {type: "small", style: Style.SCRIPT}, + {type: "small", style: Style.TEXT}, + {type: "large", size: 1}, + {type: "large", size: 2}, + {type: "large", size: 3}, + {type: "large", size: 4} +]; + +// Delimiters that always stack try the small delimiters first, then stack +var stackAlwaysDelimiterSequence = [ + {type: "small", style: Style.SCRIPTSCRIPT}, + {type: "small", style: Style.SCRIPT}, + {type: "small", style: Style.TEXT}, + {type: "stack"} +]; + +// Delimiters that stack when large try the small and then large delimiters, and +// stack afterwards +var stackLargeDelimiterSequence = [ + {type: "small", style: Style.SCRIPTSCRIPT}, + {type: "small", style: Style.SCRIPT}, + {type: "small", style: Style.TEXT}, + {type: "large", size: 1}, + {type: "large", size: 2}, + {type: "large", size: 3}, + {type: "large", size: 4}, + {type: "stack"} +]; + +/** + * Get the font used in a delimiter based on what kind of delimiter it is. + */ +var delimTypeToFont = function(type) { + if (type.type === "small") { + return "Main-Regular"; + } else if (type.type === "large") { + return "Size" + type.size + "-Regular"; + } else if (type.type === "stack") { + return "Size4-Regular"; + } +}; + +/** + * Traverse a sequence of types of delimiters to decide what kind of delimiter + * should be used to create a delimiter of the given height+depth. + */ +var traverseSequence = function(delim, height, sequence, options) { + // Here, we choose the index we should start at in the sequences. In smaller + // sizes (which correspond to larger numbers in style.size) we start earlier + // in the sequence. Thus, scriptscript starts at index 3-3=0, script starts + // at index 3-2=1, text starts at 3-1=2, and display starts at min(2,3-0)=2 + var start = Math.min(2, 3 - options.style.size); + for (var i = start; i < sequence.length; i++) { + if (sequence[i].type === "stack") { + // This is always the last delimiter, so we just break the loop now. + break; + } + + var metrics = getMetrics(delim, delimTypeToFont(sequence[i])); + var heightDepth = metrics.height + metrics.depth; + + // Small delimiters are scaled down versions of the same font, so we + // account for the style change size. + + if (sequence[i].type === "small") { + heightDepth *= sequence[i].style.sizeMultiplier; + } + + // Check if the delimiter at this size works for the given height. + if (heightDepth > height) { + return sequence[i]; + } + } + + // If we reached the end of the sequence, return the last sequence element. + return sequence[sequence.length - 1]; +}; + +/** + * Make a delimiter of a given height+depth, with optional centering. Here, we + * traverse the sequences, and create a delimiter that the sequence tells us to. + */ +var makeCustomSizedDelim = function(delim, height, center, options, mode, + classes) { + if (delim === "<" || delim === "\\lt") { + delim = "\\langle"; + } else if (delim === ">" || delim === "\\gt") { + delim = "\\rangle"; + } + + // Decide what sequence to use + var sequence; + if (utils.contains(stackNeverDelimiters, delim)) { + sequence = stackNeverDelimiterSequence; + } else if (utils.contains(stackLargeDelimiters, delim)) { + sequence = stackLargeDelimiterSequence; + } else { + sequence = stackAlwaysDelimiterSequence; + } + + // Look through the sequence + var delimType = traverseSequence(delim, height, sequence, options); + + // Depending on the sequence element we decided on, call the appropriate + // function. + if (delimType.type === "small") { + return makeSmallDelim(delim, delimType.style, center, options, mode, + classes); + } else if (delimType.type === "large") { + return makeLargeDelim(delim, delimType.size, center, options, mode, + classes); + } else if (delimType.type === "stack") { + return makeStackedDelim(delim, height, center, options, mode, classes); + } +}; + +/** + * Make a delimiter for use with `\left` and `\right`, given a height and depth + * of an expression that the delimiters surround. + */ +var makeLeftRightDelim = function(delim, height, depth, options, mode, + classes) { + // We always center \left/\right delimiters, so the axis is always shifted + var axisHeight = + options.style.metrics.axisHeight * options.style.sizeMultiplier; + + // Taken from TeX source, tex.web, function make_left_right + var delimiterFactor = 901; + var delimiterExtend = 5.0 / fontMetrics.metrics.ptPerEm; + + var maxDistFromAxis = Math.max( + height - axisHeight, depth + axisHeight); + + var totalHeight = Math.max( + // In real TeX, calculations are done using integral values which are + // 65536 per pt, or 655360 per em. So, the division here truncates in + // TeX but doesn't here, producing different results. If we wanted to + // exactly match TeX's calculation, we could do + // Math.floor(655360 * maxDistFromAxis / 500) * + // delimiterFactor / 655360 + // (To see the difference, compare + // x^{x^{\left(\rule{0.1em}{0.68em}\right)}} + // in TeX and KaTeX) + maxDistFromAxis / 500 * delimiterFactor, + 2 * maxDistFromAxis - delimiterExtend); + + // Finally, we defer to `makeCustomSizedDelim` with our calculated total + // height + return makeCustomSizedDelim(delim, totalHeight, true, options, mode, + classes); +}; + +module.exports = { + sizedDelim: makeSizedDelim, + customSizedDelim: makeCustomSizedDelim, + leftRightDelim: makeLeftRightDelim +}; + +},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./fontMetrics":17,"./symbols":23,"./utils":25}],15:[function(require,module,exports){ +/** + * These objects store the data about the DOM nodes we create, as well as some + * extra data. They can then be transformed into real DOM nodes with the + * `toNode` function or HTML markup using `toMarkup`. They are useful for both + * storing extra properties on the nodes, as well as providing a way to easily + * work with the DOM. + * + * Similar functions for working with MathML nodes exist in mathMLTree.js. + */ +var unicodeRegexes = require("./unicodeRegexes"); +var utils = require("./utils"); + +/** + * Create an HTML className based on a list of classes. In addition to joining + * with spaces, we also remove null or empty classes. + */ +var createClass = function(classes) { + classes = classes.slice(); + for (var i = classes.length - 1; i >= 0; i--) { + if (!classes[i]) { + classes.splice(i, 1); + } + } + + return classes.join(" "); +}; + +/** + * This node represents a span node, with a className, a list of children, and + * an inline style. It also contains information about its height, depth, and + * maxFontSize. + */ +function span(classes, children, options) { + this.classes = classes || []; + this.children = children || []; + this.height = 0; + this.depth = 0; + this.maxFontSize = 0; + this.style = {}; + this.attributes = {}; + if (options) { + if (options.style.isTight()) { + this.classes.push("mtight"); + } + if (options.getColor()) { + this.style.color = options.getColor(); + } + } +} + +/** + * Sets an arbitrary attribute on the span. Warning: use this wisely. Not all + * browsers support attributes the same, and having too many custom attributes + * is probably bad. + */ +span.prototype.setAttribute = function(attribute, value) { + this.attributes[attribute] = value; +}; + +span.prototype.tryCombine = function(sibling) { + return false; +}; + +/** + * Convert the span into an HTML node + */ +span.prototype.toNode = function() { + var span = document.createElement("span"); + + // Apply the class + span.className = createClass(this.classes); + + // Apply inline styles + for (var style in this.style) { + if (Object.prototype.hasOwnProperty.call(this.style, style)) { + span.style[style] = this.style[style]; + } + } + + // Apply attributes + for (var attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + span.setAttribute(attr, this.attributes[attr]); + } + } + + // Append the children, also as HTML nodes + for (var i = 0; i < this.children.length; i++) { + span.appendChild(this.children[i].toNode()); + } + + return span; +}; + +/** + * Convert the span into an HTML markup string + */ +span.prototype.toMarkup = function() { + var markup = " 0 + || createClass(this.classes) !== createClass(sibling.classes) + || this.skew !== sibling.skew + || this.maxFontSize !== sibling.maxFontSize) { + return false; + } + for (var style in this.style) { + if (this.style.hasOwnProperty(style) + && this.style[style] !== sibling.style[style]) { + return false; + } + } + for (style in sibling.style) { + if (sibling.style.hasOwnProperty(style) + && this.style[style] !== sibling.style[style]) { + return false; + } + } + this.value += sibling.value; + this.height = Math.max(this.height, sibling.height); + this.depth = Math.max(this.depth, sibling.depth); + this.italic = sibling.italic; + return true; +}; + +/** + * Creates a text node or span from a symbol node. Note that a span is only + * created if it is needed. + */ +symbolNode.prototype.toNode = function() { + var node = document.createTextNode(this.value); + var span = null; + + if (this.italic > 0) { + span = document.createElement("span"); + span.style.marginRight = this.italic + "em"; + } + + if (this.classes.length > 0) { + span = span || document.createElement("span"); + span.className = createClass(this.classes); + } + + for (var style in this.style) { + if (this.style.hasOwnProperty(style)) { + span = span || document.createElement("span"); + span.style[style] = this.style[style]; + } + } + + if (span) { + span.appendChild(node); + return span; + } else { + return node; + } +}; + +/** + * Creates markup for a symbol node. + */ +symbolNode.prototype.toMarkup = function() { + // TODO(alpert): More duplication than I'd like from + // span.prototype.toMarkup and symbolNode.prototype.toNode... + var needsSpan = false; + + var markup = " 0) { + styles += "margin-right:" + this.italic + "em;"; + } + for (var style in this.style) { + if (this.style.hasOwnProperty(style)) { + styles += utils.hyphenate(style) + ":" + this.style[style] + ";"; + } + } + + if (styles) { + needsSpan = true; + markup += " style=\"" + utils.escape(styles) + "\""; + } + + var escaped = utils.escape(this.value); + if (needsSpan) { + markup += ">"; + markup += escaped; + markup += ""; + return markup; + } else { + return escaped; + } +}; + +module.exports = { + span: span, + documentFragment: documentFragment, + symbolNode: symbolNode +}; + +},{"./unicodeRegexes":24,"./utils":25}],16:[function(require,module,exports){ +/* eslint no-constant-condition:0 */ +var parseData = require("./parseData"); +var ParseError = require("./ParseError"); +var Style = require("./Style"); + +var ParseNode = parseData.ParseNode; + +/** + * Parse the body of the environment, with rows delimited by \\ and + * columns delimited by &, and create a nested list in row-major order + * with one group per cell. + */ +function parseArray(parser, result) { + var row = []; + var body = [row]; + var rowGaps = []; + while (true) { + var cell = parser.parseExpression(false, null); + row.push(new ParseNode("ordgroup", cell, parser.mode)); + var next = parser.nextToken.text; + if (next === "&") { + parser.consume(); + } else if (next === "\\end") { + break; + } else if (next === "\\\\" || next === "\\cr") { + var cr = parser.parseFunction(); + rowGaps.push(cr.value.size); + row = []; + body.push(row); + } else { + throw new ParseError("Expected & or \\\\ or \\end", + parser.nextToken); + } + } + result.body = body; + result.rowGaps = rowGaps; + return new ParseNode(result.type, result, parser.mode); +} + +/* + * An environment definition is very similar to a function definition: + * it is declared with a name or a list of names, a set of properties + * and a handler containing the actual implementation. + * + * The properties include: + * - numArgs: The number of arguments after the \begin{name} function. + * - argTypes: (optional) Just like for a function + * - allowedInText: (optional) Whether or not the environment is allowed inside + * text mode (default false) (not enforced yet) + * - numOptionalArgs: (optional) Just like for a function + * A bare number instead of that object indicates the numArgs value. + * + * The handler function will receive two arguments + * - context: information and references provided by the parser + * - args: an array of arguments passed to \begin{name} + * The context contains the following properties: + * - envName: the name of the environment, one of the listed names. + * - parser: the parser object + * - lexer: the lexer object + * - positions: the positions associated with these arguments from args. + * The handler must return a ParseResult. + */ + +function defineEnvironment(names, props, handler) { + if (typeof names === "string") { + names = [names]; + } + if (typeof props === "number") { + props = { numArgs: props }; + } + // Set default values of environments + var data = { + numArgs: props.numArgs || 0, + argTypes: props.argTypes, + greediness: 1, + allowedInText: !!props.allowedInText, + numOptionalArgs: props.numOptionalArgs || 0, + handler: handler + }; + for (var i = 0; i < names.length; ++i) { + module.exports[names[i]] = data; + } +} + +// Arrays are part of LaTeX, defined in lttab.dtx so its documentation +// is part of the source2e.pdf file of LaTeX2e source documentation. +defineEnvironment("array", { + numArgs: 1 +}, function(context, args) { + var colalign = args[0]; + colalign = colalign.value.map ? colalign.value : [colalign]; + var cols = colalign.map(function(node) { + var ca = node.value; + if ("lcr".indexOf(ca) !== -1) { + return { + type: "align", + align: ca + }; + } else if (ca === "|") { + return { + type: "separator", + separator: "|" + }; + } + throw new ParseError( + "Unknown column alignment: " + node.value, + node); + }); + var res = { + type: "array", + cols: cols, + hskipBeforeAndAfter: true // \@preamble in lttab.dtx + }; + res = parseArray(context.parser, res); + return res; +}); + +// The matrix environments of amsmath builds on the array environment +// of LaTeX, which is discussed above. +defineEnvironment([ + "matrix", + "pmatrix", + "bmatrix", + "Bmatrix", + "vmatrix", + "Vmatrix" +], { +}, function(context) { + var delimiters = { + "matrix": null, + "pmatrix": ["(", ")"], + "bmatrix": ["[", "]"], + "Bmatrix": ["\\{", "\\}"], + "vmatrix": ["|", "|"], + "Vmatrix": ["\\Vert", "\\Vert"] + }[context.envName]; + var res = { + type: "array", + hskipBeforeAndAfter: false // \hskip -\arraycolsep in amsmath + }; + res = parseArray(context.parser, res); + if (delimiters) { + res = new ParseNode("leftright", { + body: [res], + left: delimiters[0], + right: delimiters[1] + }, context.mode); + } + return res; +}); + +// A cases environment (in amsmath.sty) is almost equivalent to +// \def\arraystretch{1.2}% +// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. +defineEnvironment("cases", { +}, function(context) { + var res = { + type: "array", + arraystretch: 1.2, + cols: [{ + type: "align", + align: "l", + pregap: 0, + // TODO(kevinb) get the current style. + // For now we use the metrics for TEXT style which is what we were + // doing before. Before attempting to get the current style we + // should look at TeX's behavior especially for \over and matrices. + postgap: Style.TEXT.metrics.quad + }, { + type: "align", + align: "l", + pregap: 0, + postgap: 0 + }] + }; + res = parseArray(context.parser, res); + res = new ParseNode("leftright", { + body: [res], + left: "\\{", + right: "." + }, context.mode); + return res; +}); + +// An aligned environment is like the align* environment +// except it operates within math mode. +// Note that we assume \nomallineskiplimit to be zero, +// so that \strut@ is the same as \strut. +defineEnvironment("aligned", { +}, function(context) { + var res = { + type: "array", + cols: [] + }; + res = parseArray(context.parser, res); + var emptyGroup = new ParseNode("ordgroup", [], context.mode); + var numCols = 0; + res.value.body.forEach(function(row) { + var i; + for (i = 1; i < row.length; i += 2) { + row[i].value.unshift(emptyGroup); + } + if (numCols < row.length) { + numCols = row.length; + } + }); + for (var i = 0; i < numCols; ++i) { + var align = "r"; + var pregap = 0; + if (i % 2 === 1) { + align = "l"; + } else if (i > 0) { + pregap = 2; // one \qquad between columns + } + res.value.cols[i] = { + type: "align", + align: align, + pregap: pregap, + postgap: 0 + }; + } + return res; +}); + +},{"./ParseError":6,"./Style":9,"./parseData":21}],17:[function(require,module,exports){ +/* eslint no-unused-vars:0 */ + +var Style = require("./Style"); +var cjkRegex = require("./unicodeRegexes").cjkRegex; + +/** + * This file contains metrics regarding fonts and individual symbols. The sigma + * and xi variables, as well as the metricMap map contain data extracted from + * TeX, TeX font metrics, and the TTF files. These data are then exposed via the + * `metrics` variable and the getCharacterMetrics function. + */ + +// In TeX, there are actually three sets of dimensions, one for each of +// textstyle, scriptstyle, and scriptscriptstyle. These are provided in the +// the arrays below, in that order. +// +// The font metrics are stored in fonts cmsy10, cmsy7, and cmsy5 respsectively. +// This was determined by running the folllowing script: +// +// latex -interaction=nonstopmode \ +// '\documentclass{article}\usepackage{amsmath}\begin{document}' \ +// '$a$ \expandafter\show\the\textfont2' \ +// '\expandafter\show\the\scriptfont2' \ +// '\expandafter\show\the\scriptscriptfont2' \ +// '\stop' +// +// The metrics themselves were retreived using the following commands: +// +// tftopl cmsy10 +// tftopl cmsy7 +// tftopl cmsy5 +// +// The output of each of these commands is quite lengthy. The only part we +// care about is the FONTDIMEN section. Each value is measured in EMs. +var sigmas = { + slant: [0.250, 0.250, 0.250], // sigma1 + space: [0.000, 0.000, 0.000], // sigma2 + stretch: [0.000, 0.000, 0.000], // sigma3 + shrink: [0.000, 0.000, 0.000], // sigma4 + xHeight: [0.431, 0.431, 0.431], // sigma5 + quad: [1.000, 1.171, 1.472], // sigma6 + extraSpace: [0.000, 0.000, 0.000], // sigma7 + num1: [0.677, 0.732, 0.925], // sigma8 + num2: [0.394, 0.384, 0.387], // sigma9 + num3: [0.444, 0.471, 0.504], // sigma10 + denom1: [0.686, 0.752, 1.025], // sigma11 + denom2: [0.345, 0.344, 0.532], // sigma12 + sup1: [0.413, 0.503, 0.504], // sigma13 + sup2: [0.363, 0.431, 0.404], // sigma14 + sup3: [0.289, 0.286, 0.294], // sigma15 + sub1: [0.150, 0.143, 0.200], // sigma16 + sub2: [0.247, 0.286, 0.400], // sigma17 + supDrop: [0.386, 0.353, 0.494], // sigma18 + subDrop: [0.050, 0.071, 0.100], // sigma19 + delim1: [2.390, 1.700, 1.980], // sigma20 + delim2: [1.010, 1.157, 1.420], // sigma21 + axisHeight: [0.250, 0.250, 0.250] // sigma22 +}; + +// These font metrics are extracted from TeX by using +// \font\a=cmex10 +// \showthe\fontdimenX\a +// where X is the corresponding variable number. These correspond to the font +// parameters of the extension fonts (family 3). See the TeXbook, page 441. +var xi1 = 0; +var xi2 = 0; +var xi3 = 0; +var xi4 = 0; +var xi5 = 0.431; +var xi6 = 1; +var xi7 = 0; +var xi8 = 0.04; +var xi9 = 0.111; +var xi10 = 0.166; +var xi11 = 0.2; +var xi12 = 0.6; +var xi13 = 0.1; + +// This value determines how large a pt is, for metrics which are defined in +// terms of pts. +// This value is also used in katex.less; if you change it make sure the values +// match. +var ptPerEm = 10.0; + +// The space between adjacent `|` columns in an array definition. From +// `\showthe\doublerulesep` in LaTeX. +var doubleRuleSep = 2.0 / ptPerEm; + +/** + * This is just a mapping from common names to real metrics + */ +var metrics = { + defaultRuleThickness: xi8, + bigOpSpacing1: xi9, + bigOpSpacing2: xi10, + bigOpSpacing3: xi11, + bigOpSpacing4: xi12, + bigOpSpacing5: xi13, + ptPerEm: ptPerEm, + doubleRuleSep: doubleRuleSep +}; + +// This map contains a mapping from font name and character code to character +// metrics, including height, depth, italic correction, and skew (kern from the +// character to the corresponding \skewchar) +// This map is generated via `make metrics`. It should not be changed manually. +var metricMap = require("./fontMetricsData"); + +// These are very rough approximations. We default to Times New Roman which +// should have Latin-1 and Cyrillic characters, but may not depending on the +// operating system. The metrics do not account for extra height from the +// accents. In the case of Cyrillic characters which have both ascenders and +// descenders we prefer approximations with ascenders, primarily to prevent +// the fraction bar or root line from intersecting the glyph. +// TODO(kevinb) allow union of multiple glyph metrics for better accuracy. +var extraCharacterMap = { + // Latin-1 + 'À': 'A', + 'Á': 'A', + 'Â': 'A', + 'Ã': 'A', + 'Ä': 'A', + 'Å': 'A', + 'Æ': 'A', + 'Ç': 'C', + 'È': 'E', + 'É': 'E', + 'Ê': 'E', + 'Ë': 'E', + 'Ì': 'I', + 'Í': 'I', + 'Î': 'I', + 'Ï': 'I', + 'Ð': 'D', + 'Ñ': 'N', + 'Ò': 'O', + 'Ó': 'O', + 'Ô': 'O', + 'Õ': 'O', + 'Ö': 'O', + 'Ø': 'O', + 'Ù': 'U', + 'Ú': 'U', + 'Û': 'U', + 'Ü': 'U', + 'Ý': 'Y', + 'Þ': 'o', + 'ß': 'B', + 'à': 'a', + 'á': 'a', + 'â': 'a', + 'ã': 'a', + 'ä': 'a', + 'å': 'a', + 'æ': 'a', + 'ç': 'c', + 'è': 'e', + 'é': 'e', + 'ê': 'e', + 'ë': 'e', + 'ì': 'i', + 'í': 'i', + 'î': 'i', + 'ï': 'i', + 'ð': 'd', + 'ñ': 'n', + 'ò': 'o', + 'ó': 'o', + 'ô': 'o', + 'õ': 'o', + 'ö': 'o', + 'ø': 'o', + 'ù': 'u', + 'ú': 'u', + 'û': 'u', + 'ü': 'u', + 'ý': 'y', + 'þ': 'o', + 'ÿ': 'y', + + // Cyrillic + 'А': 'A', + 'Б': 'B', + 'В': 'B', + 'Г': 'F', + 'Д': 'A', + 'Е': 'E', + 'Ж': 'K', + 'З': '3', + 'И': 'N', + 'Й': 'N', + 'К': 'K', + 'Л': 'N', + 'М': 'M', + 'Н': 'H', + 'О': 'O', + 'П': 'N', + 'Р': 'P', + 'С': 'C', + 'Т': 'T', + 'У': 'y', + 'Ф': 'O', + 'Х': 'X', + 'Ц': 'U', + 'Ч': 'h', + 'Ш': 'W', + 'Щ': 'W', + 'Ъ': 'B', + 'Ы': 'X', + 'Ь': 'B', + 'Э': '3', + 'Ю': 'X', + 'Я': 'R', + 'а': 'a', + 'б': 'b', + 'в': 'a', + 'г': 'r', + 'д': 'y', + 'е': 'e', + 'ж': 'm', + 'з': 'e', + 'и': 'n', + 'й': 'n', + 'к': 'n', + 'л': 'n', + 'м': 'm', + 'н': 'n', + 'о': 'o', + 'п': 'n', + 'р': 'p', + 'с': 'c', + 'т': 'o', + 'у': 'y', + 'ф': 'b', + 'х': 'x', + 'ц': 'n', + 'ч': 'n', + 'ш': 'w', + 'щ': 'w', + 'ъ': 'a', + 'ы': 'm', + 'ь': 'a', + 'э': 'e', + 'ю': 'm', + 'я': 'r' +}; + +/** + * This function is a convenience function for looking up information in the + * metricMap table. It takes a character as a string, and a style. + * + * Note: the `width` property may be undefined if fontMetricsData.js wasn't + * built using `Make extended_metrics`. + */ +var getCharacterMetrics = function(character, style) { + var ch = character.charCodeAt(0); + if (character[0] in extraCharacterMap) { + ch = extraCharacterMap[character[0]].charCodeAt(0); + } else if (cjkRegex.test(character[0])) { + ch = 'M'.charCodeAt(0); + } + var metrics = metricMap[style][ch]; + if (metrics) { + return { + depth: metrics[0], + height: metrics[1], + italic: metrics[2], + skew: metrics[3], + width: metrics[4] + }; + } +}; + +module.exports = { + metrics: metrics, + sigmas: sigmas, + getCharacterMetrics: getCharacterMetrics +}; + +},{"./Style":9,"./fontMetricsData":18,"./unicodeRegexes":24}],18:[function(require,module,exports){ +module.exports = { + "AMS-Regular": { + "65": [0, 0.68889, 0, 0], + "66": [0, 0.68889, 0, 0], + "67": [0, 0.68889, 0, 0], + "68": [0, 0.68889, 0, 0], + "69": [0, 0.68889, 0, 0], + "70": [0, 0.68889, 0, 0], + "71": [0, 0.68889, 0, 0], + "72": [0, 0.68889, 0, 0], + "73": [0, 0.68889, 0, 0], + "74": [0.16667, 0.68889, 0, 0], + "75": [0, 0.68889, 0, 0], + "76": [0, 0.68889, 0, 0], + "77": [0, 0.68889, 0, 0], + "78": [0, 0.68889, 0, 0], + "79": [0.16667, 0.68889, 0, 0], + "80": [0, 0.68889, 0, 0], + "81": [0.16667, 0.68889, 0, 0], + "82": [0, 0.68889, 0, 0], + "83": [0, 0.68889, 0, 0], + "84": [0, 0.68889, 0, 0], + "85": [0, 0.68889, 0, 0], + "86": [0, 0.68889, 0, 0], + "87": [0, 0.68889, 0, 0], + "88": [0, 0.68889, 0, 0], + "89": [0, 0.68889, 0, 0], + "90": [0, 0.68889, 0, 0], + "107": [0, 0.68889, 0, 0], + "165": [0, 0.675, 0.025, 0], + "174": [0.15559, 0.69224, 0, 0], + "240": [0, 0.68889, 0, 0], + "295": [0, 0.68889, 0, 0], + "710": [0, 0.825, 0, 0], + "732": [0, 0.9, 0, 0], + "770": [0, 0.825, 0, 0], + "771": [0, 0.9, 0, 0], + "989": [0.08167, 0.58167, 0, 0], + "1008": [0, 0.43056, 0.04028, 0], + "8245": [0, 0.54986, 0, 0], + "8463": [0, 0.68889, 0, 0], + "8487": [0, 0.68889, 0, 0], + "8498": [0, 0.68889, 0, 0], + "8502": [0, 0.68889, 0, 0], + "8503": [0, 0.68889, 0, 0], + "8504": [0, 0.68889, 0, 0], + "8513": [0, 0.68889, 0, 0], + "8592": [-0.03598, 0.46402, 0, 0], + "8594": [-0.03598, 0.46402, 0, 0], + "8602": [-0.13313, 0.36687, 0, 0], + "8603": [-0.13313, 0.36687, 0, 0], + "8606": [0.01354, 0.52239, 0, 0], + "8608": [0.01354, 0.52239, 0, 0], + "8610": [0.01354, 0.52239, 0, 0], + "8611": [0.01354, 0.52239, 0, 0], + "8619": [0, 0.54986, 0, 0], + "8620": [0, 0.54986, 0, 0], + "8621": [-0.13313, 0.37788, 0, 0], + "8622": [-0.13313, 0.36687, 0, 0], + "8624": [0, 0.69224, 0, 0], + "8625": [0, 0.69224, 0, 0], + "8630": [0, 0.43056, 0, 0], + "8631": [0, 0.43056, 0, 0], + "8634": [0.08198, 0.58198, 0, 0], + "8635": [0.08198, 0.58198, 0, 0], + "8638": [0.19444, 0.69224, 0, 0], + "8639": [0.19444, 0.69224, 0, 0], + "8642": [0.19444, 0.69224, 0, 0], + "8643": [0.19444, 0.69224, 0, 0], + "8644": [0.1808, 0.675, 0, 0], + "8646": [0.1808, 0.675, 0, 0], + "8647": [0.1808, 0.675, 0, 0], + "8648": [0.19444, 0.69224, 0, 0], + "8649": [0.1808, 0.675, 0, 0], + "8650": [0.19444, 0.69224, 0, 0], + "8651": [0.01354, 0.52239, 0, 0], + "8652": [0.01354, 0.52239, 0, 0], + "8653": [-0.13313, 0.36687, 0, 0], + "8654": [-0.13313, 0.36687, 0, 0], + "8655": [-0.13313, 0.36687, 0, 0], + "8666": [0.13667, 0.63667, 0, 0], + "8667": [0.13667, 0.63667, 0, 0], + "8669": [-0.13313, 0.37788, 0, 0], + "8672": [-0.064, 0.437, 0, 0], + "8674": [-0.064, 0.437, 0, 0], + "8705": [0, 0.825, 0, 0], + "8708": [0, 0.68889, 0, 0], + "8709": [0.08167, 0.58167, 0, 0], + "8717": [0, 0.43056, 0, 0], + "8722": [-0.03598, 0.46402, 0, 0], + "8724": [0.08198, 0.69224, 0, 0], + "8726": [0.08167, 0.58167, 0, 0], + "8733": [0, 0.69224, 0, 0], + "8736": [0, 0.69224, 0, 0], + "8737": [0, 0.69224, 0, 0], + "8738": [0.03517, 0.52239, 0, 0], + "8739": [0.08167, 0.58167, 0, 0], + "8740": [0.25142, 0.74111, 0, 0], + "8741": [0.08167, 0.58167, 0, 0], + "8742": [0.25142, 0.74111, 0, 0], + "8756": [0, 0.69224, 0, 0], + "8757": [0, 0.69224, 0, 0], + "8764": [-0.13313, 0.36687, 0, 0], + "8765": [-0.13313, 0.37788, 0, 0], + "8769": [-0.13313, 0.36687, 0, 0], + "8770": [-0.03625, 0.46375, 0, 0], + "8774": [0.30274, 0.79383, 0, 0], + "8776": [-0.01688, 0.48312, 0, 0], + "8778": [0.08167, 0.58167, 0, 0], + "8782": [0.06062, 0.54986, 0, 0], + "8783": [0.06062, 0.54986, 0, 0], + "8785": [0.08198, 0.58198, 0, 0], + "8786": [0.08198, 0.58198, 0, 0], + "8787": [0.08198, 0.58198, 0, 0], + "8790": [0, 0.69224, 0, 0], + "8791": [0.22958, 0.72958, 0, 0], + "8796": [0.08198, 0.91667, 0, 0], + "8806": [0.25583, 0.75583, 0, 0], + "8807": [0.25583, 0.75583, 0, 0], + "8808": [0.25142, 0.75726, 0, 0], + "8809": [0.25142, 0.75726, 0, 0], + "8812": [0.25583, 0.75583, 0, 0], + "8814": [0.20576, 0.70576, 0, 0], + "8815": [0.20576, 0.70576, 0, 0], + "8816": [0.30274, 0.79383, 0, 0], + "8817": [0.30274, 0.79383, 0, 0], + "8818": [0.22958, 0.72958, 0, 0], + "8819": [0.22958, 0.72958, 0, 0], + "8822": [0.1808, 0.675, 0, 0], + "8823": [0.1808, 0.675, 0, 0], + "8828": [0.13667, 0.63667, 0, 0], + "8829": [0.13667, 0.63667, 0, 0], + "8830": [0.22958, 0.72958, 0, 0], + "8831": [0.22958, 0.72958, 0, 0], + "8832": [0.20576, 0.70576, 0, 0], + "8833": [0.20576, 0.70576, 0, 0], + "8840": [0.30274, 0.79383, 0, 0], + "8841": [0.30274, 0.79383, 0, 0], + "8842": [0.13597, 0.63597, 0, 0], + "8843": [0.13597, 0.63597, 0, 0], + "8847": [0.03517, 0.54986, 0, 0], + "8848": [0.03517, 0.54986, 0, 0], + "8858": [0.08198, 0.58198, 0, 0], + "8859": [0.08198, 0.58198, 0, 0], + "8861": [0.08198, 0.58198, 0, 0], + "8862": [0, 0.675, 0, 0], + "8863": [0, 0.675, 0, 0], + "8864": [0, 0.675, 0, 0], + "8865": [0, 0.675, 0, 0], + "8872": [0, 0.69224, 0, 0], + "8873": [0, 0.69224, 0, 0], + "8874": [0, 0.69224, 0, 0], + "8876": [0, 0.68889, 0, 0], + "8877": [0, 0.68889, 0, 0], + "8878": [0, 0.68889, 0, 0], + "8879": [0, 0.68889, 0, 0], + "8882": [0.03517, 0.54986, 0, 0], + "8883": [0.03517, 0.54986, 0, 0], + "8884": [0.13667, 0.63667, 0, 0], + "8885": [0.13667, 0.63667, 0, 0], + "8888": [0, 0.54986, 0, 0], + "8890": [0.19444, 0.43056, 0, 0], + "8891": [0.19444, 0.69224, 0, 0], + "8892": [0.19444, 0.69224, 0, 0], + "8901": [0, 0.54986, 0, 0], + "8903": [0.08167, 0.58167, 0, 0], + "8905": [0.08167, 0.58167, 0, 0], + "8906": [0.08167, 0.58167, 0, 0], + "8907": [0, 0.69224, 0, 0], + "8908": [0, 0.69224, 0, 0], + "8909": [-0.03598, 0.46402, 0, 0], + "8910": [0, 0.54986, 0, 0], + "8911": [0, 0.54986, 0, 0], + "8912": [0.03517, 0.54986, 0, 0], + "8913": [0.03517, 0.54986, 0, 0], + "8914": [0, 0.54986, 0, 0], + "8915": [0, 0.54986, 0, 0], + "8916": [0, 0.69224, 0, 0], + "8918": [0.0391, 0.5391, 0, 0], + "8919": [0.0391, 0.5391, 0, 0], + "8920": [0.03517, 0.54986, 0, 0], + "8921": [0.03517, 0.54986, 0, 0], + "8922": [0.38569, 0.88569, 0, 0], + "8923": [0.38569, 0.88569, 0, 0], + "8926": [0.13667, 0.63667, 0, 0], + "8927": [0.13667, 0.63667, 0, 0], + "8928": [0.30274, 0.79383, 0, 0], + "8929": [0.30274, 0.79383, 0, 0], + "8934": [0.23222, 0.74111, 0, 0], + "8935": [0.23222, 0.74111, 0, 0], + "8936": [0.23222, 0.74111, 0, 0], + "8937": [0.23222, 0.74111, 0, 0], + "8938": [0.20576, 0.70576, 0, 0], + "8939": [0.20576, 0.70576, 0, 0], + "8940": [0.30274, 0.79383, 0, 0], + "8941": [0.30274, 0.79383, 0, 0], + "8994": [0.19444, 0.69224, 0, 0], + "8995": [0.19444, 0.69224, 0, 0], + "9416": [0.15559, 0.69224, 0, 0], + "9484": [0, 0.69224, 0, 0], + "9488": [0, 0.69224, 0, 0], + "9492": [0, 0.37788, 0, 0], + "9496": [0, 0.37788, 0, 0], + "9585": [0.19444, 0.68889, 0, 0], + "9586": [0.19444, 0.74111, 0, 0], + "9632": [0, 0.675, 0, 0], + "9633": [0, 0.675, 0, 0], + "9650": [0, 0.54986, 0, 0], + "9651": [0, 0.54986, 0, 0], + "9654": [0.03517, 0.54986, 0, 0], + "9660": [0, 0.54986, 0, 0], + "9661": [0, 0.54986, 0, 0], + "9664": [0.03517, 0.54986, 0, 0], + "9674": [0.11111, 0.69224, 0, 0], + "9733": [0.19444, 0.69224, 0, 0], + "10003": [0, 0.69224, 0, 0], + "10016": [0, 0.69224, 0, 0], + "10731": [0.11111, 0.69224, 0, 0], + "10846": [0.19444, 0.75583, 0, 0], + "10877": [0.13667, 0.63667, 0, 0], + "10878": [0.13667, 0.63667, 0, 0], + "10885": [0.25583, 0.75583, 0, 0], + "10886": [0.25583, 0.75583, 0, 0], + "10887": [0.13597, 0.63597, 0, 0], + "10888": [0.13597, 0.63597, 0, 0], + "10889": [0.26167, 0.75726, 0, 0], + "10890": [0.26167, 0.75726, 0, 0], + "10891": [0.48256, 0.98256, 0, 0], + "10892": [0.48256, 0.98256, 0, 0], + "10901": [0.13667, 0.63667, 0, 0], + "10902": [0.13667, 0.63667, 0, 0], + "10933": [0.25142, 0.75726, 0, 0], + "10934": [0.25142, 0.75726, 0, 0], + "10935": [0.26167, 0.75726, 0, 0], + "10936": [0.26167, 0.75726, 0, 0], + "10937": [0.26167, 0.75726, 0, 0], + "10938": [0.26167, 0.75726, 0, 0], + "10949": [0.25583, 0.75583, 0, 0], + "10950": [0.25583, 0.75583, 0, 0], + "10955": [0.28481, 0.79383, 0, 0], + "10956": [0.28481, 0.79383, 0, 0], + "57350": [0.08167, 0.58167, 0, 0], + "57351": [0.08167, 0.58167, 0, 0], + "57352": [0.08167, 0.58167, 0, 0], + "57353": [0, 0.43056, 0.04028, 0], + "57356": [0.25142, 0.75726, 0, 0], + "57357": [0.25142, 0.75726, 0, 0], + "57358": [0.41951, 0.91951, 0, 0], + "57359": [0.30274, 0.79383, 0, 0], + "57360": [0.30274, 0.79383, 0, 0], + "57361": [0.41951, 0.91951, 0, 0], + "57366": [0.25142, 0.75726, 0, 0], + "57367": [0.25142, 0.75726, 0, 0], + "57368": [0.25142, 0.75726, 0, 0], + "57369": [0.25142, 0.75726, 0, 0], + "57370": [0.13597, 0.63597, 0, 0], + "57371": [0.13597, 0.63597, 0, 0] + }, + "Caligraphic-Regular": { + "48": [0, 0.43056, 0, 0], + "49": [0, 0.43056, 0, 0], + "50": [0, 0.43056, 0, 0], + "51": [0.19444, 0.43056, 0, 0], + "52": [0.19444, 0.43056, 0, 0], + "53": [0.19444, 0.43056, 0, 0], + "54": [0, 0.64444, 0, 0], + "55": [0.19444, 0.43056, 0, 0], + "56": [0, 0.64444, 0, 0], + "57": [0.19444, 0.43056, 0, 0], + "65": [0, 0.68333, 0, 0.19445], + "66": [0, 0.68333, 0.03041, 0.13889], + "67": [0, 0.68333, 0.05834, 0.13889], + "68": [0, 0.68333, 0.02778, 0.08334], + "69": [0, 0.68333, 0.08944, 0.11111], + "70": [0, 0.68333, 0.09931, 0.11111], + "71": [0.09722, 0.68333, 0.0593, 0.11111], + "72": [0, 0.68333, 0.00965, 0.11111], + "73": [0, 0.68333, 0.07382, 0], + "74": [0.09722, 0.68333, 0.18472, 0.16667], + "75": [0, 0.68333, 0.01445, 0.05556], + "76": [0, 0.68333, 0, 0.13889], + "77": [0, 0.68333, 0, 0.13889], + "78": [0, 0.68333, 0.14736, 0.08334], + "79": [0, 0.68333, 0.02778, 0.11111], + "80": [0, 0.68333, 0.08222, 0.08334], + "81": [0.09722, 0.68333, 0, 0.11111], + "82": [0, 0.68333, 0, 0.08334], + "83": [0, 0.68333, 0.075, 0.13889], + "84": [0, 0.68333, 0.25417, 0], + "85": [0, 0.68333, 0.09931, 0.08334], + "86": [0, 0.68333, 0.08222, 0], + "87": [0, 0.68333, 0.08222, 0.08334], + "88": [0, 0.68333, 0.14643, 0.13889], + "89": [0.09722, 0.68333, 0.08222, 0.08334], + "90": [0, 0.68333, 0.07944, 0.13889] + }, + "Fraktur-Regular": { + "33": [0, 0.69141, 0, 0], + "34": [0, 0.69141, 0, 0], + "38": [0, 0.69141, 0, 0], + "39": [0, 0.69141, 0, 0], + "40": [0.24982, 0.74947, 0, 0], + "41": [0.24982, 0.74947, 0, 0], + "42": [0, 0.62119, 0, 0], + "43": [0.08319, 0.58283, 0, 0], + "44": [0, 0.10803, 0, 0], + "45": [0.08319, 0.58283, 0, 0], + "46": [0, 0.10803, 0, 0], + "47": [0.24982, 0.74947, 0, 0], + "48": [0, 0.47534, 0, 0], + "49": [0, 0.47534, 0, 0], + "50": [0, 0.47534, 0, 0], + "51": [0.18906, 0.47534, 0, 0], + "52": [0.18906, 0.47534, 0, 0], + "53": [0.18906, 0.47534, 0, 0], + "54": [0, 0.69141, 0, 0], + "55": [0.18906, 0.47534, 0, 0], + "56": [0, 0.69141, 0, 0], + "57": [0.18906, 0.47534, 0, 0], + "58": [0, 0.47534, 0, 0], + "59": [0.12604, 0.47534, 0, 0], + "61": [-0.13099, 0.36866, 0, 0], + "63": [0, 0.69141, 0, 0], + "65": [0, 0.69141, 0, 0], + "66": [0, 0.69141, 0, 0], + "67": [0, 0.69141, 0, 0], + "68": [0, 0.69141, 0, 0], + "69": [0, 0.69141, 0, 0], + "70": [0.12604, 0.69141, 0, 0], + "71": [0, 0.69141, 0, 0], + "72": [0.06302, 0.69141, 0, 0], + "73": [0, 0.69141, 0, 0], + "74": [0.12604, 0.69141, 0, 0], + "75": [0, 0.69141, 0, 0], + "76": [0, 0.69141, 0, 0], + "77": [0, 0.69141, 0, 0], + "78": [0, 0.69141, 0, 0], + "79": [0, 0.69141, 0, 0], + "80": [0.18906, 0.69141, 0, 0], + "81": [0.03781, 0.69141, 0, 0], + "82": [0, 0.69141, 0, 0], + "83": [0, 0.69141, 0, 0], + "84": [0, 0.69141, 0, 0], + "85": [0, 0.69141, 0, 0], + "86": [0, 0.69141, 0, 0], + "87": [0, 0.69141, 0, 0], + "88": [0, 0.69141, 0, 0], + "89": [0.18906, 0.69141, 0, 0], + "90": [0.12604, 0.69141, 0, 0], + "91": [0.24982, 0.74947, 0, 0], + "93": [0.24982, 0.74947, 0, 0], + "94": [0, 0.69141, 0, 0], + "97": [0, 0.47534, 0, 0], + "98": [0, 0.69141, 0, 0], + "99": [0, 0.47534, 0, 0], + "100": [0, 0.62119, 0, 0], + "101": [0, 0.47534, 0, 0], + "102": [0.18906, 0.69141, 0, 0], + "103": [0.18906, 0.47534, 0, 0], + "104": [0.18906, 0.69141, 0, 0], + "105": [0, 0.69141, 0, 0], + "106": [0, 0.69141, 0, 0], + "107": [0, 0.69141, 0, 0], + "108": [0, 0.69141, 0, 0], + "109": [0, 0.47534, 0, 0], + "110": [0, 0.47534, 0, 0], + "111": [0, 0.47534, 0, 0], + "112": [0.18906, 0.52396, 0, 0], + "113": [0.18906, 0.47534, 0, 0], + "114": [0, 0.47534, 0, 0], + "115": [0, 0.47534, 0, 0], + "116": [0, 0.62119, 0, 0], + "117": [0, 0.47534, 0, 0], + "118": [0, 0.52396, 0, 0], + "119": [0, 0.52396, 0, 0], + "120": [0.18906, 0.47534, 0, 0], + "121": [0.18906, 0.47534, 0, 0], + "122": [0.18906, 0.47534, 0, 0], + "8216": [0, 0.69141, 0, 0], + "8217": [0, 0.69141, 0, 0], + "58112": [0, 0.62119, 0, 0], + "58113": [0, 0.62119, 0, 0], + "58114": [0.18906, 0.69141, 0, 0], + "58115": [0.18906, 0.69141, 0, 0], + "58116": [0.18906, 0.47534, 0, 0], + "58117": [0, 0.69141, 0, 0], + "58118": [0, 0.62119, 0, 0], + "58119": [0, 0.47534, 0, 0] + }, + "Main-Bold": { + "33": [0, 0.69444, 0, 0], + "34": [0, 0.69444, 0, 0], + "35": [0.19444, 0.69444, 0, 0], + "36": [0.05556, 0.75, 0, 0], + "37": [0.05556, 0.75, 0, 0], + "38": [0, 0.69444, 0, 0], + "39": [0, 0.69444, 0, 0], + "40": [0.25, 0.75, 0, 0], + "41": [0.25, 0.75, 0, 0], + "42": [0, 0.75, 0, 0], + "43": [0.13333, 0.63333, 0, 0], + "44": [0.19444, 0.15556, 0, 0], + "45": [0, 0.44444, 0, 0], + "46": [0, 0.15556, 0, 0], + "47": [0.25, 0.75, 0, 0], + "48": [0, 0.64444, 0, 0], + "49": [0, 0.64444, 0, 0], + "50": [0, 0.64444, 0, 0], + "51": [0, 0.64444, 0, 0], + "52": [0, 0.64444, 0, 0], + "53": [0, 0.64444, 0, 0], + "54": [0, 0.64444, 0, 0], + "55": [0, 0.64444, 0, 0], + "56": [0, 0.64444, 0, 0], + "57": [0, 0.64444, 0, 0], + "58": [0, 0.44444, 0, 0], + "59": [0.19444, 0.44444, 0, 0], + "60": [0.08556, 0.58556, 0, 0], + "61": [-0.10889, 0.39111, 0, 0], + "62": [0.08556, 0.58556, 0, 0], + "63": [0, 0.69444, 0, 0], + "64": [0, 0.69444, 0, 0], + "65": [0, 0.68611, 0, 0], + "66": [0, 0.68611, 0, 0], + "67": [0, 0.68611, 0, 0], + "68": [0, 0.68611, 0, 0], + "69": [0, 0.68611, 0, 0], + "70": [0, 0.68611, 0, 0], + "71": [0, 0.68611, 0, 0], + "72": [0, 0.68611, 0, 0], + "73": [0, 0.68611, 0, 0], + "74": [0, 0.68611, 0, 0], + "75": [0, 0.68611, 0, 0], + "76": [0, 0.68611, 0, 0], + "77": [0, 0.68611, 0, 0], + "78": [0, 0.68611, 0, 0], + "79": [0, 0.68611, 0, 0], + "80": [0, 0.68611, 0, 0], + "81": [0.19444, 0.68611, 0, 0], + "82": [0, 0.68611, 0, 0], + "83": [0, 0.68611, 0, 0], + "84": [0, 0.68611, 0, 0], + "85": [0, 0.68611, 0, 0], + "86": [0, 0.68611, 0.01597, 0], + "87": [0, 0.68611, 0.01597, 0], + "88": [0, 0.68611, 0, 0], + "89": [0, 0.68611, 0.02875, 0], + "90": [0, 0.68611, 0, 0], + "91": [0.25, 0.75, 0, 0], + "92": [0.25, 0.75, 0, 0], + "93": [0.25, 0.75, 0, 0], + "94": [0, 0.69444, 0, 0], + "95": [0.31, 0.13444, 0.03194, 0], + "96": [0, 0.69444, 0, 0], + "97": [0, 0.44444, 0, 0], + "98": [0, 0.69444, 0, 0], + "99": [0, 0.44444, 0, 0], + "100": [0, 0.69444, 0, 0], + "101": [0, 0.44444, 0, 0], + "102": [0, 0.69444, 0.10903, 0], + "103": [0.19444, 0.44444, 0.01597, 0], + "104": [0, 0.69444, 0, 0], + "105": [0, 0.69444, 0, 0], + "106": [0.19444, 0.69444, 0, 0], + "107": [0, 0.69444, 0, 0], + "108": [0, 0.69444, 0, 0], + "109": [0, 0.44444, 0, 0], + "110": [0, 0.44444, 0, 0], + "111": [0, 0.44444, 0, 0], + "112": [0.19444, 0.44444, 0, 0], + "113": [0.19444, 0.44444, 0, 0], + "114": [0, 0.44444, 0, 0], + "115": [0, 0.44444, 0, 0], + "116": [0, 0.63492, 0, 0], + "117": [0, 0.44444, 0, 0], + "118": [0, 0.44444, 0.01597, 0], + "119": [0, 0.44444, 0.01597, 0], + "120": [0, 0.44444, 0, 0], + "121": [0.19444, 0.44444, 0.01597, 0], + "122": [0, 0.44444, 0, 0], + "123": [0.25, 0.75, 0, 0], + "124": [0.25, 0.75, 0, 0], + "125": [0.25, 0.75, 0, 0], + "126": [0.35, 0.34444, 0, 0], + "168": [0, 0.69444, 0, 0], + "172": [0, 0.44444, 0, 0], + "175": [0, 0.59611, 0, 0], + "176": [0, 0.69444, 0, 0], + "177": [0.13333, 0.63333, 0, 0], + "180": [0, 0.69444, 0, 0], + "215": [0.13333, 0.63333, 0, 0], + "247": [0.13333, 0.63333, 0, 0], + "305": [0, 0.44444, 0, 0], + "567": [0.19444, 0.44444, 0, 0], + "710": [0, 0.69444, 0, 0], + "711": [0, 0.63194, 0, 0], + "713": [0, 0.59611, 0, 0], + "714": [0, 0.69444, 0, 0], + "715": [0, 0.69444, 0, 0], + "728": [0, 0.69444, 0, 0], + "729": [0, 0.69444, 0, 0], + "730": [0, 0.69444, 0, 0], + "732": [0, 0.69444, 0, 0], + "768": [0, 0.69444, 0, 0], + "769": [0, 0.69444, 0, 0], + "770": [0, 0.69444, 0, 0], + "771": [0, 0.69444, 0, 0], + "772": [0, 0.59611, 0, 0], + "774": [0, 0.69444, 0, 0], + "775": [0, 0.69444, 0, 0], + "776": [0, 0.69444, 0, 0], + "778": [0, 0.69444, 0, 0], + "779": [0, 0.69444, 0, 0], + "780": [0, 0.63194, 0, 0], + "824": [0.19444, 0.69444, 0, 0], + "915": [0, 0.68611, 0, 0], + "916": [0, 0.68611, 0, 0], + "920": [0, 0.68611, 0, 0], + "923": [0, 0.68611, 0, 0], + "926": [0, 0.68611, 0, 0], + "928": [0, 0.68611, 0, 0], + "931": [0, 0.68611, 0, 0], + "933": [0, 0.68611, 0, 0], + "934": [0, 0.68611, 0, 0], + "936": [0, 0.68611, 0, 0], + "937": [0, 0.68611, 0, 0], + "8211": [0, 0.44444, 0.03194, 0], + "8212": [0, 0.44444, 0.03194, 0], + "8216": [0, 0.69444, 0, 0], + "8217": [0, 0.69444, 0, 0], + "8220": [0, 0.69444, 0, 0], + "8221": [0, 0.69444, 0, 0], + "8224": [0.19444, 0.69444, 0, 0], + "8225": [0.19444, 0.69444, 0, 0], + "8242": [0, 0.55556, 0, 0], + "8407": [0, 0.72444, 0.15486, 0], + "8463": [0, 0.69444, 0, 0], + "8465": [0, 0.69444, 0, 0], + "8467": [0, 0.69444, 0, 0], + "8472": [0.19444, 0.44444, 0, 0], + "8476": [0, 0.69444, 0, 0], + "8501": [0, 0.69444, 0, 0], + "8592": [-0.10889, 0.39111, 0, 0], + "8593": [0.19444, 0.69444, 0, 0], + "8594": [-0.10889, 0.39111, 0, 0], + "8595": [0.19444, 0.69444, 0, 0], + "8596": [-0.10889, 0.39111, 0, 0], + "8597": [0.25, 0.75, 0, 0], + "8598": [0.19444, 0.69444, 0, 0], + "8599": [0.19444, 0.69444, 0, 0], + "8600": [0.19444, 0.69444, 0, 0], + "8601": [0.19444, 0.69444, 0, 0], + "8636": [-0.10889, 0.39111, 0, 0], + "8637": [-0.10889, 0.39111, 0, 0], + "8640": [-0.10889, 0.39111, 0, 0], + "8641": [-0.10889, 0.39111, 0, 0], + "8656": [-0.10889, 0.39111, 0, 0], + "8657": [0.19444, 0.69444, 0, 0], + "8658": [-0.10889, 0.39111, 0, 0], + "8659": [0.19444, 0.69444, 0, 0], + "8660": [-0.10889, 0.39111, 0, 0], + "8661": [0.25, 0.75, 0, 0], + "8704": [0, 0.69444, 0, 0], + "8706": [0, 0.69444, 0.06389, 0], + "8707": [0, 0.69444, 0, 0], + "8709": [0.05556, 0.75, 0, 0], + "8711": [0, 0.68611, 0, 0], + "8712": [0.08556, 0.58556, 0, 0], + "8715": [0.08556, 0.58556, 0, 0], + "8722": [0.13333, 0.63333, 0, 0], + "8723": [0.13333, 0.63333, 0, 0], + "8725": [0.25, 0.75, 0, 0], + "8726": [0.25, 0.75, 0, 0], + "8727": [-0.02778, 0.47222, 0, 0], + "8728": [-0.02639, 0.47361, 0, 0], + "8729": [-0.02639, 0.47361, 0, 0], + "8730": [0.18, 0.82, 0, 0], + "8733": [0, 0.44444, 0, 0], + "8734": [0, 0.44444, 0, 0], + "8736": [0, 0.69224, 0, 0], + "8739": [0.25, 0.75, 0, 0], + "8741": [0.25, 0.75, 0, 0], + "8743": [0, 0.55556, 0, 0], + "8744": [0, 0.55556, 0, 0], + "8745": [0, 0.55556, 0, 0], + "8746": [0, 0.55556, 0, 0], + "8747": [0.19444, 0.69444, 0.12778, 0], + "8764": [-0.10889, 0.39111, 0, 0], + "8768": [0.19444, 0.69444, 0, 0], + "8771": [0.00222, 0.50222, 0, 0], + "8776": [0.02444, 0.52444, 0, 0], + "8781": [0.00222, 0.50222, 0, 0], + "8801": [0.00222, 0.50222, 0, 0], + "8804": [0.19667, 0.69667, 0, 0], + "8805": [0.19667, 0.69667, 0, 0], + "8810": [0.08556, 0.58556, 0, 0], + "8811": [0.08556, 0.58556, 0, 0], + "8826": [0.08556, 0.58556, 0, 0], + "8827": [0.08556, 0.58556, 0, 0], + "8834": [0.08556, 0.58556, 0, 0], + "8835": [0.08556, 0.58556, 0, 0], + "8838": [0.19667, 0.69667, 0, 0], + "8839": [0.19667, 0.69667, 0, 0], + "8846": [0, 0.55556, 0, 0], + "8849": [0.19667, 0.69667, 0, 0], + "8850": [0.19667, 0.69667, 0, 0], + "8851": [0, 0.55556, 0, 0], + "8852": [0, 0.55556, 0, 0], + "8853": [0.13333, 0.63333, 0, 0], + "8854": [0.13333, 0.63333, 0, 0], + "8855": [0.13333, 0.63333, 0, 0], + "8856": [0.13333, 0.63333, 0, 0], + "8857": [0.13333, 0.63333, 0, 0], + "8866": [0, 0.69444, 0, 0], + "8867": [0, 0.69444, 0, 0], + "8868": [0, 0.69444, 0, 0], + "8869": [0, 0.69444, 0, 0], + "8900": [-0.02639, 0.47361, 0, 0], + "8901": [-0.02639, 0.47361, 0, 0], + "8902": [-0.02778, 0.47222, 0, 0], + "8968": [0.25, 0.75, 0, 0], + "8969": [0.25, 0.75, 0, 0], + "8970": [0.25, 0.75, 0, 0], + "8971": [0.25, 0.75, 0, 0], + "8994": [-0.13889, 0.36111, 0, 0], + "8995": [-0.13889, 0.36111, 0, 0], + "9651": [0.19444, 0.69444, 0, 0], + "9657": [-0.02778, 0.47222, 0, 0], + "9661": [0.19444, 0.69444, 0, 0], + "9667": [-0.02778, 0.47222, 0, 0], + "9711": [0.19444, 0.69444, 0, 0], + "9824": [0.12963, 0.69444, 0, 0], + "9825": [0.12963, 0.69444, 0, 0], + "9826": [0.12963, 0.69444, 0, 0], + "9827": [0.12963, 0.69444, 0, 0], + "9837": [0, 0.75, 0, 0], + "9838": [0.19444, 0.69444, 0, 0], + "9839": [0.19444, 0.69444, 0, 0], + "10216": [0.25, 0.75, 0, 0], + "10217": [0.25, 0.75, 0, 0], + "10815": [0, 0.68611, 0, 0], + "10927": [0.19667, 0.69667, 0, 0], + "10928": [0.19667, 0.69667, 0, 0] + }, + "Main-Italic": { + "33": [0, 0.69444, 0.12417, 0], + "34": [0, 0.69444, 0.06961, 0], + "35": [0.19444, 0.69444, 0.06616, 0], + "37": [0.05556, 0.75, 0.13639, 0], + "38": [0, 0.69444, 0.09694, 0], + "39": [0, 0.69444, 0.12417, 0], + "40": [0.25, 0.75, 0.16194, 0], + "41": [0.25, 0.75, 0.03694, 0], + "42": [0, 0.75, 0.14917, 0], + "43": [0.05667, 0.56167, 0.03694, 0], + "44": [0.19444, 0.10556, 0, 0], + "45": [0, 0.43056, 0.02826, 0], + "46": [0, 0.10556, 0, 0], + "47": [0.25, 0.75, 0.16194, 0], + "48": [0, 0.64444, 0.13556, 0], + "49": [0, 0.64444, 0.13556, 0], + "50": [0, 0.64444, 0.13556, 0], + "51": [0, 0.64444, 0.13556, 0], + "52": [0.19444, 0.64444, 0.13556, 0], + "53": [0, 0.64444, 0.13556, 0], + "54": [0, 0.64444, 0.13556, 0], + "55": [0.19444, 0.64444, 0.13556, 0], + "56": [0, 0.64444, 0.13556, 0], + "57": [0, 0.64444, 0.13556, 0], + "58": [0, 0.43056, 0.0582, 0], + "59": [0.19444, 0.43056, 0.0582, 0], + "61": [-0.13313, 0.36687, 0.06616, 0], + "63": [0, 0.69444, 0.1225, 0], + "64": [0, 0.69444, 0.09597, 0], + "65": [0, 0.68333, 0, 0], + "66": [0, 0.68333, 0.10257, 0], + "67": [0, 0.68333, 0.14528, 0], + "68": [0, 0.68333, 0.09403, 0], + "69": [0, 0.68333, 0.12028, 0], + "70": [0, 0.68333, 0.13305, 0], + "71": [0, 0.68333, 0.08722, 0], + "72": [0, 0.68333, 0.16389, 0], + "73": [0, 0.68333, 0.15806, 0], + "74": [0, 0.68333, 0.14028, 0], + "75": [0, 0.68333, 0.14528, 0], + "76": [0, 0.68333, 0, 0], + "77": [0, 0.68333, 0.16389, 0], + "78": [0, 0.68333, 0.16389, 0], + "79": [0, 0.68333, 0.09403, 0], + "80": [0, 0.68333, 0.10257, 0], + "81": [0.19444, 0.68333, 0.09403, 0], + "82": [0, 0.68333, 0.03868, 0], + "83": [0, 0.68333, 0.11972, 0], + "84": [0, 0.68333, 0.13305, 0], + "85": [0, 0.68333, 0.16389, 0], + "86": [0, 0.68333, 0.18361, 0], + "87": [0, 0.68333, 0.18361, 0], + "88": [0, 0.68333, 0.15806, 0], + "89": [0, 0.68333, 0.19383, 0], + "90": [0, 0.68333, 0.14528, 0], + "91": [0.25, 0.75, 0.1875, 0], + "93": [0.25, 0.75, 0.10528, 0], + "94": [0, 0.69444, 0.06646, 0], + "95": [0.31, 0.12056, 0.09208, 0], + "97": [0, 0.43056, 0.07671, 0], + "98": [0, 0.69444, 0.06312, 0], + "99": [0, 0.43056, 0.05653, 0], + "100": [0, 0.69444, 0.10333, 0], + "101": [0, 0.43056, 0.07514, 0], + "102": [0.19444, 0.69444, 0.21194, 0], + "103": [0.19444, 0.43056, 0.08847, 0], + "104": [0, 0.69444, 0.07671, 0], + "105": [0, 0.65536, 0.1019, 0], + "106": [0.19444, 0.65536, 0.14467, 0], + "107": [0, 0.69444, 0.10764, 0], + "108": [0, 0.69444, 0.10333, 0], + "109": [0, 0.43056, 0.07671, 0], + "110": [0, 0.43056, 0.07671, 0], + "111": [0, 0.43056, 0.06312, 0], + "112": [0.19444, 0.43056, 0.06312, 0], + "113": [0.19444, 0.43056, 0.08847, 0], + "114": [0, 0.43056, 0.10764, 0], + "115": [0, 0.43056, 0.08208, 0], + "116": [0, 0.61508, 0.09486, 0], + "117": [0, 0.43056, 0.07671, 0], + "118": [0, 0.43056, 0.10764, 0], + "119": [0, 0.43056, 0.10764, 0], + "120": [0, 0.43056, 0.12042, 0], + "121": [0.19444, 0.43056, 0.08847, 0], + "122": [0, 0.43056, 0.12292, 0], + "126": [0.35, 0.31786, 0.11585, 0], + "163": [0, 0.69444, 0, 0], + "305": [0, 0.43056, 0, 0.02778], + "567": [0.19444, 0.43056, 0, 0.08334], + "768": [0, 0.69444, 0, 0], + "769": [0, 0.69444, 0.09694, 0], + "770": [0, 0.69444, 0.06646, 0], + "771": [0, 0.66786, 0.11585, 0], + "772": [0, 0.56167, 0.10333, 0], + "774": [0, 0.69444, 0.10806, 0], + "775": [0, 0.66786, 0.11752, 0], + "776": [0, 0.66786, 0.10474, 0], + "778": [0, 0.69444, 0, 0], + "779": [0, 0.69444, 0.1225, 0], + "780": [0, 0.62847, 0.08295, 0], + "915": [0, 0.68333, 0.13305, 0], + "916": [0, 0.68333, 0, 0], + "920": [0, 0.68333, 0.09403, 0], + "923": [0, 0.68333, 0, 0], + "926": [0, 0.68333, 0.15294, 0], + "928": [0, 0.68333, 0.16389, 0], + "931": [0, 0.68333, 0.12028, 0], + "933": [0, 0.68333, 0.11111, 0], + "934": [0, 0.68333, 0.05986, 0], + "936": [0, 0.68333, 0.11111, 0], + "937": [0, 0.68333, 0.10257, 0], + "8211": [0, 0.43056, 0.09208, 0], + "8212": [0, 0.43056, 0.09208, 0], + "8216": [0, 0.69444, 0.12417, 0], + "8217": [0, 0.69444, 0.12417, 0], + "8220": [0, 0.69444, 0.1685, 0], + "8221": [0, 0.69444, 0.06961, 0], + "8463": [0, 0.68889, 0, 0] + }, + "Main-Regular": { + "32": [0, 0, 0, 0], + "33": [0, 0.69444, 0, 0], + "34": [0, 0.69444, 0, 0], + "35": [0.19444, 0.69444, 0, 0], + "36": [0.05556, 0.75, 0, 0], + "37": [0.05556, 0.75, 0, 0], + "38": [0, 0.69444, 0, 0], + "39": [0, 0.69444, 0, 0], + "40": [0.25, 0.75, 0, 0], + "41": [0.25, 0.75, 0, 0], + "42": [0, 0.75, 0, 0], + "43": [0.08333, 0.58333, 0, 0], + "44": [0.19444, 0.10556, 0, 0], + "45": [0, 0.43056, 0, 0], + "46": [0, 0.10556, 0, 0], + "47": [0.25, 0.75, 0, 0], + "48": [0, 0.64444, 0, 0], + "49": [0, 0.64444, 0, 0], + "50": [0, 0.64444, 0, 0], + "51": [0, 0.64444, 0, 0], + "52": [0, 0.64444, 0, 0], + "53": [0, 0.64444, 0, 0], + "54": [0, 0.64444, 0, 0], + "55": [0, 0.64444, 0, 0], + "56": [0, 0.64444, 0, 0], + "57": [0, 0.64444, 0, 0], + "58": [0, 0.43056, 0, 0], + "59": [0.19444, 0.43056, 0, 0], + "60": [0.0391, 0.5391, 0, 0], + "61": [-0.13313, 0.36687, 0, 0], + "62": [0.0391, 0.5391, 0, 0], + "63": [0, 0.69444, 0, 0], + "64": [0, 0.69444, 0, 0], + "65": [0, 0.68333, 0, 0], + "66": [0, 0.68333, 0, 0], + "67": [0, 0.68333, 0, 0], + "68": [0, 0.68333, 0, 0], + "69": [0, 0.68333, 0, 0], + "70": [0, 0.68333, 0, 0], + "71": [0, 0.68333, 0, 0], + "72": [0, 0.68333, 0, 0], + "73": [0, 0.68333, 0, 0], + "74": [0, 0.68333, 0, 0], + "75": [0, 0.68333, 0, 0], + "76": [0, 0.68333, 0, 0], + "77": [0, 0.68333, 0, 0], + "78": [0, 0.68333, 0, 0], + "79": [0, 0.68333, 0, 0], + "80": [0, 0.68333, 0, 0], + "81": [0.19444, 0.68333, 0, 0], + "82": [0, 0.68333, 0, 0], + "83": [0, 0.68333, 0, 0], + "84": [0, 0.68333, 0, 0], + "85": [0, 0.68333, 0, 0], + "86": [0, 0.68333, 0.01389, 0], + "87": [0, 0.68333, 0.01389, 0], + "88": [0, 0.68333, 0, 0], + "89": [0, 0.68333, 0.025, 0], + "90": [0, 0.68333, 0, 0], + "91": [0.25, 0.75, 0, 0], + "92": [0.25, 0.75, 0, 0], + "93": [0.25, 0.75, 0, 0], + "94": [0, 0.69444, 0, 0], + "95": [0.31, 0.12056, 0.02778, 0], + "96": [0, 0.69444, 0, 0], + "97": [0, 0.43056, 0, 0], + "98": [0, 0.69444, 0, 0], + "99": [0, 0.43056, 0, 0], + "100": [0, 0.69444, 0, 0], + "101": [0, 0.43056, 0, 0], + "102": [0, 0.69444, 0.07778, 0], + "103": [0.19444, 0.43056, 0.01389, 0], + "104": [0, 0.69444, 0, 0], + "105": [0, 0.66786, 0, 0], + "106": [0.19444, 0.66786, 0, 0], + "107": [0, 0.69444, 0, 0], + "108": [0, 0.69444, 0, 0], + "109": [0, 0.43056, 0, 0], + "110": [0, 0.43056, 0, 0], + "111": [0, 0.43056, 0, 0], + "112": [0.19444, 0.43056, 0, 0], + "113": [0.19444, 0.43056, 0, 0], + "114": [0, 0.43056, 0, 0], + "115": [0, 0.43056, 0, 0], + "116": [0, 0.61508, 0, 0], + "117": [0, 0.43056, 0, 0], + "118": [0, 0.43056, 0.01389, 0], + "119": [0, 0.43056, 0.01389, 0], + "120": [0, 0.43056, 0, 0], + "121": [0.19444, 0.43056, 0.01389, 0], + "122": [0, 0.43056, 0, 0], + "123": [0.25, 0.75, 0, 0], + "124": [0.25, 0.75, 0, 0], + "125": [0.25, 0.75, 0, 0], + "126": [0.35, 0.31786, 0, 0], + "160": [0, 0, 0, 0], + "168": [0, 0.66786, 0, 0], + "172": [0, 0.43056, 0, 0], + "175": [0, 0.56778, 0, 0], + "176": [0, 0.69444, 0, 0], + "177": [0.08333, 0.58333, 0, 0], + "180": [0, 0.69444, 0, 0], + "215": [0.08333, 0.58333, 0, 0], + "247": [0.08333, 0.58333, 0, 0], + "305": [0, 0.43056, 0, 0], + "567": [0.19444, 0.43056, 0, 0], + "710": [0, 0.69444, 0, 0], + "711": [0, 0.62847, 0, 0], + "713": [0, 0.56778, 0, 0], + "714": [0, 0.69444, 0, 0], + "715": [0, 0.69444, 0, 0], + "728": [0, 0.69444, 0, 0], + "729": [0, 0.66786, 0, 0], + "730": [0, 0.69444, 0, 0], + "732": [0, 0.66786, 0, 0], + "768": [0, 0.69444, 0, 0], + "769": [0, 0.69444, 0, 0], + "770": [0, 0.69444, 0, 0], + "771": [0, 0.66786, 0, 0], + "772": [0, 0.56778, 0, 0], + "774": [0, 0.69444, 0, 0], + "775": [0, 0.66786, 0, 0], + "776": [0, 0.66786, 0, 0], + "778": [0, 0.69444, 0, 0], + "779": [0, 0.69444, 0, 0], + "780": [0, 0.62847, 0, 0], + "824": [0.19444, 0.69444, 0, 0], + "915": [0, 0.68333, 0, 0], + "916": [0, 0.68333, 0, 0], + "920": [0, 0.68333, 0, 0], + "923": [0, 0.68333, 0, 0], + "926": [0, 0.68333, 0, 0], + "928": [0, 0.68333, 0, 0], + "931": [0, 0.68333, 0, 0], + "933": [0, 0.68333, 0, 0], + "934": [0, 0.68333, 0, 0], + "936": [0, 0.68333, 0, 0], + "937": [0, 0.68333, 0, 0], + "8211": [0, 0.43056, 0.02778, 0], + "8212": [0, 0.43056, 0.02778, 0], + "8216": [0, 0.69444, 0, 0], + "8217": [0, 0.69444, 0, 0], + "8220": [0, 0.69444, 0, 0], + "8221": [0, 0.69444, 0, 0], + "8224": [0.19444, 0.69444, 0, 0], + "8225": [0.19444, 0.69444, 0, 0], + "8230": [0, 0.12, 0, 0], + "8242": [0, 0.55556, 0, 0], + "8407": [0, 0.71444, 0.15382, 0], + "8463": [0, 0.68889, 0, 0], + "8465": [0, 0.69444, 0, 0], + "8467": [0, 0.69444, 0, 0.11111], + "8472": [0.19444, 0.43056, 0, 0.11111], + "8476": [0, 0.69444, 0, 0], + "8501": [0, 0.69444, 0, 0], + "8592": [-0.13313, 0.36687, 0, 0], + "8593": [0.19444, 0.69444, 0, 0], + "8594": [-0.13313, 0.36687, 0, 0], + "8595": [0.19444, 0.69444, 0, 0], + "8596": [-0.13313, 0.36687, 0, 0], + "8597": [0.25, 0.75, 0, 0], + "8598": [0.19444, 0.69444, 0, 0], + "8599": [0.19444, 0.69444, 0, 0], + "8600": [0.19444, 0.69444, 0, 0], + "8601": [0.19444, 0.69444, 0, 0], + "8614": [0.011, 0.511, 0, 0], + "8617": [0.011, 0.511, 0, 0], + "8618": [0.011, 0.511, 0, 0], + "8636": [-0.13313, 0.36687, 0, 0], + "8637": [-0.13313, 0.36687, 0, 0], + "8640": [-0.13313, 0.36687, 0, 0], + "8641": [-0.13313, 0.36687, 0, 0], + "8652": [0.011, 0.671, 0, 0], + "8656": [-0.13313, 0.36687, 0, 0], + "8657": [0.19444, 0.69444, 0, 0], + "8658": [-0.13313, 0.36687, 0, 0], + "8659": [0.19444, 0.69444, 0, 0], + "8660": [-0.13313, 0.36687, 0, 0], + "8661": [0.25, 0.75, 0, 0], + "8704": [0, 0.69444, 0, 0], + "8706": [0, 0.69444, 0.05556, 0.08334], + "8707": [0, 0.69444, 0, 0], + "8709": [0.05556, 0.75, 0, 0], + "8711": [0, 0.68333, 0, 0], + "8712": [0.0391, 0.5391, 0, 0], + "8715": [0.0391, 0.5391, 0, 0], + "8722": [0.08333, 0.58333, 0, 0], + "8723": [0.08333, 0.58333, 0, 0], + "8725": [0.25, 0.75, 0, 0], + "8726": [0.25, 0.75, 0, 0], + "8727": [-0.03472, 0.46528, 0, 0], + "8728": [-0.05555, 0.44445, 0, 0], + "8729": [-0.05555, 0.44445, 0, 0], + "8730": [0.2, 0.8, 0, 0], + "8733": [0, 0.43056, 0, 0], + "8734": [0, 0.43056, 0, 0], + "8736": [0, 0.69224, 0, 0], + "8739": [0.25, 0.75, 0, 0], + "8741": [0.25, 0.75, 0, 0], + "8743": [0, 0.55556, 0, 0], + "8744": [0, 0.55556, 0, 0], + "8745": [0, 0.55556, 0, 0], + "8746": [0, 0.55556, 0, 0], + "8747": [0.19444, 0.69444, 0.11111, 0], + "8764": [-0.13313, 0.36687, 0, 0], + "8768": [0.19444, 0.69444, 0, 0], + "8771": [-0.03625, 0.46375, 0, 0], + "8773": [-0.022, 0.589, 0, 0], + "8776": [-0.01688, 0.48312, 0, 0], + "8781": [-0.03625, 0.46375, 0, 0], + "8784": [-0.133, 0.67, 0, 0], + "8800": [0.215, 0.716, 0, 0], + "8801": [-0.03625, 0.46375, 0, 0], + "8804": [0.13597, 0.63597, 0, 0], + "8805": [0.13597, 0.63597, 0, 0], + "8810": [0.0391, 0.5391, 0, 0], + "8811": [0.0391, 0.5391, 0, 0], + "8826": [0.0391, 0.5391, 0, 0], + "8827": [0.0391, 0.5391, 0, 0], + "8834": [0.0391, 0.5391, 0, 0], + "8835": [0.0391, 0.5391, 0, 0], + "8838": [0.13597, 0.63597, 0, 0], + "8839": [0.13597, 0.63597, 0, 0], + "8846": [0, 0.55556, 0, 0], + "8849": [0.13597, 0.63597, 0, 0], + "8850": [0.13597, 0.63597, 0, 0], + "8851": [0, 0.55556, 0, 0], + "8852": [0, 0.55556, 0, 0], + "8853": [0.08333, 0.58333, 0, 0], + "8854": [0.08333, 0.58333, 0, 0], + "8855": [0.08333, 0.58333, 0, 0], + "8856": [0.08333, 0.58333, 0, 0], + "8857": [0.08333, 0.58333, 0, 0], + "8866": [0, 0.69444, 0, 0], + "8867": [0, 0.69444, 0, 0], + "8868": [0, 0.69444, 0, 0], + "8869": [0, 0.69444, 0, 0], + "8872": [0.249, 0.75, 0, 0], + "8900": [-0.05555, 0.44445, 0, 0], + "8901": [-0.05555, 0.44445, 0, 0], + "8902": [-0.03472, 0.46528, 0, 0], + "8904": [0.005, 0.505, 0, 0], + "8942": [0.03, 0.9, 0, 0], + "8943": [-0.19, 0.31, 0, 0], + "8945": [-0.1, 0.82, 0, 0], + "8968": [0.25, 0.75, 0, 0], + "8969": [0.25, 0.75, 0, 0], + "8970": [0.25, 0.75, 0, 0], + "8971": [0.25, 0.75, 0, 0], + "8994": [-0.14236, 0.35764, 0, 0], + "8995": [-0.14236, 0.35764, 0, 0], + "9136": [0.244, 0.744, 0, 0], + "9137": [0.244, 0.744, 0, 0], + "9651": [0.19444, 0.69444, 0, 0], + "9657": [-0.03472, 0.46528, 0, 0], + "9661": [0.19444, 0.69444, 0, 0], + "9667": [-0.03472, 0.46528, 0, 0], + "9711": [0.19444, 0.69444, 0, 0], + "9824": [0.12963, 0.69444, 0, 0], + "9825": [0.12963, 0.69444, 0, 0], + "9826": [0.12963, 0.69444, 0, 0], + "9827": [0.12963, 0.69444, 0, 0], + "9837": [0, 0.75, 0, 0], + "9838": [0.19444, 0.69444, 0, 0], + "9839": [0.19444, 0.69444, 0, 0], + "10216": [0.25, 0.75, 0, 0], + "10217": [0.25, 0.75, 0, 0], + "10222": [0.244, 0.744, 0, 0], + "10223": [0.244, 0.744, 0, 0], + "10229": [0.011, 0.511, 0, 0], + "10230": [0.011, 0.511, 0, 0], + "10231": [0.011, 0.511, 0, 0], + "10232": [0.024, 0.525, 0, 0], + "10233": [0.024, 0.525, 0, 0], + "10234": [0.024, 0.525, 0, 0], + "10236": [0.011, 0.511, 0, 0], + "10815": [0, 0.68333, 0, 0], + "10927": [0.13597, 0.63597, 0, 0], + "10928": [0.13597, 0.63597, 0, 0] + }, + "Math-BoldItalic": { + "47": [0.19444, 0.69444, 0, 0], + "65": [0, 0.68611, 0, 0], + "66": [0, 0.68611, 0.04835, 0], + "67": [0, 0.68611, 0.06979, 0], + "68": [0, 0.68611, 0.03194, 0], + "69": [0, 0.68611, 0.05451, 0], + "70": [0, 0.68611, 0.15972, 0], + "71": [0, 0.68611, 0, 0], + "72": [0, 0.68611, 0.08229, 0], + "73": [0, 0.68611, 0.07778, 0], + "74": [0, 0.68611, 0.10069, 0], + "75": [0, 0.68611, 0.06979, 0], + "76": [0, 0.68611, 0, 0], + "77": [0, 0.68611, 0.11424, 0], + "78": [0, 0.68611, 0.11424, 0], + "79": [0, 0.68611, 0.03194, 0], + "80": [0, 0.68611, 0.15972, 0], + "81": [0.19444, 0.68611, 0, 0], + "82": [0, 0.68611, 0.00421, 0], + "83": [0, 0.68611, 0.05382, 0], + "84": [0, 0.68611, 0.15972, 0], + "85": [0, 0.68611, 0.11424, 0], + "86": [0, 0.68611, 0.25555, 0], + "87": [0, 0.68611, 0.15972, 0], + "88": [0, 0.68611, 0.07778, 0], + "89": [0, 0.68611, 0.25555, 0], + "90": [0, 0.68611, 0.06979, 0], + "97": [0, 0.44444, 0, 0], + "98": [0, 0.69444, 0, 0], + "99": [0, 0.44444, 0, 0], + "100": [0, 0.69444, 0, 0], + "101": [0, 0.44444, 0, 0], + "102": [0.19444, 0.69444, 0.11042, 0], + "103": [0.19444, 0.44444, 0.03704, 0], + "104": [0, 0.69444, 0, 0], + "105": [0, 0.69326, 0, 0], + "106": [0.19444, 0.69326, 0.0622, 0], + "107": [0, 0.69444, 0.01852, 0], + "108": [0, 0.69444, 0.0088, 0], + "109": [0, 0.44444, 0, 0], + "110": [0, 0.44444, 0, 0], + "111": [0, 0.44444, 0, 0], + "112": [0.19444, 0.44444, 0, 0], + "113": [0.19444, 0.44444, 0.03704, 0], + "114": [0, 0.44444, 0.03194, 0], + "115": [0, 0.44444, 0, 0], + "116": [0, 0.63492, 0, 0], + "117": [0, 0.44444, 0, 0], + "118": [0, 0.44444, 0.03704, 0], + "119": [0, 0.44444, 0.02778, 0], + "120": [0, 0.44444, 0, 0], + "121": [0.19444, 0.44444, 0.03704, 0], + "122": [0, 0.44444, 0.04213, 0], + "915": [0, 0.68611, 0.15972, 0], + "916": [0, 0.68611, 0, 0], + "920": [0, 0.68611, 0.03194, 0], + "923": [0, 0.68611, 0, 0], + "926": [0, 0.68611, 0.07458, 0], + "928": [0, 0.68611, 0.08229, 0], + "931": [0, 0.68611, 0.05451, 0], + "933": [0, 0.68611, 0.15972, 0], + "934": [0, 0.68611, 0, 0], + "936": [0, 0.68611, 0.11653, 0], + "937": [0, 0.68611, 0.04835, 0], + "945": [0, 0.44444, 0, 0], + "946": [0.19444, 0.69444, 0.03403, 0], + "947": [0.19444, 0.44444, 0.06389, 0], + "948": [0, 0.69444, 0.03819, 0], + "949": [0, 0.44444, 0, 0], + "950": [0.19444, 0.69444, 0.06215, 0], + "951": [0.19444, 0.44444, 0.03704, 0], + "952": [0, 0.69444, 0.03194, 0], + "953": [0, 0.44444, 0, 0], + "954": [0, 0.44444, 0, 0], + "955": [0, 0.69444, 0, 0], + "956": [0.19444, 0.44444, 0, 0], + "957": [0, 0.44444, 0.06898, 0], + "958": [0.19444, 0.69444, 0.03021, 0], + "959": [0, 0.44444, 0, 0], + "960": [0, 0.44444, 0.03704, 0], + "961": [0.19444, 0.44444, 0, 0], + "962": [0.09722, 0.44444, 0.07917, 0], + "963": [0, 0.44444, 0.03704, 0], + "964": [0, 0.44444, 0.13472, 0], + "965": [0, 0.44444, 0.03704, 0], + "966": [0.19444, 0.44444, 0, 0], + "967": [0.19444, 0.44444, 0, 0], + "968": [0.19444, 0.69444, 0.03704, 0], + "969": [0, 0.44444, 0.03704, 0], + "977": [0, 0.69444, 0, 0], + "981": [0.19444, 0.69444, 0, 0], + "982": [0, 0.44444, 0.03194, 0], + "1009": [0.19444, 0.44444, 0, 0], + "1013": [0, 0.44444, 0, 0] + }, + "Math-Italic": { + "47": [0.19444, 0.69444, 0, 0], + "65": [0, 0.68333, 0, 0.13889], + "66": [0, 0.68333, 0.05017, 0.08334], + "67": [0, 0.68333, 0.07153, 0.08334], + "68": [0, 0.68333, 0.02778, 0.05556], + "69": [0, 0.68333, 0.05764, 0.08334], + "70": [0, 0.68333, 0.13889, 0.08334], + "71": [0, 0.68333, 0, 0.08334], + "72": [0, 0.68333, 0.08125, 0.05556], + "73": [0, 0.68333, 0.07847, 0.11111], + "74": [0, 0.68333, 0.09618, 0.16667], + "75": [0, 0.68333, 0.07153, 0.05556], + "76": [0, 0.68333, 0, 0.02778], + "77": [0, 0.68333, 0.10903, 0.08334], + "78": [0, 0.68333, 0.10903, 0.08334], + "79": [0, 0.68333, 0.02778, 0.08334], + "80": [0, 0.68333, 0.13889, 0.08334], + "81": [0.19444, 0.68333, 0, 0.08334], + "82": [0, 0.68333, 0.00773, 0.08334], + "83": [0, 0.68333, 0.05764, 0.08334], + "84": [0, 0.68333, 0.13889, 0.08334], + "85": [0, 0.68333, 0.10903, 0.02778], + "86": [0, 0.68333, 0.22222, 0], + "87": [0, 0.68333, 0.13889, 0], + "88": [0, 0.68333, 0.07847, 0.08334], + "89": [0, 0.68333, 0.22222, 0], + "90": [0, 0.68333, 0.07153, 0.08334], + "97": [0, 0.43056, 0, 0], + "98": [0, 0.69444, 0, 0], + "99": [0, 0.43056, 0, 0.05556], + "100": [0, 0.69444, 0, 0.16667], + "101": [0, 0.43056, 0, 0.05556], + "102": [0.19444, 0.69444, 0.10764, 0.16667], + "103": [0.19444, 0.43056, 0.03588, 0.02778], + "104": [0, 0.69444, 0, 0], + "105": [0, 0.65952, 0, 0], + "106": [0.19444, 0.65952, 0.05724, 0], + "107": [0, 0.69444, 0.03148, 0], + "108": [0, 0.69444, 0.01968, 0.08334], + "109": [0, 0.43056, 0, 0], + "110": [0, 0.43056, 0, 0], + "111": [0, 0.43056, 0, 0.05556], + "112": [0.19444, 0.43056, 0, 0.08334], + "113": [0.19444, 0.43056, 0.03588, 0.08334], + "114": [0, 0.43056, 0.02778, 0.05556], + "115": [0, 0.43056, 0, 0.05556], + "116": [0, 0.61508, 0, 0.08334], + "117": [0, 0.43056, 0, 0.02778], + "118": [0, 0.43056, 0.03588, 0.02778], + "119": [0, 0.43056, 0.02691, 0.08334], + "120": [0, 0.43056, 0, 0.02778], + "121": [0.19444, 0.43056, 0.03588, 0.05556], + "122": [0, 0.43056, 0.04398, 0.05556], + "915": [0, 0.68333, 0.13889, 0.08334], + "916": [0, 0.68333, 0, 0.16667], + "920": [0, 0.68333, 0.02778, 0.08334], + "923": [0, 0.68333, 0, 0.16667], + "926": [0, 0.68333, 0.07569, 0.08334], + "928": [0, 0.68333, 0.08125, 0.05556], + "931": [0, 0.68333, 0.05764, 0.08334], + "933": [0, 0.68333, 0.13889, 0.05556], + "934": [0, 0.68333, 0, 0.08334], + "936": [0, 0.68333, 0.11, 0.05556], + "937": [0, 0.68333, 0.05017, 0.08334], + "945": [0, 0.43056, 0.0037, 0.02778], + "946": [0.19444, 0.69444, 0.05278, 0.08334], + "947": [0.19444, 0.43056, 0.05556, 0], + "948": [0, 0.69444, 0.03785, 0.05556], + "949": [0, 0.43056, 0, 0.08334], + "950": [0.19444, 0.69444, 0.07378, 0.08334], + "951": [0.19444, 0.43056, 0.03588, 0.05556], + "952": [0, 0.69444, 0.02778, 0.08334], + "953": [0, 0.43056, 0, 0.05556], + "954": [0, 0.43056, 0, 0], + "955": [0, 0.69444, 0, 0], + "956": [0.19444, 0.43056, 0, 0.02778], + "957": [0, 0.43056, 0.06366, 0.02778], + "958": [0.19444, 0.69444, 0.04601, 0.11111], + "959": [0, 0.43056, 0, 0.05556], + "960": [0, 0.43056, 0.03588, 0], + "961": [0.19444, 0.43056, 0, 0.08334], + "962": [0.09722, 0.43056, 0.07986, 0.08334], + "963": [0, 0.43056, 0.03588, 0], + "964": [0, 0.43056, 0.1132, 0.02778], + "965": [0, 0.43056, 0.03588, 0.02778], + "966": [0.19444, 0.43056, 0, 0.08334], + "967": [0.19444, 0.43056, 0, 0.05556], + "968": [0.19444, 0.69444, 0.03588, 0.11111], + "969": [0, 0.43056, 0.03588, 0], + "977": [0, 0.69444, 0, 0.08334], + "981": [0.19444, 0.69444, 0, 0.08334], + "982": [0, 0.43056, 0.02778, 0], + "1009": [0.19444, 0.43056, 0, 0.08334], + "1013": [0, 0.43056, 0, 0.05556] + }, + "Math-Regular": { + "65": [0, 0.68333, 0, 0.13889], + "66": [0, 0.68333, 0.05017, 0.08334], + "67": [0, 0.68333, 0.07153, 0.08334], + "68": [0, 0.68333, 0.02778, 0.05556], + "69": [0, 0.68333, 0.05764, 0.08334], + "70": [0, 0.68333, 0.13889, 0.08334], + "71": [0, 0.68333, 0, 0.08334], + "72": [0, 0.68333, 0.08125, 0.05556], + "73": [0, 0.68333, 0.07847, 0.11111], + "74": [0, 0.68333, 0.09618, 0.16667], + "75": [0, 0.68333, 0.07153, 0.05556], + "76": [0, 0.68333, 0, 0.02778], + "77": [0, 0.68333, 0.10903, 0.08334], + "78": [0, 0.68333, 0.10903, 0.08334], + "79": [0, 0.68333, 0.02778, 0.08334], + "80": [0, 0.68333, 0.13889, 0.08334], + "81": [0.19444, 0.68333, 0, 0.08334], + "82": [0, 0.68333, 0.00773, 0.08334], + "83": [0, 0.68333, 0.05764, 0.08334], + "84": [0, 0.68333, 0.13889, 0.08334], + "85": [0, 0.68333, 0.10903, 0.02778], + "86": [0, 0.68333, 0.22222, 0], + "87": [0, 0.68333, 0.13889, 0], + "88": [0, 0.68333, 0.07847, 0.08334], + "89": [0, 0.68333, 0.22222, 0], + "90": [0, 0.68333, 0.07153, 0.08334], + "97": [0, 0.43056, 0, 0], + "98": [0, 0.69444, 0, 0], + "99": [0, 0.43056, 0, 0.05556], + "100": [0, 0.69444, 0, 0.16667], + "101": [0, 0.43056, 0, 0.05556], + "102": [0.19444, 0.69444, 0.10764, 0.16667], + "103": [0.19444, 0.43056, 0.03588, 0.02778], + "104": [0, 0.69444, 0, 0], + "105": [0, 0.65952, 0, 0], + "106": [0.19444, 0.65952, 0.05724, 0], + "107": [0, 0.69444, 0.03148, 0], + "108": [0, 0.69444, 0.01968, 0.08334], + "109": [0, 0.43056, 0, 0], + "110": [0, 0.43056, 0, 0], + "111": [0, 0.43056, 0, 0.05556], + "112": [0.19444, 0.43056, 0, 0.08334], + "113": [0.19444, 0.43056, 0.03588, 0.08334], + "114": [0, 0.43056, 0.02778, 0.05556], + "115": [0, 0.43056, 0, 0.05556], + "116": [0, 0.61508, 0, 0.08334], + "117": [0, 0.43056, 0, 0.02778], + "118": [0, 0.43056, 0.03588, 0.02778], + "119": [0, 0.43056, 0.02691, 0.08334], + "120": [0, 0.43056, 0, 0.02778], + "121": [0.19444, 0.43056, 0.03588, 0.05556], + "122": [0, 0.43056, 0.04398, 0.05556], + "915": [0, 0.68333, 0.13889, 0.08334], + "916": [0, 0.68333, 0, 0.16667], + "920": [0, 0.68333, 0.02778, 0.08334], + "923": [0, 0.68333, 0, 0.16667], + "926": [0, 0.68333, 0.07569, 0.08334], + "928": [0, 0.68333, 0.08125, 0.05556], + "931": [0, 0.68333, 0.05764, 0.08334], + "933": [0, 0.68333, 0.13889, 0.05556], + "934": [0, 0.68333, 0, 0.08334], + "936": [0, 0.68333, 0.11, 0.05556], + "937": [0, 0.68333, 0.05017, 0.08334], + "945": [0, 0.43056, 0.0037, 0.02778], + "946": [0.19444, 0.69444, 0.05278, 0.08334], + "947": [0.19444, 0.43056, 0.05556, 0], + "948": [0, 0.69444, 0.03785, 0.05556], + "949": [0, 0.43056, 0, 0.08334], + "950": [0.19444, 0.69444, 0.07378, 0.08334], + "951": [0.19444, 0.43056, 0.03588, 0.05556], + "952": [0, 0.69444, 0.02778, 0.08334], + "953": [0, 0.43056, 0, 0.05556], + "954": [0, 0.43056, 0, 0], + "955": [0, 0.69444, 0, 0], + "956": [0.19444, 0.43056, 0, 0.02778], + "957": [0, 0.43056, 0.06366, 0.02778], + "958": [0.19444, 0.69444, 0.04601, 0.11111], + "959": [0, 0.43056, 0, 0.05556], + "960": [0, 0.43056, 0.03588, 0], + "961": [0.19444, 0.43056, 0, 0.08334], + "962": [0.09722, 0.43056, 0.07986, 0.08334], + "963": [0, 0.43056, 0.03588, 0], + "964": [0, 0.43056, 0.1132, 0.02778], + "965": [0, 0.43056, 0.03588, 0.02778], + "966": [0.19444, 0.43056, 0, 0.08334], + "967": [0.19444, 0.43056, 0, 0.05556], + "968": [0.19444, 0.69444, 0.03588, 0.11111], + "969": [0, 0.43056, 0.03588, 0], + "977": [0, 0.69444, 0, 0.08334], + "981": [0.19444, 0.69444, 0, 0.08334], + "982": [0, 0.43056, 0.02778, 0], + "1009": [0.19444, 0.43056, 0, 0.08334], + "1013": [0, 0.43056, 0, 0.05556] + }, + "SansSerif-Regular": { + "33": [0, 0.69444, 0, 0], + "34": [0, 0.69444, 0, 0], + "35": [0.19444, 0.69444, 0, 0], + "36": [0.05556, 0.75, 0, 0], + "37": [0.05556, 0.75, 0, 0], + "38": [0, 0.69444, 0, 0], + "39": [0, 0.69444, 0, 0], + "40": [0.25, 0.75, 0, 0], + "41": [0.25, 0.75, 0, 0], + "42": [0, 0.75, 0, 0], + "43": [0.08333, 0.58333, 0, 0], + "44": [0.125, 0.08333, 0, 0], + "45": [0, 0.44444, 0, 0], + "46": [0, 0.08333, 0, 0], + "47": [0.25, 0.75, 0, 0], + "48": [0, 0.65556, 0, 0], + "49": [0, 0.65556, 0, 0], + "50": [0, 0.65556, 0, 0], + "51": [0, 0.65556, 0, 0], + "52": [0, 0.65556, 0, 0], + "53": [0, 0.65556, 0, 0], + "54": [0, 0.65556, 0, 0], + "55": [0, 0.65556, 0, 0], + "56": [0, 0.65556, 0, 0], + "57": [0, 0.65556, 0, 0], + "58": [0, 0.44444, 0, 0], + "59": [0.125, 0.44444, 0, 0], + "61": [-0.13, 0.37, 0, 0], + "63": [0, 0.69444, 0, 0], + "64": [0, 0.69444, 0, 0], + "65": [0, 0.69444, 0, 0], + "66": [0, 0.69444, 0, 0], + "67": [0, 0.69444, 0, 0], + "68": [0, 0.69444, 0, 0], + "69": [0, 0.69444, 0, 0], + "70": [0, 0.69444, 0, 0], + "71": [0, 0.69444, 0, 0], + "72": [0, 0.69444, 0, 0], + "73": [0, 0.69444, 0, 0], + "74": [0, 0.69444, 0, 0], + "75": [0, 0.69444, 0, 0], + "76": [0, 0.69444, 0, 0], + "77": [0, 0.69444, 0, 0], + "78": [0, 0.69444, 0, 0], + "79": [0, 0.69444, 0, 0], + "80": [0, 0.69444, 0, 0], + "81": [0.125, 0.69444, 0, 0], + "82": [0, 0.69444, 0, 0], + "83": [0, 0.69444, 0, 0], + "84": [0, 0.69444, 0, 0], + "85": [0, 0.69444, 0, 0], + "86": [0, 0.69444, 0.01389, 0], + "87": [0, 0.69444, 0.01389, 0], + "88": [0, 0.69444, 0, 0], + "89": [0, 0.69444, 0.025, 0], + "90": [0, 0.69444, 0, 0], + "91": [0.25, 0.75, 0, 0], + "93": [0.25, 0.75, 0, 0], + "94": [0, 0.69444, 0, 0], + "95": [0.35, 0.09444, 0.02778, 0], + "97": [0, 0.44444, 0, 0], + "98": [0, 0.69444, 0, 0], + "99": [0, 0.44444, 0, 0], + "100": [0, 0.69444, 0, 0], + "101": [0, 0.44444, 0, 0], + "102": [0, 0.69444, 0.06944, 0], + "103": [0.19444, 0.44444, 0.01389, 0], + "104": [0, 0.69444, 0, 0], + "105": [0, 0.67937, 0, 0], + "106": [0.19444, 0.67937, 0, 0], + "107": [0, 0.69444, 0, 0], + "108": [0, 0.69444, 0, 0], + "109": [0, 0.44444, 0, 0], + "110": [0, 0.44444, 0, 0], + "111": [0, 0.44444, 0, 0], + "112": [0.19444, 0.44444, 0, 0], + "113": [0.19444, 0.44444, 0, 0], + "114": [0, 0.44444, 0.01389, 0], + "115": [0, 0.44444, 0, 0], + "116": [0, 0.57143, 0, 0], + "117": [0, 0.44444, 0, 0], + "118": [0, 0.44444, 0.01389, 0], + "119": [0, 0.44444, 0.01389, 0], + "120": [0, 0.44444, 0, 0], + "121": [0.19444, 0.44444, 0.01389, 0], + "122": [0, 0.44444, 0, 0], + "126": [0.35, 0.32659, 0, 0], + "305": [0, 0.44444, 0, 0], + "567": [0.19444, 0.44444, 0, 0], + "768": [0, 0.69444, 0, 0], + "769": [0, 0.69444, 0, 0], + "770": [0, 0.69444, 0, 0], + "771": [0, 0.67659, 0, 0], + "772": [0, 0.60889, 0, 0], + "774": [0, 0.69444, 0, 0], + "775": [0, 0.67937, 0, 0], + "776": [0, 0.67937, 0, 0], + "778": [0, 0.69444, 0, 0], + "779": [0, 0.69444, 0, 0], + "780": [0, 0.63194, 0, 0], + "915": [0, 0.69444, 0, 0], + "916": [0, 0.69444, 0, 0], + "920": [0, 0.69444, 0, 0], + "923": [0, 0.69444, 0, 0], + "926": [0, 0.69444, 0, 0], + "928": [0, 0.69444, 0, 0], + "931": [0, 0.69444, 0, 0], + "933": [0, 0.69444, 0, 0], + "934": [0, 0.69444, 0, 0], + "936": [0, 0.69444, 0, 0], + "937": [0, 0.69444, 0, 0], + "8211": [0, 0.44444, 0.02778, 0], + "8212": [0, 0.44444, 0.02778, 0], + "8216": [0, 0.69444, 0, 0], + "8217": [0, 0.69444, 0, 0], + "8220": [0, 0.69444, 0, 0], + "8221": [0, 0.69444, 0, 0] + }, + "Script-Regular": { + "65": [0, 0.7, 0.22925, 0], + "66": [0, 0.7, 0.04087, 0], + "67": [0, 0.7, 0.1689, 0], + "68": [0, 0.7, 0.09371, 0], + "69": [0, 0.7, 0.18583, 0], + "70": [0, 0.7, 0.13634, 0], + "71": [0, 0.7, 0.17322, 0], + "72": [0, 0.7, 0.29694, 0], + "73": [0, 0.7, 0.19189, 0], + "74": [0.27778, 0.7, 0.19189, 0], + "75": [0, 0.7, 0.31259, 0], + "76": [0, 0.7, 0.19189, 0], + "77": [0, 0.7, 0.15981, 0], + "78": [0, 0.7, 0.3525, 0], + "79": [0, 0.7, 0.08078, 0], + "80": [0, 0.7, 0.08078, 0], + "81": [0, 0.7, 0.03305, 0], + "82": [0, 0.7, 0.06259, 0], + "83": [0, 0.7, 0.19189, 0], + "84": [0, 0.7, 0.29087, 0], + "85": [0, 0.7, 0.25815, 0], + "86": [0, 0.7, 0.27523, 0], + "87": [0, 0.7, 0.27523, 0], + "88": [0, 0.7, 0.26006, 0], + "89": [0, 0.7, 0.2939, 0], + "90": [0, 0.7, 0.24037, 0] + }, + "Size1-Regular": { + "40": [0.35001, 0.85, 0, 0], + "41": [0.35001, 0.85, 0, 0], + "47": [0.35001, 0.85, 0, 0], + "91": [0.35001, 0.85, 0, 0], + "92": [0.35001, 0.85, 0, 0], + "93": [0.35001, 0.85, 0, 0], + "123": [0.35001, 0.85, 0, 0], + "125": [0.35001, 0.85, 0, 0], + "710": [0, 0.72222, 0, 0], + "732": [0, 0.72222, 0, 0], + "770": [0, 0.72222, 0, 0], + "771": [0, 0.72222, 0, 0], + "8214": [-0.00099, 0.601, 0, 0], + "8593": [1e-05, 0.6, 0, 0], + "8595": [1e-05, 0.6, 0, 0], + "8657": [1e-05, 0.6, 0, 0], + "8659": [1e-05, 0.6, 0, 0], + "8719": [0.25001, 0.75, 0, 0], + "8720": [0.25001, 0.75, 0, 0], + "8721": [0.25001, 0.75, 0, 0], + "8730": [0.35001, 0.85, 0, 0], + "8739": [-0.00599, 0.606, 0, 0], + "8741": [-0.00599, 0.606, 0, 0], + "8747": [0.30612, 0.805, 0.19445, 0], + "8748": [0.306, 0.805, 0.19445, 0], + "8749": [0.306, 0.805, 0.19445, 0], + "8750": [0.30612, 0.805, 0.19445, 0], + "8896": [0.25001, 0.75, 0, 0], + "8897": [0.25001, 0.75, 0, 0], + "8898": [0.25001, 0.75, 0, 0], + "8899": [0.25001, 0.75, 0, 0], + "8968": [0.35001, 0.85, 0, 0], + "8969": [0.35001, 0.85, 0, 0], + "8970": [0.35001, 0.85, 0, 0], + "8971": [0.35001, 0.85, 0, 0], + "9168": [-0.00099, 0.601, 0, 0], + "10216": [0.35001, 0.85, 0, 0], + "10217": [0.35001, 0.85, 0, 0], + "10752": [0.25001, 0.75, 0, 0], + "10753": [0.25001, 0.75, 0, 0], + "10754": [0.25001, 0.75, 0, 0], + "10756": [0.25001, 0.75, 0, 0], + "10758": [0.25001, 0.75, 0, 0] + }, + "Size2-Regular": { + "40": [0.65002, 1.15, 0, 0], + "41": [0.65002, 1.15, 0, 0], + "47": [0.65002, 1.15, 0, 0], + "91": [0.65002, 1.15, 0, 0], + "92": [0.65002, 1.15, 0, 0], + "93": [0.65002, 1.15, 0, 0], + "123": [0.65002, 1.15, 0, 0], + "125": [0.65002, 1.15, 0, 0], + "710": [0, 0.75, 0, 0], + "732": [0, 0.75, 0, 0], + "770": [0, 0.75, 0, 0], + "771": [0, 0.75, 0, 0], + "8719": [0.55001, 1.05, 0, 0], + "8720": [0.55001, 1.05, 0, 0], + "8721": [0.55001, 1.05, 0, 0], + "8730": [0.65002, 1.15, 0, 0], + "8747": [0.86225, 1.36, 0.44445, 0], + "8748": [0.862, 1.36, 0.44445, 0], + "8749": [0.862, 1.36, 0.44445, 0], + "8750": [0.86225, 1.36, 0.44445, 0], + "8896": [0.55001, 1.05, 0, 0], + "8897": [0.55001, 1.05, 0, 0], + "8898": [0.55001, 1.05, 0, 0], + "8899": [0.55001, 1.05, 0, 0], + "8968": [0.65002, 1.15, 0, 0], + "8969": [0.65002, 1.15, 0, 0], + "8970": [0.65002, 1.15, 0, 0], + "8971": [0.65002, 1.15, 0, 0], + "10216": [0.65002, 1.15, 0, 0], + "10217": [0.65002, 1.15, 0, 0], + "10752": [0.55001, 1.05, 0, 0], + "10753": [0.55001, 1.05, 0, 0], + "10754": [0.55001, 1.05, 0, 0], + "10756": [0.55001, 1.05, 0, 0], + "10758": [0.55001, 1.05, 0, 0] + }, + "Size3-Regular": { + "40": [0.95003, 1.45, 0, 0], + "41": [0.95003, 1.45, 0, 0], + "47": [0.95003, 1.45, 0, 0], + "91": [0.95003, 1.45, 0, 0], + "92": [0.95003, 1.45, 0, 0], + "93": [0.95003, 1.45, 0, 0], + "123": [0.95003, 1.45, 0, 0], + "125": [0.95003, 1.45, 0, 0], + "710": [0, 0.75, 0, 0], + "732": [0, 0.75, 0, 0], + "770": [0, 0.75, 0, 0], + "771": [0, 0.75, 0, 0], + "8730": [0.95003, 1.45, 0, 0], + "8968": [0.95003, 1.45, 0, 0], + "8969": [0.95003, 1.45, 0, 0], + "8970": [0.95003, 1.45, 0, 0], + "8971": [0.95003, 1.45, 0, 0], + "10216": [0.95003, 1.45, 0, 0], + "10217": [0.95003, 1.45, 0, 0] + }, + "Size4-Regular": { + "40": [1.25003, 1.75, 0, 0], + "41": [1.25003, 1.75, 0, 0], + "47": [1.25003, 1.75, 0, 0], + "91": [1.25003, 1.75, 0, 0], + "92": [1.25003, 1.75, 0, 0], + "93": [1.25003, 1.75, 0, 0], + "123": [1.25003, 1.75, 0, 0], + "125": [1.25003, 1.75, 0, 0], + "710": [0, 0.825, 0, 0], + "732": [0, 0.825, 0, 0], + "770": [0, 0.825, 0, 0], + "771": [0, 0.825, 0, 0], + "8730": [1.25003, 1.75, 0, 0], + "8968": [1.25003, 1.75, 0, 0], + "8969": [1.25003, 1.75, 0, 0], + "8970": [1.25003, 1.75, 0, 0], + "8971": [1.25003, 1.75, 0, 0], + "9115": [0.64502, 1.155, 0, 0], + "9116": [1e-05, 0.6, 0, 0], + "9117": [0.64502, 1.155, 0, 0], + "9118": [0.64502, 1.155, 0, 0], + "9119": [1e-05, 0.6, 0, 0], + "9120": [0.64502, 1.155, 0, 0], + "9121": [0.64502, 1.155, 0, 0], + "9122": [-0.00099, 0.601, 0, 0], + "9123": [0.64502, 1.155, 0, 0], + "9124": [0.64502, 1.155, 0, 0], + "9125": [-0.00099, 0.601, 0, 0], + "9126": [0.64502, 1.155, 0, 0], + "9127": [1e-05, 0.9, 0, 0], + "9128": [0.65002, 1.15, 0, 0], + "9129": [0.90001, 0, 0, 0], + "9130": [0, 0.3, 0, 0], + "9131": [1e-05, 0.9, 0, 0], + "9132": [0.65002, 1.15, 0, 0], + "9133": [0.90001, 0, 0, 0], + "9143": [0.88502, 0.915, 0, 0], + "10216": [1.25003, 1.75, 0, 0], + "10217": [1.25003, 1.75, 0, 0], + "57344": [-0.00499, 0.605, 0, 0], + "57345": [-0.00499, 0.605, 0, 0], + "57680": [0, 0.12, 0, 0], + "57681": [0, 0.12, 0, 0], + "57682": [0, 0.12, 0, 0], + "57683": [0, 0.12, 0, 0] + }, + "Typewriter-Regular": { + "33": [0, 0.61111, 0, 0], + "34": [0, 0.61111, 0, 0], + "35": [0, 0.61111, 0, 0], + "36": [0.08333, 0.69444, 0, 0], + "37": [0.08333, 0.69444, 0, 0], + "38": [0, 0.61111, 0, 0], + "39": [0, 0.61111, 0, 0], + "40": [0.08333, 0.69444, 0, 0], + "41": [0.08333, 0.69444, 0, 0], + "42": [0, 0.52083, 0, 0], + "43": [-0.08056, 0.53055, 0, 0], + "44": [0.13889, 0.125, 0, 0], + "45": [-0.08056, 0.53055, 0, 0], + "46": [0, 0.125, 0, 0], + "47": [0.08333, 0.69444, 0, 0], + "48": [0, 0.61111, 0, 0], + "49": [0, 0.61111, 0, 0], + "50": [0, 0.61111, 0, 0], + "51": [0, 0.61111, 0, 0], + "52": [0, 0.61111, 0, 0], + "53": [0, 0.61111, 0, 0], + "54": [0, 0.61111, 0, 0], + "55": [0, 0.61111, 0, 0], + "56": [0, 0.61111, 0, 0], + "57": [0, 0.61111, 0, 0], + "58": [0, 0.43056, 0, 0], + "59": [0.13889, 0.43056, 0, 0], + "60": [-0.05556, 0.55556, 0, 0], + "61": [-0.19549, 0.41562, 0, 0], + "62": [-0.05556, 0.55556, 0, 0], + "63": [0, 0.61111, 0, 0], + "64": [0, 0.61111, 0, 0], + "65": [0, 0.61111, 0, 0], + "66": [0, 0.61111, 0, 0], + "67": [0, 0.61111, 0, 0], + "68": [0, 0.61111, 0, 0], + "69": [0, 0.61111, 0, 0], + "70": [0, 0.61111, 0, 0], + "71": [0, 0.61111, 0, 0], + "72": [0, 0.61111, 0, 0], + "73": [0, 0.61111, 0, 0], + "74": [0, 0.61111, 0, 0], + "75": [0, 0.61111, 0, 0], + "76": [0, 0.61111, 0, 0], + "77": [0, 0.61111, 0, 0], + "78": [0, 0.61111, 0, 0], + "79": [0, 0.61111, 0, 0], + "80": [0, 0.61111, 0, 0], + "81": [0.13889, 0.61111, 0, 0], + "82": [0, 0.61111, 0, 0], + "83": [0, 0.61111, 0, 0], + "84": [0, 0.61111, 0, 0], + "85": [0, 0.61111, 0, 0], + "86": [0, 0.61111, 0, 0], + "87": [0, 0.61111, 0, 0], + "88": [0, 0.61111, 0, 0], + "89": [0, 0.61111, 0, 0], + "90": [0, 0.61111, 0, 0], + "91": [0.08333, 0.69444, 0, 0], + "92": [0.08333, 0.69444, 0, 0], + "93": [0.08333, 0.69444, 0, 0], + "94": [0, 0.61111, 0, 0], + "95": [0.09514, 0, 0, 0], + "96": [0, 0.61111, 0, 0], + "97": [0, 0.43056, 0, 0], + "98": [0, 0.61111, 0, 0], + "99": [0, 0.43056, 0, 0], + "100": [0, 0.61111, 0, 0], + "101": [0, 0.43056, 0, 0], + "102": [0, 0.61111, 0, 0], + "103": [0.22222, 0.43056, 0, 0], + "104": [0, 0.61111, 0, 0], + "105": [0, 0.61111, 0, 0], + "106": [0.22222, 0.61111, 0, 0], + "107": [0, 0.61111, 0, 0], + "108": [0, 0.61111, 0, 0], + "109": [0, 0.43056, 0, 0], + "110": [0, 0.43056, 0, 0], + "111": [0, 0.43056, 0, 0], + "112": [0.22222, 0.43056, 0, 0], + "113": [0.22222, 0.43056, 0, 0], + "114": [0, 0.43056, 0, 0], + "115": [0, 0.43056, 0, 0], + "116": [0, 0.55358, 0, 0], + "117": [0, 0.43056, 0, 0], + "118": [0, 0.43056, 0, 0], + "119": [0, 0.43056, 0, 0], + "120": [0, 0.43056, 0, 0], + "121": [0.22222, 0.43056, 0, 0], + "122": [0, 0.43056, 0, 0], + "123": [0.08333, 0.69444, 0, 0], + "124": [0.08333, 0.69444, 0, 0], + "125": [0.08333, 0.69444, 0, 0], + "126": [0, 0.61111, 0, 0], + "127": [0, 0.61111, 0, 0], + "305": [0, 0.43056, 0, 0], + "567": [0.22222, 0.43056, 0, 0], + "768": [0, 0.61111, 0, 0], + "769": [0, 0.61111, 0, 0], + "770": [0, 0.61111, 0, 0], + "771": [0, 0.61111, 0, 0], + "772": [0, 0.56555, 0, 0], + "774": [0, 0.61111, 0, 0], + "776": [0, 0.61111, 0, 0], + "778": [0, 0.61111, 0, 0], + "780": [0, 0.56597, 0, 0], + "915": [0, 0.61111, 0, 0], + "916": [0, 0.61111, 0, 0], + "920": [0, 0.61111, 0, 0], + "923": [0, 0.61111, 0, 0], + "926": [0, 0.61111, 0, 0], + "928": [0, 0.61111, 0, 0], + "931": [0, 0.61111, 0, 0], + "933": [0, 0.61111, 0, 0], + "934": [0, 0.61111, 0, 0], + "936": [0, 0.61111, 0, 0], + "937": [0, 0.61111, 0, 0], + "2018": [0, 0.61111, 0, 0], + "2019": [0, 0.61111, 0, 0], + "8242": [0, 0.61111, 0, 0] + } +}; + +},{}],19:[function(require,module,exports){ +var utils = require("./utils"); +var ParseError = require("./ParseError"); +var parseData = require("./parseData"); +var ParseNode = parseData.ParseNode; + +/* This file contains a list of functions that we parse, identified by + * the calls to defineFunction. + * + * The first argument to defineFunction is a single name or a list of names. + * All functions named in such a list will share a single implementation. + * + * Each declared function can have associated properties, which + * include the following: + * + * - numArgs: The number of arguments the function takes. + * If this is the only property, it can be passed as a number + * instead of an element of a properties object. + * - argTypes: (optional) An array corresponding to each argument of the + * function, giving the type of argument that should be parsed. Its + * length should be equal to `numArgs + numOptionalArgs`. Valid + * types: + * - "size": A size-like thing, such as "1em" or "5ex" + * - "color": An html color, like "#abc" or "blue" + * - "original": The same type as the environment that the + * function being parsed is in (e.g. used for the + * bodies of functions like \color where the first + * argument is special and the second argument is + * parsed normally) + * Other possible types (probably shouldn't be used) + * - "text": Text-like (e.g. \text) + * - "math": Normal math + * If undefined, this will be treated as an appropriate length + * array of "original" strings + * - greediness: (optional) The greediness of the function to use ungrouped + * arguments. + * + * E.g. if you have an expression + * \sqrt \frac 1 2 + * since \frac has greediness=2 vs \sqrt's greediness=1, \frac + * will use the two arguments '1' and '2' as its two arguments, + * then that whole function will be used as the argument to + * \sqrt. On the other hand, the expressions + * \frac \frac 1 2 3 + * and + * \frac \sqrt 1 2 + * will fail because \frac and \frac have equal greediness + * and \sqrt has a lower greediness than \frac respectively. To + * make these parse, we would have to change them to: + * \frac {\frac 1 2} 3 + * and + * \frac {\sqrt 1} 2 + * + * The default value is `1` + * - allowedInText: (optional) Whether or not the function is allowed inside + * text mode (default false) + * - numOptionalArgs: (optional) The number of optional arguments the function + * should parse. If the optional arguments aren't found, + * `null` will be passed to the handler in their place. + * (default 0) + * - infix: (optional) Must be true if the function is an infix operator. + * + * The last argument is that implementation, the handler for the function(s). + * It is called to handle these functions and their arguments. + * It receives two arguments: + * - context contains information and references provided by the parser + * - args is an array of arguments obtained from TeX input + * The context contains the following properties: + * - funcName: the text (i.e. name) of the function, including \ + * - parser: the parser object + * - lexer: the lexer object + * - positions: the positions in the overall string of the function + * and the arguments. + * The latter three should only be used to produce error messages. + * + * The function should return an object with the following keys: + * - type: The type of element that this is. This is then used in + * buildHTML/buildMathML to determine which function + * should be called to build this node into a DOM node + * Any other data can be added to the object, which will be passed + * in to the function in buildHTML/buildMathML as `group.value`. + */ + +function defineFunction(names, props, handler) { + if (typeof names === "string") { + names = [names]; + } + if (typeof props === "number") { + props = { numArgs: props }; + } + // Set default values of functions + var data = { + numArgs: props.numArgs, + argTypes: props.argTypes, + greediness: (props.greediness === undefined) ? 1 : props.greediness, + allowedInText: !!props.allowedInText, + numOptionalArgs: props.numOptionalArgs || 0, + infix: !!props.infix, + handler: handler + }; + for (var i = 0; i < names.length; ++i) { + module.exports[names[i]] = data; + } +} + +// Since the corresponding buildHTML/buildMathML function expects a +// list of elements, we normalize for different kinds of arguments +var ordargument = function(arg) { + if (arg.type === "ordgroup") { + return arg.value; + } else { + return [arg]; + } +}; + +// A normal square root +defineFunction("\\sqrt", { + numArgs: 1, + numOptionalArgs: 1 +}, function(context, args) { + var index = args[0]; + var body = args[1]; + return { + type: "sqrt", + body: body, + index: index + }; +}); + +// Non-mathy text, possibly in a font +var textFunctionStyles = { + "\\text": undefined, "\\textrm": "mathrm", "\\textsf": "mathsf", + "\\texttt": "mathtt", "\\textnormal": "mathrm", "\\textbf": "mathbf", + "\\textit": "textit" +}; + +defineFunction([ + "\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal", + "\\textbf", "\\textit" +], { + numArgs: 1, + argTypes: ["text"], + greediness: 2, + allowedInText: true +}, function(context, args) { + var body = args[0]; + return { + type: "text", + body: ordargument(body), + style: textFunctionStyles[context.funcName] + }; +}); + +// A two-argument custom color +defineFunction("\\color", { + numArgs: 2, + allowedInText: true, + greediness: 3, + argTypes: ["color", "original"] +}, function(context, args) { + var color = args[0]; + var body = args[1]; + return { + type: "color", + color: color.value, + value: ordargument(body) + }; +}); + +// An overline +defineFunction("\\overline", { + numArgs: 1 +}, function(context, args) { + var body = args[0]; + return { + type: "overline", + body: body + }; +}); + +// An underline +defineFunction("\\underline", { + numArgs: 1 +}, function(context, args) { + var body = args[0]; + return { + type: "underline", + body: body + }; +}); + +// A box of the width and height +defineFunction("\\rule", { + numArgs: 2, + numOptionalArgs: 1, + argTypes: ["size", "size", "size"] +}, function(context, args) { + var shift = args[0]; + var width = args[1]; + var height = args[2]; + return { + type: "rule", + shift: shift && shift.value, + width: width.value, + height: height.value + }; +}); + +// TODO: In TeX, \mkern only accepts mu-units, and \kern does not accept +// mu-units. In current KaTeX we relax this; both commands accept any unit. +defineFunction(["\\kern", "\\mkern"], { + numArgs: 1, + argTypes: ["size"] +}, function(context, args) { + return { + type: "kern", + dimension: args[0].value + }; +}); + +// A KaTeX logo +defineFunction("\\KaTeX", { + numArgs: 0 +}, function(context) { + return { + type: "katex" + }; +}); + +defineFunction("\\phantom", { + numArgs: 1 +}, function(context, args) { + var body = args[0]; + return { + type: "phantom", + value: ordargument(body) + }; +}); + +// Math class commands except \mathop +defineFunction([ + "\\mathord", "\\mathbin", "\\mathrel", "\\mathopen", + "\\mathclose", "\\mathpunct", "\\mathinner" +], { + numArgs: 1 +}, function(context, args) { + var body = args[0]; + return { + type: "mclass", + mclass: "m" + context.funcName.substr(5), + value: ordargument(body) + }; +}); + +// Build a relation by placing one symbol on top of another +defineFunction("\\stackrel", { + numArgs: 2 +}, function(context, args) { + var top = args[0]; + var bottom = args[1]; + + var bottomop = new ParseNode("op", { + type: "op", + limits: true, + alwaysHandleSupSub: true, + symbol: false, + value: ordargument(bottom) + }, bottom.mode); + + var supsub = new ParseNode("supsub", { + base: bottomop, + sup: top, + sub: null + }, top.mode); + + return { + type: "mclass", + mclass: "mrel", + value: [supsub] + }; +}); + +// \mod-type functions +defineFunction("\\bmod", { + numArgs: 0 +}, function(context, args) { + return { + type: "mod", + modType: "bmod", + value: null + }; +}); + +defineFunction(["\\pod", "\\pmod", "\\mod"], { + numArgs: 1 +}, function(context, args) { + var body = args[0]; + return { + type: "mod", + modType: context.funcName.substr(1), + value: ordargument(body) + }; +}); + +// Extra data needed for the delimiter handler down below +var delimiterSizes = { + "\\bigl" : {mclass: "mopen", size: 1}, + "\\Bigl" : {mclass: "mopen", size: 2}, + "\\biggl": {mclass: "mopen", size: 3}, + "\\Biggl": {mclass: "mopen", size: 4}, + "\\bigr" : {mclass: "mclose", size: 1}, + "\\Bigr" : {mclass: "mclose", size: 2}, + "\\biggr": {mclass: "mclose", size: 3}, + "\\Biggr": {mclass: "mclose", size: 4}, + "\\bigm" : {mclass: "mrel", size: 1}, + "\\Bigm" : {mclass: "mrel", size: 2}, + "\\biggm": {mclass: "mrel", size: 3}, + "\\Biggm": {mclass: "mrel", size: 4}, + "\\big" : {mclass: "mord", size: 1}, + "\\Big" : {mclass: "mord", size: 2}, + "\\bigg" : {mclass: "mord", size: 3}, + "\\Bigg" : {mclass: "mord", size: 4} +}; + +var delimiters = [ + "(", ")", "[", "\\lbrack", "]", "\\rbrack", + "\\{", "\\lbrace", "\\}", "\\rbrace", + "\\lfloor", "\\rfloor", "\\lceil", "\\rceil", + "<", ">", "\\langle", "\\rangle", "\\lt", "\\gt", + "\\lvert", "\\rvert", "\\lVert", "\\rVert", + "\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache", + "/", "\\backslash", + "|", "\\vert", "\\|", "\\Vert", + "\\uparrow", "\\Uparrow", + "\\downarrow", "\\Downarrow", + "\\updownarrow", "\\Updownarrow", + "." +]; + +var fontAliases = { + "\\Bbb": "\\mathbb", + "\\bold": "\\mathbf", + "\\frak": "\\mathfrak" +}; + +// Single-argument color functions +defineFunction([ + "\\blue", "\\orange", "\\pink", "\\red", + "\\green", "\\gray", "\\purple", + "\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE", + "\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE", + "\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE", + "\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE", + "\\redA", "\\redB", "\\redC", "\\redD", "\\redE", + "\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE", + "\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE", + "\\mintA", "\\mintB", "\\mintC", + "\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE", + "\\grayF", "\\grayG", "\\grayH", "\\grayI", + "\\kaBlue", "\\kaGreen" +], { + numArgs: 1, + allowedInText: true, + greediness: 3 +}, function(context, args) { + var body = args[0]; + return { + type: "color", + color: "katex-" + context.funcName.slice(1), + value: ordargument(body) + }; +}); + +// There are 2 flags for operators; whether they produce limits in +// displaystyle, and whether they are symbols and should grow in +// displaystyle. These four groups cover the four possible choices. + +// No limits, not symbols +defineFunction([ + "\\arcsin", "\\arccos", "\\arctan", "\\arg", "\\cos", "\\cosh", + "\\cot", "\\coth", "\\csc", "\\deg", "\\dim", "\\exp", "\\hom", + "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh", + "\\tan", "\\tanh" +], { + numArgs: 0 +}, function(context) { + return { + type: "op", + limits: false, + symbol: false, + body: context.funcName + }; +}); + +// Limits, not symbols +defineFunction([ + "\\det", "\\gcd", "\\inf", "\\lim", "\\liminf", "\\limsup", "\\max", + "\\min", "\\Pr", "\\sup" +], { + numArgs: 0 +}, function(context) { + return { + type: "op", + limits: true, + symbol: false, + body: context.funcName + }; +}); + +// No limits, symbols +defineFunction([ + "\\int", "\\iint", "\\iiint", "\\oint" +], { + numArgs: 0 +}, function(context) { + return { + type: "op", + limits: false, + symbol: true, + body: context.funcName + }; +}); + +// Limits, symbols +defineFunction([ + "\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap", + "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes", + "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint" +], { + numArgs: 0 +}, function(context) { + return { + type: "op", + limits: true, + symbol: true, + body: context.funcName + }; +}); + +// \mathop class command +defineFunction("\\mathop", { + numArgs: 1 +}, function(context, args) { + var body = args[0]; + return { + type: "op", + limits: false, + symbol: false, + value: ordargument(body) + }; +}); + +// Fractions +defineFunction([ + "\\dfrac", "\\frac", "\\tfrac", + "\\dbinom", "\\binom", "\\tbinom", + "\\\\atopfrac" // can’t be entered directly +], { + numArgs: 2, + greediness: 2 +}, function(context, args) { + var numer = args[0]; + var denom = args[1]; + var hasBarLine; + var leftDelim = null; + var rightDelim = null; + var size = "auto"; + + switch (context.funcName) { + case "\\dfrac": + case "\\frac": + case "\\tfrac": + hasBarLine = true; + break; + case "\\\\atopfrac": + hasBarLine = false; + break; + case "\\dbinom": + case "\\binom": + case "\\tbinom": + hasBarLine = false; + leftDelim = "("; + rightDelim = ")"; + break; + default: + throw new Error("Unrecognized genfrac command"); + } + + switch (context.funcName) { + case "\\dfrac": + case "\\dbinom": + size = "display"; + break; + case "\\tfrac": + case "\\tbinom": + size = "text"; + break; + } + + return { + type: "genfrac", + numer: numer, + denom: denom, + hasBarLine: hasBarLine, + leftDelim: leftDelim, + rightDelim: rightDelim, + size: size + }; +}); + +// Left and right overlap functions +defineFunction(["\\llap", "\\rlap"], { + numArgs: 1, + allowedInText: true +}, function(context, args) { + var body = args[0]; + return { + type: context.funcName.slice(1), + body: body + }; +}); + +// Delimiter functions +var checkDelimiter = function(delim, context) { + if (utils.contains(delimiters, delim.value)) { + return delim; + } else { + throw new ParseError( + "Invalid delimiter: '" + delim.value + "' after '" + + context.funcName + "'", delim); + } +}; + +defineFunction([ + "\\bigl", "\\Bigl", "\\biggl", "\\Biggl", + "\\bigr", "\\Bigr", "\\biggr", "\\Biggr", + "\\bigm", "\\Bigm", "\\biggm", "\\Biggm", + "\\big", "\\Big", "\\bigg", "\\Bigg" +], { + numArgs: 1 +}, function(context, args) { + var delim = checkDelimiter(args[0], context); + + return { + type: "delimsizing", + size: delimiterSizes[context.funcName].size, + mclass: delimiterSizes[context.funcName].mclass, + value: delim.value + }; +}); + +defineFunction([ + "\\left", "\\right" +], { + numArgs: 1 +}, function(context, args) { + var delim = checkDelimiter(args[0], context); + + // \left and \right are caught somewhere in Parser.js, which is + // why this data doesn't match what is in buildHTML. + return { + type: "leftright", + value: delim.value + }; +}); + +defineFunction("\\middle", { + numArgs: 1 +}, function(context, args) { + var delim = checkDelimiter(args[0], context); + if (!context.parser.leftrightDepth) { + throw new ParseError("\\middle without preceding \\left", delim); + } + + return { + type: "middle", + value: delim.value + }; +}); + +// Sizing functions (handled in Parser.js explicitly, hence no handler) +defineFunction([ + "\\tiny", "\\scriptsize", "\\footnotesize", "\\small", + "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge" +], 0, null); + +// Style changing functions (handled in Parser.js explicitly, hence no +// handler) +defineFunction([ + "\\displaystyle", "\\textstyle", "\\scriptstyle", + "\\scriptscriptstyle" +], 0, null); + +defineFunction([ + // styles + "\\mathrm", "\\mathit", "\\mathbf", + + // families + "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf", + "\\mathtt", + + // aliases + "\\Bbb", "\\bold", "\\frak" +], { + numArgs: 1, + greediness: 2 +}, function(context, args) { + var body = args[0]; + var func = context.funcName; + if (func in fontAliases) { + func = fontAliases[func]; + } + return { + type: "font", + font: func.slice(1), + body: body + }; +}); + +// Accents +defineFunction([ + "\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve", + "\\check", "\\hat", "\\vec", "\\dot" + // We don't support expanding accents yet + // "\\widetilde", "\\widehat" +], { + numArgs: 1 +}, function(context, args) { + var base = args[0]; + return { + type: "accent", + accent: context.funcName, + base: base + }; +}); + +// Infix generalized fractions +defineFunction(["\\over", "\\choose", "\\atop"], { + numArgs: 0, + infix: true +}, function(context) { + var replaceWith; + switch (context.funcName) { + case "\\over": + replaceWith = "\\frac"; + break; + case "\\choose": + replaceWith = "\\binom"; + break; + case "\\atop": + replaceWith = "\\\\atopfrac"; + break; + default: + throw new Error("Unrecognized infix genfrac command"); + } + return { + type: "infix", + replaceWith: replaceWith, + token: context.token + }; +}); + +// Row breaks for aligned data +defineFunction(["\\\\", "\\cr"], { + numArgs: 0, + numOptionalArgs: 1, + argTypes: ["size"] +}, function(context, args) { + var size = args[0]; + return { + type: "cr", + size: size + }; +}); + +// Environment delimiters +defineFunction(["\\begin", "\\end"], { + numArgs: 1, + argTypes: ["text"] +}, function(context, args) { + var nameGroup = args[0]; + if (nameGroup.type !== "ordgroup") { + throw new ParseError("Invalid environment name", nameGroup); + } + var name = ""; + for (var i = 0; i < nameGroup.value.length; ++i) { + name += nameGroup.value[i].value; + } + return { + type: "environment", + name: name, + nameGroup: nameGroup + }; +}); + +},{"./ParseError":6,"./parseData":21,"./utils":25}],20:[function(require,module,exports){ +/** + * These objects store data about MathML nodes. This is the MathML equivalent + * of the types in domTree.js. Since MathML handles its own rendering, and + * since we're mainly using MathML to improve accessibility, we don't manage + * any of the styling state that the plain DOM nodes do. + * + * The `toNode` and `toMarkup` functions work simlarly to how they do in + * domTree.js, creating namespaced DOM nodes and HTML text markup respectively. + */ + +var utils = require("./utils"); + +/** + * This node represents a general purpose MathML node of any type. The + * constructor requires the type of node to create (for example, `"mo"` or + * `"mspace"`, corresponding to `` and `` tags). + */ +function MathNode(type, children) { + this.type = type; + this.attributes = {}; + this.children = children || []; +} + +/** + * Sets an attribute on a MathML node. MathML depends on attributes to convey a + * semantic content, so this is used heavily. + */ +MathNode.prototype.setAttribute = function(name, value) { + this.attributes[name] = value; +}; + +/** + * Converts the math node into a MathML-namespaced DOM element. + */ +MathNode.prototype.toNode = function() { + var node = document.createElementNS( + "http://www.w3.org/1998/Math/MathML", this.type); + + for (var attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + node.setAttribute(attr, this.attributes[attr]); + } + } + + for (var i = 0; i < this.children.length; i++) { + node.appendChild(this.children[i].toNode()); + } + + return node; +}; + +/** + * Converts the math node into an HTML markup string. + */ +MathNode.prototype.toMarkup = function() { + var markup = "<" + this.type; + + // Add the attributes + for (var attr in this.attributes) { + if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { + markup += " " + attr + "=\""; + markup += utils.escape(this.attributes[attr]); + markup += "\""; + } + } + + markup += ">"; + + for (var i = 0; i < this.children.length; i++) { + markup += this.children[i].toMarkup(); + } + + markup += ""; + + return markup; +}; + +/** + * This node represents a piece of text. + */ +function TextNode(text) { + this.text = text; +} + +/** + * Converts the text node into a DOM text node. + */ +TextNode.prototype.toNode = function() { + return document.createTextNode(this.text); +}; + +/** + * Converts the text node into HTML markup (which is just the text itself). + */ +TextNode.prototype.toMarkup = function() { + return utils.escape(this.text); +}; + +module.exports = { + MathNode: MathNode, + TextNode: TextNode +}; + +},{"./utils":25}],21:[function(require,module,exports){ +/** + * The resulting parse tree nodes of the parse tree. + * + * It is possible to provide position information, so that a ParseNode can + * fulfil a role similar to a Token in error reporting. + * For details on the corresponding properties see Token constructor. + * Providing such information can lead to better error reporting. + * + * @param {string} type type of node, like e.g. "ordgroup" + * @param {?object} value type-specific representation of the node + * @param {string} mode parse mode in action for this node, + * "math" or "text" + * @param {Token=} firstToken first token of the input for this node, + * will omit position information if unset + * @param {Token=} lastToken last token of the input for this node, + * will default to firstToken if unset + */ +function ParseNode(type, value, mode, firstToken, lastToken) { + this.type = type; + this.value = value; + this.mode = mode; + if (firstToken && (!lastToken || lastToken.lexer === firstToken.lexer)) { + this.lexer = firstToken.lexer; + this.start = firstToken.start; + this.end = (lastToken || firstToken).end; + } +} + +module.exports = { + ParseNode: ParseNode +}; + + +},{}],22:[function(require,module,exports){ +/** + * Provides a single function for parsing an expression using a Parser + * TODO(emily): Remove this + */ + +var Parser = require("./Parser"); + +/** + * Parses an expression using a Parser, then returns the parsed result. + */ +var parseTree = function(toParse, settings) { + if (!(typeof toParse === 'string' || toParse instanceof String)) { + throw new TypeError('KaTeX can only parse string typed expression'); + } + var parser = new Parser(toParse, settings); + + return parser.parse(); +}; + +module.exports = parseTree; + +},{"./Parser":7}],23:[function(require,module,exports){ +/** + * This file holds a list of all no-argument functions and single-character + * symbols (like 'a' or ';'). + * + * For each of the symbols, there are three properties they can have: + * - font (required): the font to be used for this symbol. Either "main" (the + normal font), or "ams" (the ams fonts). + * - group (required): the ParseNode group type the symbol should have (i.e. + "textord", "mathord", etc). + See https://github.com/Khan/KaTeX/wiki/Examining-TeX#group-types + * - replace: the character that this symbol or function should be + * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi + * character in the main font). + * + * The outermost map in the table indicates what mode the symbols should be + * accepted in (e.g. "math" or "text"). + */ + +module.exports = { + math: {}, + text: {} +}; + +function defineSymbol(mode, font, group, replace, name) { + module.exports[mode][name] = { + font: font, + group: group, + replace: replace + }; +} + +// Some abbreviations for commonly used strings. +// This helps minify the code, and also spotting typos using jshint. + +// modes: +var math = "math"; +var text = "text"; + +// fonts: +var main = "main"; +var ams = "ams"; + +// groups: +var accent = "accent"; +var bin = "bin"; +var close = "close"; +var inner = "inner"; +var mathord = "mathord"; +var op = "op"; +var open = "open"; +var punct = "punct"; +var rel = "rel"; +var spacing = "spacing"; +var textord = "textord"; + +// Now comes the symbol table + +// Relation Symbols +defineSymbol(math, main, rel, "\u2261", "\\equiv"); +defineSymbol(math, main, rel, "\u227a", "\\prec"); +defineSymbol(math, main, rel, "\u227b", "\\succ"); +defineSymbol(math, main, rel, "\u223c", "\\sim"); +defineSymbol(math, main, rel, "\u22a5", "\\perp"); +defineSymbol(math, main, rel, "\u2aaf", "\\preceq"); +defineSymbol(math, main, rel, "\u2ab0", "\\succeq"); +defineSymbol(math, main, rel, "\u2243", "\\simeq"); +defineSymbol(math, main, rel, "\u2223", "\\mid"); +defineSymbol(math, main, rel, "\u226a", "\\ll"); +defineSymbol(math, main, rel, "\u226b", "\\gg"); +defineSymbol(math, main, rel, "\u224d", "\\asymp"); +defineSymbol(math, main, rel, "\u2225", "\\parallel"); +defineSymbol(math, main, rel, "\u22c8", "\\bowtie"); +defineSymbol(math, main, rel, "\u2323", "\\smile"); +defineSymbol(math, main, rel, "\u2291", "\\sqsubseteq"); +defineSymbol(math, main, rel, "\u2292", "\\sqsupseteq"); +defineSymbol(math, main, rel, "\u2250", "\\doteq"); +defineSymbol(math, main, rel, "\u2322", "\\frown"); +defineSymbol(math, main, rel, "\u220b", "\\ni"); +defineSymbol(math, main, rel, "\u221d", "\\propto"); +defineSymbol(math, main, rel, "\u22a2", "\\vdash"); +defineSymbol(math, main, rel, "\u22a3", "\\dashv"); +defineSymbol(math, main, rel, "\u220b", "\\owns"); + +// Punctuation +defineSymbol(math, main, punct, "\u002e", "\\ldotp"); +defineSymbol(math, main, punct, "\u22c5", "\\cdotp"); + +// Misc Symbols +defineSymbol(math, main, textord, "\u0023", "\\#"); +defineSymbol(text, main, textord, "\u0023", "\\#"); +defineSymbol(math, main, textord, "\u0026", "\\&"); +defineSymbol(text, main, textord, "\u0026", "\\&"); +defineSymbol(math, main, textord, "\u2135", "\\aleph"); +defineSymbol(math, main, textord, "\u2200", "\\forall"); +defineSymbol(math, main, textord, "\u210f", "\\hbar"); +defineSymbol(math, main, textord, "\u2203", "\\exists"); +defineSymbol(math, main, textord, "\u2207", "\\nabla"); +defineSymbol(math, main, textord, "\u266d", "\\flat"); +defineSymbol(math, main, textord, "\u2113", "\\ell"); +defineSymbol(math, main, textord, "\u266e", "\\natural"); +defineSymbol(math, main, textord, "\u2663", "\\clubsuit"); +defineSymbol(math, main, textord, "\u2118", "\\wp"); +defineSymbol(math, main, textord, "\u266f", "\\sharp"); +defineSymbol(math, main, textord, "\u2662", "\\diamondsuit"); +defineSymbol(math, main, textord, "\u211c", "\\Re"); +defineSymbol(math, main, textord, "\u2661", "\\heartsuit"); +defineSymbol(math, main, textord, "\u2111", "\\Im"); +defineSymbol(math, main, textord, "\u2660", "\\spadesuit"); + +// Math and Text +defineSymbol(math, main, textord, "\u2020", "\\dag"); +defineSymbol(math, main, textord, "\u2021", "\\ddag"); + +// Large Delimiters +defineSymbol(math, main, close, "\u23b1", "\\rmoustache"); +defineSymbol(math, main, open, "\u23b0", "\\lmoustache"); +defineSymbol(math, main, close, "\u27ef", "\\rgroup"); +defineSymbol(math, main, open, "\u27ee", "\\lgroup"); + +// Binary Operators +defineSymbol(math, main, bin, "\u2213", "\\mp"); +defineSymbol(math, main, bin, "\u2296", "\\ominus"); +defineSymbol(math, main, bin, "\u228e", "\\uplus"); +defineSymbol(math, main, bin, "\u2293", "\\sqcap"); +defineSymbol(math, main, bin, "\u2217", "\\ast"); +defineSymbol(math, main, bin, "\u2294", "\\sqcup"); +defineSymbol(math, main, bin, "\u25ef", "\\bigcirc"); +defineSymbol(math, main, bin, "\u2219", "\\bullet"); +defineSymbol(math, main, bin, "\u2021", "\\ddagger"); +defineSymbol(math, main, bin, "\u2240", "\\wr"); +defineSymbol(math, main, bin, "\u2a3f", "\\amalg"); + +// Arrow Symbols +defineSymbol(math, main, rel, "\u27f5", "\\longleftarrow"); +defineSymbol(math, main, rel, "\u21d0", "\\Leftarrow"); +defineSymbol(math, main, rel, "\u27f8", "\\Longleftarrow"); +defineSymbol(math, main, rel, "\u27f6", "\\longrightarrow"); +defineSymbol(math, main, rel, "\u21d2", "\\Rightarrow"); +defineSymbol(math, main, rel, "\u27f9", "\\Longrightarrow"); +defineSymbol(math, main, rel, "\u2194", "\\leftrightarrow"); +defineSymbol(math, main, rel, "\u27f7", "\\longleftrightarrow"); +defineSymbol(math, main, rel, "\u21d4", "\\Leftrightarrow"); +defineSymbol(math, main, rel, "\u27fa", "\\Longleftrightarrow"); +defineSymbol(math, main, rel, "\u21a6", "\\mapsto"); +defineSymbol(math, main, rel, "\u27fc", "\\longmapsto"); +defineSymbol(math, main, rel, "\u2197", "\\nearrow"); +defineSymbol(math, main, rel, "\u21a9", "\\hookleftarrow"); +defineSymbol(math, main, rel, "\u21aa", "\\hookrightarrow"); +defineSymbol(math, main, rel, "\u2198", "\\searrow"); +defineSymbol(math, main, rel, "\u21bc", "\\leftharpoonup"); +defineSymbol(math, main, rel, "\u21c0", "\\rightharpoonup"); +defineSymbol(math, main, rel, "\u2199", "\\swarrow"); +defineSymbol(math, main, rel, "\u21bd", "\\leftharpoondown"); +defineSymbol(math, main, rel, "\u21c1", "\\rightharpoondown"); +defineSymbol(math, main, rel, "\u2196", "\\nwarrow"); +defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons"); + +// AMS Negated Binary Relations +defineSymbol(math, ams, rel, "\u226e", "\\nless"); +defineSymbol(math, ams, rel, "\ue010", "\\nleqslant"); +defineSymbol(math, ams, rel, "\ue011", "\\nleqq"); +defineSymbol(math, ams, rel, "\u2a87", "\\lneq"); +defineSymbol(math, ams, rel, "\u2268", "\\lneqq"); +defineSymbol(math, ams, rel, "\ue00c", "\\lvertneqq"); +defineSymbol(math, ams, rel, "\u22e6", "\\lnsim"); +defineSymbol(math, ams, rel, "\u2a89", "\\lnapprox"); +defineSymbol(math, ams, rel, "\u2280", "\\nprec"); +defineSymbol(math, ams, rel, "\u22e0", "\\npreceq"); +defineSymbol(math, ams, rel, "\u22e8", "\\precnsim"); +defineSymbol(math, ams, rel, "\u2ab9", "\\precnapprox"); +defineSymbol(math, ams, rel, "\u2241", "\\nsim"); +defineSymbol(math, ams, rel, "\ue006", "\\nshortmid"); +defineSymbol(math, ams, rel, "\u2224", "\\nmid"); +defineSymbol(math, ams, rel, "\u22ac", "\\nvdash"); +defineSymbol(math, ams, rel, "\u22ad", "\\nvDash"); +defineSymbol(math, ams, rel, "\u22ea", "\\ntriangleleft"); +defineSymbol(math, ams, rel, "\u22ec", "\\ntrianglelefteq"); +defineSymbol(math, ams, rel, "\u228a", "\\subsetneq"); +defineSymbol(math, ams, rel, "\ue01a", "\\varsubsetneq"); +defineSymbol(math, ams, rel, "\u2acb", "\\subsetneqq"); +defineSymbol(math, ams, rel, "\ue017", "\\varsubsetneqq"); +defineSymbol(math, ams, rel, "\u226f", "\\ngtr"); +defineSymbol(math, ams, rel, "\ue00f", "\\ngeqslant"); +defineSymbol(math, ams, rel, "\ue00e", "\\ngeqq"); +defineSymbol(math, ams, rel, "\u2a88", "\\gneq"); +defineSymbol(math, ams, rel, "\u2269", "\\gneqq"); +defineSymbol(math, ams, rel, "\ue00d", "\\gvertneqq"); +defineSymbol(math, ams, rel, "\u22e7", "\\gnsim"); +defineSymbol(math, ams, rel, "\u2a8a", "\\gnapprox"); +defineSymbol(math, ams, rel, "\u2281", "\\nsucc"); +defineSymbol(math, ams, rel, "\u22e1", "\\nsucceq"); +defineSymbol(math, ams, rel, "\u22e9", "\\succnsim"); +defineSymbol(math, ams, rel, "\u2aba", "\\succnapprox"); +defineSymbol(math, ams, rel, "\u2246", "\\ncong"); +defineSymbol(math, ams, rel, "\ue007", "\\nshortparallel"); +defineSymbol(math, ams, rel, "\u2226", "\\nparallel"); +defineSymbol(math, ams, rel, "\u22af", "\\nVDash"); +defineSymbol(math, ams, rel, "\u22eb", "\\ntriangleright"); +defineSymbol(math, ams, rel, "\u22ed", "\\ntrianglerighteq"); +defineSymbol(math, ams, rel, "\ue018", "\\nsupseteqq"); +defineSymbol(math, ams, rel, "\u228b", "\\supsetneq"); +defineSymbol(math, ams, rel, "\ue01b", "\\varsupsetneq"); +defineSymbol(math, ams, rel, "\u2acc", "\\supsetneqq"); +defineSymbol(math, ams, rel, "\ue019", "\\varsupsetneqq"); +defineSymbol(math, ams, rel, "\u22ae", "\\nVdash"); +defineSymbol(math, ams, rel, "\u2ab5", "\\precneqq"); +defineSymbol(math, ams, rel, "\u2ab6", "\\succneqq"); +defineSymbol(math, ams, rel, "\ue016", "\\nsubseteqq"); +defineSymbol(math, ams, bin, "\u22b4", "\\unlhd"); +defineSymbol(math, ams, bin, "\u22b5", "\\unrhd"); + +// AMS Negated Arrows +defineSymbol(math, ams, rel, "\u219a", "\\nleftarrow"); +defineSymbol(math, ams, rel, "\u219b", "\\nrightarrow"); +defineSymbol(math, ams, rel, "\u21cd", "\\nLeftarrow"); +defineSymbol(math, ams, rel, "\u21cf", "\\nRightarrow"); +defineSymbol(math, ams, rel, "\u21ae", "\\nleftrightarrow"); +defineSymbol(math, ams, rel, "\u21ce", "\\nLeftrightarrow"); + +// AMS Misc +defineSymbol(math, ams, rel, "\u25b3", "\\vartriangle"); +defineSymbol(math, ams, textord, "\u210f", "\\hslash"); +defineSymbol(math, ams, textord, "\u25bd", "\\triangledown"); +defineSymbol(math, ams, textord, "\u25ca", "\\lozenge"); +defineSymbol(math, ams, textord, "\u24c8", "\\circledS"); +defineSymbol(math, ams, textord, "\u00ae", "\\circledR"); +defineSymbol(math, ams, textord, "\u2221", "\\measuredangle"); +defineSymbol(math, ams, textord, "\u2204", "\\nexists"); +defineSymbol(math, ams, textord, "\u2127", "\\mho"); +defineSymbol(math, ams, textord, "\u2132", "\\Finv"); +defineSymbol(math, ams, textord, "\u2141", "\\Game"); +defineSymbol(math, ams, textord, "\u006b", "\\Bbbk"); +defineSymbol(math, ams, textord, "\u2035", "\\backprime"); +defineSymbol(math, ams, textord, "\u25b2", "\\blacktriangle"); +defineSymbol(math, ams, textord, "\u25bc", "\\blacktriangledown"); +defineSymbol(math, ams, textord, "\u25a0", "\\blacksquare"); +defineSymbol(math, ams, textord, "\u29eb", "\\blacklozenge"); +defineSymbol(math, ams, textord, "\u2605", "\\bigstar"); +defineSymbol(math, ams, textord, "\u2222", "\\sphericalangle"); +defineSymbol(math, ams, textord, "\u2201", "\\complement"); +defineSymbol(math, ams, textord, "\u00f0", "\\eth"); +defineSymbol(math, ams, textord, "\u2571", "\\diagup"); +defineSymbol(math, ams, textord, "\u2572", "\\diagdown"); +defineSymbol(math, ams, textord, "\u25a1", "\\square"); +defineSymbol(math, ams, textord, "\u25a1", "\\Box"); +defineSymbol(math, ams, textord, "\u25ca", "\\Diamond"); +defineSymbol(math, ams, textord, "\u00a5", "\\yen"); +defineSymbol(math, ams, textord, "\u2713", "\\checkmark"); + +// AMS Hebrew +defineSymbol(math, ams, textord, "\u2136", "\\beth"); +defineSymbol(math, ams, textord, "\u2138", "\\daleth"); +defineSymbol(math, ams, textord, "\u2137", "\\gimel"); + +// AMS Greek +defineSymbol(math, ams, textord, "\u03dd", "\\digamma"); +defineSymbol(math, ams, textord, "\u03f0", "\\varkappa"); + +// AMS Delimiters +defineSymbol(math, ams, open, "\u250c", "\\ulcorner"); +defineSymbol(math, ams, close, "\u2510", "\\urcorner"); +defineSymbol(math, ams, open, "\u2514", "\\llcorner"); +defineSymbol(math, ams, close, "\u2518", "\\lrcorner"); + +// AMS Binary Relations +defineSymbol(math, ams, rel, "\u2266", "\\leqq"); +defineSymbol(math, ams, rel, "\u2a7d", "\\leqslant"); +defineSymbol(math, ams, rel, "\u2a95", "\\eqslantless"); +defineSymbol(math, ams, rel, "\u2272", "\\lesssim"); +defineSymbol(math, ams, rel, "\u2a85", "\\lessapprox"); +defineSymbol(math, ams, rel, "\u224a", "\\approxeq"); +defineSymbol(math, ams, bin, "\u22d6", "\\lessdot"); +defineSymbol(math, ams, rel, "\u22d8", "\\lll"); +defineSymbol(math, ams, rel, "\u2276", "\\lessgtr"); +defineSymbol(math, ams, rel, "\u22da", "\\lesseqgtr"); +defineSymbol(math, ams, rel, "\u2a8b", "\\lesseqqgtr"); +defineSymbol(math, ams, rel, "\u2251", "\\doteqdot"); +defineSymbol(math, ams, rel, "\u2253", "\\risingdotseq"); +defineSymbol(math, ams, rel, "\u2252", "\\fallingdotseq"); +defineSymbol(math, ams, rel, "\u223d", "\\backsim"); +defineSymbol(math, ams, rel, "\u22cd", "\\backsimeq"); +defineSymbol(math, ams, rel, "\u2ac5", "\\subseteqq"); +defineSymbol(math, ams, rel, "\u22d0", "\\Subset"); +defineSymbol(math, ams, rel, "\u228f", "\\sqsubset"); +defineSymbol(math, ams, rel, "\u227c", "\\preccurlyeq"); +defineSymbol(math, ams, rel, "\u22de", "\\curlyeqprec"); +defineSymbol(math, ams, rel, "\u227e", "\\precsim"); +defineSymbol(math, ams, rel, "\u2ab7", "\\precapprox"); +defineSymbol(math, ams, rel, "\u22b2", "\\vartriangleleft"); +defineSymbol(math, ams, rel, "\u22b4", "\\trianglelefteq"); +defineSymbol(math, ams, rel, "\u22a8", "\\vDash"); +defineSymbol(math, ams, rel, "\u22aa", "\\Vvdash"); +defineSymbol(math, ams, rel, "\u2323", "\\smallsmile"); +defineSymbol(math, ams, rel, "\u2322", "\\smallfrown"); +defineSymbol(math, ams, rel, "\u224f", "\\bumpeq"); +defineSymbol(math, ams, rel, "\u224e", "\\Bumpeq"); +defineSymbol(math, ams, rel, "\u2267", "\\geqq"); +defineSymbol(math, ams, rel, "\u2a7e", "\\geqslant"); +defineSymbol(math, ams, rel, "\u2a96", "\\eqslantgtr"); +defineSymbol(math, ams, rel, "\u2273", "\\gtrsim"); +defineSymbol(math, ams, rel, "\u2a86", "\\gtrapprox"); +defineSymbol(math, ams, bin, "\u22d7", "\\gtrdot"); +defineSymbol(math, ams, rel, "\u22d9", "\\ggg"); +defineSymbol(math, ams, rel, "\u2277", "\\gtrless"); +defineSymbol(math, ams, rel, "\u22db", "\\gtreqless"); +defineSymbol(math, ams, rel, "\u2a8c", "\\gtreqqless"); +defineSymbol(math, ams, rel, "\u2256", "\\eqcirc"); +defineSymbol(math, ams, rel, "\u2257", "\\circeq"); +defineSymbol(math, ams, rel, "\u225c", "\\triangleq"); +defineSymbol(math, ams, rel, "\u223c", "\\thicksim"); +defineSymbol(math, ams, rel, "\u2248", "\\thickapprox"); +defineSymbol(math, ams, rel, "\u2ac6", "\\supseteqq"); +defineSymbol(math, ams, rel, "\u22d1", "\\Supset"); +defineSymbol(math, ams, rel, "\u2290", "\\sqsupset"); +defineSymbol(math, ams, rel, "\u227d", "\\succcurlyeq"); +defineSymbol(math, ams, rel, "\u22df", "\\curlyeqsucc"); +defineSymbol(math, ams, rel, "\u227f", "\\succsim"); +defineSymbol(math, ams, rel, "\u2ab8", "\\succapprox"); +defineSymbol(math, ams, rel, "\u22b3", "\\vartriangleright"); +defineSymbol(math, ams, rel, "\u22b5", "\\trianglerighteq"); +defineSymbol(math, ams, rel, "\u22a9", "\\Vdash"); +defineSymbol(math, ams, rel, "\u2223", "\\shortmid"); +defineSymbol(math, ams, rel, "\u2225", "\\shortparallel"); +defineSymbol(math, ams, rel, "\u226c", "\\between"); +defineSymbol(math, ams, rel, "\u22d4", "\\pitchfork"); +defineSymbol(math, ams, rel, "\u221d", "\\varpropto"); +defineSymbol(math, ams, rel, "\u25c0", "\\blacktriangleleft"); +defineSymbol(math, ams, rel, "\u2234", "\\therefore"); +defineSymbol(math, ams, rel, "\u220d", "\\backepsilon"); +defineSymbol(math, ams, rel, "\u25b6", "\\blacktriangleright"); +defineSymbol(math, ams, rel, "\u2235", "\\because"); +defineSymbol(math, ams, rel, "\u22d8", "\\llless"); +defineSymbol(math, ams, rel, "\u22d9", "\\gggtr"); +defineSymbol(math, ams, bin, "\u22b2", "\\lhd"); +defineSymbol(math, ams, bin, "\u22b3", "\\rhd"); +defineSymbol(math, ams, rel, "\u2242", "\\eqsim"); +defineSymbol(math, main, rel, "\u22c8", "\\Join"); +defineSymbol(math, ams, rel, "\u2251", "\\Doteq"); + +// AMS Binary Operators +defineSymbol(math, ams, bin, "\u2214", "\\dotplus"); +defineSymbol(math, ams, bin, "\u2216", "\\smallsetminus"); +defineSymbol(math, ams, bin, "\u22d2", "\\Cap"); +defineSymbol(math, ams, bin, "\u22d3", "\\Cup"); +defineSymbol(math, ams, bin, "\u2a5e", "\\doublebarwedge"); +defineSymbol(math, ams, bin, "\u229f", "\\boxminus"); +defineSymbol(math, ams, bin, "\u229e", "\\boxplus"); +defineSymbol(math, ams, bin, "\u22c7", "\\divideontimes"); +defineSymbol(math, ams, bin, "\u22c9", "\\ltimes"); +defineSymbol(math, ams, bin, "\u22ca", "\\rtimes"); +defineSymbol(math, ams, bin, "\u22cb", "\\leftthreetimes"); +defineSymbol(math, ams, bin, "\u22cc", "\\rightthreetimes"); +defineSymbol(math, ams, bin, "\u22cf", "\\curlywedge"); +defineSymbol(math, ams, bin, "\u22ce", "\\curlyvee"); +defineSymbol(math, ams, bin, "\u229d", "\\circleddash"); +defineSymbol(math, ams, bin, "\u229b", "\\circledast"); +defineSymbol(math, ams, bin, "\u22c5", "\\centerdot"); +defineSymbol(math, ams, bin, "\u22ba", "\\intercal"); +defineSymbol(math, ams, bin, "\u22d2", "\\doublecap"); +defineSymbol(math, ams, bin, "\u22d3", "\\doublecup"); +defineSymbol(math, ams, bin, "\u22a0", "\\boxtimes"); + +// AMS Arrows +defineSymbol(math, ams, rel, "\u21e2", "\\dashrightarrow"); +defineSymbol(math, ams, rel, "\u21e0", "\\dashleftarrow"); +defineSymbol(math, ams, rel, "\u21c7", "\\leftleftarrows"); +defineSymbol(math, ams, rel, "\u21c6", "\\leftrightarrows"); +defineSymbol(math, ams, rel, "\u21da", "\\Lleftarrow"); +defineSymbol(math, ams, rel, "\u219e", "\\twoheadleftarrow"); +defineSymbol(math, ams, rel, "\u21a2", "\\leftarrowtail"); +defineSymbol(math, ams, rel, "\u21ab", "\\looparrowleft"); +defineSymbol(math, ams, rel, "\u21cb", "\\leftrightharpoons"); +defineSymbol(math, ams, rel, "\u21b6", "\\curvearrowleft"); +defineSymbol(math, ams, rel, "\u21ba", "\\circlearrowleft"); +defineSymbol(math, ams, rel, "\u21b0", "\\Lsh"); +defineSymbol(math, ams, rel, "\u21c8", "\\upuparrows"); +defineSymbol(math, ams, rel, "\u21bf", "\\upharpoonleft"); +defineSymbol(math, ams, rel, "\u21c3", "\\downharpoonleft"); +defineSymbol(math, ams, rel, "\u22b8", "\\multimap"); +defineSymbol(math, ams, rel, "\u21ad", "\\leftrightsquigarrow"); +defineSymbol(math, ams, rel, "\u21c9", "\\rightrightarrows"); +defineSymbol(math, ams, rel, "\u21c4", "\\rightleftarrows"); +defineSymbol(math, ams, rel, "\u21a0", "\\twoheadrightarrow"); +defineSymbol(math, ams, rel, "\u21a3", "\\rightarrowtail"); +defineSymbol(math, ams, rel, "\u21ac", "\\looparrowright"); +defineSymbol(math, ams, rel, "\u21b7", "\\curvearrowright"); +defineSymbol(math, ams, rel, "\u21bb", "\\circlearrowright"); +defineSymbol(math, ams, rel, "\u21b1", "\\Rsh"); +defineSymbol(math, ams, rel, "\u21ca", "\\downdownarrows"); +defineSymbol(math, ams, rel, "\u21be", "\\upharpoonright"); +defineSymbol(math, ams, rel, "\u21c2", "\\downharpoonright"); +defineSymbol(math, ams, rel, "\u21dd", "\\rightsquigarrow"); +defineSymbol(math, ams, rel, "\u21dd", "\\leadsto"); +defineSymbol(math, ams, rel, "\u21db", "\\Rrightarrow"); +defineSymbol(math, ams, rel, "\u21be", "\\restriction"); + +defineSymbol(math, main, textord, "\u2018", "`"); +defineSymbol(math, main, textord, "$", "\\$"); +defineSymbol(text, main, textord, "$", "\\$"); +defineSymbol(math, main, textord, "%", "\\%"); +defineSymbol(text, main, textord, "%", "\\%"); +defineSymbol(math, main, textord, "_", "\\_"); +defineSymbol(text, main, textord, "_", "\\_"); +defineSymbol(math, main, textord, "\u2220", "\\angle"); +defineSymbol(math, main, textord, "\u221e", "\\infty"); +defineSymbol(math, main, textord, "\u2032", "\\prime"); +defineSymbol(math, main, textord, "\u25b3", "\\triangle"); +defineSymbol(math, main, textord, "\u0393", "\\Gamma"); +defineSymbol(math, main, textord, "\u0394", "\\Delta"); +defineSymbol(math, main, textord, "\u0398", "\\Theta"); +defineSymbol(math, main, textord, "\u039b", "\\Lambda"); +defineSymbol(math, main, textord, "\u039e", "\\Xi"); +defineSymbol(math, main, textord, "\u03a0", "\\Pi"); +defineSymbol(math, main, textord, "\u03a3", "\\Sigma"); +defineSymbol(math, main, textord, "\u03a5", "\\Upsilon"); +defineSymbol(math, main, textord, "\u03a6", "\\Phi"); +defineSymbol(math, main, textord, "\u03a8", "\\Psi"); +defineSymbol(math, main, textord, "\u03a9", "\\Omega"); +defineSymbol(math, main, textord, "\u00ac", "\\neg"); +defineSymbol(math, main, textord, "\u00ac", "\\lnot"); +defineSymbol(math, main, textord, "\u22a4", "\\top"); +defineSymbol(math, main, textord, "\u22a5", "\\bot"); +defineSymbol(math, main, textord, "\u2205", "\\emptyset"); +defineSymbol(math, ams, textord, "\u2205", "\\varnothing"); +defineSymbol(math, main, mathord, "\u03b1", "\\alpha"); +defineSymbol(math, main, mathord, "\u03b2", "\\beta"); +defineSymbol(math, main, mathord, "\u03b3", "\\gamma"); +defineSymbol(math, main, mathord, "\u03b4", "\\delta"); +defineSymbol(math, main, mathord, "\u03f5", "\\epsilon"); +defineSymbol(math, main, mathord, "\u03b6", "\\zeta"); +defineSymbol(math, main, mathord, "\u03b7", "\\eta"); +defineSymbol(math, main, mathord, "\u03b8", "\\theta"); +defineSymbol(math, main, mathord, "\u03b9", "\\iota"); +defineSymbol(math, main, mathord, "\u03ba", "\\kappa"); +defineSymbol(math, main, mathord, "\u03bb", "\\lambda"); +defineSymbol(math, main, mathord, "\u03bc", "\\mu"); +defineSymbol(math, main, mathord, "\u03bd", "\\nu"); +defineSymbol(math, main, mathord, "\u03be", "\\xi"); +defineSymbol(math, main, mathord, "o", "\\omicron"); +defineSymbol(math, main, mathord, "\u03c0", "\\pi"); +defineSymbol(math, main, mathord, "\u03c1", "\\rho"); +defineSymbol(math, main, mathord, "\u03c3", "\\sigma"); +defineSymbol(math, main, mathord, "\u03c4", "\\tau"); +defineSymbol(math, main, mathord, "\u03c5", "\\upsilon"); +defineSymbol(math, main, mathord, "\u03d5", "\\phi"); +defineSymbol(math, main, mathord, "\u03c7", "\\chi"); +defineSymbol(math, main, mathord, "\u03c8", "\\psi"); +defineSymbol(math, main, mathord, "\u03c9", "\\omega"); +defineSymbol(math, main, mathord, "\u03b5", "\\varepsilon"); +defineSymbol(math, main, mathord, "\u03d1", "\\vartheta"); +defineSymbol(math, main, mathord, "\u03d6", "\\varpi"); +defineSymbol(math, main, mathord, "\u03f1", "\\varrho"); +defineSymbol(math, main, mathord, "\u03c2", "\\varsigma"); +defineSymbol(math, main, mathord, "\u03c6", "\\varphi"); +defineSymbol(math, main, bin, "\u2217", "*"); +defineSymbol(math, main, bin, "+", "+"); +defineSymbol(math, main, bin, "\u2212", "-"); +defineSymbol(math, main, bin, "\u22c5", "\\cdot"); +defineSymbol(math, main, bin, "\u2218", "\\circ"); +defineSymbol(math, main, bin, "\u00f7", "\\div"); +defineSymbol(math, main, bin, "\u00b1", "\\pm"); +defineSymbol(math, main, bin, "\u00d7", "\\times"); +defineSymbol(math, main, bin, "\u2229", "\\cap"); +defineSymbol(math, main, bin, "\u222a", "\\cup"); +defineSymbol(math, main, bin, "\u2216", "\\setminus"); +defineSymbol(math, main, bin, "\u2227", "\\land"); +defineSymbol(math, main, bin, "\u2228", "\\lor"); +defineSymbol(math, main, bin, "\u2227", "\\wedge"); +defineSymbol(math, main, bin, "\u2228", "\\vee"); +defineSymbol(math, main, textord, "\u221a", "\\surd"); +defineSymbol(math, main, open, "(", "("); +defineSymbol(math, main, open, "[", "["); +defineSymbol(math, main, open, "\u27e8", "\\langle"); +defineSymbol(math, main, open, "\u2223", "\\lvert"); +defineSymbol(math, main, open, "\u2225", "\\lVert"); +defineSymbol(math, main, close, ")", ")"); +defineSymbol(math, main, close, "]", "]"); +defineSymbol(math, main, close, "?", "?"); +defineSymbol(math, main, close, "!", "!"); +defineSymbol(math, main, close, "\u27e9", "\\rangle"); +defineSymbol(math, main, close, "\u2223", "\\rvert"); +defineSymbol(math, main, close, "\u2225", "\\rVert"); +defineSymbol(math, main, rel, "=", "="); +defineSymbol(math, main, rel, "<", "<"); +defineSymbol(math, main, rel, ">", ">"); +defineSymbol(math, main, rel, ":", ":"); +defineSymbol(math, main, rel, "\u2248", "\\approx"); +defineSymbol(math, main, rel, "\u2245", "\\cong"); +defineSymbol(math, main, rel, "\u2265", "\\ge"); +defineSymbol(math, main, rel, "\u2265", "\\geq"); +defineSymbol(math, main, rel, "\u2190", "\\gets"); +defineSymbol(math, main, rel, ">", "\\gt"); +defineSymbol(math, main, rel, "\u2208", "\\in"); +defineSymbol(math, main, rel, "\u2209", "\\notin"); +defineSymbol(math, main, rel, "\u2282", "\\subset"); +defineSymbol(math, main, rel, "\u2283", "\\supset"); +defineSymbol(math, main, rel, "\u2286", "\\subseteq"); +defineSymbol(math, main, rel, "\u2287", "\\supseteq"); +defineSymbol(math, ams, rel, "\u2288", "\\nsubseteq"); +defineSymbol(math, ams, rel, "\u2289", "\\nsupseteq"); +defineSymbol(math, main, rel, "\u22a8", "\\models"); +defineSymbol(math, main, rel, "\u2190", "\\leftarrow"); +defineSymbol(math, main, rel, "\u2264", "\\le"); +defineSymbol(math, main, rel, "\u2264", "\\leq"); +defineSymbol(math, main, rel, "<", "\\lt"); +defineSymbol(math, main, rel, "\u2260", "\\ne"); +defineSymbol(math, main, rel, "\u2260", "\\neq"); +defineSymbol(math, main, rel, "\u2192", "\\rightarrow"); +defineSymbol(math, main, rel, "\u2192", "\\to"); +defineSymbol(math, ams, rel, "\u2271", "\\ngeq"); +defineSymbol(math, ams, rel, "\u2270", "\\nleq"); +defineSymbol(math, main, spacing, null, "\\!"); +defineSymbol(math, main, spacing, "\u00a0", "\\ "); +defineSymbol(math, main, spacing, "\u00a0", "~"); +defineSymbol(math, main, spacing, null, "\\,"); +defineSymbol(math, main, spacing, null, "\\:"); +defineSymbol(math, main, spacing, null, "\\;"); +defineSymbol(math, main, spacing, null, "\\enspace"); +defineSymbol(math, main, spacing, null, "\\qquad"); +defineSymbol(math, main, spacing, null, "\\quad"); +defineSymbol(math, main, spacing, "\u00a0", "\\space"); +defineSymbol(math, main, punct, ",", ","); +defineSymbol(math, main, punct, ";", ";"); +defineSymbol(math, main, punct, ":", "\\colon"); +defineSymbol(math, ams, bin, "\u22bc", "\\barwedge"); +defineSymbol(math, ams, bin, "\u22bb", "\\veebar"); +defineSymbol(math, main, bin, "\u2299", "\\odot"); +defineSymbol(math, main, bin, "\u2295", "\\oplus"); +defineSymbol(math, main, bin, "\u2297", "\\otimes"); +defineSymbol(math, main, textord, "\u2202", "\\partial"); +defineSymbol(math, main, bin, "\u2298", "\\oslash"); +defineSymbol(math, ams, bin, "\u229a", "\\circledcirc"); +defineSymbol(math, ams, bin, "\u22a1", "\\boxdot"); +defineSymbol(math, main, bin, "\u25b3", "\\bigtriangleup"); +defineSymbol(math, main, bin, "\u25bd", "\\bigtriangledown"); +defineSymbol(math, main, bin, "\u2020", "\\dagger"); +defineSymbol(math, main, bin, "\u22c4", "\\diamond"); +defineSymbol(math, main, bin, "\u22c6", "\\star"); +defineSymbol(math, main, bin, "\u25c3", "\\triangleleft"); +defineSymbol(math, main, bin, "\u25b9", "\\triangleright"); +defineSymbol(math, main, open, "{", "\\{"); +defineSymbol(text, main, textord, "{", "\\{"); +defineSymbol(math, main, close, "}", "\\}"); +defineSymbol(text, main, textord, "}", "\\}"); +defineSymbol(math, main, open, "{", "\\lbrace"); +defineSymbol(math, main, close, "}", "\\rbrace"); +defineSymbol(math, main, open, "[", "\\lbrack"); +defineSymbol(math, main, close, "]", "\\rbrack"); +defineSymbol(math, main, open, "\u230a", "\\lfloor"); +defineSymbol(math, main, close, "\u230b", "\\rfloor"); +defineSymbol(math, main, open, "\u2308", "\\lceil"); +defineSymbol(math, main, close, "\u2309", "\\rceil"); +defineSymbol(math, main, textord, "\\", "\\backslash"); +defineSymbol(math, main, textord, "\u2223", "|"); +defineSymbol(math, main, textord, "\u2223", "\\vert"); +defineSymbol(math, main, textord, "\u2225", "\\|"); +defineSymbol(math, main, textord, "\u2225", "\\Vert"); +defineSymbol(math, main, rel, "\u2191", "\\uparrow"); +defineSymbol(math, main, rel, "\u21d1", "\\Uparrow"); +defineSymbol(math, main, rel, "\u2193", "\\downarrow"); +defineSymbol(math, main, rel, "\u21d3", "\\Downarrow"); +defineSymbol(math, main, rel, "\u2195", "\\updownarrow"); +defineSymbol(math, main, rel, "\u21d5", "\\Updownarrow"); +defineSymbol(math, math, op, "\u2210", "\\coprod"); +defineSymbol(math, math, op, "\u22c1", "\\bigvee"); +defineSymbol(math, math, op, "\u22c0", "\\bigwedge"); +defineSymbol(math, math, op, "\u2a04", "\\biguplus"); +defineSymbol(math, math, op, "\u22c2", "\\bigcap"); +defineSymbol(math, math, op, "\u22c3", "\\bigcup"); +defineSymbol(math, math, op, "\u222b", "\\int"); +defineSymbol(math, math, op, "\u222b", "\\intop"); +defineSymbol(math, math, op, "\u222c", "\\iint"); +defineSymbol(math, math, op, "\u222d", "\\iiint"); +defineSymbol(math, math, op, "\u220f", "\\prod"); +defineSymbol(math, math, op, "\u2211", "\\sum"); +defineSymbol(math, math, op, "\u2a02", "\\bigotimes"); +defineSymbol(math, math, op, "\u2a01", "\\bigoplus"); +defineSymbol(math, math, op, "\u2a00", "\\bigodot"); +defineSymbol(math, math, op, "\u222e", "\\oint"); +defineSymbol(math, math, op, "\u2a06", "\\bigsqcup"); +defineSymbol(math, math, op, "\u222b", "\\smallint"); +defineSymbol(text, main, inner, "\u2026", "\\textellipsis"); +defineSymbol(math, main, inner, "\u2026", "\\mathellipsis"); +defineSymbol(text, main, inner, "\u2026", "\\ldots"); +defineSymbol(math, main, inner, "\u2026", "\\ldots"); +defineSymbol(math, main, inner, "\u22ef", "\\cdots"); +defineSymbol(math, main, inner, "\u22f1", "\\ddots"); +defineSymbol(math, main, textord, "\u22ee", "\\vdots"); +defineSymbol(math, main, accent, "\u00b4", "\\acute"); +defineSymbol(math, main, accent, "\u0060", "\\grave"); +defineSymbol(math, main, accent, "\u00a8", "\\ddot"); +defineSymbol(math, main, accent, "\u007e", "\\tilde"); +defineSymbol(math, main, accent, "\u00af", "\\bar"); +defineSymbol(math, main, accent, "\u02d8", "\\breve"); +defineSymbol(math, main, accent, "\u02c7", "\\check"); +defineSymbol(math, main, accent, "\u005e", "\\hat"); +defineSymbol(math, main, accent, "\u20d7", "\\vec"); +defineSymbol(math, main, accent, "\u02d9", "\\dot"); +defineSymbol(math, main, mathord, "\u0131", "\\imath"); +defineSymbol(math, main, mathord, "\u0237", "\\jmath"); + +defineSymbol(text, main, textord, "\u2013", "--"); +defineSymbol(text, main, textord, "\u2014", "---"); +defineSymbol(text, main, textord, "\u2018", "`"); +defineSymbol(text, main, textord, "\u2019", "'"); +defineSymbol(text, main, textord, "\u201c", "``"); +defineSymbol(text, main, textord, "\u201d", "''"); +defineSymbol(math, main, textord, "\u00b0", "\\degree"); +defineSymbol(text, main, textord, "\u00b0", "\\degree"); +defineSymbol(math, main, mathord, "\u00a3", "\\pounds"); +defineSymbol(math, ams, textord, "\u2720", "\\maltese"); +defineSymbol(text, ams, textord, "\u2720", "\\maltese"); + +defineSymbol(text, main, spacing, "\u00a0", "\\ "); +defineSymbol(text, main, spacing, "\u00a0", " "); +defineSymbol(text, main, spacing, "\u00a0", "~"); + +// There are lots of symbols which are the same, so we add them in afterwards. +var i; +var ch; + +// All of these are textords in math mode +var mathTextSymbols = "0123456789/@.\""; +for (i = 0; i < mathTextSymbols.length; i++) { + ch = mathTextSymbols.charAt(i); + defineSymbol(math, main, textord, ch, ch); +} + +// All of these are textords in text mode +var textSymbols = "0123456789!@*()-=+[]\";:?/.,"; +for (i = 0; i < textSymbols.length; i++) { + ch = textSymbols.charAt(i); + defineSymbol(text, main, textord, ch, ch); +} + +// All of these are textords in text mode, and mathords in math mode +var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +for (i = 0; i < letters.length; i++) { + ch = letters.charAt(i); + defineSymbol(math, main, mathord, ch, ch); + defineSymbol(text, main, textord, ch, ch); +} + +// Latin-1 letters +for (i = 0x00C0; i <= 0x00D6; i++) { + ch = String.fromCharCode(i); + defineSymbol(text, main, textord, ch, ch); +} + +for (i = 0x00D8; i <= 0x00F6; i++) { + ch = String.fromCharCode(i); + defineSymbol(text, main, textord, ch, ch); +} + +for (i = 0x00F8; i <= 0x00FF; i++) { + ch = String.fromCharCode(i); + defineSymbol(text, main, textord, ch, ch); +} + +// Cyrillic +for (i = 0x0410; i <= 0x044F; i++) { + ch = String.fromCharCode(i); + defineSymbol(text, main, textord, ch, ch); +} + +// Unicode versions of existing characters +defineSymbol(text, main, textord, "\u2013", "–"); +defineSymbol(text, main, textord, "\u2014", "—"); +defineSymbol(text, main, textord, "\u2018", "‘"); +defineSymbol(text, main, textord, "\u2019", "’"); +defineSymbol(text, main, textord, "\u201c", "“"); +defineSymbol(text, main, textord, "\u201d", "”"); + +},{}],24:[function(require,module,exports){ +var hangulRegex = /[\uAC00-\uD7AF]/; + +// This regex combines +// - Hiragana: [\u3040-\u309F] +// - Katakana: [\u30A0-\u30FF] +// - CJK ideograms: [\u4E00-\u9FAF] +// - Hangul syllables: [\uAC00-\uD7AF] +// Notably missing are halfwidth Katakana and Romanji glyphs. +var cjkRegex = + /[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FAF]|[\uAC00-\uD7AF]/; + +module.exports = { + cjkRegex: cjkRegex, + hangulRegex: hangulRegex +}; + +},{}],25:[function(require,module,exports){ +/** + * This file contains a list of utility functions which are useful in other + * files. + */ + +/** + * Provide an `indexOf` function which works in IE8, but defers to native if + * possible. + */ +var nativeIndexOf = Array.prototype.indexOf; +var indexOf = function(list, elem) { + if (list == null) { + return -1; + } + if (nativeIndexOf && list.indexOf === nativeIndexOf) { + return list.indexOf(elem); + } + var i = 0; + var l = list.length; + for (; i < l; i++) { + if (list[i] === elem) { + return i; + } + } + return -1; +}; + +/** + * Return whether an element is contained in a list + */ +var contains = function(list, elem) { + return indexOf(list, elem) !== -1; +}; + +/** + * Provide a default value if a setting is undefined + */ +var deflt = function(setting, defaultIfUndefined) { + return setting === undefined ? defaultIfUndefined : setting; +}; + +// hyphenate and escape adapted from Facebook's React under Apache 2 license + +var uppercase = /([A-Z])/g; +var hyphenate = function(str) { + return str.replace(uppercase, "-$1").toLowerCase(); +}; + +var ESCAPE_LOOKUP = { + "&": "&", + ">": ">", + "<": "<", + "\"": """, + "'": "'" +}; + +var ESCAPE_REGEX = /[&><"']/g; + +function escaper(match) { + return ESCAPE_LOOKUP[match]; +} + +/** + * Escapes text to prevent scripting attacks. + * + * @param {*} text Text value to escape. + * @return {string} An escaped string. + */ +function escape(text) { + return ("" + text).replace(ESCAPE_REGEX, escaper); +} + +/** + * A function to set the text content of a DOM element in all supported + * browsers. Note that we don't define this if there is no document. + */ +var setTextContent; +if (typeof document !== "undefined") { + var testNode = document.createElement("span"); + if ("textContent" in testNode) { + setTextContent = function(node, text) { + node.textContent = text; + }; + } else { + setTextContent = function(node, text) { + node.innerText = text; + }; + } +} + +/** + * A function to clear a node. + */ +function clearNode(node) { + setTextContent(node, ""); +} + +module.exports = { + contains: contains, + deflt: deflt, + escape: escape, + hyphenate: hyphenate, + indexOf: indexOf, + setTextContent: setTextContent, + clearNode: clearNode +}; + +},{}]},{},[1])(1) +}); \ No newline at end of file diff --git a/public/katex/katex.min.css b/public/katex/katex.min.css new file mode 100644 index 000000000..d6fb8374d --- /dev/null +++ b/public/katex/katex.min.css @@ -0,0 +1 @@ +@font-face{font-family:KaTeX_AMS;src:url(fonts/KaTeX_AMS-Regular.eot);src:url(fonts/KaTeX_AMS-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_AMS-Regular.woff2) format('woff2'),url(fonts/KaTeX_AMS-Regular.woff) format('woff'),url(fonts/KaTeX_AMS-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Bold.eot);src:url(fonts/KaTeX_Caligraphic-Bold.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Caligraphic-Bold.woff2) format('woff2'),url(fonts/KaTeX_Caligraphic-Bold.woff) format('woff'),url(fonts/KaTeX_Caligraphic-Bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Regular.eot);src:url(fonts/KaTeX_Caligraphic-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Caligraphic-Regular.woff2) format('woff2'),url(fonts/KaTeX_Caligraphic-Regular.woff) format('woff'),url(fonts/KaTeX_Caligraphic-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Bold.eot);src:url(fonts/KaTeX_Fraktur-Bold.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Fraktur-Bold.woff2) format('woff2'),url(fonts/KaTeX_Fraktur-Bold.woff) format('woff'),url(fonts/KaTeX_Fraktur-Bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Regular.eot);src:url(fonts/KaTeX_Fraktur-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Fraktur-Regular.woff2) format('woff2'),url(fonts/KaTeX_Fraktur-Regular.woff) format('woff'),url(fonts/KaTeX_Fraktur-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Bold.eot);src:url(fonts/KaTeX_Main-Bold.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Main-Bold.woff2) format('woff2'),url(fonts/KaTeX_Main-Bold.woff) format('woff'),url(fonts/KaTeX_Main-Bold.ttf) format('truetype');font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Italic.eot);src:url(fonts/KaTeX_Main-Italic.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Main-Italic.woff2) format('woff2'),url(fonts/KaTeX_Main-Italic.woff) format('woff'),url(fonts/KaTeX_Main-Italic.ttf) format('truetype');font-weight:400;font-style:italic}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Regular.eot);src:url(fonts/KaTeX_Main-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Main-Regular.woff2) format('woff2'),url(fonts/KaTeX_Main-Regular.woff) format('woff'),url(fonts/KaTeX_Main-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Math;src:url(fonts/KaTeX_Math-Italic.eot);src:url(fonts/KaTeX_Math-Italic.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Math-Italic.woff2) format('woff2'),url(fonts/KaTeX_Math-Italic.woff) format('woff'),url(fonts/KaTeX_Math-Italic.ttf) format('truetype');font-weight:400;font-style:italic}@font-face{font-family:KaTeX_SansSerif;src:url(fonts/KaTeX_SansSerif-Regular.eot);src:url(fonts/KaTeX_SansSerif-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_SansSerif-Regular.woff2) format('woff2'),url(fonts/KaTeX_SansSerif-Regular.woff) format('woff'),url(fonts/KaTeX_SansSerif-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Script;src:url(fonts/KaTeX_Script-Regular.eot);src:url(fonts/KaTeX_Script-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Script-Regular.woff2) format('woff2'),url(fonts/KaTeX_Script-Regular.woff) format('woff'),url(fonts/KaTeX_Script-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size1;src:url(fonts/KaTeX_Size1-Regular.eot);src:url(fonts/KaTeX_Size1-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size1-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size1-Regular.woff) format('woff'),url(fonts/KaTeX_Size1-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size2;src:url(fonts/KaTeX_Size2-Regular.eot);src:url(fonts/KaTeX_Size2-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size2-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size2-Regular.woff) format('woff'),url(fonts/KaTeX_Size2-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size3;src:url(fonts/KaTeX_Size3-Regular.eot);src:url(fonts/KaTeX_Size3-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size3-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size3-Regular.woff) format('woff'),url(fonts/KaTeX_Size3-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size4;src:url(fonts/KaTeX_Size4-Regular.eot);src:url(fonts/KaTeX_Size4-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Size4-Regular.woff2) format('woff2'),url(fonts/KaTeX_Size4-Regular.woff) format('woff'),url(fonts/KaTeX_Size4-Regular.ttf) format('truetype');font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Typewriter;src:url(fonts/KaTeX_Typewriter-Regular.eot);src:url(fonts/KaTeX_Typewriter-Regular.eot#iefix) format('embedded-opentype'),url(fonts/KaTeX_Typewriter-Regular.woff2) format('woff2'),url(fonts/KaTeX_Typewriter-Regular.woff) format('woff'),url(fonts/KaTeX_Typewriter-Regular.ttf) format('truetype');font-weight:400;font-style:normal}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:inline-block;text-align:initial}.katex{font:400 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;white-space:nowrap;text-indent:0}.katex .katex-html{display:inline-block}.katex .katex-mathml{position:absolute;clip:rect(1px,1px,1px,1px);padding:0;border:0;height:1px;width:1px;overflow:hidden}.katex .base,.katex .strut{display:inline-block}.katex .mathrm{font-style:normal}.katex .textit{font-style:italic}.katex .mathit{font-family:KaTeX_Math;font-style:italic}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .amsrm,.katex .mathbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak{font-family:KaTeX_Fraktur}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr{font-family:KaTeX_Script}.katex .mathsf{font-family:KaTeX_SansSerif}.katex .mainit{font-family:KaTeX_Main;font-style:italic}.katex .mord+.mop{margin-left:.16667em}.katex .mord+.mbin{margin-left:.22222em}.katex .mord+.mrel{margin-left:.27778em}.katex .mop+.mop,.katex .mop+.mord,.katex .mord+.minner{margin-left:.16667em}.katex .mop+.mrel{margin-left:.27778em}.katex .mop+.minner{margin-left:.16667em}.katex .mbin+.minner,.katex .mbin+.mop,.katex .mbin+.mopen,.katex .mbin+.mord{margin-left:.22222em}.katex .mrel+.minner,.katex .mrel+.mop,.katex .mrel+.mopen,.katex .mrel+.mord{margin-left:.27778em}.katex .mclose+.mop{margin-left:.16667em}.katex .mclose+.mbin{margin-left:.22222em}.katex .mclose+.mrel{margin-left:.27778em}.katex .mclose+.minner,.katex .minner+.mop,.katex .minner+.mord,.katex .mpunct+.mclose,.katex .mpunct+.minner,.katex .mpunct+.mop,.katex .mpunct+.mopen,.katex .mpunct+.mord,.katex .mpunct+.mpunct,.katex .mpunct+.mrel{margin-left:.16667em}.katex .minner+.mbin{margin-left:.22222em}.katex .minner+.mrel{margin-left:.27778em}.katex .minner+.minner,.katex .minner+.mopen,.katex .minner+.mpunct{margin-left:.16667em}.katex .mbin.mtight,.katex .mclose.mtight,.katex .minner.mtight,.katex .mop.mtight,.katex .mopen.mtight,.katex .mord.mtight,.katex .mpunct.mtight,.katex .mrel.mtight{margin-left:0}.katex .mclose+.mop.mtight,.katex .minner+.mop.mtight,.katex .mop+.mop.mtight,.katex .mop+.mord.mtight,.katex .mord+.mop.mtight{margin-left:.16667em}.katex .reset-textstyle.textstyle{font-size:1em}.katex .reset-textstyle.scriptstyle{font-size:.7em}.katex .reset-textstyle.scriptscriptstyle{font-size:.5em}.katex .reset-scriptstyle.textstyle{font-size:1.42857em}.katex .reset-scriptstyle.scriptstyle{font-size:1em}.katex .reset-scriptstyle.scriptscriptstyle{font-size:.71429em}.katex .reset-scriptscriptstyle.textstyle{font-size:2em}.katex .reset-scriptscriptstyle.scriptstyle{font-size:1.4em}.katex .reset-scriptscriptstyle.scriptscriptstyle{font-size:1em}.katex .style-wrap{position:relative}.katex .vlist{display:inline-block}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist .baseline-fix{display:inline-table;table-layout:fixed}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{width:100%}.katex .mfrac .frac-line:before{border-bottom-style:solid;border-bottom-width:1px;content:"";display:block}.katex .mfrac .frac-line:after{border-bottom-style:solid;border-bottom-width:.04em;content:"";display:block;margin-top:-1px}.katex .mspace{display:inline-block}.katex .mspace.negativethinspace{margin-left:-.16667em}.katex .mspace.thinspace{width:.16667em}.katex .mspace.negativemediumspace{margin-left:-.22222em}.katex .mspace.mediumspace{width:.22222em}.katex .mspace.thickspace{width:.27778em}.katex .mspace.sixmuspace{width:.333333em}.katex .mspace.eightmuspace{width:.444444em}.katex .mspace.enspace{width:.5em}.katex .mspace.twelvemuspace{width:.666667em}.katex .mspace.quad{width:1em}.katex .mspace.qquad{width:2em}.katex .llap,.katex .rlap{width:0;position:relative}.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .rlap>.inner{left:0}.katex .katex-logo .a{font-size:.75em;margin-left:-.32em;position:relative;top:-.2em}.katex .katex-logo .t{margin-left:-.23em}.katex .katex-logo .e{margin-left:-.1667em;position:relative;top:.2155em}.katex .katex-logo .x{margin-left:-.125em}.katex .rule{display:inline-block;border:0 solid;position:relative}.katex .overline .overline-line,.katex .underline .underline-line{width:100%}.katex .overline .overline-line:before,.katex .underline .underline-line:before{border-bottom-style:solid;border-bottom-width:1px;content:"";display:block}.katex .overline .overline-line:after,.katex .underline .underline-line:after{border-bottom-style:solid;border-bottom-width:.04em;content:"";display:block;margin-top:-1px}.katex .sqrt>.sqrt-sign{position:relative}.katex .sqrt .sqrt-line{width:100%}.katex .sqrt .sqrt-line:before{border-bottom-style:solid;border-bottom-width:1px;content:"";display:block}.katex .sqrt .sqrt-line:after{border-bottom-style:solid;border-bottom-width:.04em;content:"";display:block;margin-top:-1px}.katex .sqrt>.root{margin-left:.27777778em;margin-right:-.55555556em}.katex .fontsize-ensurer,.katex .sizing{display:inline-block}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:2em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:3.46em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:4.14em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.98em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.71428571em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.14285714em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.28571429em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.42857143em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.71428571em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2.05714286em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.47142857em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.95714286em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.55714286em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.875em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.125em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.25em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.5em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.8em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.1625em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.5875em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:3.1125em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.55555556em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.77777778em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.88888889em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.11111111em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.6em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.92222222em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.3em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.76666667em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.7em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.8em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.9em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.2em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.44em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.73em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:2.07em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.49em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.41666667em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.58333333em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.66666667em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.75em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.83333333em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44166667em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.725em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.075em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.34722222em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.48611111em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.55555556em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.625em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.69444444em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.83333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.20138889em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.4375em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.72916667em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.28901734em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.40462428em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.46242775em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.52023121em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.57803468em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.69364162em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.83236994em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.19653179em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.43930636em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.24154589em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.33816425em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.38647343em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.43478261em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.48309179em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.57971014em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.69565217em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.83574879em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.20289855em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.20080321em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.2811245em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.32128514em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.36144578em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.40160643em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.48192771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.57831325em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.69477912em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.8313253em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist>span,.katex .op-limits>.vlist>span{text-align:center}.katex .accent .accent-body>span{width:0}.katex .accent .accent-body.accent-vec>span{position:relative;left:.326em}.katex .mtable .vertical-separator{display:inline-block;margin:0 -.025em;border-right:.05em solid #000}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist{text-align:center}.katex .mtable .col-align-l>.vlist{text-align:left}.katex .mtable .col-align-r>.vlist{text-align:right} \ No newline at end of file diff --git a/public/katex/katex.min.js b/public/katex/katex.min.js new file mode 100644 index 000000000..b8df4cc0c --- /dev/null +++ b/public/katex/katex.min.js @@ -0,0 +1,4 @@ +(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.katex=e()}})(function(){var e,t,r;return function a(e,t,r){function i(s,l){if(!t[s]){if(!e[s]){var o=typeof require=="function"&&require;if(!l&&o)return o(s,!0);if(n)return n(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var p=t[s]={exports:{}};e[s][0].call(p.exports,function(t){var r=e[s][1][t];return i(r?r:t)},p,p.exports,a,e,t,r)}return t[s].exports}var n=typeof require=="function"&&require;for(var s=0;s15){o="\u2026"+s.slice(i-15,i)}else{o=s.slice(0,i)}var u;if(n+15v){return this.parseFunction(i)}else{throw new p("Got function '"+i.result+"' with no arguments "+"as "+e,t)}}else{return i.result}};h.prototype.handleUnsupportedCmd=function(){var e=this.nextToken.text;var t=[];for(var r=0;ri){c=this.parseFunction(h)}else{throw new p("Got function '"+h.result+"' as "+"argument to '"+e+"'",o)}}else{c=h.result}s.push(c);n.push(this.pos)}s.push(n);return s};h.prototype.parseGroupOfType=function(e,t){var r=this.mode;if(e==="original"){e=r}if(e==="color"){return this.parseColorGroup(t)}if(e==="size"){return this.parseSizeGroup(t)}this.switchMode(e);if(e==="text"){while(this.nextToken.text===" "){this.consume()}}var a=this.parseGroup(t);this.switchMode(r);return a};h.prototype.parseStringGroup=function(e,t){if(t&&this.nextToken.text!=="["){return null}var r=this.mode;this.mode="text";this.expect(t?"[":"{");var a="";var i=this.nextToken;var n=i;while(this.nextToken.text!==(t?"]":"}")){if(this.nextToken.text==="EOF"){throw new p("Unexpected end of input in "+e,i.range(this.nextToken,a))}n=this.nextToken;a+=n.text;this.consume()}this.mode=r;this.expect(t?"]":"}");return i.range(n,a)};h.prototype.parseRegexGroup=function(e,t){var r=this.mode;this.mode="text";var a=this.nextToken;var i=a;var n="";while(this.nextToken.text!=="EOF"&&e.test(n+this.nextToken.text)){i=this.nextToken;n+=i.text;this.consume()}if(n===""){throw new p("Invalid "+t+": '"+a.text+"'",a)}this.mode=r;return a.range(i,n)};h.prototype.parseColorGroup=function(e){var t=this.parseStringGroup("color",e);if(!t){return null}var r=/^(#[a-z0-9]+|[a-z]+)$/i.exec(t.text);if(!r){throw new p("Invalid color: '"+t.text+"'",t)}return new m(new c("color",r[0],this.mode),false)};h.prototype.parseSizeGroup=function(e){var t;if(!e&&this.nextToken.text!=="{"){t=this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2}$/,"size")}else{t=this.parseStringGroup("size",e)}if(!t){return null}var r=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(t.text);if(!r){throw new p("Invalid size: '"+t.text+"'",t)}var a={number:+(r[1]+r[2]),unit:r[3]};if(a.unit!=="em"&&a.unit!=="ex"&&a.unit!=="mu"){throw new p("Invalid unit: '"+a.unit+"'",t)}return new m(new c("color",a,this.mode),false)};h.prototype.parseGroup=function(e){var t=this.nextToken;if(this.nextToken.text===(e?"[":"{")){this.consume();var r=this.parseExpression(false,e?"]":null);var a=this.nextToken;this.expect(e?"]":"}");if(this.mode==="text"){this.formLigatures(r)}return new m(new c("ordgroup",r,this.mode,t,a),false)}else{return e?null:this.parseSymbol()}};h.prototype.formLigatures=function(e){var t;var r=e.length-1;for(t=0;t0?t-1:0]}l.prototype.sup=function(){return y[x[this.id]]};l.prototype.sub=function(){return y[b[this.id]]};l.prototype.fracNum=function(){return y[w[this.id]]};l.prototype.fracDen=function(){return y[k[this.id]]};l.prototype.cramp=function(){return y[z[this.id]]};l.prototype.cls=function(){return d[this.size]+(this.cramped?" cramped":" uncramped")};l.prototype.reset=function(){return g[this.size]};l.prototype.isTight=function(){return this.size>=2};var o=0;var u=1;var p=2;var h=3;var c=4;var m=5;var f=6;var v=7;var d=["displaystyle textstyle","textstyle","scriptstyle","scriptscriptstyle"];var g=["reset-textstyle","reset-textstyle","reset-scriptstyle","reset-scriptscriptstyle"];var y=[new l(o,0,1,false),new l(u,0,1,true),new l(p,1,1,false),new l(h,1,1,true),new l(c,2,.7,false),new l(m,2,.7,true),new l(f,3,.5,false),new l(v,3,.5,true)];var x=[c,m,c,m,f,v,f,v];var b=[m,m,m,m,v,v,v,v];var w=[p,h,c,m,f,v,f,v];var k=[h,h,m,m,v,v,v,v];var z=[u,u,h,h,m,m,v,v];t.exports={DISPLAY:y[o],TEXT:y[p],SCRIPT:y[c],SCRIPTSCRIPT:y[f]}},{"./fontMetrics.js":17}],10:[function(e,t,r){var a=e("./domTree");var i=e("./fontMetrics");var n=e("./symbols");var s=e("./utils");var l=["\\Gamma","\\Delta","\\Theta","\\Lambda","\\Xi","\\Pi","\\Sigma","\\Upsilon","\\Phi","\\Psi","\\Omega"];var o=["\u0131","\u0237","\xa3"];var u=function(e,t,r,s,l){if(n[r][e]&&n[r][e].replace){e=n[r][e].replace}var o=i.getCharacterMetrics(e,t);var u;if(o){var p=o.italic;if(r==="text"){p=0}u=new a.symbolNode(e,o.height,o.depth,p,o.skew,l)}else{typeof console!=="undefined"&&console.warn("No character metrics for '"+e+"' in style '"+t+"'");u=new a.symbolNode(e,0,0,0,0,l)}if(s){if(s.style.isTight()){u.classes.push("mtight")}if(s.getColor()){u.style.color=s.getColor()}}return u};var p=function(e,t,r,a){if(e==="\\"||n[t][e].font==="main"){return u(e,"Main-Regular",t,r,a)}else{return u(e,"AMS-Regular",t,r,a.concat(["amsrm"]))}};var h=function(e,t,r,a,i){if(i==="mathord"){return c(e,t,r,a)}else if(i==="textord"){return u(e,"Main-Regular",t,r,a.concat(["mathrm"]))}else{throw new Error("unexpected type: "+i+" in mathDefault")}};var c=function(e,t,r,a){if(/[0-9]/.test(e.charAt(0))||s.contains(o,e)||s.contains(l,e)){return u(e,"Main-Italic",t,r,a.concat(["mainit"]))}else{return u(e,"Math-Italic",t,r,a.concat(["mathit"]))}};var m=function(e,t,r){var a=e.mode;var l=e.value;if(n[a][l]&&n[a][l].replace){l=n[a][l].replace}var p=["mord"];var m=t.font;if(m){if(m==="mathit"||s.contains(o,l)){return c(l,a,t,p)}else{var f=k[m].fontName;if(i.getCharacterMetrics(l,f)){return u(l,f,a,t,p.concat([m]))}else{return h(l,a,t,p,r)}}}else{return h(l,a,t,p,r)}};var f=function(e){var t=0;var r=0;var a=0;if(e.children){for(var i=0;it){t=e.children[i].height}if(e.children[i].depth>r){r=e.children[i].depth}if(e.children[i].maxFontSize>a){a=e.children[i].maxFontSize}}}e.height=t;e.depth=r;e.maxFontSize=a};var v=function(e,t,r){var i=new a.span(e,t,r);f(i);return i};var d=function(e,t){e.children=t.concat(e.children);f(e)};var g=function(e){var t=new a.documentFragment(e);f(t);return t};var y=function(e,t){var r=v([],[new a.symbolNode("\u200b")]);r.style.fontSize=t/e.style.sizeMultiplier+"em";var i=v(["fontsize-ensurer","reset-"+e.size,"size5"],[r]);return i};var x=function(e,t,r,i){var n;var s;var l;if(t==="individualShift"){var o=e;e=[o[0]];n=-o[0].shift-o[0].elem.depth;s=n;for(l=1;l0){f+=T;v-=T}}S=n.makeVList([{type:"elem",elem:s,shift:v},{type:"elem",elem:a,shift:-f}],"individualShift",null,t);if(r instanceof l.symbolNode){S.children[0].style.marginLeft=-r.italic+"em"}S.children[0].style.marginRight=k;S.children[1].style.marginRight=k}var A=d(r)||"mord";return p([A],[r,p(["msupsub"],[S])],t)};w.genfrac=function(e,t){var r=t.style;if(e.value.size==="display"){r=i.DISPLAY}else if(e.value.size==="text"){r=i.TEXT}var a=r.fracNum();var l=r.fracDen();var u;u=t.withStyle(a);var h=z(e.value.numer,u);var c=p([r.reset(),a.cls()],[h],u);u=t.withStyle(l);var m=z(e.value.denom,u);var f=p([r.reset(),l.cls()],[m],u);var v;if(e.value.hasBarLine){v=o.metrics.defaultRuleThickness/t.style.sizeMultiplier}else{v=0}var d;var g;var y;if(r.size===i.DISPLAY.size){d=r.metrics.num1;if(v>0){g=3*v}else{g=7*o.metrics.defaultRuleThickness}y=r.metrics.denom1}else{if(v>0){d=r.metrics.num2;g=v}else{d=r.metrics.num3;g=3*o.metrics.defaultRuleThickness}y=r.metrics.denom2}var x;if(v===0){var w=d-h.depth-(m.height-y);if(w0){N+=x;if(M=l){continue}var I;if(i>0||e.value.hskipBeforeAndAfter){I=u.deflt(O.pregap,f);if(I!==0){C=p(["arraycolsep"],[]);C.style.width=I+"em";E.push(C)}}var L=[];for(r=0;ra.height+a.depth+c){c=(c+d-a.height-a.depth)/2}var g=-(a.height+c+l)+v.height;v.style.top=g+"em";v.height-=g;v.depth+=g;var y;if(a.height===0&&a.depth===0){y=p()}else{y=n.makeVList([{type:"elem",elem:a},{type:"kern",size:c},{type:"elem",elem:u},{type:"kern",size:l}],"firstBaseline",null,t)}if(!e.value.index){return p(["mord","sqrt"],[v,y],t)}else{var x=t.withStyle(i.SCRIPTSCRIPT);var b=z(e.value.index,x);var w=p([r.reset(),i.SCRIPTSCRIPT.cls()],[b],x);var k=Math.max(v.height,y.height);var S=Math.max(v.depth,y.depth);var M=.6*(k-S);var T=n.makeVList([{type:"elem",elem:w}],"shift",-M,t);var A=p(["root"],[T]);return p(["mord","sqrt"],[A,v,y],t)}};w.sizing=function(e,t){var r=v(e.value.value,t.withSize(e.value.size),false);var a=t.style;var i=n.sizingMultiplier[e.value.size];i=i*a.sizeMultiplier;for(var s=0;s","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"];var b=[0,1.2,1.8,2.4,3];var w=function(e,t,r,i,n){if(e==="<"||e==="\\lt"){e="\\langle"}else if(e===">"||e==="\\gt"){e="\\rangle"}if(o.contains(g,e)||o.contains(x,e)){return f(e,t,false,r,i,n)}else if(o.contains(y,e)){return d(e,b[t],false,r,i,n)}else{throw new a("Illegal delimiter: '"+e+"'")}};var k=[{type:"small",style:i.SCRIPTSCRIPT},{type:"small",style:i.SCRIPT},{type:"small",style:i.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}];var z=[{type:"small",style:i.SCRIPTSCRIPT},{type:"small",style:i.SCRIPT},{type:"small",style:i.TEXT},{type:"stack"}];var S=[{type:"small",style:i.SCRIPTSCRIPT},{type:"small",style:i.SCRIPT},{type:"small",style:i.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}];var M=function(e){if(e.type==="small"){return"Main-Regular"}else if(e.type==="large"){return"Size"+e.size+"-Regular"}else if(e.type==="stack"){return"Size4-Regular"}};var T=function(e,t,r,a){var i=Math.min(2,3-a.style.size);for(var n=i;nt){return r[n]}}return r[r.length-1]};var A=function(e,t,r,a,i,n){if(e==="<"||e==="\\lt"){e="\\langle"}else if(e===">"||e==="\\gt"){e="\\rangle"}var s;if(o.contains(x,e)){s=k}else if(o.contains(g,e)){s=S}else{s=z}var l=T(e,t,s,a);if(l.type==="small"){return m(e,l.style,r,a,i,n)}else if(l.type==="large"){return f(e,l.size,r,a,i,n)}else if(l.type==="stack"){return d(e,t,r,a,i,n)}};var N=function(e,t,r,a,i,n){var l=a.style.metrics.axisHeight*a.style.sizeMultiplier;var o=901;var u=5/s.metrics.ptPerEm;var p=Math.max(t-l,r+l);var h=Math.max(p/500*o,2*p-u);return A(e,h,true,a,i,n)};t.exports={sizedDelim:w,customSizedDelim:A,leftRightDelim:N}},{"./ParseError":6,"./Style":9,"./buildCommon":10,"./fontMetrics":17,"./symbols":23,"./utils":25}],15:[function(e,t,r){var a=e("./unicodeRegexes");var i=e("./utils");var n=function(e){e=e.slice();for(var t=e.length-1;t>=0;t--){if(!e[t]){e.splice(t,1)}}return e.join(" ")};function s(e,t,r){this.classes=e||[];this.children=t||[];this.height=0;this.depth=0;this.maxFontSize=0;this.style={};this.attributes={};if(r){if(r.style.isTight()){this.classes.push("mtight")}if(r.getColor()){this.style.color=r.getColor()}}}s.prototype.setAttribute=function(e,t){this.attributes[e]=t};s.prototype.tryCombine=function(e){return false};s.prototype.toNode=function(){var e=document.createElement("span");e.className=n(this.classes);for(var t in this.style){if(Object.prototype.hasOwnProperty.call(this.style,t)){e.style[t]=this.style[t]}}for(var r in this.attributes){if(Object.prototype.hasOwnProperty.call(this.attributes,r)){e.setAttribute(r,this.attributes[r])}}for(var a=0;a";return e};function l(e){this.children=e||[];this.height=0;this.depth=0;this.maxFontSize=0}l.prototype.toNode=function(){var e=document.createDocumentFragment();for(var t=0;t0||n(this.classes)!==n(e.classes)||this.skew!==e.skew||this.maxFontSize!==e.maxFontSize){return false}for(var t in this.style){if(this.style.hasOwnProperty(t)&&this.style[t]!==e.style[t]){return false}}for(t in e.style){if(e.style.hasOwnProperty(t)&&this.style[t]!==e.style[t]){return false}}this.value+=e.value;this.height=Math.max(this.height,e.height);this.depth=Math.max(this.depth,e.depth);this.italic=e.italic;return true};u.prototype.toNode=function(){var e=document.createTextNode(this.value);var t=null;if(this.italic>0){t=document.createElement("span");t.style.marginRight=this.italic+"em"}if(this.classes.length>0){t=t||document.createElement("span");t.className=n(this.classes)}for(var r in this.style){if(this.style.hasOwnProperty(r)){t=t||document.createElement("span");t.style[r]=this.style[r]}}if(t){t.appendChild(e);return t}else{return e}};u.prototype.toMarkup=function(){var e=false;var t="0){r+="margin-right:"+this.italic+"em;"}for(var a in this.style){if(this.style.hasOwnProperty(a)){r+=i.hyphenate(a)+":"+this.style[a]+";"}}if(r){e=true;t+=' style="'+i.escape(r)+'"'}var s=i.escape(this.value);if(e){t+=">";t+=s;t+="";return t}else{return s}};t.exports={span:s,documentFragment:l,symbolNode:u}},{"./unicodeRegexes":24,"./utils":25}],16:[function(e,t,r){var a=e("./parseData");var i=e("./ParseError");var n=e("./Style");var s=a.ParseNode;function l(e,t){var r=[];var a=[r];var n=[];while(true){var l=e.parseExpression(false,null);r.push(new s("ordgroup",l,e.mode));var o=e.nextToken.text;if(o==="&"){e.consume()}else if(o==="\\end"){break}else if(o==="\\\\"||o==="\\cr"){var u=e.parseFunction();n.push(u.value.size);r=[];a.push(r)}else{throw new i("Expected & or \\\\ or \\end",e.nextToken)}}t.body=a;t.rowGaps=n;return new s(t.type,t,e.mode)}function o(e,r,a){if(typeof e==="string"){e=[e]}if(typeof r==="number"){r={numArgs:r}}var i={numArgs:r.numArgs||0,argTypes:r.argTypes,greediness:1,allowedInText:!!r.allowedInText,numOptionalArgs:r.numOptionalArgs||0,handler:a};for(var n=0;n0){o=2}t.value.cols[i]={type:"align",align:n,pregap:o,postgap:0}}return t})},{"./ParseError":6,"./Style":9,"./parseData":21}],17:[function(e,t,r){var a=e("./Style");var i=e("./unicodeRegexes").cjkRegex;var n={slant:[.25,.25,.25],space:[0,0,0],stretch:[0,0,0],shrink:[0,0,0],xHeight:[.431,.431,.431],quad:[1,1.171,1.472],extraSpace:[0,0,0],num1:[.677,.732,.925],num2:[.394,.384,.387],num3:[.444,.471,.504],denom1:[.686,.752,1.025],denom2:[.345,.344,.532],sup1:[.413,.503,.504],sup2:[.363,.431,.404],sup3:[.289,.286,.294],sub1:[.15,.143,.2],sub2:[.247,.286,.4],supDrop:[.386,.353,.494],subDrop:[.05,.071,.1],delim1:[2.39,1.7,1.98],delim2:[1.01,1.157,1.42],axisHeight:[.25,.25,.25]};var s=0;var l=0;var o=0;var u=0;var p=.431;var h=1;var c=0;var m=.04;var f=.111;var v=.166;var d=.2;var g=.6;var y=.1;var x=10;var b=2/x;var w={defaultRuleThickness:m,bigOpSpacing1:f,bigOpSpacing2:v,bigOpSpacing3:d,bigOpSpacing4:g,bigOpSpacing5:y,ptPerEm:x,doubleRuleSep:b};var k=e("./fontMetricsData");var z={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xc6":"A","\xc7":"C","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xd0":"D","\xd1":"N","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xdd":"Y","\xde":"o","\xdf":"B","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xe6":"a","\xe7":"c","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xf0":"d","\xf1":"n","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xfd":"y","\xfe":"o","\xff":"y","\u0410":"A","\u0411":"B","\u0412":"B","\u0413":"F","\u0414":"A","\u0415":"E","\u0416":"K","\u0417":"3","\u0418":"N","\u0419":"N","\u041a":"K","\u041b":"N","\u041c":"M","\u041d":"H","\u041e":"O","\u041f":"N","\u0420":"P","\u0421":"C","\u0422":"T","\u0423":"y","\u0424":"O","\u0425":"X","\u0426":"U","\u0427":"h","\u0428":"W","\u0429":"W","\u042a":"B","\u042b":"X","\u042c":"B","\u042d":"3","\u042e":"X","\u042f":"R","\u0430":"a","\u0431":"b","\u0432":"a","\u0433":"r","\u0434":"y","\u0435":"e","\u0436":"m","\u0437":"e","\u0438":"n","\u0439":"n","\u043a":"n","\u043b":"n","\u043c":"m","\u043d":"n","\u043e":"o","\u043f":"n","\u0440":"p","\u0441":"c","\u0442":"o","\u0443":"y","\u0444":"b","\u0445":"x","\u0446":"n","\u0447":"n","\u0448":"w","\u0449":"w","\u044a":"a","\u044b":"m","\u044c":"a","\u044d":"e","\u044e":"m","\u044f":"r"};var S=function(e,t){var r=e.charCodeAt(0);if(e[0]in z){r=z[e[0]].charCodeAt(0)}else if(i.test(e[0])){r="M".charCodeAt(0)}var a=k[t][r];if(a){return{depth:a[0],height:a[1],italic:a[2],skew:a[3],width:a[4]}}};t.exports={metrics:w,sigmas:n,getCharacterMetrics:S}},{"./Style":9,"./fontMetricsData":18,"./unicodeRegexes":24}],18:[function(e,t,r){t.exports={"AMS-Regular":{65:[0,.68889,0,0],66:[0,.68889,0,0],67:[0,.68889,0,0],68:[0,.68889,0,0],69:[0,.68889,0,0],70:[0,.68889,0,0],71:[0,.68889,0,0],72:[0,.68889,0,0],73:[0,.68889,0,0],74:[.16667,.68889,0,0],75:[0,.68889,0,0],76:[0,.68889,0,0],77:[0,.68889,0,0],78:[0,.68889,0,0],79:[.16667,.68889,0,0],80:[0,.68889,0,0],81:[.16667,.68889,0,0],82:[0,.68889,0,0],83:[0,.68889,0,0],84:[0,.68889,0,0],85:[0,.68889,0,0],86:[0,.68889,0,0],87:[0,.68889,0,0],88:[0,.68889,0,0],89:[0,.68889,0,0],90:[0,.68889,0,0],107:[0,.68889,0,0],165:[0,.675,.025,0],174:[.15559,.69224,0,0],240:[0,.68889,0,0],295:[0,.68889,0,0],710:[0,.825,0,0],732:[0,.9,0,0],770:[0,.825,0,0],771:[0,.9,0,0],989:[.08167,.58167,0,0],1008:[0,.43056,.04028,0],8245:[0,.54986,0,0],8463:[0,.68889,0,0],8487:[0,.68889,0,0],8498:[0,.68889,0,0],8502:[0,.68889,0,0],8503:[0,.68889,0,0],8504:[0,.68889,0,0],8513:[0,.68889,0,0],8592:[-.03598,.46402,0,0],8594:[-.03598,.46402,0,0],8602:[-.13313,.36687,0,0],8603:[-.13313,.36687,0,0],8606:[.01354,.52239,0,0],8608:[.01354,.52239,0,0],8610:[.01354,.52239,0,0],8611:[.01354,.52239,0,0],8619:[0,.54986,0,0],8620:[0,.54986,0,0],8621:[-.13313,.37788,0,0],8622:[-.13313,.36687,0,0],8624:[0,.69224,0,0],8625:[0,.69224,0,0],8630:[0,.43056,0,0],8631:[0,.43056,0,0],8634:[.08198,.58198,0,0],8635:[.08198,.58198,0,0],8638:[.19444,.69224,0,0],8639:[.19444,.69224,0,0],8642:[.19444,.69224,0,0],8643:[.19444,.69224,0,0],8644:[.1808,.675,0,0],8646:[.1808,.675,0,0],8647:[.1808,.675,0,0],8648:[.19444,.69224,0,0],8649:[.1808,.675,0,0],8650:[.19444,.69224,0,0],8651:[.01354,.52239,0,0],8652:[.01354,.52239,0,0],8653:[-.13313,.36687,0,0],8654:[-.13313,.36687,0,0],8655:[-.13313,.36687,0,0],8666:[.13667,.63667,0,0],8667:[.13667,.63667,0,0],8669:[-.13313,.37788,0,0],8672:[-.064,.437,0,0],8674:[-.064,.437,0,0],8705:[0,.825,0,0],8708:[0,.68889,0,0],8709:[.08167,.58167,0,0],8717:[0,.43056,0,0],8722:[-.03598,.46402,0,0],8724:[.08198,.69224,0,0],8726:[.08167,.58167,0,0],8733:[0,.69224,0,0],8736:[0,.69224,0,0],8737:[0,.69224,0,0],8738:[.03517,.52239,0,0],8739:[.08167,.58167,0,0],8740:[.25142,.74111,0,0],8741:[.08167,.58167,0,0],8742:[.25142,.74111,0,0],8756:[0,.69224,0,0],8757:[0,.69224,0,0],8764:[-.13313,.36687,0,0],8765:[-.13313,.37788,0,0],8769:[-.13313,.36687,0,0],8770:[-.03625,.46375,0,0],8774:[.30274,.79383,0,0],8776:[-.01688,.48312,0,0],8778:[.08167,.58167,0,0],8782:[.06062,.54986,0,0],8783:[.06062,.54986,0,0],8785:[.08198,.58198,0,0],8786:[.08198,.58198,0,0],8787:[.08198,.58198,0,0],8790:[0,.69224,0,0],8791:[.22958,.72958,0,0],8796:[.08198,.91667,0,0],8806:[.25583,.75583,0,0], +8807:[.25583,.75583,0,0],8808:[.25142,.75726,0,0],8809:[.25142,.75726,0,0],8812:[.25583,.75583,0,0],8814:[.20576,.70576,0,0],8815:[.20576,.70576,0,0],8816:[.30274,.79383,0,0],8817:[.30274,.79383,0,0],8818:[.22958,.72958,0,0],8819:[.22958,.72958,0,0],8822:[.1808,.675,0,0],8823:[.1808,.675,0,0],8828:[.13667,.63667,0,0],8829:[.13667,.63667,0,0],8830:[.22958,.72958,0,0],8831:[.22958,.72958,0,0],8832:[.20576,.70576,0,0],8833:[.20576,.70576,0,0],8840:[.30274,.79383,0,0],8841:[.30274,.79383,0,0],8842:[.13597,.63597,0,0],8843:[.13597,.63597,0,0],8847:[.03517,.54986,0,0],8848:[.03517,.54986,0,0],8858:[.08198,.58198,0,0],8859:[.08198,.58198,0,0],8861:[.08198,.58198,0,0],8862:[0,.675,0,0],8863:[0,.675,0,0],8864:[0,.675,0,0],8865:[0,.675,0,0],8872:[0,.69224,0,0],8873:[0,.69224,0,0],8874:[0,.69224,0,0],8876:[0,.68889,0,0],8877:[0,.68889,0,0],8878:[0,.68889,0,0],8879:[0,.68889,0,0],8882:[.03517,.54986,0,0],8883:[.03517,.54986,0,0],8884:[.13667,.63667,0,0],8885:[.13667,.63667,0,0],8888:[0,.54986,0,0],8890:[.19444,.43056,0,0],8891:[.19444,.69224,0,0],8892:[.19444,.69224,0,0],8901:[0,.54986,0,0],8903:[.08167,.58167,0,0],8905:[.08167,.58167,0,0],8906:[.08167,.58167,0,0],8907:[0,.69224,0,0],8908:[0,.69224,0,0],8909:[-.03598,.46402,0,0],8910:[0,.54986,0,0],8911:[0,.54986,0,0],8912:[.03517,.54986,0,0],8913:[.03517,.54986,0,0],8914:[0,.54986,0,0],8915:[0,.54986,0,0],8916:[0,.69224,0,0],8918:[.0391,.5391,0,0],8919:[.0391,.5391,0,0],8920:[.03517,.54986,0,0],8921:[.03517,.54986,0,0],8922:[.38569,.88569,0,0],8923:[.38569,.88569,0,0],8926:[.13667,.63667,0,0],8927:[.13667,.63667,0,0],8928:[.30274,.79383,0,0],8929:[.30274,.79383,0,0],8934:[.23222,.74111,0,0],8935:[.23222,.74111,0,0],8936:[.23222,.74111,0,0],8937:[.23222,.74111,0,0],8938:[.20576,.70576,0,0],8939:[.20576,.70576,0,0],8940:[.30274,.79383,0,0],8941:[.30274,.79383,0,0],8994:[.19444,.69224,0,0],8995:[.19444,.69224,0,0],9416:[.15559,.69224,0,0],9484:[0,.69224,0,0],9488:[0,.69224,0,0],9492:[0,.37788,0,0],9496:[0,.37788,0,0],9585:[.19444,.68889,0,0],9586:[.19444,.74111,0,0],9632:[0,.675,0,0],9633:[0,.675,0,0],9650:[0,.54986,0,0],9651:[0,.54986,0,0],9654:[.03517,.54986,0,0],9660:[0,.54986,0,0],9661:[0,.54986,0,0],9664:[.03517,.54986,0,0],9674:[.11111,.69224,0,0],9733:[.19444,.69224,0,0],10003:[0,.69224,0,0],10016:[0,.69224,0,0],10731:[.11111,.69224,0,0],10846:[.19444,.75583,0,0],10877:[.13667,.63667,0,0],10878:[.13667,.63667,0,0],10885:[.25583,.75583,0,0],10886:[.25583,.75583,0,0],10887:[.13597,.63597,0,0],10888:[.13597,.63597,0,0],10889:[.26167,.75726,0,0],10890:[.26167,.75726,0,0],10891:[.48256,.98256,0,0],10892:[.48256,.98256,0,0],10901:[.13667,.63667,0,0],10902:[.13667,.63667,0,0],10933:[.25142,.75726,0,0],10934:[.25142,.75726,0,0],10935:[.26167,.75726,0,0],10936:[.26167,.75726,0,0],10937:[.26167,.75726,0,0],10938:[.26167,.75726,0,0],10949:[.25583,.75583,0,0],10950:[.25583,.75583,0,0],10955:[.28481,.79383,0,0],10956:[.28481,.79383,0,0],57350:[.08167,.58167,0,0],57351:[.08167,.58167,0,0],57352:[.08167,.58167,0,0],57353:[0,.43056,.04028,0],57356:[.25142,.75726,0,0],57357:[.25142,.75726,0,0],57358:[.41951,.91951,0,0],57359:[.30274,.79383,0,0],57360:[.30274,.79383,0,0],57361:[.41951,.91951,0,0],57366:[.25142,.75726,0,0],57367:[.25142,.75726,0,0],57368:[.25142,.75726,0,0],57369:[.25142,.75726,0,0],57370:[.13597,.63597,0,0],57371:[.13597,.63597,0,0]},"Caligraphic-Regular":{48:[0,.43056,0,0],49:[0,.43056,0,0],50:[0,.43056,0,0],51:[.19444,.43056,0,0],52:[.19444,.43056,0,0],53:[.19444,.43056,0,0],54:[0,.64444,0,0],55:[.19444,.43056,0,0],56:[0,.64444,0,0],57:[.19444,.43056,0,0],65:[0,.68333,0,.19445],66:[0,.68333,.03041,.13889],67:[0,.68333,.05834,.13889],68:[0,.68333,.02778,.08334],69:[0,.68333,.08944,.11111],70:[0,.68333,.09931,.11111],71:[.09722,.68333,.0593,.11111],72:[0,.68333,.00965,.11111],73:[0,.68333,.07382,0],74:[.09722,.68333,.18472,.16667],75:[0,.68333,.01445,.05556],76:[0,.68333,0,.13889],77:[0,.68333,0,.13889],78:[0,.68333,.14736,.08334],79:[0,.68333,.02778,.11111],80:[0,.68333,.08222,.08334],81:[.09722,.68333,0,.11111],82:[0,.68333,0,.08334],83:[0,.68333,.075,.13889],84:[0,.68333,.25417,0],85:[0,.68333,.09931,.08334],86:[0,.68333,.08222,0],87:[0,.68333,.08222,.08334],88:[0,.68333,.14643,.13889],89:[.09722,.68333,.08222,.08334],90:[0,.68333,.07944,.13889]},"Fraktur-Regular":{33:[0,.69141,0,0],34:[0,.69141,0,0],38:[0,.69141,0,0],39:[0,.69141,0,0],40:[.24982,.74947,0,0],41:[.24982,.74947,0,0],42:[0,.62119,0,0],43:[.08319,.58283,0,0],44:[0,.10803,0,0],45:[.08319,.58283,0,0],46:[0,.10803,0,0],47:[.24982,.74947,0,0],48:[0,.47534,0,0],49:[0,.47534,0,0],50:[0,.47534,0,0],51:[.18906,.47534,0,0],52:[.18906,.47534,0,0],53:[.18906,.47534,0,0],54:[0,.69141,0,0],55:[.18906,.47534,0,0],56:[0,.69141,0,0],57:[.18906,.47534,0,0],58:[0,.47534,0,0],59:[.12604,.47534,0,0],61:[-.13099,.36866,0,0],63:[0,.69141,0,0],65:[0,.69141,0,0],66:[0,.69141,0,0],67:[0,.69141,0,0],68:[0,.69141,0,0],69:[0,.69141,0,0],70:[.12604,.69141,0,0],71:[0,.69141,0,0],72:[.06302,.69141,0,0],73:[0,.69141,0,0],74:[.12604,.69141,0,0],75:[0,.69141,0,0],76:[0,.69141,0,0],77:[0,.69141,0,0],78:[0,.69141,0,0],79:[0,.69141,0,0],80:[.18906,.69141,0,0],81:[.03781,.69141,0,0],82:[0,.69141,0,0],83:[0,.69141,0,0],84:[0,.69141,0,0],85:[0,.69141,0,0],86:[0,.69141,0,0],87:[0,.69141,0,0],88:[0,.69141,0,0],89:[.18906,.69141,0,0],90:[.12604,.69141,0,0],91:[.24982,.74947,0,0],93:[.24982,.74947,0,0],94:[0,.69141,0,0],97:[0,.47534,0,0],98:[0,.69141,0,0],99:[0,.47534,0,0],100:[0,.62119,0,0],101:[0,.47534,0,0],102:[.18906,.69141,0,0],103:[.18906,.47534,0,0],104:[.18906,.69141,0,0],105:[0,.69141,0,0],106:[0,.69141,0,0],107:[0,.69141,0,0],108:[0,.69141,0,0],109:[0,.47534,0,0],110:[0,.47534,0,0],111:[0,.47534,0,0],112:[.18906,.52396,0,0],113:[.18906,.47534,0,0],114:[0,.47534,0,0],115:[0,.47534,0,0],116:[0,.62119,0,0],117:[0,.47534,0,0],118:[0,.52396,0,0],119:[0,.52396,0,0],120:[.18906,.47534,0,0],121:[.18906,.47534,0,0],122:[.18906,.47534,0,0],8216:[0,.69141,0,0],8217:[0,.69141,0,0],58112:[0,.62119,0,0],58113:[0,.62119,0,0],58114:[.18906,.69141,0,0],58115:[.18906,.69141,0,0],58116:[.18906,.47534,0,0],58117:[0,.69141,0,0],58118:[0,.62119,0,0],58119:[0,.47534,0,0]},"Main-Bold":{33:[0,.69444,0,0],34:[0,.69444,0,0],35:[.19444,.69444,0,0],36:[.05556,.75,0,0],37:[.05556,.75,0,0],38:[0,.69444,0,0],39:[0,.69444,0,0],40:[.25,.75,0,0],41:[.25,.75,0,0],42:[0,.75,0,0],43:[.13333,.63333,0,0],44:[.19444,.15556,0,0],45:[0,.44444,0,0],46:[0,.15556,0,0],47:[.25,.75,0,0],48:[0,.64444,0,0],49:[0,.64444,0,0],50:[0,.64444,0,0],51:[0,.64444,0,0],52:[0,.64444,0,0],53:[0,.64444,0,0],54:[0,.64444,0,0],55:[0,.64444,0,0],56:[0,.64444,0,0],57:[0,.64444,0,0],58:[0,.44444,0,0],59:[.19444,.44444,0,0],60:[.08556,.58556,0,0],61:[-.10889,.39111,0,0],62:[.08556,.58556,0,0],63:[0,.69444,0,0],64:[0,.69444,0,0],65:[0,.68611,0,0],66:[0,.68611,0,0],67:[0,.68611,0,0],68:[0,.68611,0,0],69:[0,.68611,0,0],70:[0,.68611,0,0],71:[0,.68611,0,0],72:[0,.68611,0,0],73:[0,.68611,0,0],74:[0,.68611,0,0],75:[0,.68611,0,0],76:[0,.68611,0,0],77:[0,.68611,0,0],78:[0,.68611,0,0],79:[0,.68611,0,0],80:[0,.68611,0,0],81:[.19444,.68611,0,0],82:[0,.68611,0,0],83:[0,.68611,0,0],84:[0,.68611,0,0],85:[0,.68611,0,0],86:[0,.68611,.01597,0],87:[0,.68611,.01597,0],88:[0,.68611,0,0],89:[0,.68611,.02875,0],90:[0,.68611,0,0],91:[.25,.75,0,0],92:[.25,.75,0,0],93:[.25,.75,0,0],94:[0,.69444,0,0],95:[.31,.13444,.03194,0],96:[0,.69444,0,0],97:[0,.44444,0,0],98:[0,.69444,0,0],99:[0,.44444,0,0],100:[0,.69444,0,0],101:[0,.44444,0,0],102:[0,.69444,.10903,0],103:[.19444,.44444,.01597,0],104:[0,.69444,0,0],105:[0,.69444,0,0],106:[.19444,.69444,0,0],107:[0,.69444,0,0],108:[0,.69444,0,0],109:[0,.44444,0,0],110:[0,.44444,0,0],111:[0,.44444,0,0],112:[.19444,.44444,0,0],113:[.19444,.44444,0,0],114:[0,.44444,0,0],115:[0,.44444,0,0],116:[0,.63492,0,0],117:[0,.44444,0,0],118:[0,.44444,.01597,0],119:[0,.44444,.01597,0],120:[0,.44444,0,0],121:[.19444,.44444,.01597,0],122:[0,.44444,0,0],123:[.25,.75,0,0],124:[.25,.75,0,0],125:[.25,.75,0,0],126:[.35,.34444,0,0],168:[0,.69444,0,0],172:[0,.44444,0,0],175:[0,.59611,0,0],176:[0,.69444,0,0],177:[.13333,.63333,0,0],180:[0,.69444,0,0],215:[.13333,.63333,0,0],247:[.13333,.63333,0,0],305:[0,.44444,0,0],567:[.19444,.44444,0,0],710:[0,.69444,0,0],711:[0,.63194,0,0],713:[0,.59611,0,0],714:[0,.69444,0,0],715:[0,.69444,0,0],728:[0,.69444,0,0],729:[0,.69444,0,0],730:[0,.69444,0,0],732:[0,.69444,0,0],768:[0,.69444,0,0],769:[0,.69444,0,0],770:[0,.69444,0,0],771:[0,.69444,0,0],772:[0,.59611,0,0],774:[0,.69444,0,0],775:[0,.69444,0,0],776:[0,.69444,0,0],778:[0,.69444,0,0],779:[0,.69444,0,0],780:[0,.63194,0,0],824:[.19444,.69444,0,0],915:[0,.68611,0,0],916:[0,.68611,0,0],920:[0,.68611,0,0],923:[0,.68611,0,0],926:[0,.68611,0,0],928:[0,.68611,0,0],931:[0,.68611,0,0],933:[0,.68611,0,0],934:[0,.68611,0,0],936:[0,.68611,0,0],937:[0,.68611,0,0],8211:[0,.44444,.03194,0],8212:[0,.44444,.03194,0],8216:[0,.69444,0,0],8217:[0,.69444,0,0],8220:[0,.69444,0,0],8221:[0,.69444,0,0],8224:[.19444,.69444,0,0],8225:[.19444,.69444,0,0],8242:[0,.55556,0,0],8407:[0,.72444,.15486,0],8463:[0,.69444,0,0],8465:[0,.69444,0,0],8467:[0,.69444,0,0],8472:[.19444,.44444,0,0],8476:[0,.69444,0,0],8501:[0,.69444,0,0],8592:[-.10889,.39111,0,0],8593:[.19444,.69444,0,0],8594:[-.10889,.39111,0,0],8595:[.19444,.69444,0,0],8596:[-.10889,.39111,0,0],8597:[.25,.75,0,0],8598:[.19444,.69444,0,0],8599:[.19444,.69444,0,0],8600:[.19444,.69444,0,0],8601:[.19444,.69444,0,0],8636:[-.10889,.39111,0,0],8637:[-.10889,.39111,0,0],8640:[-.10889,.39111,0,0],8641:[-.10889,.39111,0,0],8656:[-.10889,.39111,0,0],8657:[.19444,.69444,0,0],8658:[-.10889,.39111,0,0],8659:[.19444,.69444,0,0],8660:[-.10889,.39111,0,0],8661:[.25,.75,0,0],8704:[0,.69444,0,0],8706:[0,.69444,.06389,0],8707:[0,.69444,0,0],8709:[.05556,.75,0,0],8711:[0,.68611,0,0],8712:[.08556,.58556,0,0],8715:[.08556,.58556,0,0],8722:[.13333,.63333,0,0],8723:[.13333,.63333,0,0],8725:[.25,.75,0,0],8726:[.25,.75,0,0],8727:[-.02778,.47222,0,0],8728:[-.02639,.47361,0,0],8729:[-.02639,.47361,0,0],8730:[.18,.82,0,0],8733:[0,.44444,0,0],8734:[0,.44444,0,0],8736:[0,.69224,0,0],8739:[.25,.75,0,0],8741:[.25,.75,0,0],8743:[0,.55556,0,0],8744:[0,.55556,0,0],8745:[0,.55556,0,0],8746:[0,.55556,0,0],8747:[.19444,.69444,.12778,0],8764:[-.10889,.39111,0,0],8768:[.19444,.69444,0,0],8771:[.00222,.50222,0,0],8776:[.02444,.52444,0,0],8781:[.00222,.50222,0,0],8801:[.00222,.50222,0,0],8804:[.19667,.69667,0,0],8805:[.19667,.69667,0,0],8810:[.08556,.58556,0,0],8811:[.08556,.58556,0,0],8826:[.08556,.58556,0,0],8827:[.08556,.58556,0,0],8834:[.08556,.58556,0,0],8835:[.08556,.58556,0,0],8838:[.19667,.69667,0,0],8839:[.19667,.69667,0,0],8846:[0,.55556,0,0],8849:[.19667,.69667,0,0],8850:[.19667,.69667,0,0],8851:[0,.55556,0,0],8852:[0,.55556,0,0],8853:[.13333,.63333,0,0],8854:[.13333,.63333,0,0],8855:[.13333,.63333,0,0],8856:[.13333,.63333,0,0],8857:[.13333,.63333,0,0],8866:[0,.69444,0,0],8867:[0,.69444,0,0],8868:[0,.69444,0,0],8869:[0,.69444,0,0],8900:[-.02639,.47361,0,0],8901:[-.02639,.47361,0,0],8902:[-.02778,.47222,0,0],8968:[.25,.75,0,0],8969:[.25,.75,0,0],8970:[.25,.75,0,0],8971:[.25,.75,0,0],8994:[-.13889,.36111,0,0],8995:[-.13889,.36111,0,0],9651:[.19444,.69444,0,0],9657:[-.02778,.47222,0,0],9661:[.19444,.69444,0,0],9667:[-.02778,.47222,0,0],9711:[.19444,.69444,0,0],9824:[.12963,.69444,0,0],9825:[.12963,.69444,0,0],9826:[.12963,.69444,0,0],9827:[.12963,.69444,0,0],9837:[0,.75,0,0],9838:[.19444,.69444,0,0],9839:[.19444,.69444,0,0],10216:[.25,.75,0,0],10217:[.25,.75,0,0],10815:[0,.68611,0,0],10927:[.19667,.69667,0,0],10928:[.19667,.69667,0,0]},"Main-Italic":{33:[0,.69444,.12417,0],34:[0,.69444,.06961,0],35:[.19444,.69444,.06616,0],37:[.05556,.75,.13639,0],38:[0,.69444,.09694,0],39:[0,.69444,.12417,0],40:[.25,.75,.16194,0],41:[.25,.75,.03694,0],42:[0,.75,.14917,0],43:[.05667,.56167,.03694,0],44:[.19444,.10556,0,0],45:[0,.43056,.02826,0],46:[0,.10556,0,0],47:[.25,.75,.16194,0],48:[0,.64444,.13556,0],49:[0,.64444,.13556,0],50:[0,.64444,.13556,0],51:[0,.64444,.13556,0],52:[.19444,.64444,.13556,0],53:[0,.64444,.13556,0],54:[0,.64444,.13556,0],55:[.19444,.64444,.13556,0],56:[0,.64444,.13556,0],57:[0,.64444,.13556,0],58:[0,.43056,.0582,0],59:[.19444,.43056,.0582,0],61:[-.13313,.36687,.06616,0],63:[0,.69444,.1225,0],64:[0,.69444,.09597,0],65:[0,.68333,0,0],66:[0,.68333,.10257,0],67:[0,.68333,.14528,0],68:[0,.68333,.09403,0],69:[0,.68333,.12028,0],70:[0,.68333,.13305,0],71:[0,.68333,.08722,0],72:[0,.68333,.16389,0],73:[0,.68333,.15806,0],74:[0,.68333,.14028,0],75:[0,.68333,.14528,0],76:[0,.68333,0,0],77:[0,.68333,.16389,0],78:[0,.68333,.16389,0],79:[0,.68333,.09403,0],80:[0,.68333,.10257,0],81:[.19444,.68333,.09403,0],82:[0,.68333,.03868,0],83:[0,.68333,.11972,0],84:[0,.68333,.13305,0],85:[0,.68333,.16389,0],86:[0,.68333,.18361,0],87:[0,.68333,.18361,0],88:[0,.68333,.15806,0],89:[0,.68333,.19383,0],90:[0,.68333,.14528,0],91:[.25,.75,.1875,0],93:[.25,.75,.10528,0],94:[0,.69444,.06646,0],95:[.31,.12056,.09208,0],97:[0,.43056,.07671,0],98:[0,.69444,.06312,0],99:[0,.43056,.05653,0],100:[0,.69444,.10333,0],101:[0,.43056,.07514,0],102:[.19444,.69444,.21194,0],103:[.19444,.43056,.08847,0],104:[0,.69444,.07671,0],105:[0,.65536,.1019,0],106:[.19444,.65536,.14467,0],107:[0,.69444,.10764,0],108:[0,.69444,.10333,0],109:[0,.43056,.07671,0],110:[0,.43056,.07671,0],111:[0,.43056,.06312,0],112:[.19444,.43056,.06312,0],113:[.19444,.43056,.08847,0],114:[0,.43056,.10764,0],115:[0,.43056,.08208,0],116:[0,.61508,.09486,0],117:[0,.43056,.07671,0],118:[0,.43056,.10764,0],119:[0,.43056,.10764,0],120:[0,.43056,.12042,0],121:[.19444,.43056,.08847,0],122:[0,.43056,.12292,0],126:[.35,.31786,.11585,0],163:[0,.69444,0,0],305:[0,.43056,0,.02778],567:[.19444,.43056,0,.08334],768:[0,.69444,0,0],769:[0,.69444,.09694,0],770:[0,.69444,.06646,0],771:[0,.66786,.11585,0],772:[0,.56167,.10333,0],774:[0,.69444,.10806,0],775:[0,.66786,.11752,0],776:[0,.66786,.10474,0],778:[0,.69444,0,0],779:[0,.69444,.1225,0],780:[0,.62847,.08295,0],915:[0,.68333,.13305,0],916:[0,.68333,0,0],920:[0,.68333,.09403,0],923:[0,.68333,0,0],926:[0,.68333,.15294,0],928:[0,.68333,.16389,0],931:[0,.68333,.12028,0],933:[0,.68333,.11111,0],934:[0,.68333,.05986,0],936:[0,.68333,.11111,0],937:[0,.68333,.10257,0],8211:[0,.43056,.09208,0],8212:[0,.43056,.09208,0],8216:[0,.69444,.12417,0],8217:[0,.69444,.12417,0],8220:[0,.69444,.1685,0],8221:[0,.69444,.06961,0],8463:[0,.68889,0,0]},"Main-Regular":{32:[0,0,0,0],33:[0,.69444,0,0],34:[0,.69444,0,0],35:[.19444,.69444,0,0],36:[.05556,.75,0,0],37:[.05556,.75,0,0],38:[0,.69444,0,0],39:[0,.69444,0,0],40:[.25,.75,0,0],41:[.25,.75,0,0],42:[0,.75,0,0],43:[.08333,.58333,0,0],44:[.19444,.10556,0,0],45:[0,.43056,0,0],46:[0,.10556,0,0],47:[.25,.75,0,0],48:[0,.64444,0,0],49:[0,.64444,0,0],50:[0,.64444,0,0],51:[0,.64444,0,0],52:[0,.64444,0,0],53:[0,.64444,0,0],54:[0,.64444,0,0],55:[0,.64444,0,0],56:[0,.64444,0,0],57:[0,.64444,0,0],58:[0,.43056,0,0],59:[.19444,.43056,0,0],60:[.0391,.5391,0,0],61:[-.13313,.36687,0,0],62:[.0391,.5391,0,0],63:[0,.69444,0,0],64:[0,.69444,0,0],65:[0,.68333,0,0],66:[0,.68333,0,0],67:[0,.68333,0,0],68:[0,.68333,0,0],69:[0,.68333,0,0],70:[0,.68333,0,0],71:[0,.68333,0,0],72:[0,.68333,0,0],73:[0,.68333,0,0],74:[0,.68333,0,0],75:[0,.68333,0,0],76:[0,.68333,0,0],77:[0,.68333,0,0],78:[0,.68333,0,0],79:[0,.68333,0,0],80:[0,.68333,0,0],81:[.19444,.68333,0,0],82:[0,.68333,0,0],83:[0,.68333,0,0],84:[0,.68333,0,0],85:[0,.68333,0,0],86:[0,.68333,.01389,0],87:[0,.68333,.01389,0],88:[0,.68333,0,0],89:[0,.68333,.025,0],90:[0,.68333,0,0],91:[.25,.75,0,0],92:[.25,.75,0,0],93:[.25,.75,0,0],94:[0,.69444,0,0],95:[.31,.12056,.02778,0],96:[0,.69444,0,0],97:[0,.43056,0,0],98:[0,.69444,0,0],99:[0,.43056,0,0],100:[0,.69444,0,0],101:[0,.43056,0,0],102:[0,.69444,.07778,0],103:[.19444,.43056,.01389,0],104:[0,.69444,0,0],105:[0,.66786,0,0],106:[.19444,.66786,0,0],107:[0,.69444,0,0],108:[0,.69444,0,0],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,0],112:[.19444,.43056,0,0],113:[.19444,.43056,0,0],114:[0,.43056,0,0],115:[0,.43056,0,0],116:[0,.61508,0,0],117:[0,.43056,0,0],118:[0,.43056,.01389,0],119:[0,.43056,.01389,0],120:[0,.43056,0,0],121:[.19444,.43056,.01389,0],122:[0,.43056,0,0],123:[.25,.75,0,0],124:[.25,.75,0,0],125:[.25,.75,0,0],126:[.35,.31786,0,0],160:[0,0,0,0],168:[0,.66786,0,0],172:[0,.43056,0,0],175:[0,.56778,0,0],176:[0,.69444,0,0],177:[.08333,.58333,0,0],180:[0,.69444,0,0],215:[.08333,.58333,0,0],247:[.08333,.58333,0,0],305:[0,.43056,0,0],567:[.19444,.43056,0,0],710:[0,.69444,0,0],711:[0,.62847,0,0],713:[0,.56778,0,0],714:[0,.69444,0,0],715:[0,.69444,0,0],728:[0,.69444,0,0],729:[0,.66786,0,0],730:[0,.69444,0,0],732:[0,.66786,0,0],768:[0,.69444,0,0],769:[0,.69444,0,0],770:[0,.69444,0,0],771:[0,.66786,0,0],772:[0,.56778,0,0],774:[0,.69444,0,0],775:[0,.66786,0,0],776:[0,.66786,0,0],778:[0,.69444,0,0],779:[0,.69444,0,0],780:[0,.62847,0,0],824:[.19444,.69444,0,0],915:[0,.68333,0,0],916:[0,.68333,0,0],920:[0,.68333,0,0],923:[0,.68333,0,0],926:[0,.68333,0,0],928:[0,.68333,0,0],931:[0,.68333,0,0],933:[0,.68333,0,0],934:[0,.68333,0,0],936:[0,.68333,0,0],937:[0,.68333,0,0],8211:[0,.43056,.02778,0],8212:[0,.43056,.02778,0],8216:[0,.69444,0,0],8217:[0,.69444,0,0],8220:[0,.69444,0,0],8221:[0,.69444,0,0],8224:[.19444,.69444,0,0],8225:[.19444,.69444,0,0],8230:[0,.12,0,0],8242:[0,.55556,0,0],8407:[0,.71444,.15382,0],8463:[0,.68889,0,0],8465:[0,.69444,0,0],8467:[0,.69444,0,.11111],8472:[.19444,.43056,0,.11111],8476:[0,.69444,0,0],8501:[0,.69444,0,0],8592:[-.13313,.36687,0,0],8593:[.19444,.69444,0,0],8594:[-.13313,.36687,0,0],8595:[.19444,.69444,0,0],8596:[-.13313,.36687,0,0],8597:[.25,.75,0,0],8598:[.19444,.69444,0,0],8599:[.19444,.69444,0,0],8600:[.19444,.69444,0,0],8601:[.19444,.69444,0,0],8614:[.011,.511,0,0],8617:[.011,.511,0,0],8618:[.011,.511,0,0],8636:[-.13313,.36687,0,0],8637:[-.13313,.36687,0,0],8640:[-.13313,.36687,0,0],8641:[-.13313,.36687,0,0],8652:[.011,.671,0,0],8656:[-.13313,.36687,0,0],8657:[.19444,.69444,0,0],8658:[-.13313,.36687,0,0],8659:[.19444,.69444,0,0],8660:[-.13313,.36687,0,0],8661:[.25,.75,0,0],8704:[0,.69444,0,0],8706:[0,.69444,.05556,.08334],8707:[0,.69444,0,0],8709:[.05556,.75,0,0],8711:[0,.68333,0,0],8712:[.0391,.5391,0,0],8715:[.0391,.5391,0,0],8722:[.08333,.58333,0,0],8723:[.08333,.58333,0,0],8725:[.25,.75,0,0],8726:[.25,.75,0,0],8727:[-.03472,.46528,0,0],8728:[-.05555,.44445,0,0],8729:[-.05555,.44445,0,0],8730:[.2,.8,0,0],8733:[0,.43056,0,0],8734:[0,.43056,0,0],8736:[0,.69224,0,0],8739:[.25,.75,0,0],8741:[.25,.75,0,0],8743:[0,.55556,0,0],8744:[0,.55556,0,0],8745:[0,.55556,0,0],8746:[0,.55556,0,0],8747:[.19444,.69444,.11111,0],8764:[-.13313,.36687,0,0],8768:[.19444,.69444,0,0],8771:[-.03625,.46375,0,0],8773:[-.022,.589,0,0],8776:[-.01688,.48312,0,0],8781:[-.03625,.46375,0,0],8784:[-.133,.67,0,0],8800:[.215,.716,0,0],8801:[-.03625,.46375,0,0],8804:[.13597,.63597,0,0],8805:[.13597,.63597,0,0],8810:[.0391,.5391,0,0],8811:[.0391,.5391,0,0],8826:[.0391,.5391,0,0],8827:[.0391,.5391,0,0],8834:[.0391,.5391,0,0],8835:[.0391,.5391,0,0],8838:[.13597,.63597,0,0],8839:[.13597,.63597,0,0],8846:[0,.55556,0,0],8849:[.13597,.63597,0,0],8850:[.13597,.63597,0,0],8851:[0,.55556,0,0],8852:[0,.55556,0,0],8853:[.08333,.58333,0,0],8854:[.08333,.58333,0,0],8855:[.08333,.58333,0,0],8856:[.08333,.58333,0,0],8857:[.08333,.58333,0,0],8866:[0,.69444,0,0],8867:[0,.69444,0,0],8868:[0,.69444,0,0],8869:[0,.69444,0,0],8872:[.249,.75,0,0],8900:[-.05555,.44445,0,0],8901:[-.05555,.44445,0,0],8902:[-.03472,.46528,0,0],8904:[.005,.505,0,0],8942:[.03,.9,0,0],8943:[-.19,.31,0,0],8945:[-.1,.82,0,0],8968:[.25,.75,0,0],8969:[.25,.75,0,0],8970:[.25,.75,0,0],8971:[.25,.75,0,0],8994:[-.14236,.35764,0,0],8995:[-.14236,.35764,0,0],9136:[.244,.744,0,0],9137:[.244,.744,0,0],9651:[.19444,.69444,0,0],9657:[-.03472,.46528,0,0],9661:[.19444,.69444,0,0],9667:[-.03472,.46528,0,0],9711:[.19444,.69444,0,0],9824:[.12963,.69444,0,0],9825:[.12963,.69444,0,0],9826:[.12963,.69444,0,0],9827:[.12963,.69444,0,0],9837:[0,.75,0,0],9838:[.19444,.69444,0,0],9839:[.19444,.69444,0,0],10216:[.25,.75,0,0],10217:[.25,.75,0,0],10222:[.244,.744,0,0],10223:[.244,.744,0,0],10229:[.011,.511,0,0],10230:[.011,.511,0,0],10231:[.011,.511,0,0],10232:[.024,.525,0,0],10233:[.024,.525,0,0],10234:[.024,.525,0,0],10236:[.011,.511,0,0],10815:[0,.68333,0,0],10927:[.13597,.63597,0,0],10928:[.13597,.63597,0,0]},"Math-BoldItalic":{47:[.19444,.69444,0,0],65:[0,.68611,0,0],66:[0,.68611,.04835,0],67:[0,.68611,.06979,0],68:[0,.68611,.03194,0],69:[0,.68611,.05451,0],70:[0,.68611,.15972,0],71:[0,.68611,0,0],72:[0,.68611,.08229,0],73:[0,.68611,.07778,0],74:[0,.68611,.10069,0],75:[0,.68611,.06979,0],76:[0,.68611,0,0],77:[0,.68611,.11424,0],78:[0,.68611,.11424,0],79:[0,.68611,.03194,0],80:[0,.68611,.15972,0],81:[.19444,.68611,0,0],82:[0,.68611,.00421,0],83:[0,.68611,.05382,0],84:[0,.68611,.15972,0],85:[0,.68611,.11424,0],86:[0,.68611,.25555,0],87:[0,.68611,.15972,0],88:[0,.68611,.07778,0],89:[0,.68611,.25555,0],90:[0,.68611,.06979,0],97:[0,.44444,0,0],98:[0,.69444,0,0],99:[0,.44444,0,0],100:[0,.69444,0,0],101:[0,.44444,0,0],102:[.19444,.69444,.11042,0],103:[.19444,.44444,.03704,0],104:[0,.69444,0,0],105:[0,.69326,0,0],106:[.19444,.69326,.0622,0],107:[0,.69444,.01852,0],108:[0,.69444,.0088,0],109:[0,.44444,0,0],110:[0,.44444,0,0],111:[0,.44444,0,0],112:[.19444,.44444,0,0],113:[.19444,.44444,.03704,0],114:[0,.44444,.03194,0],115:[0,.44444,0,0],116:[0,.63492,0,0],117:[0,.44444,0,0],118:[0,.44444,.03704,0],119:[0,.44444,.02778,0],120:[0,.44444,0,0],121:[.19444,.44444,.03704,0],122:[0,.44444,.04213,0],915:[0,.68611,.15972,0],916:[0,.68611,0,0],920:[0,.68611,.03194,0],923:[0,.68611,0,0],926:[0,.68611,.07458,0],928:[0,.68611,.08229,0],931:[0,.68611,.05451,0],933:[0,.68611,.15972,0],934:[0,.68611,0,0],936:[0,.68611,.11653,0],937:[0,.68611,.04835,0],945:[0,.44444,0,0],946:[.19444,.69444,.03403,0],947:[.19444,.44444,.06389,0],948:[0,.69444,.03819,0],949:[0,.44444,0,0],950:[.19444,.69444,.06215,0],951:[.19444,.44444,.03704,0],952:[0,.69444,.03194,0],953:[0,.44444,0,0],954:[0,.44444,0,0],955:[0,.69444,0,0],956:[.19444,.44444,0,0],957:[0,.44444,.06898,0],958:[.19444,.69444,.03021,0],959:[0,.44444,0,0],960:[0,.44444,.03704,0],961:[.19444,.44444,0,0],962:[.09722,.44444,.07917,0],963:[0,.44444,.03704,0],964:[0,.44444,.13472,0],965:[0,.44444,.03704,0],966:[.19444,.44444,0,0],967:[.19444,.44444,0,0],968:[.19444,.69444,.03704,0],969:[0,.44444,.03704,0],977:[0,.69444,0,0],981:[.19444,.69444,0,0],982:[0,.44444,.03194,0],1009:[.19444,.44444,0,0],1013:[0,.44444,0,0]},"Math-Italic":{47:[.19444,.69444,0,0],65:[0,.68333,0,.13889],66:[0,.68333,.05017,.08334],67:[0,.68333,.07153,.08334],68:[0,.68333,.02778,.05556],69:[0,.68333,.05764,.08334],70:[0,.68333,.13889,.08334],71:[0,.68333,0,.08334],72:[0,.68333,.08125,.05556],73:[0,.68333,.07847,.11111],74:[0,.68333,.09618,.16667],75:[0,.68333,.07153,.05556],76:[0,.68333,0,.02778],77:[0,.68333,.10903,.08334],78:[0,.68333,.10903,.08334],79:[0,.68333,.02778,.08334],80:[0,.68333,.13889,.08334],81:[.19444,.68333,0,.08334],82:[0,.68333,.00773,.08334],83:[0,.68333,.05764,.08334],84:[0,.68333,.13889,.08334],85:[0,.68333,.10903,.02778],86:[0,.68333,.22222,0],87:[0,.68333,.13889,0],88:[0,.68333,.07847,.08334],89:[0,.68333,.22222,0],90:[0,.68333,.07153,.08334],97:[0,.43056,0,0],98:[0,.69444,0,0],99:[0,.43056,0,.05556],100:[0,.69444,0,.16667],101:[0,.43056,0,.05556],102:[.19444,.69444,.10764,.16667],103:[.19444,.43056,.03588,.02778],104:[0,.69444,0,0],105:[0,.65952,0,0],106:[.19444,.65952,.05724,0],107:[0,.69444,.03148,0],108:[0,.69444,.01968,.08334],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,.05556],112:[.19444,.43056,0,.08334],113:[.19444,.43056,.03588,.08334],114:[0,.43056,.02778,.05556],115:[0,.43056,0,.05556],116:[0,.61508,0,.08334],117:[0,.43056,0,.02778],118:[0,.43056,.03588,.02778],119:[0,.43056,.02691,.08334],120:[0,.43056,0,.02778],121:[.19444,.43056,.03588,.05556],122:[0,.43056,.04398,.05556],915:[0,.68333,.13889,.08334],916:[0,.68333,0,.16667],920:[0,.68333,.02778,.08334],923:[0,.68333,0,.16667],926:[0,.68333,.07569,.08334],928:[0,.68333,.08125,.05556],931:[0,.68333,.05764,.08334],933:[0,.68333,.13889,.05556],934:[0,.68333,0,.08334],936:[0,.68333,.11,.05556],937:[0,.68333,.05017,.08334],945:[0,.43056,.0037,.02778],946:[.19444,.69444,.05278,.08334],947:[.19444,.43056,.05556,0],948:[0,.69444,.03785,.05556],949:[0,.43056,0,.08334],950:[.19444,.69444,.07378,.08334],951:[.19444,.43056,.03588,.05556],952:[0,.69444,.02778,.08334],953:[0,.43056,0,.05556],954:[0,.43056,0,0],955:[0,.69444,0,0],956:[.19444,.43056,0,.02778],957:[0,.43056,.06366,.02778],958:[.19444,.69444,.04601,.11111],959:[0,.43056,0,.05556],960:[0,.43056,.03588,0],961:[.19444,.43056,0,.08334],962:[.09722,.43056,.07986,.08334],963:[0,.43056,.03588,0],964:[0,.43056,.1132,.02778],965:[0,.43056,.03588,.02778],966:[.19444,.43056,0,.08334],967:[.19444,.43056,0,.05556],968:[.19444,.69444,.03588,.11111],969:[0,.43056,.03588,0],977:[0,.69444,0,.08334],981:[.19444,.69444,0,.08334],982:[0,.43056,.02778,0],1009:[.19444,.43056,0,.08334],1013:[0,.43056,0,.05556]},"Math-Regular":{65:[0,.68333,0,.13889],66:[0,.68333,.05017,.08334],67:[0,.68333,.07153,.08334],68:[0,.68333,.02778,.05556],69:[0,.68333,.05764,.08334],70:[0,.68333,.13889,.08334],71:[0,.68333,0,.08334],72:[0,.68333,.08125,.05556],73:[0,.68333,.07847,.11111],74:[0,.68333,.09618,.16667],75:[0,.68333,.07153,.05556],76:[0,.68333,0,.02778],77:[0,.68333,.10903,.08334],78:[0,.68333,.10903,.08334],79:[0,.68333,.02778,.08334],80:[0,.68333,.13889,.08334],81:[.19444,.68333,0,.08334],82:[0,.68333,.00773,.08334],83:[0,.68333,.05764,.08334],84:[0,.68333,.13889,.08334],85:[0,.68333,.10903,.02778],86:[0,.68333,.22222,0],87:[0,.68333,.13889,0],88:[0,.68333,.07847,.08334],89:[0,.68333,.22222,0],90:[0,.68333,.07153,.08334],97:[0,.43056,0,0],98:[0,.69444,0,0],99:[0,.43056,0,.05556],100:[0,.69444,0,.16667],101:[0,.43056,0,.05556],102:[.19444,.69444,.10764,.16667],103:[.19444,.43056,.03588,.02778],104:[0,.69444,0,0],105:[0,.65952,0,0],106:[.19444,.65952,.05724,0],107:[0,.69444,.03148,0],108:[0,.69444,.01968,.08334],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,.05556],112:[.19444,.43056,0,.08334],113:[.19444,.43056,.03588,.08334],114:[0,.43056,.02778,.05556],115:[0,.43056,0,.05556],116:[0,.61508,0,.08334],117:[0,.43056,0,.02778],118:[0,.43056,.03588,.02778],119:[0,.43056,.02691,.08334],120:[0,.43056,0,.02778],121:[.19444,.43056,.03588,.05556],122:[0,.43056,.04398,.05556],915:[0,.68333,.13889,.08334],916:[0,.68333,0,.16667],920:[0,.68333,.02778,.08334],923:[0,.68333,0,.16667],926:[0,.68333,.07569,.08334],928:[0,.68333,.08125,.05556],931:[0,.68333,.05764,.08334],933:[0,.68333,.13889,.05556],934:[0,.68333,0,.08334],936:[0,.68333,.11,.05556],937:[0,.68333,.05017,.08334],945:[0,.43056,.0037,.02778],946:[.19444,.69444,.05278,.08334],947:[.19444,.43056,.05556,0],948:[0,.69444,.03785,.05556],949:[0,.43056,0,.08334],950:[.19444,.69444,.07378,.08334],951:[.19444,.43056,.03588,.05556],952:[0,.69444,.02778,.08334],953:[0,.43056,0,.05556],954:[0,.43056,0,0],955:[0,.69444,0,0],956:[.19444,.43056,0,.02778],957:[0,.43056,.06366,.02778],958:[.19444,.69444,.04601,.11111],959:[0,.43056,0,.05556],960:[0,.43056,.03588,0],961:[.19444,.43056,0,.08334],962:[.09722,.43056,.07986,.08334],963:[0,.43056,.03588,0],964:[0,.43056,.1132,.02778],965:[0,.43056,.03588,.02778],966:[.19444,.43056,0,.08334],967:[.19444,.43056,0,.05556],968:[.19444,.69444,.03588,.11111],969:[0,.43056,.03588,0],977:[0,.69444,0,.08334],981:[.19444,.69444,0,.08334],982:[0,.43056,.02778,0],1009:[.19444,.43056,0,.08334],1013:[0,.43056,0,.05556]},"SansSerif-Regular":{33:[0,.69444,0,0],34:[0,.69444,0,0],35:[.19444,.69444,0,0],36:[.05556,.75,0,0],37:[.05556,.75,0,0],38:[0,.69444,0,0],39:[0,.69444,0,0],40:[.25,.75,0,0],41:[.25,.75,0,0],42:[0,.75,0,0],43:[.08333,.58333,0,0],44:[.125,.08333,0,0],45:[0,.44444,0,0],46:[0,.08333,0,0],47:[.25,.75,0,0],48:[0,.65556,0,0],49:[0,.65556,0,0],50:[0,.65556,0,0],51:[0,.65556,0,0],52:[0,.65556,0,0],53:[0,.65556,0,0],54:[0,.65556,0,0],55:[0,.65556,0,0],56:[0,.65556,0,0],57:[0,.65556,0,0],58:[0,.44444,0,0],59:[.125,.44444,0,0],61:[-.13,.37,0,0],63:[0,.69444,0,0],64:[0,.69444,0,0],65:[0,.69444,0,0],66:[0,.69444,0,0],67:[0,.69444,0,0],68:[0,.69444,0,0],69:[0,.69444,0,0],70:[0,.69444,0,0],71:[0,.69444,0,0],72:[0,.69444,0,0],73:[0,.69444,0,0],74:[0,.69444,0,0],75:[0,.69444,0,0],76:[0,.69444,0,0],77:[0,.69444,0,0],78:[0,.69444,0,0],79:[0,.69444,0,0],80:[0,.69444,0,0],81:[.125,.69444,0,0],82:[0,.69444,0,0],83:[0,.69444,0,0],84:[0,.69444,0,0],85:[0,.69444,0,0],86:[0,.69444,.01389,0],87:[0,.69444,.01389,0],88:[0,.69444,0,0],89:[0,.69444,.025,0],90:[0,.69444,0,0],91:[.25,.75,0,0],93:[.25,.75,0,0],94:[0,.69444,0,0],95:[.35,.09444,.02778,0],97:[0,.44444,0,0],98:[0,.69444,0,0],99:[0,.44444,0,0],100:[0,.69444,0,0],101:[0,.44444,0,0],102:[0,.69444,.06944,0],103:[.19444,.44444,.01389,0],104:[0,.69444,0,0],105:[0,.67937,0,0],106:[.19444,.67937,0,0],107:[0,.69444,0,0],108:[0,.69444,0,0],109:[0,.44444,0,0],110:[0,.44444,0,0],111:[0,.44444,0,0],112:[.19444,.44444,0,0],113:[.19444,.44444,0,0],114:[0,.44444,.01389,0],115:[0,.44444,0,0],116:[0,.57143,0,0],117:[0,.44444,0,0],118:[0,.44444,.01389,0],119:[0,.44444,.01389,0],120:[0,.44444,0,0],121:[.19444,.44444,.01389,0],122:[0,.44444,0,0],126:[.35,.32659,0,0],305:[0,.44444,0,0],567:[.19444,.44444,0,0],768:[0,.69444,0,0],769:[0,.69444,0,0],770:[0,.69444,0,0],771:[0,.67659,0,0],772:[0,.60889,0,0],774:[0,.69444,0,0],775:[0,.67937,0,0],776:[0,.67937,0,0],778:[0,.69444,0,0],779:[0,.69444,0,0],780:[0,.63194,0,0],915:[0,.69444,0,0],916:[0,.69444,0,0],920:[0,.69444,0,0],923:[0,.69444,0,0],926:[0,.69444,0,0],928:[0,.69444,0,0],931:[0,.69444,0,0],933:[0,.69444,0,0],934:[0,.69444,0,0],936:[0,.69444,0,0],937:[0,.69444,0,0],8211:[0,.44444,.02778,0],8212:[0,.44444,.02778,0],8216:[0,.69444,0,0],8217:[0,.69444,0,0],8220:[0,.69444,0,0],8221:[0,.69444,0,0]},"Script-Regular":{65:[0,.7,.22925,0],66:[0,.7,.04087,0],67:[0,.7,.1689,0],68:[0,.7,.09371,0],69:[0,.7,.18583,0],70:[0,.7,.13634,0],71:[0,.7,.17322,0],72:[0,.7,.29694,0],73:[0,.7,.19189,0],74:[.27778,.7,.19189,0],75:[0,.7,.31259,0],76:[0,.7,.19189,0],77:[0,.7,.15981,0],78:[0,.7,.3525,0],79:[0,.7,.08078,0],80:[0,.7,.08078,0],81:[0,.7,.03305,0],82:[0,.7,.06259,0],83:[0,.7,.19189,0],84:[0,.7,.29087,0],85:[0,.7,.25815,0],86:[0,.7,.27523,0],87:[0,.7,.27523,0],88:[0,.7,.26006,0],89:[0,.7,.2939,0],90:[0,.7,.24037,0]},"Size1-Regular":{40:[.35001,.85,0,0],41:[.35001,.85,0,0],47:[.35001,.85,0,0],91:[.35001,.85,0,0],92:[.35001,.85,0,0],93:[.35001,.85,0,0],123:[.35001,.85,0,0],125:[.35001,.85,0,0],710:[0,.72222,0,0],732:[0,.72222,0,0],770:[0,.72222,0,0],771:[0,.72222,0,0],8214:[-99e-5,.601,0,0],8593:[1e-5,.6,0,0],8595:[1e-5,.6,0,0],8657:[1e-5,.6,0,0],8659:[1e-5,.6,0,0],8719:[.25001,.75,0,0],8720:[.25001,.75,0,0],8721:[.25001,.75,0,0],8730:[.35001,.85,0,0],8739:[-.00599,.606,0,0],8741:[-.00599,.606,0,0],8747:[.30612,.805,.19445,0],8748:[.306,.805,.19445,0],8749:[.306,.805,.19445,0],8750:[.30612,.805,.19445,0],8896:[.25001,.75,0,0],8897:[.25001,.75,0,0],8898:[.25001,.75,0,0],8899:[.25001,.75,0,0],8968:[.35001,.85,0,0],8969:[.35001,.85,0,0],8970:[.35001,.85,0,0],8971:[.35001,.85,0,0],9168:[-99e-5,.601,0,0],10216:[.35001,.85,0,0],10217:[.35001,.85,0,0],10752:[.25001,.75,0,0],10753:[.25001,.75,0,0],10754:[.25001,.75,0,0],10756:[.25001,.75,0,0],10758:[.25001,.75,0,0]},"Size2-Regular":{40:[.65002,1.15,0,0],41:[.65002,1.15,0,0],47:[.65002,1.15,0,0],91:[.65002,1.15,0,0],92:[.65002,1.15,0,0],93:[.65002,1.15,0,0],123:[.65002,1.15,0,0],125:[.65002,1.15,0,0],710:[0,.75,0,0],732:[0,.75,0,0],770:[0,.75,0,0],771:[0,.75,0,0],8719:[.55001,1.05,0,0],8720:[.55001,1.05,0,0],8721:[.55001,1.05,0,0],8730:[.65002,1.15,0,0],8747:[.86225,1.36,.44445,0],8748:[.862,1.36,.44445,0],8749:[.862,1.36,.44445,0],8750:[.86225,1.36,.44445,0],8896:[.55001,1.05,0,0],8897:[.55001,1.05,0,0],8898:[.55001,1.05,0,0],8899:[.55001,1.05,0,0],8968:[.65002,1.15,0,0],8969:[.65002,1.15,0,0],8970:[.65002,1.15,0,0],8971:[.65002,1.15,0,0],10216:[.65002,1.15,0,0],10217:[.65002,1.15,0,0],10752:[.55001,1.05,0,0],10753:[.55001,1.05,0,0],10754:[.55001,1.05,0,0], +10756:[.55001,1.05,0,0],10758:[.55001,1.05,0,0]},"Size3-Regular":{40:[.95003,1.45,0,0],41:[.95003,1.45,0,0],47:[.95003,1.45,0,0],91:[.95003,1.45,0,0],92:[.95003,1.45,0,0],93:[.95003,1.45,0,0],123:[.95003,1.45,0,0],125:[.95003,1.45,0,0],710:[0,.75,0,0],732:[0,.75,0,0],770:[0,.75,0,0],771:[0,.75,0,0],8730:[.95003,1.45,0,0],8968:[.95003,1.45,0,0],8969:[.95003,1.45,0,0],8970:[.95003,1.45,0,0],8971:[.95003,1.45,0,0],10216:[.95003,1.45,0,0],10217:[.95003,1.45,0,0]},"Size4-Regular":{40:[1.25003,1.75,0,0],41:[1.25003,1.75,0,0],47:[1.25003,1.75,0,0],91:[1.25003,1.75,0,0],92:[1.25003,1.75,0,0],93:[1.25003,1.75,0,0],123:[1.25003,1.75,0,0],125:[1.25003,1.75,0,0],710:[0,.825,0,0],732:[0,.825,0,0],770:[0,.825,0,0],771:[0,.825,0,0],8730:[1.25003,1.75,0,0],8968:[1.25003,1.75,0,0],8969:[1.25003,1.75,0,0],8970:[1.25003,1.75,0,0],8971:[1.25003,1.75,0,0],9115:[.64502,1.155,0,0],9116:[1e-5,.6,0,0],9117:[.64502,1.155,0,0],9118:[.64502,1.155,0,0],9119:[1e-5,.6,0,0],9120:[.64502,1.155,0,0],9121:[.64502,1.155,0,0],9122:[-99e-5,.601,0,0],9123:[.64502,1.155,0,0],9124:[.64502,1.155,0,0],9125:[-99e-5,.601,0,0],9126:[.64502,1.155,0,0],9127:[1e-5,.9,0,0],9128:[.65002,1.15,0,0],9129:[.90001,0,0,0],9130:[0,.3,0,0],9131:[1e-5,.9,0,0],9132:[.65002,1.15,0,0],9133:[.90001,0,0,0],9143:[.88502,.915,0,0],10216:[1.25003,1.75,0,0],10217:[1.25003,1.75,0,0],57344:[-.00499,.605,0,0],57345:[-.00499,.605,0,0],57680:[0,.12,0,0],57681:[0,.12,0,0],57682:[0,.12,0,0],57683:[0,.12,0,0]},"Typewriter-Regular":{33:[0,.61111,0,0],34:[0,.61111,0,0],35:[0,.61111,0,0],36:[.08333,.69444,0,0],37:[.08333,.69444,0,0],38:[0,.61111,0,0],39:[0,.61111,0,0],40:[.08333,.69444,0,0],41:[.08333,.69444,0,0],42:[0,.52083,0,0],43:[-.08056,.53055,0,0],44:[.13889,.125,0,0],45:[-.08056,.53055,0,0],46:[0,.125,0,0],47:[.08333,.69444,0,0],48:[0,.61111,0,0],49:[0,.61111,0,0],50:[0,.61111,0,0],51:[0,.61111,0,0],52:[0,.61111,0,0],53:[0,.61111,0,0],54:[0,.61111,0,0],55:[0,.61111,0,0],56:[0,.61111,0,0],57:[0,.61111,0,0],58:[0,.43056,0,0],59:[.13889,.43056,0,0],60:[-.05556,.55556,0,0],61:[-.19549,.41562,0,0],62:[-.05556,.55556,0,0],63:[0,.61111,0,0],64:[0,.61111,0,0],65:[0,.61111,0,0],66:[0,.61111,0,0],67:[0,.61111,0,0],68:[0,.61111,0,0],69:[0,.61111,0,0],70:[0,.61111,0,0],71:[0,.61111,0,0],72:[0,.61111,0,0],73:[0,.61111,0,0],74:[0,.61111,0,0],75:[0,.61111,0,0],76:[0,.61111,0,0],77:[0,.61111,0,0],78:[0,.61111,0,0],79:[0,.61111,0,0],80:[0,.61111,0,0],81:[.13889,.61111,0,0],82:[0,.61111,0,0],83:[0,.61111,0,0],84:[0,.61111,0,0],85:[0,.61111,0,0],86:[0,.61111,0,0],87:[0,.61111,0,0],88:[0,.61111,0,0],89:[0,.61111,0,0],90:[0,.61111,0,0],91:[.08333,.69444,0,0],92:[.08333,.69444,0,0],93:[.08333,.69444,0,0],94:[0,.61111,0,0],95:[.09514,0,0,0],96:[0,.61111,0,0],97:[0,.43056,0,0],98:[0,.61111,0,0],99:[0,.43056,0,0],100:[0,.61111,0,0],101:[0,.43056,0,0],102:[0,.61111,0,0],103:[.22222,.43056,0,0],104:[0,.61111,0,0],105:[0,.61111,0,0],106:[.22222,.61111,0,0],107:[0,.61111,0,0],108:[0,.61111,0,0],109:[0,.43056,0,0],110:[0,.43056,0,0],111:[0,.43056,0,0],112:[.22222,.43056,0,0],113:[.22222,.43056,0,0],114:[0,.43056,0,0],115:[0,.43056,0,0],116:[0,.55358,0,0],117:[0,.43056,0,0],118:[0,.43056,0,0],119:[0,.43056,0,0],120:[0,.43056,0,0],121:[.22222,.43056,0,0],122:[0,.43056,0,0],123:[.08333,.69444,0,0],124:[.08333,.69444,0,0],125:[.08333,.69444,0,0],126:[0,.61111,0,0],127:[0,.61111,0,0],305:[0,.43056,0,0],567:[.22222,.43056,0,0],768:[0,.61111,0,0],769:[0,.61111,0,0],770:[0,.61111,0,0],771:[0,.61111,0,0],772:[0,.56555,0,0],774:[0,.61111,0,0],776:[0,.61111,0,0],778:[0,.61111,0,0],780:[0,.56597,0,0],915:[0,.61111,0,0],916:[0,.61111,0,0],920:[0,.61111,0,0],923:[0,.61111,0,0],926:[0,.61111,0,0],928:[0,.61111,0,0],931:[0,.61111,0,0],933:[0,.61111,0,0],934:[0,.61111,0,0],936:[0,.61111,0,0],937:[0,.61111,0,0],2018:[0,.61111,0,0],2019:[0,.61111,0,0],8242:[0,.61111,0,0]}}},{}],19:[function(e,t,r){var a=e("./utils");var i=e("./ParseError");var n=e("./parseData");var s=n.ParseNode;function l(e,r,a){if(typeof e==="string"){e=[e]}if(typeof r==="number"){r={numArgs:r}}var i={numArgs:r.numArgs,argTypes:r.argTypes,greediness:r.greediness===undefined?1:r.greediness,allowedInText:!!r.allowedInText,numOptionalArgs:r.numOptionalArgs||0,infix:!!r.infix,handler:a};for(var n=0;n","\\langle","\\rangle","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\\lmoustache","\\rmoustache","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."];var c={"\\Bbb":"\\mathbb","\\bold":"\\mathbf","\\frak":"\\mathfrak"};l(["\\blue","\\orange","\\pink","\\red","\\green","\\gray","\\purple","\\blueA","\\blueB","\\blueC","\\blueD","\\blueE","\\tealA","\\tealB","\\tealC","\\tealD","\\tealE","\\greenA","\\greenB","\\greenC","\\greenD","\\greenE","\\goldA","\\goldB","\\goldC","\\goldD","\\goldE","\\redA","\\redB","\\redC","\\redD","\\redE","\\maroonA","\\maroonB","\\maroonC","\\maroonD","\\maroonE","\\purpleA","\\purpleB","\\purpleC","\\purpleD","\\purpleE","\\mintA","\\mintB","\\mintC","\\grayA","\\grayB","\\grayC","\\grayD","\\grayE","\\grayF","\\grayG","\\grayH","\\grayI","\\kaBlue","\\kaGreen"],{numArgs:1,allowedInText:true,greediness:3},function(e,t){var r=t[0];return{type:"color",color:"katex-"+e.funcName.slice(1),value:o(r)}});l(["\\arcsin","\\arccos","\\arctan","\\arg","\\cos","\\cosh","\\cot","\\coth","\\csc","\\deg","\\dim","\\exp","\\hom","\\ker","\\lg","\\ln","\\log","\\sec","\\sin","\\sinh","\\tan","\\tanh"],{numArgs:0},function(e){return{type:"op",limits:false,symbol:false,body:e.funcName}});l(["\\det","\\gcd","\\inf","\\lim","\\liminf","\\limsup","\\max","\\min","\\Pr","\\sup"],{numArgs:0},function(e){return{type:"op",limits:true,symbol:false,body:e.funcName}});l(["\\int","\\iint","\\iiint","\\oint"],{numArgs:0},function(e){return{type:"op",limits:false,symbol:true,body:e.funcName}});l(["\\coprod","\\bigvee","\\bigwedge","\\biguplus","\\bigcap","\\bigcup","\\intop","\\prod","\\sum","\\bigotimes","\\bigoplus","\\bigodot","\\bigsqcup","\\smallint"],{numArgs:0},function(e){return{type:"op",limits:true,symbol:true,body:e.funcName}});l("\\mathop",{numArgs:1},function(e,t){var r=t[0];return{type:"op",limits:false,symbol:false,value:o(r)}});l(["\\dfrac","\\frac","\\tfrac","\\dbinom","\\binom","\\tbinom","\\\\atopfrac"],{numArgs:2,greediness:2},function(e,t){var r=t[0];var a=t[1];var i;var n=null;var s=null;var l="auto";switch(e.funcName){case"\\dfrac":case"\\frac":case"\\tfrac":i=true;break;case"\\\\atopfrac":i=false;break;case"\\dbinom":case"\\binom":case"\\tbinom":i=false;n="(";s=")";break;default:throw new Error("Unrecognized genfrac command")}switch(e.funcName){case"\\dfrac":case"\\dbinom":l="display";break;case"\\tfrac":case"\\tbinom":l="text";break}return{type:"genfrac",numer:r,denom:a,hasBarLine:i,leftDelim:n,rightDelim:s,size:l}});l(["\\llap","\\rlap"],{numArgs:1,allowedInText:true},function(e,t){var r=t[0];return{type:e.funcName.slice(1),body:r}});var m=function(e,t){if(a.contains(h,e.value)){return e}else{throw new i("Invalid delimiter: '"+e.value+"' after '"+t.funcName+"'",e)}};l(["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],{numArgs:1},function(e,t){var r=m(t[0],e);return{type:"delimsizing",size:p[e.funcName].size,mclass:p[e.funcName].mclass,value:r.value}});l(["\\left","\\right"],{numArgs:1},function(e,t){var r=m(t[0],e);return{type:"leftright",value:r.value}});l("\\middle",{numArgs:1},function(e,t){var r=m(t[0],e);if(!e.parser.leftrightDepth){throw new i("\\middle without preceding \\left",r)}return{type:"middle",value:r.value}});l(["\\tiny","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"],0,null);l(["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],0,null);l(["\\mathrm","\\mathit","\\mathbf","\\mathbb","\\mathcal","\\mathfrak","\\mathscr","\\mathsf","\\mathtt","\\Bbb","\\bold","\\frak"],{numArgs:1,greediness:2},function(e,t){var r=t[0];var a=e.funcName;if(a in c){a=c[a]}return{type:"font",font:a.slice(1),body:r}});l(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot"],{numArgs:1},function(e,t){var r=t[0];return{type:"accent",accent:e.funcName,base:r}});l(["\\over","\\choose","\\atop"],{numArgs:0,infix:true},function(e){var t;switch(e.funcName){case"\\over":t="\\frac";break;case"\\choose":t="\\binom";break;case"\\atop":t="\\\\atopfrac";break;default:throw new Error("Unrecognized infix genfrac command")}return{type:"infix",replaceWith:t,token:e.token}});l(["\\\\","\\cr"],{numArgs:0,numOptionalArgs:1,argTypes:["size"]},function(e,t){var r=t[0];return{type:"cr",size:r}});l(["\\begin","\\end"],{numArgs:1,argTypes:["text"]},function(e,t){var r=t[0];if(r.type!=="ordgroup"){throw new i("Invalid environment name",r)}var a="";for(var n=0;n";return e};function n(e){this.text=e}n.prototype.toNode=function(){return document.createTextNode(this.text)};n.prototype.toMarkup=function(){return a.escape(this.text)};t.exports={MathNode:i,TextNode:n}},{"./utils":25}],21:[function(e,t,r){function a(e,t,r,a,i){this.type=e;this.value=t;this.mode=r;if(a&&(!i||i.lexer===a.lexer)){this.lexer=a.lexer;this.start=a.start;this.end=(i||a).end}}t.exports={ParseNode:a}},{}],22:[function(e,t,r){var a=e("./Parser");var i=function(e,t){if(!(typeof e==="string"||e instanceof String)){throw new TypeError("KaTeX can only parse string typed expression")}var r=new a(e,t);return r.parse()};t.exports=i},{"./Parser":7}],23:[function(e,t,r){t.exports={math:{},text:{}};function a(e,r,a,i,n){t.exports[e][n]={font:r,group:a,replace:i}}var i="math";var n="text";var s="main";var l="ams";var o="accent";var u="bin";var p="close";var h="inner";var c="mathord";var m="op";var f="open";var v="punct";var d="rel";var g="spacing";var y="textord";a(i,s,d,"\u2261","\\equiv");a(i,s,d,"\u227a","\\prec");a(i,s,d,"\u227b","\\succ");a(i,s,d,"\u223c","\\sim");a(i,s,d,"\u22a5","\\perp");a(i,s,d,"\u2aaf","\\preceq");a(i,s,d,"\u2ab0","\\succeq");a(i,s,d,"\u2243","\\simeq");a(i,s,d,"\u2223","\\mid");a(i,s,d,"\u226a","\\ll");a(i,s,d,"\u226b","\\gg");a(i,s,d,"\u224d","\\asymp");a(i,s,d,"\u2225","\\parallel");a(i,s,d,"\u22c8","\\bowtie");a(i,s,d,"\u2323","\\smile");a(i,s,d,"\u2291","\\sqsubseteq");a(i,s,d,"\u2292","\\sqsupseteq");a(i,s,d,"\u2250","\\doteq");a(i,s,d,"\u2322","\\frown");a(i,s,d,"\u220b","\\ni");a(i,s,d,"\u221d","\\propto");a(i,s,d,"\u22a2","\\vdash");a(i,s,d,"\u22a3","\\dashv");a(i,s,d,"\u220b","\\owns");a(i,s,v,".","\\ldotp");a(i,s,v,"\u22c5","\\cdotp");a(i,s,y,"#","\\#");a(n,s,y,"#","\\#");a(i,s,y,"&","\\&");a(n,s,y,"&","\\&");a(i,s,y,"\u2135","\\aleph");a(i,s,y,"\u2200","\\forall");a(i,s,y,"\u210f","\\hbar");a(i,s,y,"\u2203","\\exists");a(i,s,y,"\u2207","\\nabla");a(i,s,y,"\u266d","\\flat");a(i,s,y,"\u2113","\\ell");a(i,s,y,"\u266e","\\natural");a(i,s,y,"\u2663","\\clubsuit");a(i,s,y,"\u2118","\\wp");a(i,s,y,"\u266f","\\sharp");a(i,s,y,"\u2662","\\diamondsuit");a(i,s,y,"\u211c","\\Re");a(i,s,y,"\u2661","\\heartsuit");a(i,s,y,"\u2111","\\Im");a(i,s,y,"\u2660","\\spadesuit");a(i,s,y,"\u2020","\\dag");a(i,s,y,"\u2021","\\ddag");a(i,s,p,"\u23b1","\\rmoustache");a(i,s,f,"\u23b0","\\lmoustache");a(i,s,p,"\u27ef","\\rgroup");a(i,s,f,"\u27ee","\\lgroup");a(i,s,u,"\u2213","\\mp");a(i,s,u,"\u2296","\\ominus");a(i,s,u,"\u228e","\\uplus");a(i,s,u,"\u2293","\\sqcap");a(i,s,u,"\u2217","\\ast");a(i,s,u,"\u2294","\\sqcup");a(i,s,u,"\u25ef","\\bigcirc");a(i,s,u,"\u2219","\\bullet");a(i,s,u,"\u2021","\\ddagger");a(i,s,u,"\u2240","\\wr");a(i,s,u,"\u2a3f","\\amalg");a(i,s,d,"\u27f5","\\longleftarrow");a(i,s,d,"\u21d0","\\Leftarrow");a(i,s,d,"\u27f8","\\Longleftarrow");a(i,s,d,"\u27f6","\\longrightarrow");a(i,s,d,"\u21d2","\\Rightarrow");a(i,s,d,"\u27f9","\\Longrightarrow");a(i,s,d,"\u2194","\\leftrightarrow");a(i,s,d,"\u27f7","\\longleftrightarrow");a(i,s,d,"\u21d4","\\Leftrightarrow");a(i,s,d,"\u27fa","\\Longleftrightarrow");a(i,s,d,"\u21a6","\\mapsto");a(i,s,d,"\u27fc","\\longmapsto");a(i,s,d,"\u2197","\\nearrow");a(i,s,d,"\u21a9","\\hookleftarrow");a(i,s,d,"\u21aa","\\hookrightarrow");a(i,s,d,"\u2198","\\searrow");a(i,s,d,"\u21bc","\\leftharpoonup");a(i,s,d,"\u21c0","\\rightharpoonup");a(i,s,d,"\u2199","\\swarrow");a(i,s,d,"\u21bd","\\leftharpoondown");a(i,s,d,"\u21c1","\\rightharpoondown");a(i,s,d,"\u2196","\\nwarrow");a(i,s,d,"\u21cc","\\rightleftharpoons");a(i,l,d,"\u226e","\\nless");a(i,l,d,"\ue010","\\nleqslant");a(i,l,d,"\ue011","\\nleqq");a(i,l,d,"\u2a87","\\lneq");a(i,l,d,"\u2268","\\lneqq");a(i,l,d,"\ue00c","\\lvertneqq");a(i,l,d,"\u22e6","\\lnsim");a(i,l,d,"\u2a89","\\lnapprox");a(i,l,d,"\u2280","\\nprec");a(i,l,d,"\u22e0","\\npreceq");a(i,l,d,"\u22e8","\\precnsim");a(i,l,d,"\u2ab9","\\precnapprox");a(i,l,d,"\u2241","\\nsim");a(i,l,d,"\ue006","\\nshortmid");a(i,l,d,"\u2224","\\nmid");a(i,l,d,"\u22ac","\\nvdash");a(i,l,d,"\u22ad","\\nvDash");a(i,l,d,"\u22ea","\\ntriangleleft");a(i,l,d,"\u22ec","\\ntrianglelefteq");a(i,l,d,"\u228a","\\subsetneq");a(i,l,d,"\ue01a","\\varsubsetneq");a(i,l,d,"\u2acb","\\subsetneqq");a(i,l,d,"\ue017","\\varsubsetneqq");a(i,l,d,"\u226f","\\ngtr");a(i,l,d,"\ue00f","\\ngeqslant");a(i,l,d,"\ue00e","\\ngeqq");a(i,l,d,"\u2a88","\\gneq");a(i,l,d,"\u2269","\\gneqq");a(i,l,d,"\ue00d","\\gvertneqq");a(i,l,d,"\u22e7","\\gnsim");a(i,l,d,"\u2a8a","\\gnapprox");a(i,l,d,"\u2281","\\nsucc");a(i,l,d,"\u22e1","\\nsucceq");a(i,l,d,"\u22e9","\\succnsim");a(i,l,d,"\u2aba","\\succnapprox");a(i,l,d,"\u2246","\\ncong");a(i,l,d,"\ue007","\\nshortparallel");a(i,l,d,"\u2226","\\nparallel");a(i,l,d,"\u22af","\\nVDash");a(i,l,d,"\u22eb","\\ntriangleright");a(i,l,d,"\u22ed","\\ntrianglerighteq");a(i,l,d,"\ue018","\\nsupseteqq");a(i,l,d,"\u228b","\\supsetneq");a(i,l,d,"\ue01b","\\varsupsetneq");a(i,l,d,"\u2acc","\\supsetneqq");a(i,l,d,"\ue019","\\varsupsetneqq");a(i,l,d,"\u22ae","\\nVdash");a(i,l,d,"\u2ab5","\\precneqq");a(i,l,d,"\u2ab6","\\succneqq");a(i,l,d,"\ue016","\\nsubseteqq");a(i,l,u,"\u22b4","\\unlhd");a(i,l,u,"\u22b5","\\unrhd");a(i,l,d,"\u219a","\\nleftarrow");a(i,l,d,"\u219b","\\nrightarrow");a(i,l,d,"\u21cd","\\nLeftarrow");a(i,l,d,"\u21cf","\\nRightarrow");a(i,l,d,"\u21ae","\\nleftrightarrow");a(i,l,d,"\u21ce","\\nLeftrightarrow");a(i,l,d,"\u25b3","\\vartriangle");a(i,l,y,"\u210f","\\hslash");a(i,l,y,"\u25bd","\\triangledown");a(i,l,y,"\u25ca","\\lozenge");a(i,l,y,"\u24c8","\\circledS");a(i,l,y,"\xae","\\circledR");a(i,l,y,"\u2221","\\measuredangle");a(i,l,y,"\u2204","\\nexists");a(i,l,y,"\u2127","\\mho");a(i,l,y,"\u2132","\\Finv");a(i,l,y,"\u2141","\\Game");a(i,l,y,"k","\\Bbbk");a(i,l,y,"\u2035","\\backprime");a(i,l,y,"\u25b2","\\blacktriangle");a(i,l,y,"\u25bc","\\blacktriangledown");a(i,l,y,"\u25a0","\\blacksquare");a(i,l,y,"\u29eb","\\blacklozenge");a(i,l,y,"\u2605","\\bigstar");a(i,l,y,"\u2222","\\sphericalangle");a(i,l,y,"\u2201","\\complement");a(i,l,y,"\xf0","\\eth");a(i,l,y,"\u2571","\\diagup");a(i,l,y,"\u2572","\\diagdown");a(i,l,y,"\u25a1","\\square");a(i,l,y,"\u25a1","\\Box");a(i,l,y,"\u25ca","\\Diamond");a(i,l,y,"\xa5","\\yen");a(i,l,y,"\u2713","\\checkmark");a(i,l,y,"\u2136","\\beth");a(i,l,y,"\u2138","\\daleth");a(i,l,y,"\u2137","\\gimel");a(i,l,y,"\u03dd","\\digamma");a(i,l,y,"\u03f0","\\varkappa");a(i,l,f,"\u250c","\\ulcorner");a(i,l,p,"\u2510","\\urcorner");a(i,l,f,"\u2514","\\llcorner");a(i,l,p,"\u2518","\\lrcorner");a(i,l,d,"\u2266","\\leqq");a(i,l,d,"\u2a7d","\\leqslant");a(i,l,d,"\u2a95","\\eqslantless");a(i,l,d,"\u2272","\\lesssim");a(i,l,d,"\u2a85","\\lessapprox");a(i,l,d,"\u224a","\\approxeq");a(i,l,u,"\u22d6","\\lessdot");a(i,l,d,"\u22d8","\\lll");a(i,l,d,"\u2276","\\lessgtr");a(i,l,d,"\u22da","\\lesseqgtr");a(i,l,d,"\u2a8b","\\lesseqqgtr");a(i,l,d,"\u2251","\\doteqdot");a(i,l,d,"\u2253","\\risingdotseq");a(i,l,d,"\u2252","\\fallingdotseq");a(i,l,d,"\u223d","\\backsim");a(i,l,d,"\u22cd","\\backsimeq");a(i,l,d,"\u2ac5","\\subseteqq");a(i,l,d,"\u22d0","\\Subset");a(i,l,d,"\u228f","\\sqsubset");a(i,l,d,"\u227c","\\preccurlyeq");a(i,l,d,"\u22de","\\curlyeqprec");a(i,l,d,"\u227e","\\precsim");a(i,l,d,"\u2ab7","\\precapprox");a(i,l,d,"\u22b2","\\vartriangleleft");a(i,l,d,"\u22b4","\\trianglelefteq");a(i,l,d,"\u22a8","\\vDash");a(i,l,d,"\u22aa","\\Vvdash");a(i,l,d,"\u2323","\\smallsmile");a(i,l,d,"\u2322","\\smallfrown");a(i,l,d,"\u224f","\\bumpeq");a(i,l,d,"\u224e","\\Bumpeq");a(i,l,d,"\u2267","\\geqq");a(i,l,d,"\u2a7e","\\geqslant");a(i,l,d,"\u2a96","\\eqslantgtr");a(i,l,d,"\u2273","\\gtrsim");a(i,l,d,"\u2a86","\\gtrapprox");a(i,l,u,"\u22d7","\\gtrdot");a(i,l,d,"\u22d9","\\ggg");a(i,l,d,"\u2277","\\gtrless");a(i,l,d,"\u22db","\\gtreqless");a(i,l,d,"\u2a8c","\\gtreqqless");a(i,l,d,"\u2256","\\eqcirc");a(i,l,d,"\u2257","\\circeq");a(i,l,d,"\u225c","\\triangleq");a(i,l,d,"\u223c","\\thicksim");a(i,l,d,"\u2248","\\thickapprox");a(i,l,d,"\u2ac6","\\supseteqq");a(i,l,d,"\u22d1","\\Supset");a(i,l,d,"\u2290","\\sqsupset");a(i,l,d,"\u227d","\\succcurlyeq");a(i,l,d,"\u22df","\\curlyeqsucc");a(i,l,d,"\u227f","\\succsim");a(i,l,d,"\u2ab8","\\succapprox");a(i,l,d,"\u22b3","\\vartriangleright");a(i,l,d,"\u22b5","\\trianglerighteq");a(i,l,d,"\u22a9","\\Vdash");a(i,l,d,"\u2223","\\shortmid");a(i,l,d,"\u2225","\\shortparallel");a(i,l,d,"\u226c","\\between");a(i,l,d,"\u22d4","\\pitchfork");a(i,l,d,"\u221d","\\varpropto");a(i,l,d,"\u25c0","\\blacktriangleleft");a(i,l,d,"\u2234","\\therefore");a(i,l,d,"\u220d","\\backepsilon");a(i,l,d,"\u25b6","\\blacktriangleright");a(i,l,d,"\u2235","\\because");a(i,l,d,"\u22d8","\\llless");a(i,l,d,"\u22d9","\\gggtr");a(i,l,u,"\u22b2","\\lhd");a(i,l,u,"\u22b3","\\rhd");a(i,l,d,"\u2242","\\eqsim");a(i,s,d,"\u22c8","\\Join");a(i,l,d,"\u2251","\\Doteq");a(i,l,u,"\u2214","\\dotplus");a(i,l,u,"\u2216","\\smallsetminus");a(i,l,u,"\u22d2","\\Cap");a(i,l,u,"\u22d3","\\Cup");a(i,l,u,"\u2a5e","\\doublebarwedge");a(i,l,u,"\u229f","\\boxminus");a(i,l,u,"\u229e","\\boxplus");a(i,l,u,"\u22c7","\\divideontimes");a(i,l,u,"\u22c9","\\ltimes");a(i,l,u,"\u22ca","\\rtimes");a(i,l,u,"\u22cb","\\leftthreetimes");a(i,l,u,"\u22cc","\\rightthreetimes");a(i,l,u,"\u22cf","\\curlywedge");a(i,l,u,"\u22ce","\\curlyvee");a(i,l,u,"\u229d","\\circleddash");a(i,l,u,"\u229b","\\circledast");a(i,l,u,"\u22c5","\\centerdot");a(i,l,u,"\u22ba","\\intercal");a(i,l,u,"\u22d2","\\doublecap");a(i,l,u,"\u22d3","\\doublecup");a(i,l,u,"\u22a0","\\boxtimes");a(i,l,d,"\u21e2","\\dashrightarrow");a(i,l,d,"\u21e0","\\dashleftarrow");a(i,l,d,"\u21c7","\\leftleftarrows");a(i,l,d,"\u21c6","\\leftrightarrows");a(i,l,d,"\u21da","\\Lleftarrow");a(i,l,d,"\u219e","\\twoheadleftarrow");a(i,l,d,"\u21a2","\\leftarrowtail");a(i,l,d,"\u21ab","\\looparrowleft");a(i,l,d,"\u21cb","\\leftrightharpoons");a(i,l,d,"\u21b6","\\curvearrowleft");a(i,l,d,"\u21ba","\\circlearrowleft");a(i,l,d,"\u21b0","\\Lsh");a(i,l,d,"\u21c8","\\upuparrows");a(i,l,d,"\u21bf","\\upharpoonleft");a(i,l,d,"\u21c3","\\downharpoonleft");a(i,l,d,"\u22b8","\\multimap");a(i,l,d,"\u21ad","\\leftrightsquigarrow");a(i,l,d,"\u21c9","\\rightrightarrows");a(i,l,d,"\u21c4","\\rightleftarrows");a(i,l,d,"\u21a0","\\twoheadrightarrow");a(i,l,d,"\u21a3","\\rightarrowtail");a(i,l,d,"\u21ac","\\looparrowright");a(i,l,d,"\u21b7","\\curvearrowright");a(i,l,d,"\u21bb","\\circlearrowright");a(i,l,d,"\u21b1","\\Rsh");a(i,l,d,"\u21ca","\\downdownarrows");a(i,l,d,"\u21be","\\upharpoonright");a(i,l,d,"\u21c2","\\downharpoonright");a(i,l,d,"\u21dd","\\rightsquigarrow");a(i,l,d,"\u21dd","\\leadsto");a(i,l,d,"\u21db","\\Rrightarrow");a(i,l,d,"\u21be","\\restriction");a(i,s,y,"\u2018","`");a(i,s,y,"$","\\$");a(n,s,y,"$","\\$");a(i,s,y,"%","\\%");a(n,s,y,"%","\\%");a(i,s,y,"_","\\_");a(n,s,y,"_","\\_");a(i,s,y,"\u2220","\\angle");a(i,s,y,"\u221e","\\infty");a(i,s,y,"\u2032","\\prime");a(i,s,y,"\u25b3","\\triangle");a(i,s,y,"\u0393","\\Gamma");a(i,s,y,"\u0394","\\Delta");a(i,s,y,"\u0398","\\Theta");a(i,s,y,"\u039b","\\Lambda");a(i,s,y,"\u039e","\\Xi");a(i,s,y,"\u03a0","\\Pi");a(i,s,y,"\u03a3","\\Sigma");a(i,s,y,"\u03a5","\\Upsilon");a(i,s,y,"\u03a6","\\Phi");a(i,s,y,"\u03a8","\\Psi");a(i,s,y,"\u03a9","\\Omega");a(i,s,y,"\xac","\\neg");a(i,s,y,"\xac","\\lnot");a(i,s,y,"\u22a4","\\top");a(i,s,y,"\u22a5","\\bot");a(i,s,y,"\u2205","\\emptyset");a(i,l,y,"\u2205","\\varnothing");a(i,s,c,"\u03b1","\\alpha");a(i,s,c,"\u03b2","\\beta");a(i,s,c,"\u03b3","\\gamma");a(i,s,c,"\u03b4","\\delta");a(i,s,c,"\u03f5","\\epsilon");a(i,s,c,"\u03b6","\\zeta");a(i,s,c,"\u03b7","\\eta");a(i,s,c,"\u03b8","\\theta");a(i,s,c,"\u03b9","\\iota");a(i,s,c,"\u03ba","\\kappa");a(i,s,c,"\u03bb","\\lambda");a(i,s,c,"\u03bc","\\mu");a(i,s,c,"\u03bd","\\nu");a(i,s,c,"\u03be","\\xi");a(i,s,c,"o","\\omicron");a(i,s,c,"\u03c0","\\pi");a(i,s,c,"\u03c1","\\rho");a(i,s,c,"\u03c3","\\sigma");a(i,s,c,"\u03c4","\\tau");a(i,s,c,"\u03c5","\\upsilon");a(i,s,c,"\u03d5","\\phi");a(i,s,c,"\u03c7","\\chi");a(i,s,c,"\u03c8","\\psi");a(i,s,c,"\u03c9","\\omega");a(i,s,c,"\u03b5","\\varepsilon");a(i,s,c,"\u03d1","\\vartheta");a(i,s,c,"\u03d6","\\varpi");a(i,s,c,"\u03f1","\\varrho");a(i,s,c,"\u03c2","\\varsigma");a(i,s,c,"\u03c6","\\varphi");a(i,s,u,"\u2217","*");a(i,s,u,"+","+");a(i,s,u,"\u2212","-");a(i,s,u,"\u22c5","\\cdot");a(i,s,u,"\u2218","\\circ");a(i,s,u,"\xf7","\\div");a(i,s,u,"\xb1","\\pm");a(i,s,u,"\xd7","\\times");a(i,s,u,"\u2229","\\cap");a(i,s,u,"\u222a","\\cup");a(i,s,u,"\u2216","\\setminus");a(i,s,u,"\u2227","\\land");a(i,s,u,"\u2228","\\lor");a(i,s,u,"\u2227","\\wedge");a(i,s,u,"\u2228","\\vee");a(i,s,y,"\u221a","\\surd");a(i,s,f,"(","(");a(i,s,f,"[","[");a(i,s,f,"\u27e8","\\langle");a(i,s,f,"\u2223","\\lvert");a(i,s,f,"\u2225","\\lVert");a(i,s,p,")",")");a(i,s,p,"]","]");a(i,s,p,"?","?");a(i,s,p,"!","!");a(i,s,p,"\u27e9","\\rangle");a(i,s,p,"\u2223","\\rvert");a(i,s,p,"\u2225","\\rVert");a(i,s,d,"=","=");a(i,s,d,"<","<");a(i,s,d,">",">");a(i,s,d,":",":");a(i,s,d,"\u2248","\\approx");a(i,s,d,"\u2245","\\cong");a(i,s,d,"\u2265","\\ge");a(i,s,d,"\u2265","\\geq");a(i,s,d,"\u2190","\\gets");a(i,s,d,">","\\gt");a(i,s,d,"\u2208","\\in");a(i,s,d,"\u2209","\\notin");a(i,s,d,"\u2282","\\subset");a(i,s,d,"\u2283","\\supset");a(i,s,d,"\u2286","\\subseteq");a(i,s,d,"\u2287","\\supseteq");a(i,l,d,"\u2288","\\nsubseteq");a(i,l,d,"\u2289","\\nsupseteq");a(i,s,d,"\u22a8","\\models");a(i,s,d,"\u2190","\\leftarrow");a(i,s,d,"\u2264","\\le");a(i,s,d,"\u2264","\\leq");a(i,s,d,"<","\\lt");a(i,s,d,"\u2260","\\ne");a(i,s,d,"\u2260","\\neq");a(i,s,d,"\u2192","\\rightarrow");a(i,s,d,"\u2192","\\to");a(i,l,d,"\u2271","\\ngeq");a(i,l,d,"\u2270","\\nleq");a(i,s,g,null,"\\!");a(i,s,g,"\xa0","\\ ");a(i,s,g,"\xa0","~");a(i,s,g,null,"\\,");a(i,s,g,null,"\\:");a(i,s,g,null,"\\;");a(i,s,g,null,"\\enspace");a(i,s,g,null,"\\qquad");a(i,s,g,null,"\\quad");a(i,s,g,"\xa0","\\space");a(i,s,v,",",",");a(i,s,v,";",";");a(i,s,v,":","\\colon");a(i,l,u,"\u22bc","\\barwedge");a(i,l,u,"\u22bb","\\veebar");a(i,s,u,"\u2299","\\odot");a(i,s,u,"\u2295","\\oplus");a(i,s,u,"\u2297","\\otimes");a(i,s,y,"\u2202","\\partial");a(i,s,u,"\u2298","\\oslash");a(i,l,u,"\u229a","\\circledcirc");a(i,l,u,"\u22a1","\\boxdot");a(i,s,u,"\u25b3","\\bigtriangleup");a(i,s,u,"\u25bd","\\bigtriangledown");a(i,s,u,"\u2020","\\dagger");a(i,s,u,"\u22c4","\\diamond");a(i,s,u,"\u22c6","\\star");a(i,s,u,"\u25c3","\\triangleleft");a(i,s,u,"\u25b9","\\triangleright");a(i,s,f,"{","\\{");a(n,s,y,"{","\\{");a(i,s,p,"}","\\}");a(n,s,y,"}","\\}");a(i,s,f,"{","\\lbrace");a(i,s,p,"}","\\rbrace");a(i,s,f,"[","\\lbrack");a(i,s,p,"]","\\rbrack");a(i,s,f,"\u230a","\\lfloor");a(i,s,p,"\u230b","\\rfloor");a(i,s,f,"\u2308","\\lceil");a(i,s,p,"\u2309","\\rceil");a(i,s,y,"\\","\\backslash");a(i,s,y,"\u2223","|");a(i,s,y,"\u2223","\\vert");a(i,s,y,"\u2225","\\|");a(i,s,y,"\u2225","\\Vert");a(i,s,d,"\u2191","\\uparrow");a(i,s,d,"\u21d1","\\Uparrow");a(i,s,d,"\u2193","\\downarrow");a(i,s,d,"\u21d3","\\Downarrow");a(i,s,d,"\u2195","\\updownarrow");a(i,s,d,"\u21d5","\\Updownarrow");a(i,i,m,"\u2210","\\coprod");a(i,i,m,"\u22c1","\\bigvee");a(i,i,m,"\u22c0","\\bigwedge");a(i,i,m,"\u2a04","\\biguplus");a(i,i,m,"\u22c2","\\bigcap");a(i,i,m,"\u22c3","\\bigcup");a(i,i,m,"\u222b","\\int");a(i,i,m,"\u222b","\\intop");a(i,i,m,"\u222c","\\iint");a(i,i,m,"\u222d","\\iiint");a(i,i,m,"\u220f","\\prod");a(i,i,m,"\u2211","\\sum");a(i,i,m,"\u2a02","\\bigotimes");a(i,i,m,"\u2a01","\\bigoplus");a(i,i,m,"\u2a00","\\bigodot");a(i,i,m,"\u222e","\\oint");a(i,i,m,"\u2a06","\\bigsqcup");a(i,i,m,"\u222b","\\smallint");a(n,s,h,"\u2026","\\textellipsis");a(i,s,h,"\u2026","\\mathellipsis");a(n,s,h,"\u2026","\\ldots");a(i,s,h,"\u2026","\\ldots");a(i,s,h,"\u22ef","\\cdots");a(i,s,h,"\u22f1","\\ddots");a(i,s,y,"\u22ee","\\vdots");a(i,s,o,"\xb4","\\acute");a(i,s,o,"`","\\grave");a(i,s,o,"\xa8","\\ddot");a(i,s,o,"~","\\tilde");a(i,s,o,"\xaf","\\bar");a(i,s,o,"\u02d8","\\breve");a(i,s,o,"\u02c7","\\check");a(i,s,o,"^","\\hat");a(i,s,o,"\u20d7","\\vec");a(i,s,o,"\u02d9","\\dot");a(i,s,c,"\u0131","\\imath");a(i,s,c,"\u0237","\\jmath");a(n,s,y,"\u2013","--");a(n,s,y,"\u2014","---");a(n,s,y,"\u2018","`");a(n,s,y,"\u2019","'");a(n,s,y,"\u201c","``");a(n,s,y,"\u201d","''");a(i,s,y,"\xb0","\\degree");a(n,s,y,"\xb0","\\degree");a(i,s,c,"\xa3","\\pounds");a(i,l,y,"\u2720","\\maltese");a(n,l,y,"\u2720","\\maltese");a(n,s,g,"\xa0","\\ ");a(n,s,g,"\xa0"," ");a(n,s,g,"\xa0","~");var x;var b;var w='0123456789/@."';for(x=0;x":">","<":"<",'"':""","'":"'"};var p=/[&><"']/g;function h(e){return u[e]}function c(e){return(""+e).replace(p,h)}var m;if(typeof document!=="undefined"){var f=document.createElement("span");if("textContent"in f){m=function(e,t){e.textContent=t}}else{m=function(e,t){e.innerText=t}}}function v(e){m(e,"")}t.exports={contains:n,deflt:s,escape:c,hyphenate:o,indexOf:i,setTextContent:m,clearNode:v}},{}]},{},[1])(1)}); diff --git a/public/react/add.txt b/public/react/add.txt new file mode 100644 index 000000000..8bd5bb1d3 --- /dev/null +++ b/public/react/add.txt @@ -0,0 +1,34 @@ + +新版tpi改动的文件: +Index.js +contex/TPIContextProvider.js +page/main/LeftViewContainer.js +taskList/TaskList.js +TPMIndexHOC.js +App.js +CodeRepositoryViewContainer.js + +Index.js + choose={context.chooses} + + +TPIContextProvider.js + +LeftViewContainer.js + +TaskList.js + +TPMIndexHOC.js + +MainContentContainer + 新:rep_content返回值多了一层 {content: '...'} + + + + +TODO + 待同步 + 1、timer图标样式更换 + index.html + WebSSHTimer.css + WebSSHTimer.js \ No newline at end of file diff --git a/public/react/config/env.js b/public/react/config/env.js new file mode 100644 index 000000000..aef6a8ff4 --- /dev/null +++ b/public/react/config/env.js @@ -0,0 +1,93 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const paths = require('./paths'); + +// Make sure that including paths.js after env.js will read .env variables. +delete require.cache[require.resolve('./paths')]; + +const NODE_ENV = process.env.NODE_ENV; +if (!NODE_ENV) { + throw new Error( + 'The NODE_ENV environment variable is required but was not specified.' + ); +} + +// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use +var dotenvFiles = [ + `${paths.dotenv}.${NODE_ENV}.local`, + `${paths.dotenv}.${NODE_ENV}`, + // Don't include `.env.local` for `test` environment + // since normally you expect tests to produce the same + // results for everyone + NODE_ENV !== 'test' && `${paths.dotenv}.local`, + paths.dotenv, +].filter(Boolean); + +// Load environment variables from .env* files. Suppress warnings using silent +// if this file is missing. dotenv will never modify any environment variables +// that have already been set. Variable expansion is supported in .env files. +// https://github.com/motdotla/dotenv +// https://github.com/motdotla/dotenv-expand +dotenvFiles.forEach(dotenvFile => { + if (fs.existsSync(dotenvFile)) { + require('dotenv-expand')( + require('dotenv').config({ + path: dotenvFile, + }) + ); + } +}); + +// We support resolving modules according to `NODE_PATH`. +// This lets you use absolute paths in imports inside large monorepos: +// https://github.com/facebookincubator/create-react-app/issues/253. +// It works similar to `NODE_PATH` in Node itself: +// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders +// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. +// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims. +// https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421 +// We also resolve them to make sure all tools using them work consistently. +const appDirectory = fs.realpathSync(process.cwd()); +process.env.NODE_PATH = (process.env.NODE_PATH || '') + .split(path.delimiter) + .filter(folder => folder && !path.isAbsolute(folder)) + .map(folder => path.resolve(appDirectory, folder)) + .join(path.delimiter); + +// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be +// injected into the application via DefinePlugin in Webpack configuration. +const REACT_APP = /^REACT_APP_/i; + +function getClientEnvironment(publicUrl) { + const raw = Object.keys(process.env) + .filter(key => REACT_APP.test(key)) + .reduce( + (env, key) => { + env[key] = process.env[key]; + return env; + }, + { + // Useful for determining whether we’re running in production mode. + // Most importantly, it switches React into the correct mode. + NODE_ENV: process.env.NODE_ENV || 'development', + // Useful for resolving the correct path to static assets in `public`. + // For example, . + // This should only be used as an escape hatch. Normally you would put + // images into the `src` and `import` them in code to get their paths. + PUBLIC_URL: '/react/build/.', + } + ); + // Stringify all values so we can feed into Webpack DefinePlugin + const stringified = { + 'process.env': Object.keys(raw).reduce((env, key) => { + env[key] = JSON.stringify(raw[key]); + return env; + }, {}), + }; + + return { raw, stringified }; +} + +module.exports = getClientEnvironment; diff --git a/public/react/config/jest/cssTransform.js b/public/react/config/jest/cssTransform.js new file mode 100644 index 000000000..0f38ef800 --- /dev/null +++ b/public/react/config/jest/cssTransform.js @@ -0,0 +1,14 @@ +'use strict'; + +// This is a custom Jest transformer turning style imports into empty objects. +// http://facebook.github.io/jest/docs/en/webpack.html + +module.exports = { + process() { + return 'module.exports = {};'; + }, + getCacheKey() { + // The output is always the same. + return 'cssTransform'; + }, +}; diff --git a/public/react/config/jest/fileTransform.js b/public/react/config/jest/fileTransform.js new file mode 100644 index 000000000..7d4bc6abe --- /dev/null +++ b/public/react/config/jest/fileTransform.js @@ -0,0 +1,12 @@ +'use strict'; + +const path = require('path'); + +// This is a custom Jest transformer turning file imports into filenames. +// http://facebook.github.io/jest/docs/en/webpack.html + +module.exports = { + process(src, filename) { + return `module.exports = ${JSON.stringify(path.basename(filename))};`; + }, +}; diff --git a/public/react/config/paths.js b/public/react/config/paths.js new file mode 100644 index 000000000..eca9f3738 --- /dev/null +++ b/public/react/config/paths.js @@ -0,0 +1,55 @@ +'use strict'; + +const path = require('path'); +const fs = require('fs'); +const url = require('url'); + +// Make sure any symlinks in the project folder are resolved: +// https://github.com/facebookincubator/create-react-app/issues/637 +const appDirectory = fs.realpathSync(process.cwd()); +const resolveApp = relativePath => path.resolve(appDirectory, relativePath); + +const envPublicUrl = process.env.PUBLIC_URL; + +function ensureSlash(path, needsSlash) { + const hasSlash = path.endsWith('/'); + if (hasSlash && !needsSlash) { + return path.substr(path, path.length - 1); + } else if (!hasSlash && needsSlash) { + return `${path}/`; + } else { + return path; + } +} + +const getPublicUrl = appPackageJson => + envPublicUrl || require(appPackageJson).homepage; + +// We use `PUBLIC_URL` environment variable or "homepage" field to infer +// "public path" at which the app is served. +// Webpack needs to know it to put the right + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                + + + + + + + + + + + + + + + + + + + + + +
                                + + + + + + + + + + + + + + + diff --git a/public/react/public/index.test.html b/public/react/public/index.test.html new file mode 100755 index 000000000..7d584f876 --- /dev/null +++ b/public/react/public/index.test.html @@ -0,0 +1,111 @@ + + + + + + + + + + + Educoder + + + + + + + + + + + + + + + + + + +
                                +
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/react/public/js/codemirror/addon/active-line.js b/public/react/public/js/codemirror/addon/active-line.js new file mode 100755 index 000000000..844987e13 --- /dev/null +++ b/public/react/public/js/codemirror/addon/active-line.js @@ -0,0 +1,70 @@ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var WRAP_CLASS = "CodeMirror-activeline"; + var BACK_CLASS = "CodeMirror-activeline-background"; + var GUTT_CLASS = "CodeMirror-activeline-gutter"; + + CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { + var prev = old == CodeMirror.Init ? false : old; + if (val == prev) return + if (prev) { + cm.off("beforeSelectionChange", selectionChange); + clearActiveLines(cm); + delete cm.state.activeLines; + } + if (val) { + cm.state.activeLines = []; + updateActiveLines(cm, cm.listSelections()); + cm.on("beforeSelectionChange", selectionChange); + } + }); + + function clearActiveLines(cm) { + for (var i = 0; i < cm.state.activeLines.length; i++) { + cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); + cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); + cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS); + } + } + + function sameArray(a, b) { + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) + if (a[i] != b[i]) return false; + return true; + } + + function updateActiveLines(cm, ranges) { + var active = []; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + var option = cm.getOption("styleActiveLine"); + if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty()) + continue + var line = cm.getLineHandleVisualStart(range.head.line); + if (active[active.length - 1] != line) active.push(line); + } + if (sameArray(cm.state.activeLines, active)) return; + cm.operation(function() { + clearActiveLines(cm); + for (var i = 0; i < active.length; i++) { + cm.addLineClass(active[i], "wrap", WRAP_CLASS); + cm.addLineClass(active[i], "background", BACK_CLASS); + cm.addLineClass(active[i], "gutter", GUTT_CLASS); + } + cm.state.activeLines = active; + }); + } + + function selectionChange(cm, sel) { + updateActiveLines(cm, sel.ranges); + } +}); \ No newline at end of file diff --git a/public/react/public/js/codemirror/addon/hint/anyword-hint.js b/public/react/public/js/codemirror/addon/hint/anyword-hint.js new file mode 100755 index 000000000..35a588bff --- /dev/null +++ b/public/react/public/js/codemirror/addon/hint/anyword-hint.js @@ -0,0 +1,43 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + // var WORD = /[\w$]+/ + var WORD = /[A-z]+/ + , RANGE = 500; + + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { + var word = options && options.word || WORD; + var range = options && options.range || RANGE; + var cur = editor.getCursor(), curLine = editor.getLine(cur.line); + var end = cur.ch, start = end; + while (start && word.test(curLine.charAt(start - 1))) --start; + var curWord = start != end && curLine.slice(start, end); + + var list = options && options.list || [], seen = {}; + var re = new RegExp(word.source, "g"); + for (var dir = -1; dir <= 1; dir += 2) { + var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; + for (; line != endLine; line += dir) { + var text = editor.getLine(line), m; + while (m = re.exec(text)) { + if (line == cur.line && m[0] === curWord) continue; + if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { + seen[m[0]] = true; + list.push(m[0]); + } + } + } + } + return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; + }); +}); diff --git a/public/react/public/js/codemirror/addon/hint/javascript-hint.js b/public/react/public/js/codemirror/addon/hint/javascript-hint.js new file mode 100755 index 000000000..891481764 --- /dev/null +++ b/public/react/public/js/codemirror/addon/hint/javascript-hint.js @@ -0,0 +1,188 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var Pos = CodeMirror.Pos; + + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) != -1; + } + + function scriptHint(editor, keywords, getToken, options) { + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur); + if (/\b(?:string|comment)\b/.test(token.type)) return; + token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = {start: cur.ch, end: cur.ch, string: "", state: token.state, + type: token.string == "." ? "property" : null}; + } else if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + var tprop = token; + // If it is a property, find out what it is a property of. + while (tprop.type == "property") { + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (tprop.string != ".") return; + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (!context) var context = []; + context.push(tprop); + } + // 发消息让其他组件注入 其他hint + CodeMirror.signal(editor, "hinting"); + var myhints = editor.state.myhints + var needToClearJSHint = editor.state.needToClearJSHint + if (needToClearJSHint) { // 不使用js的hint,可能注入了其他语言的hint + keywords = [] + editor.state.needToClearJSHint = false; + } + myhints && myhints.forEach(function(item) { + if (!arrayContains(keywords, item)) keywords.push(item) + }) + + return {list: getCompletions(token, context, keywords, options), + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end)}; + } + + function javascriptHint(editor, options) { + return scriptHint(editor, javascriptKeywords, + function (e, cur) {return e.getTokenAt(cur);}, + options); + }; + CodeMirror.registerHelper("hint", "javascript", javascriptHint); + + function getCoffeeScriptToken(editor, cur) { + // This getToken, it is for coffeescript, imitates the behavior of + // getTokenAt method in javascript.js, that is, returning "property" + // type and treat "." as indepenent token. + var token = editor.getTokenAt(cur); + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { + token.end = token.start; + token.string = '.'; + token.type = "property"; + } + else if (/^\.[\w$_]*$/.test(token.string)) { + token.type = "property"; + token.start++; + token.string = token.string.replace(/\./, ''); + } + return token; + } + + function coffeescriptHint(editor, options) { + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); + } + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); + +/* var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + + "toUpperCase toLowerCase split concat match replace search").split(" "); + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); + var funcProps = "prototype apply call bind".split(" ");*/ + var javascriptKeywords = ("double float int long short null true false enum super this void auto for register static const friend mutable explicit virtual template typename printf " + + "break continue return do while if else for instanceof switch case default try catch finally throw throws assert import package boolean byte char delete private " + + "inline struct union signed unsigned export extern namespace using operator sizeof typedef typeid and del from not as elif or with pass except " + + "print exec raise is def lambda private protected public abstract class extends final implements interface native new static strictfp synchronized transient main " + + "String string System println vector bool boolean FALSE TRUE function").split(" "); +/* + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); +*/ + + function forAllProps(obj, callback) { + if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) { + for (var name in obj) callback(name) + } else { + for (var o = obj; o; o = Object.getPrototypeOf(o)) + Object.getOwnPropertyNames(o).forEach(callback) + } + } + + function getCompletions(token, context, keywords, options) { + var found = [], start = token.string, global = options && options.globalScope || window; + function maybeAdd(str) { + // var results = fuzzysort.go(start, [str]) + // if ( results.total && !arrayContains(found, str) ) found.push(str); + + if (fuzzysort && fuzzysort.single) { + // 使用模糊搜索 + var results = fuzzysort.single(start, str) + if ( results && results.score <= 0 && !arrayContains(found, str)) found.push(str); + } else { + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); + } + } + function gatherCompletions(obj) { + if (typeof obj == "string") forEach(stringProps, maybeAdd); + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); + else if (obj instanceof Function) forEach(funcProps, maybeAdd); + forAllProps(obj, maybeAdd) + } + + // 不启用context context强制要求了lib的调用才提示,比如Math.a 就会提示 Math.abs + if (false && context && context.length) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + if (obj.type && obj.type.indexOf("variable") === 0) { + if (options && options.additionalContext) + base = options.additionalContext[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || global[obj.string]; + } else if (obj.type == "string") { + base = ""; + } else if (obj.type == "atom") { + base = 1; + } else if (obj.type == "function") { + if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && + (typeof global.jQuery == 'function')) + base = global.jQuery(); + else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) + base = global._(); + } + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } else { + // If not, just look in the global object and any local scope + // (reading into JS mode internals to get at the local and global variables) + /* for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);*/ +/* for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); + if (!options || options.useGlobalScope !== false) + gatherCompletions(global);*/ + + // forEach(keywords, maybeAdd); + + var result = fuzzysort.go(start, keywords) + result && result.forEach(function(item) { + found.push(item.target) + }) + } + return found; + } +}); diff --git a/public/react/public/js/codemirror/addon/hint/show-hint.css b/public/react/public/js/codemirror/addon/hint/show-hint.css new file mode 100755 index 000000000..5617ccca2 --- /dev/null +++ b/public/react/public/js/codemirror/addon/hint/show-hint.css @@ -0,0 +1,36 @@ +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 2px; + + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + border-radius: 3px; + border: 1px solid silver; + + background: white; + font-size: 90%; + font-family: monospace; + + max-height: 20em; + overflow-y: auto; +} + +.CodeMirror-hint { + margin: 0; + padding: 0 4px; + border-radius: 2px; + white-space: pre; + color: black; + cursor: pointer; +} + +li.CodeMirror-hint-active { + background: #08f; + color: white; +} diff --git a/public/react/public/js/codemirror/addon/hint/show-hint.js b/public/react/public/js/codemirror/addon/hint/show-hint.js new file mode 100755 index 000000000..3c715eb7b --- /dev/null +++ b/public/react/public/js/codemirror/addon/hint/show-hint.js @@ -0,0 +1,458 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; + var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; + + // This is the old interface, kept around for now to stay + // backwards-compatible. + CodeMirror.showHint = function(cm, getHints, options) { + if (!getHints) return cm.showHint(options); + if (options && options.async) getHints.async = true; + var newOpts = {hint: getHints}; + if (options) for (var prop in options) newOpts[prop] = options[prop]; + return cm.showHint(newOpts); + }; + + CodeMirror.defineExtension("showHint", function(options) { + options = parseOptions(this, this.getCursor("start"), options); + var selections = this.listSelections() + if (selections.length > 1) return; + // By default, don't allow completion when something is selected. + // A hint function can have a `supportsSelection` property to + // indicate that it can handle selections. + if (this.somethingSelected()) { + if (!options.hint.supportsSelection) return; + // Don't try with cross-line selections + for (var i = 0; i < selections.length; i++) + if (selections[i].head.line != selections[i].anchor.line) return; + } + + if (this.state.completionActive) this.state.completionActive.close(); + var completion = this.state.completionActive = new Completion(this, options); + if (!completion.options.hint) return; + + CodeMirror.signal(this, "startCompletion", this); + completion.update(true); + }); + + function Completion(cm, options) { + this.cm = cm; + this.options = options; + this.widget = null; + this.debounce = 0; + this.tick = 0; + this.startPos = this.cm.getCursor("start"); + this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; + + var self = this; + cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); + } + + var requestAnimationFrame = window.requestAnimationFrame || function(fn) { + return setTimeout(fn, 1000/60); + }; + var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; + + Completion.prototype = { + close: function() { + if (!this.active()) return; + this.cm.state.completionActive = null; + this.tick = null; + this.cm.off("cursorActivity", this.activityFunc); + + if (this.widget && this.data) CodeMirror.signal(this.data, "close"); + if (this.widget) this.widget.close(); + CodeMirror.signal(this.cm, "endCompletion", this.cm); + }, + + active: function() { + return this.cm.state.completionActive == this; + }, + + pick: function(data, i) { + var completion = data.list[i]; + if (completion.hint) completion.hint(this.cm, data, completion); + else this.cm.replaceRange(getText(completion), completion.from || data.from, + completion.to || data.to, "complete"); + CodeMirror.signal(data, "pick", completion); + this.close(); + }, + + cursorActivity: function() { + if (this.debounce) { + cancelAnimationFrame(this.debounce); + this.debounce = 0; + } + + var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); + if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || + pos.ch < this.startPos.ch || this.cm.somethingSelected() || + (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { + this.close(); + } else { + var self = this; + this.debounce = requestAnimationFrame(function() {self.update();}); + if (this.widget) this.widget.disable(); + } + }, + + update: function(first) { + if (this.tick == null) return + var self = this, myTick = ++this.tick + fetchHints(this.options.hint, this.cm, this.options, function(data) { + if (self.tick == myTick) self.finishUpdate(data, first) + }) + }, + + finishUpdate: function(data, first) { + if (this.data) CodeMirror.signal(this.data, "update"); + + var picked = (this.widget && this.widget.picked) // || (first && this.options.completeSingle); + if (this.widget) this.widget.close(); + + if (data && this.data && isNewCompletion(this.data, data)) return; + this.data = data; + + if (data && data.list.length) { + if (picked && data.list.length == 1) { + this.pick(data, 0); + } else { + // 使得输入完后,刚好输入和hint一样,则不再显示hint + if (data.list.length == 1 && data.to.ch - data.from.ch === data.list[0].length) { + return; + } + this.widget = new Widget(this, data); + CodeMirror.signal(data, "shown"); + } + } + } + }; + + function isNewCompletion(old, nw) { + var moved = CodeMirror.cmpPos(nw.from, old.from) + return moved > 0 && old.to.ch - old.from.ch != nw.to.ch - nw.from.ch + } + + function parseOptions(cm, pos, options) { + var editor = cm.options.hintOptions; + var out = {}; + for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; + if (editor) for (var prop in editor) + if (editor[prop] !== undefined) out[prop] = editor[prop]; + if (options) for (var prop in options) + if (options[prop] !== undefined) out[prop] = options[prop]; + if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) + return out; + } + + function getText(completion) { + if (typeof completion == "string") return completion; + else return completion.text; + } + + function buildKeyMap(completion, handle) { + var baseMap = { + Up: function() {handle.moveFocus(-1);}, + Down: function() {handle.moveFocus(1);}, + PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, + PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, + Home: function() {handle.setFocus(0);}, + End: function() {handle.setFocus(handle.length - 1);}, + Enter: handle.pick, + Tab: handle.pick, + Esc: handle.close + }; + var custom = completion.options.customKeys; + var ourMap = custom ? {} : baseMap; + function addBinding(key, val) { + var bound; + if (typeof val != "string") + bound = function(cm) { return val(cm, handle); }; + // This mechanism is deprecated + else if (baseMap.hasOwnProperty(val)) + bound = baseMap[val]; + else + bound = val; + ourMap[key] = bound; + } + if (custom) + for (var key in custom) if (custom.hasOwnProperty(key)) + addBinding(key, custom[key]); + var extra = completion.options.extraKeys; + if (extra) + for (var key in extra) if (extra.hasOwnProperty(key)) + addBinding(key, extra[key]); + return ourMap; + } + + function getHintElement(hintsElement, el) { + while (el && el != hintsElement) { + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; + el = el.parentNode; + } + } + + function Widget(completion, data) { + this.completion = completion; + this.data = data; + this.picked = false; + var widget = this, cm = completion.cm; + + var hints = this.hints = document.createElement("ul"); + hints.className = "CodeMirror-hints"; + this.selectedHint = data.selectedHint || 0; + + var completions = data.list; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + if (cur.render) cur.render(elt, data, cur); + else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); + elt.hintId = i; + } + + var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); + var left = pos.left, top = pos.bottom, below = true; + hints.style.left = left + "px"; + hints.style.top = top + "px"; + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + (completion.options.container || document.body).appendChild(hints); + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; + var scrolls = hints.scrollHeight > hints.clientHeight + 1 + var startScroll = cm.getScrollInfo(); + + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = pos.top - height) + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + hints.style.top = (top = pos.bottom - box.top) + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left) + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.right - winW; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (left = pos.left - overlapX) + "px"; + } + if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) + node.style.paddingRight = cm.display.nativeBarWidth + "px" + + cm.addKeyMap(this.keyMap = buildKeyMap(completion, { + moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, + setFocus: function(n) { widget.changeActive(n); }, + menuSize: function() { return widget.screenAmount(); }, + length: completions.length, + close: function() { completion.close(); }, + pick: function() { widget.pick(); }, + data: data + })); + + if (completion.options.closeOnUnfocus) { + var closingOnBlur; + cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); + cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); + } + + cm.on("scroll", this.onScroll = function() { + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top; + var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return completion.close(); + hints.style.top = newTop + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; + }); + + CodeMirror.on(hints, "dblclick", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} + }); + + CodeMirror.on(hints, "click", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + if (completion.options.completeOnSingleClick) widget.pick(); + } + }); + + CodeMirror.on(hints, "mousedown", function() { + setTimeout(function(){cm.focus();}, 20); + }); + + CodeMirror.signal(data, "select", completions[0], hints.firstChild); + return true; + } + + Widget.prototype = { + close: function() { + if (this.completion.widget != this) return; + this.completion.widget = null; + this.hints.parentNode.removeChild(this.hints); + this.completion.cm.removeKeyMap(this.keyMap); + + var cm = this.completion.cm; + if (this.completion.options.closeOnUnfocus) { + cm.off("blur", this.onBlur); + cm.off("focus", this.onFocus); + } + cm.off("scroll", this.onScroll); + }, + + disable: function() { + this.completion.cm.removeKeyMap(this.keyMap); + var widget = this; + this.keyMap = {Enter: function() { widget.picked = true; }}; + this.completion.cm.addKeyMap(this.keyMap); + }, + + pick: function() { + this.completion.pick(this.data, this.selectedHint); + }, + + changeActive: function(i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; + if (this.selectedHint == i) return; + var node = this.hints.childNodes[this.selectedHint]; + node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + node = this.hints.childNodes[this.selectedHint = i]; + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; + if (node.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node.offsetTop - 3; + else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); + }, + + screenAmount: function() { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + } + }; + + function applicableHelpers(cm, helpers) { + if (!cm.somethingSelected()) return helpers + var result = [] + for (var i = 0; i < helpers.length; i++) + if (helpers[i].supportsSelection) result.push(helpers[i]) + return result + } + + function fetchHints(hint, cm, options, callback) { + if (hint.async) { + hint(cm, callback, options) + } else { + var result = hint(cm, options) + if (result && result.then) result.then(callback) + else callback(result) + } + } + + function resolveAutoHints(cm, pos) { + var helpers = cm.getHelpers(pos, "hint"), words + if (helpers.length) { + var resolved = function(cm, callback, options) { + var app = applicableHelpers(cm, helpers); + function run(i) { + if (i == app.length) return callback(null) + fetchHints(app[i], cm, options, function(result) { + if (result && result.list.length > 0) callback(result) + else run(i + 1) + }) + } + run(0) + } + resolved.async = true + resolved.supportsSelection = true + return resolved + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { + // 发消息让其他组件注入 其他hint + CodeMirror.signal(cm, "hinting", words); + var myhints = cm.state.myhints + var wordsTemp = words.slice(0) + myhints && myhints.forEach(function(item) { + if (words.indexOf(item) === -1) wordsTemp.push(item) + }) + return function(cm) { + return CodeMirror.hint.fromList(cm, {words: wordsTemp}) + } + } else if (CodeMirror.hint.anyword) { + return function(cm, options) { return CodeMirror.hint.anyword(cm, options) } + } else { + return function() {} + } + } + + CodeMirror.registerHelper("hint", "auto", { + resolve: resolveAutoHints + }); + + CodeMirror.registerHelper("hint", "fromList", function(cm, options) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var to = CodeMirror.Pos(cur.line, token.end); + if (token.string && /\w/.test(token.string[token.string.length - 1])) { + var term = token.string, from = CodeMirror.Pos(cur.line, token.start); + } else { + var term = "", from = to; + } + var found = []; + + if (fuzzysort && fuzzysort.go) { + var result = fuzzysort.go(term, options.words) + result && result.forEach(function(item) { + found.push(item.target) + }) + } else { + for (var i = 0; i < options.words.length; i++) { + var word = options.words[i]; + if (word.slice(0, term.length) == term) + found.push(word); + } + } + if (found.length) return {list: found, from: from, to: to}; + }); + + CodeMirror.commands.autocomplete = CodeMirror.showHint; + + var defaultOptions = { + hint: CodeMirror.hint.auto, + completeSingle: true, + alignWithWord: true, + closeCharacters: /[\s()\[\]{};:>,]/, + closeOnUnfocus: true, + completeOnSingleClick: true, + container: null, + customKeys: null, + extraKeys: null + }; + + CodeMirror.defineOption("hintOptions", null); +}); diff --git a/public/react/public/js/codemirror/codemirror.js b/public/react/public/js/codemirror/codemirror.js new file mode 100755 index 000000000..73e034ebb --- /dev/null +++ b/public/react/public/js/codemirror/codemirror.js @@ -0,0 +1,9304 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// This is CodeMirror (http://codemirror.net), a code editor +// implemented in JavaScript on top of the browser's DOM. +// +// You can find some technical background for some of the code below +// at http://marijnhaverbeke.nl/blog/#cm-internals . + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.CodeMirror = factory()); +}(this, (function () { 'use strict'; + +// Kludges for bugs and behavior differences that can't be feature +// detected are enabled based on userAgent etc sniffing. +var userAgent = navigator.userAgent +var platform = navigator.platform + +var gecko = /gecko\/\d/i.test(userAgent) +var ie_upto10 = /MSIE \d/.test(userAgent) +var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent) +var edge = /Edge\/(\d+)/.exec(userAgent) +var ie = ie_upto10 || ie_11up || edge +var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]) +var webkit = !edge && /WebKit\//.test(userAgent) +var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent) +var chrome = !edge && /Chrome\//.test(userAgent) +var presto = /Opera\//.test(userAgent) +var safari = /Apple Computer/.test(navigator.vendor) +var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent) +var phantom = /PhantomJS/.test(userAgent) + +var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent) +var android = /Android/.test(userAgent) +// This is woefully incomplete. Suggestions for alternative methods welcome. +var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent) +var mac = ios || /Mac/.test(platform) +var chromeOS = /\bCrOS\b/.test(userAgent) +var windows = /win/i.test(platform) + +var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/) +if (presto_version) { presto_version = Number(presto_version[1]) } +if (presto_version && presto_version >= 15) { presto = false; webkit = true } +// Some browsers use the wrong event properties to signal cmd/ctrl on OS X +var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)) +var captureRightClick = gecko || (ie && ie_version >= 9) + +function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } + +var rmClass = function(node, cls) { + var current = node.className + var match = classTest(cls).exec(current) + if (match) { + var after = current.slice(match.index + match[0].length) + node.className = current.slice(0, match.index) + (after ? match[1] + after : "") + } +} + +function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + { e.removeChild(e.firstChild) } + return e +} + +function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e) +} + +function elt(tag, content, className, style) { + var e = document.createElement(tag) + if (className) { e.className = className } + if (style) { e.style.cssText = style } + if (typeof content == "string") { e.appendChild(document.createTextNode(content)) } + else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]) } } + return e +} +// wrapper for elt, which removes the elt from the accessibility tree +function eltP(tag, content, className, style) { + var e = elt(tag, content, className, style) + e.setAttribute("role", "presentation") + return e +} + +var range +if (document.createRange) { range = function(node, start, end, endNode) { + var r = document.createRange() + r.setEnd(endNode || node, end) + r.setStart(node, start) + return r +} } +else { range = function(node, start, end) { + var r = document.body.createTextRange() + try { r.moveToElementText(node.parentNode) } + catch(e) { return r } + r.collapse(true) + r.moveEnd("character", end) + r.moveStart("character", start) + return r +} } + +function contains(parent, child) { + if (child.nodeType == 3) // Android browser always returns false when child is a textnode + { child = child.parentNode } + if (parent.contains) + { return parent.contains(child) } + do { + if (child.nodeType == 11) { child = child.host } + if (child == parent) { return true } + } while (child = child.parentNode) +} + +function activeElt() { + // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement. + // IE < 10 will throw when accessed while the page is loading or in an iframe. + // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable. + var activeElement + try { + activeElement = document.activeElement + } catch(e) { + activeElement = document.body || null + } + while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement) + { activeElement = activeElement.shadowRoot.activeElement } + return activeElement +} + +function addClass(node, cls) { + var current = node.className + if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls } +} +function joinClasses(a, b) { + var as = a.split(" ") + for (var i = 0; i < as.length; i++) + { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i] } } + return b +} + +var selectInput = function(node) { node.select() } +if (ios) // Mobile Safari apparently has a bug where select() is broken. + { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length } } +else if (ie) // Suppress mysterious IE10 errors + { selectInput = function(node) { try { node.select() } catch(_e) {} } } + +function bind(f) { + var args = Array.prototype.slice.call(arguments, 1) + return function(){return f.apply(null, args)} +} + +function copyObj(obj, target, overwrite) { + if (!target) { target = {} } + for (var prop in obj) + { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + { target[prop] = obj[prop] } } + return target +} + +// Counts the column offset in a string, taking tabs into account. +// Used mostly to find indentation. +function countColumn(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/) + if (end == -1) { end = string.length } + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i) + if (nextTab < 0 || nextTab >= end) + { return n + (end - i) } + n += nextTab - i + n += tabSize - (n % tabSize) + i = nextTab + 1 + } +} + +var Delayed = function() {this.id = null}; +Delayed.prototype.set = function (ms, f) { + clearTimeout(this.id) + this.id = setTimeout(f, ms) +}; + +function indexOf(array, elt) { + for (var i = 0; i < array.length; ++i) + { if (array[i] == elt) { return i } } + return -1 +} + +// Number of pixels added to scroller and sizer to hide scrollbar +var scrollerGap = 30 + +// Returned or thrown by various protocols to signal 'I'm not +// handling this'. +var Pass = {toString: function(){return "CodeMirror.Pass"}} + +// Reused option objects for setSelection & friends +var sel_dontScroll = {scroll: false}; +var sel_mouse = {origin: "*mouse"}; +var sel_move = {origin: "+move"}; +// The inverse of countColumn -- find the offset that corresponds to +// a particular column. +function findColumn(string, goal, tabSize) { + for (var pos = 0, col = 0;;) { + var nextTab = string.indexOf("\t", pos) + if (nextTab == -1) { nextTab = string.length } + var skipped = nextTab - pos + if (nextTab == string.length || col + skipped >= goal) + { return pos + Math.min(skipped, goal - col) } + col += nextTab - pos + col += tabSize - (col % tabSize) + pos = nextTab + 1 + if (col >= goal) { return pos } + } +} + +var spaceStrs = [""] +function spaceStr(n) { + while (spaceStrs.length <= n) + { spaceStrs.push(lst(spaceStrs) + " ") } + return spaceStrs[n] +} + +function lst(arr) { return arr[arr.length-1] } + +function map(array, f) { + var out = [] + for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i) } + return out +} + +function insertSorted(array, value, score) { + var pos = 0, priority = score(value) + while (pos < array.length && score(array[pos]) <= priority) { pos++ } + array.splice(pos, 0, value) +} + +function nothing() {} + +function createObj(base, props) { + var inst + if (Object.create) { + inst = Object.create(base) + } else { + nothing.prototype = base + inst = new nothing() + } + if (props) { copyObj(props, inst) } + return inst +} + +var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/ +function isWordCharBasic(ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)) +} +function isWordChar(ch, helper) { + if (!helper) { return isWordCharBasic(ch) } + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true } + return helper.test(ch) +} + +function isEmpty(obj) { + for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } } + return true +} + +// Extending unicode characters. A series of a non-extending char + +// any number of extending chars is treated as a single unit as far +// as editing and measuring is concerned. This is not fully correct, +// since some scripts/fonts/browsers also treat other configurations +// of code points as a group. +var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/ +function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) } + +// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range. +function skipExtendingChars(str, pos, dir) { + while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir } + return pos +} + +// Returns the value from the range [`from`; `to`] that satisfies +// `pred` and is closest to `from`. Assumes that at least `to` satisfies `pred`. +function findFirst(pred, from, to) { + for (;;) { + if (Math.abs(from - to) <= 1) { return pred(from) ? from : to } + var mid = Math.floor((from + to) / 2) + if (pred(mid)) { to = mid } + else { from = mid } + } +} + +// The display handles the DOM integration, both for input reading +// and content drawing. It holds references to DOM nodes and +// display-related state. + +function Display(place, doc, input) { + var d = this + this.input = input + + // Covers bottom-right square when both scrollbars are present. + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler") + d.scrollbarFiller.setAttribute("cm-not-content", "true") + // Covers bottom of gutter when coverGutterNextToScrollbar is on + // and h scrollbar is present. + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler") + d.gutterFiller.setAttribute("cm-not-content", "true") + // Will contain the actual code, positioned to cover the viewport. + d.lineDiv = eltP("div", null, "CodeMirror-code") + // Elements are added to these to represent selection and cursors. + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1") + d.cursorDiv = elt("div", null, "CodeMirror-cursors") + // A visibility: hidden element used to find the size of things. + d.measure = elt("div", null, "CodeMirror-measure") + // When lines outside of the viewport are measured, they are drawn in this. + d.lineMeasure = elt("div", null, "CodeMirror-measure") + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], + null, "position: relative; outline: none") + var lines = eltP("div", [d.lineSpace], "CodeMirror-lines") + // Moved around its parent to cover visible view. + d.mover = elt("div", [lines], null, "position: relative") + // Set to the height of the document, allowing scrolling. + d.sizer = elt("div", [d.mover], "CodeMirror-sizer") + d.sizerWidth = null + // Behavior of elts with overflow: auto and padding is + // inconsistent across browsers. This is used to ensure the + // scrollable area is big enough. + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;") + // Will contain the gutters, if any. + d.gutters = elt("div", null, "CodeMirror-gutters") + d.lineGutter = null + // Actual scrollable element. + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll") + d.scroller.setAttribute("tabIndex", "-1") + // The element in which the editor lives. + d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror") + + // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0 } + if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true } + + if (place) { + if (place.appendChild) { place.appendChild(d.wrapper) } + else { place(d.wrapper) } + } + + // Current rendered range (may be bigger than the view window). + d.viewFrom = d.viewTo = doc.first + d.reportedViewFrom = d.reportedViewTo = doc.first + // Information about the rendered lines. + d.view = [] + d.renderedView = null + // Holds info about a single rendered line when it was rendered + // for measurement, while not in view. + d.externalMeasured = null + // Empty space (in pixels) above the view + d.viewOffset = 0 + d.lastWrapHeight = d.lastWrapWidth = 0 + d.updateLineNumbers = null + + d.nativeBarWidth = d.barHeight = d.barWidth = 0 + d.scrollbarsClipped = false + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null + // Set to true when a non-horizontal-scrolling line widget is + // added. As an optimization, line widget aligning is skipped when + // this is false. + d.alignWidgets = false + + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null + d.maxLineLength = 0 + d.maxLineChanged = false + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null + + // True when shift is held down. + d.shift = false + + // Used to track whether anything happened since the context menu + // was opened. + d.selForContextMenu = null + + d.activeTouch = null + + input.init(d) +} + +// Find the line object corresponding to the given line number. +function getLine(doc, n) { + n -= doc.first + if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") } + var chunk = doc + while (!chunk.lines) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize() + if (n < sz) { chunk = child; break } + n -= sz + } + } + return chunk.lines[n] +} + +// Get the part of a document between two positions, as an array of +// strings. +function getBetween(doc, start, end) { + var out = [], n = start.line + doc.iter(start.line, end.line + 1, function (line) { + var text = line.text + if (n == end.line) { text = text.slice(0, end.ch) } + if (n == start.line) { text = text.slice(start.ch) } + out.push(text) + ++n + }) + return out +} +// Get the lines between from and to, as array of strings. +function getLines(doc, from, to) { + var out = [] + doc.iter(from, to, function (line) { out.push(line.text) }) // iter aborts when callback returns truthy value + return out +} + +// Update the height of a line, propagating the height change +// upwards to parent nodes. +function updateLineHeight(line, height) { + var diff = height - line.height + if (diff) { for (var n = line; n; n = n.parent) { n.height += diff } } +} + +// Given a line object, find its line number by walking up through +// its parent links. +function lineNo(line) { + if (line.parent == null) { return null } + var cur = line.parent, no = indexOf(cur.lines, line) + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0;; ++i) { + if (chunk.children[i] == cur) { break } + no += chunk.children[i].chunkSize() + } + } + return no + cur.first +} + +// Find the line at the given vertical position, using the height +// information in the document tree. +function lineAtHeight(chunk, h) { + var n = chunk.first + outer: do { + for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) { + var child = chunk.children[i$1], ch = child.height + if (h < ch) { chunk = child; continue outer } + h -= ch + n += child.chunkSize() + } + return n + } while (!chunk.lines) + var i = 0 + for (; i < chunk.lines.length; ++i) { + var line = chunk.lines[i], lh = line.height + if (h < lh) { break } + h -= lh + } + return n + i +} + +function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size} + +function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)) +} + +// A Pos instance represents a position within the text. +function Pos(line, ch, sticky) { + if ( sticky === void 0 ) sticky = null; + + if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) } + this.line = line + this.ch = ch + this.sticky = sticky +} + +// Compare two positions, return 0 if they are the same, a negative +// number when a is less, and a positive number otherwise. +function cmp(a, b) { return a.line - b.line || a.ch - b.ch } + +function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 } + +function copyPos(x) {return Pos(x.line, x.ch)} +function maxPos(a, b) { return cmp(a, b) < 0 ? b : a } +function minPos(a, b) { return cmp(a, b) < 0 ? a : b } + +// Most of the external API clips given positions to make sure they +// actually exist within the document. +function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))} +function clipPos(doc, pos) { + if (pos.line < doc.first) { return Pos(doc.first, 0) } + var last = doc.first + doc.size - 1 + if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) } + return clipToLen(pos, getLine(doc, pos.line).text.length) +} +function clipToLen(pos, linelen) { + var ch = pos.ch + if (ch == null || ch > linelen) { return Pos(pos.line, linelen) } + else if (ch < 0) { return Pos(pos.line, 0) } + else { return pos } +} +function clipPosArray(doc, array) { + var out = [] + for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]) } + return out +} + +// Optimize some code when these features are not used. +var sawReadOnlySpans = false; +var sawCollapsedSpans = false; +function seeReadOnlySpans() { + sawReadOnlySpans = true +} + +function seeCollapsedSpans() { + sawCollapsedSpans = true +} + +// TEXTMARKER SPANS + +function MarkedSpan(marker, from, to) { + this.marker = marker + this.from = from; this.to = to +} + +// Search an array of spans for a span matching the given marker. +function getMarkedSpanFor(spans, marker) { + if (spans) { for (var i = 0; i < spans.length; ++i) { + var span = spans[i] + if (span.marker == marker) { return span } + } } +} +// Remove a span from an array, returning undefined if no spans are +// left (we don't store arrays for lines without spans). +function removeMarkedSpan(spans, span) { + var r + for (var i = 0; i < spans.length; ++i) + { if (spans[i] != span) { (r || (r = [])).push(spans[i]) } } + return r +} +// Add a span to a line. +function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span] + span.marker.attachLine(line) +} + +// Used for the algorithm that adjusts markers for a change in the +// document. These functions cut an array of spans at a given +// character position, returning an array of remaining chunks (or +// undefined if nothing remains). +function markedSpansBefore(old, startCh, isInsert) { + var nw + if (old) { for (var i = 0; i < old.length; ++i) { + var span = old[i], marker = span.marker + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh) + if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh) + ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)) + } + } } + return nw +} +function markedSpansAfter(old, endCh, isInsert) { + var nw + if (old) { for (var i = 0; i < old.length; ++i) { + var span = old[i], marker = span.marker + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh) + if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh) + ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)) + } + } } + return nw +} + +// Given a change object, compute the new set of marker spans that +// cover the line in which the change took place. Removes spans +// entirely within the change, reconnects spans belonging to the +// same marker that appear on both sides of the change, and cuts off +// spans partially within the change. Returns an array of span +// arrays with one element for each line in (after) the change. +function stretchSpansOverChange(doc, change) { + if (change.full) { return null } + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans + if (!oldFirst && !oldLast) { return null } + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0 + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert) + var last = markedSpansAfter(oldLast, endCh, isInsert) + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0) + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i] + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker) + if (!found) { span.to = startCh } + else if (sameLine) { span.to = found.to == null ? null : found.to + offset } + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i$1 = 0; i$1 < last.length; ++i$1) { + var span$1 = last[i$1] + if (span$1.to != null) { span$1.to += offset } + if (span$1.from == null) { + var found$1 = getMarkedSpanFor(first, span$1.marker) + if (!found$1) { + span$1.from = offset + if (sameLine) { (first || (first = [])).push(span$1) } + } + } else { + span$1.from += offset + if (sameLine) { (first || (first = [])).push(span$1) } + } + } + } + // Make sure we didn't create any zero-length spans + if (first) { first = clearEmptySpans(first) } + if (last && last != first) { last = clearEmptySpans(last) } + + var newMarkers = [first] + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers + if (gap > 0 && first) + { for (var i$2 = 0; i$2 < first.length; ++i$2) + { if (first[i$2].to == null) + { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)) } } } + for (var i$3 = 0; i$3 < gap; ++i$3) + { newMarkers.push(gapMarkers) } + newMarkers.push(last) + } + return newMarkers +} + +// Remove spans that are empty and don't have a clearWhenEmpty +// option of false. +function clearEmptySpans(spans) { + for (var i = 0; i < spans.length; ++i) { + var span = spans[i] + if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) + { spans.splice(i--, 1) } + } + if (!spans.length) { return null } + return spans +} + +// Used to 'clip' out readOnly ranges when making a change. +function removeReadOnlyRanges(doc, from, to) { + var markers = null + doc.iter(from.line, to.line + 1, function (line) { + if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + { (markers || (markers = [])).push(mark) } + } } + }) + if (!markers) { return null } + var parts = [{from: from, to: to}] + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(0) + for (var j = 0; j < parts.length; ++j) { + var p = parts[j] + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue } + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to) + if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) + { newParts.push({from: p.from, to: m.from}) } + if (dto > 0 || !mk.inclusiveRight && !dto) + { newParts.push({from: m.to, to: p.to}) } + parts.splice.apply(parts, newParts) + j += newParts.length - 3 + } + } + return parts +} + +// Connect or disconnect spans from a line. +function detachMarkedSpans(line) { + var spans = line.markedSpans + if (!spans) { return } + for (var i = 0; i < spans.length; ++i) + { spans[i].marker.detachLine(line) } + line.markedSpans = null +} +function attachMarkedSpans(line, spans) { + if (!spans) { return } + for (var i = 0; i < spans.length; ++i) + { spans[i].marker.attachLine(line) } + line.markedSpans = spans +} + +// Helpers used when computing which overlapping collapsed span +// counts as the larger one. +function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 } +function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 } + +// Returns a number indicating which of two overlapping collapsed +// spans is larger (and thus includes the other). Falls back to +// comparing ids when the spans cover exactly the same range. +function compareCollapsedMarkers(a, b) { + var lenDiff = a.lines.length - b.lines.length + if (lenDiff != 0) { return lenDiff } + var aPos = a.find(), bPos = b.find() + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b) + if (fromCmp) { return -fromCmp } + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b) + if (toCmp) { return toCmp } + return b.id - a.id +} + +// Find out whether a line ends or starts in a collapsed span. If +// so, return the marker for that span. +function collapsedSpanAtSide(line, start) { + var sps = sawCollapsedSpans && line.markedSpans, found + if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { + sp = sps[i] + if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) + { found = sp.marker } + } } + return found +} +function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) } +function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) } + +// Test whether there exists a collapsed span that partially +// overlaps (covers the start or end, but not both) of a new span. +// Such overlap is not allowed. +function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo) + var sps = sawCollapsedSpans && line.markedSpans + if (sps) { for (var i = 0; i < sps.length; ++i) { + var sp = sps[i] + if (!sp.marker.collapsed) { continue } + var found = sp.marker.find(0) + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker) + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker) + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue } + if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) || + fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0)) + { return true } + } } +} + +// A visual line is a line as drawn on the screen. Folding, for +// example, can cause multiple logical lines to appear on the same +// visual line. This finds the start of the visual line that the +// given line is part of (usually that is the line itself). +function visualLine(line) { + var merged + while (merged = collapsedSpanAtStart(line)) + { line = merged.find(-1, true).line } + return line +} + +function visualLineEnd(line) { + var merged + while (merged = collapsedSpanAtEnd(line)) + { line = merged.find(1, true).line } + return line +} + +// Returns an array of logical lines that continue the visual line +// started by the argument, or undefined if there are no such lines. +function visualLineContinued(line) { + var merged, lines + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line + ;(lines || (lines = [])).push(line) + } + return lines +} + +// Get the line number of the start of the visual line that the +// given line number is part of. +function visualLineNo(doc, lineN) { + var line = getLine(doc, lineN), vis = visualLine(line) + if (line == vis) { return lineN } + return lineNo(vis) +} + +// Get the line number of the start of the next visual line after +// the given line. +function visualLineEndNo(doc, lineN) { + if (lineN > doc.lastLine()) { return lineN } + var line = getLine(doc, lineN), merged + if (!lineIsHidden(doc, line)) { return lineN } + while (merged = collapsedSpanAtEnd(line)) + { line = merged.find(1, true).line } + return lineNo(line) + 1 +} + +// Compute whether a line is hidden. Lines count as hidden when they +// are part of a visual line that starts with another line, or when +// they are entirely covered by collapsed, non-widget span. +function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans + if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { + sp = sps[i] + if (!sp.marker.collapsed) { continue } + if (sp.from == null) { return true } + if (sp.marker.widgetNode) { continue } + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + { return true } + } } +} +function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find(1, true) + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)) + } + if (span.marker.inclusiveRight && span.to == line.text.length) + { return true } + for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i] + if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && + (sp.to == null || sp.to != span.from) && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) { return true } + } +} + +// Find the height above the given line. +function heightAtLine(lineObj) { + lineObj = visualLine(lineObj) + + var h = 0, chunk = lineObj.parent + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i] + if (line == lineObj) { break } + else { h += line.height } + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i$1 = 0; i$1 < p.children.length; ++i$1) { + var cur = p.children[i$1] + if (cur == chunk) { break } + else { h += cur.height } + } + } + return h +} + +// Compute the character length of a line, taking into account +// collapsed ranges (see markText) that might hide parts, and join +// other lines onto it. +function lineLength(line) { + if (line.height == 0) { return 0 } + var len = line.text.length, merged, cur = line + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(0, true) + cur = found.from.line + len += found.from.ch - found.to.ch + } + cur = line + while (merged = collapsedSpanAtEnd(cur)) { + var found$1 = merged.find(0, true) + len -= cur.text.length - found$1.from.ch + cur = found$1.to.line + len += cur.text.length - found$1.to.ch + } + return len +} + +// Find the longest line in the document. +function findMaxLine(cm) { + var d = cm.display, doc = cm.doc + d.maxLine = getLine(doc, doc.first) + d.maxLineLength = lineLength(d.maxLine) + d.maxLineChanged = true + doc.iter(function (line) { + var len = lineLength(line) + if (len > d.maxLineLength) { + d.maxLineLength = len + d.maxLine = line + } + }) +} + +// BIDI HELPERS + +function iterateBidiSections(order, from, to, f) { + if (!order) { return f(from, to, "ltr") } + var found = false + for (var i = 0; i < order.length; ++i) { + var part = order[i] + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr") + found = true + } + } + if (!found) { f(from, to, "ltr") } +} + +var bidiOther = null +function getBidiPartAt(order, ch, sticky) { + var found + bidiOther = null + for (var i = 0; i < order.length; ++i) { + var cur = order[i] + if (cur.from < ch && cur.to > ch) { return i } + if (cur.to == ch) { + if (cur.from != cur.to && sticky == "before") { found = i } + else { bidiOther = i } + } + if (cur.from == ch) { + if (cur.from != cur.to && sticky != "before") { found = i } + else { bidiOther = i } + } + } + return found != null ? found : bidiOther +} + +// Bidirectional ordering algorithm +// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm +// that this (partially) implements. + +// One-char codes used for character types: +// L (L): Left-to-Right +// R (R): Right-to-Left +// r (AL): Right-to-Left Arabic +// 1 (EN): European Number +// + (ES): European Number Separator +// % (ET): European Number Terminator +// n (AN): Arabic Number +// , (CS): Common Number Separator +// m (NSM): Non-Spacing Mark +// b (BN): Boundary Neutral +// s (B): Paragraph Separator +// t (S): Segment Separator +// w (WS): Whitespace +// N (ON): Other Neutrals + +// Returns null if characters are ordered as they appear +// (left-to-right), or an array of sections ({from, to, level} +// objects) in the order in which they occur visually. +var bidiOrdering = (function() { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN" + // Character types for codepoints 0x600 to 0x6f9 + var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111" + function charType(code) { + if (code <= 0xf7) { return lowTypes.charAt(code) } + else if (0x590 <= code && code <= 0x5f4) { return "R" } + else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) } + else if (0x6ee <= code && code <= 0x8ac) { return "r" } + else if (0x2000 <= code && code <= 0x200b) { return "w" } + else if (code == 0x200c) { return "b" } + else { return "L" } + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/ + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/ + + function BidiSpan(level, from, to) { + this.level = level + this.from = from; this.to = to + } + + return function(str, direction) { + var outerType = direction == "ltr" ? "L" : "R" + + if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false } + var len = str.length, types = [] + for (var i = 0; i < len; ++i) + { types.push(charType(str.charCodeAt(i))) } + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) { + var type = types[i$1] + if (type == "m") { types[i$1] = prev } + else { prev = type } + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) { + var type$1 = types[i$2] + if (type$1 == "1" && cur == "r") { types[i$2] = "n" } + else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R" } } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) { + var type$2 = types[i$3] + if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1" } + else if (type$2 == "," && prev$1 == types[i$3+1] && + (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1 } + prev$1 = type$2 + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i$4 = 0; i$4 < len; ++i$4) { + var type$3 = types[i$4] + if (type$3 == ",") { types[i$4] = "N" } + else if (type$3 == "%") { + var end = (void 0) + for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {} + var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N" + for (var j = i$4; j < end; ++j) { types[j] = replace } + i$4 = end - 1 + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) { + var type$4 = types[i$5] + if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L" } + else if (isStrong.test(type$4)) { cur$1 = type$4 } + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i$6 = 0; i$6 < len; ++i$6) { + if (isNeutral.test(types[i$6])) { + var end$1 = (void 0) + for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {} + var before = (i$6 ? types[i$6-1] : outerType) == "L" + var after = (end$1 < len ? types[end$1] : outerType) == "L" + var replace$1 = before == after ? (before ? "L" : "R") : outerType + for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1 } + i$6 = end$1 - 1 + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m + for (var i$7 = 0; i$7 < len;) { + if (countsAsLeft.test(types[i$7])) { + var start = i$7 + for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {} + order.push(new BidiSpan(0, start, i$7)) + } else { + var pos = i$7, at = order.length + for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {} + for (var j$2 = pos; j$2 < i$7;) { + if (countsAsNum.test(types[j$2])) { + if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)) } + var nstart = j$2 + for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {} + order.splice(at, 0, new BidiSpan(2, nstart, j$2)) + pos = j$2 + } else { ++j$2 } + } + if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)) } + } + } + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length + order.unshift(new BidiSpan(0, 0, m[0].length)) + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length + order.push(new BidiSpan(0, len - m[0].length, len)) + } + + return direction == "rtl" ? order.reverse() : order + } +})() + +// Get the bidi ordering for the given line (and cache it). Returns +// false for lines that are fully left-to-right, and an array of +// BidiSpan objects otherwise. +function getOrder(line, direction) { + var order = line.order + if (order == null) { order = line.order = bidiOrdering(line.text, direction) } + return order +} + +function moveCharLogically(line, ch, dir) { + var target = skipExtendingChars(line.text, ch + dir, dir) + return target < 0 || target > line.text.length ? null : target +} + +function moveLogically(line, start, dir) { + var ch = moveCharLogically(line, start.ch, dir) + return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before") +} + +function endOfLine(visually, cm, lineObj, lineNo, dir) { + if (visually) { + var order = getOrder(lineObj, cm.doc.direction) + if (order) { + var part = dir < 0 ? lst(order) : order[0] + var moveInStorageOrder = (dir < 0) == (part.level == 1) + var sticky = moveInStorageOrder ? "after" : "before" + var ch + // With a wrapped rtl chunk (possibly spanning multiple bidi parts), + // it could be that the last bidi part is not on the last visual line, + // since visual lines contain content order-consecutive chunks. + // Thus, in rtl, we are looking for the first (content-order) character + // in the rtl chunk that is on the last line (that is, the same line + // as the last (content-order) character). + if (part.level > 0) { + var prep = prepareMeasureForLine(cm, lineObj) + ch = dir < 0 ? lineObj.text.length - 1 : 0 + var targetTop = measureCharPrepared(cm, prep, ch).top + ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch) + if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1, true) } + } else { ch = dir < 0 ? part.to : part.from } + return new Pos(lineNo, ch, sticky) + } + } + return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after") +} + +function moveVisually(cm, line, start, dir) { + var bidi = getOrder(line, cm.doc.direction) + if (!bidi) { return moveLogically(line, start, dir) } + if (start.ch >= line.text.length) { + start.ch = line.text.length + start.sticky = "before" + } else if (start.ch <= 0) { + start.ch = 0 + start.sticky = "after" + } + var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos] + if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) { + // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines, + // nothing interesting happens. + return moveLogically(line, start, dir) + } + + var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); } + var prep + var getWrappedLineExtent = function (ch) { + if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} } + prep = prep || prepareMeasureForLine(cm, line) + return wrappedLineExtentChar(cm, line, prep, ch) + } + var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch) + + if (cm.doc.direction == "rtl" || part.level == 1) { + var moveInStorageOrder = (part.level == 1) == (dir < 0) + var ch = mv(start, moveInStorageOrder ? 1 : -1) + if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) { + // Case 2: We move within an rtl part or in an rtl editor on the same visual line + var sticky = moveInStorageOrder ? "before" : "after" + return new Pos(start.line, ch, sticky) + } + } + + // Case 3: Could not move within this bidi part in this visual line, so leave + // the current bidi part + + var searchInVisualLine = function (partPos, dir, wrappedLineExtent) { + var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder + ? new Pos(start.line, mv(ch, 1), "before") + : new Pos(start.line, ch, "after"); } + + for (; partPos >= 0 && partPos < bidi.length; partPos += dir) { + var part = bidi[partPos] + var moveInStorageOrder = (dir > 0) == (part.level != 1) + var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1) + if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) } + ch = moveInStorageOrder ? part.from : mv(part.to, -1) + if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) } + } + } + + // Case 3a: Look for other bidi parts on the same visual line + var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent) + if (res) { return res } + + // Case 3b: Look for other bidi parts on the next visual line + var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1) + if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) { + res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh)) + if (res) { return res } + } + + // Case 4: Nowhere to move + return null +} + +// EVENT HANDLING + +// Lightweight event framework. on/off also work on DOM nodes, +// registering native DOM handlers. + +var noHandlers = [] + +var on = function(emitter, type, f) { + if (emitter.addEventListener) { + emitter.addEventListener(type, f, false) + } else if (emitter.attachEvent) { + emitter.attachEvent("on" + type, f) + } else { + var map = emitter._handlers || (emitter._handlers = {}) + map[type] = (map[type] || noHandlers).concat(f) + } +} + +function getHandlers(emitter, type) { + return emitter._handlers && emitter._handlers[type] || noHandlers +} + +function off(emitter, type, f) { + if (emitter.removeEventListener) { + emitter.removeEventListener(type, f, false) + } else if (emitter.detachEvent) { + emitter.detachEvent("on" + type, f) + } else { + var map = emitter._handlers, arr = map && map[type] + if (arr) { + var index = indexOf(arr, f) + if (index > -1) + { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)) } + } + } +} + +function signal(emitter, type /*, values...*/) { + var handlers = getHandlers(emitter, type) + if (!handlers.length) { return } + var args = Array.prototype.slice.call(arguments, 2) + for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args) } +} + +// The DOM events that CodeMirror handles can be overridden by +// registering a (non-DOM) handler on the editor for the event name, +// and preventDefault-ing the event in that handler. +function signalDOMEvent(cm, e, override) { + if (typeof e == "string") + { e = {type: e, preventDefault: function() { this.defaultPrevented = true }} } + signal(cm, override || e.type, cm, e) + return e_defaultPrevented(e) || e.codemirrorIgnore +} + +function signalCursorActivity(cm) { + var arr = cm._handlers && cm._handlers.cursorActivity + if (!arr) { return } + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []) + for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1) + { set.push(arr[i]) } } +} + +function hasHandler(emitter, type) { + return getHandlers(emitter, type).length > 0 +} + +// Add on and off methods to a constructor's prototype, to make +// registering events on such objects more convenient. +function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f)} + ctor.prototype.off = function(type, f) {off(this, type, f)} +} + +// Due to the fact that we still support jurassic IE versions, some +// compatibility wrappers are needed. + +function e_preventDefault(e) { + if (e.preventDefault) { e.preventDefault() } + else { e.returnValue = false } +} +function e_stopPropagation(e) { + if (e.stopPropagation) { e.stopPropagation() } + else { e.cancelBubble = true } +} +function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false +} +function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)} + +function e_target(e) {return e.target || e.srcElement} +function e_button(e) { + var b = e.which + if (b == null) { + if (e.button & 1) { b = 1 } + else if (e.button & 2) { b = 3 } + else if (e.button & 4) { b = 2 } + } + if (mac && e.ctrlKey && b == 1) { b = 3 } + return b +} + +// Detect drag-and-drop +var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie && ie_version < 9) { return false } + var div = elt('div') + return "draggable" in div || "dragDrop" in div +}() + +var zwspSupported +function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b") + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])) + if (measure.firstChild.offsetHeight != 0) + { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8) } + } + var node = zwspSupported ? elt("span", "\u200b") : + elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px") + node.setAttribute("cm-text", "") + return node +} + +// Feature-detect IE's crummy client rect reporting for bidi text +var badBidiRects +function hasBadBidiRects(measure) { + if (badBidiRects != null) { return badBidiRects } + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")) + var r0 = range(txt, 0, 1).getBoundingClientRect() + var r1 = range(txt, 1, 2).getBoundingClientRect() + removeChildren(measure) + if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780) + return badBidiRects = (r1.right - r0.right < 3) +} + +// See if "".split is the broken IE version, if so, provide an +// alternative way to split lines. +var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) { + var pos = 0, result = [], l = string.length + while (pos <= l) { + var nl = string.indexOf("\n", pos) + if (nl == -1) { nl = string.length } + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl) + var rt = line.indexOf("\r") + if (rt != -1) { + result.push(line.slice(0, rt)) + pos += rt + 1 + } else { + result.push(line) + pos = nl + 1 + } + } + return result +} : function (string) { return string.split(/\r\n?|\n/); } + +var hasSelection = window.getSelection ? function (te) { + try { return te.selectionStart != te.selectionEnd } + catch(e) { return false } +} : function (te) { + var range + try {range = te.ownerDocument.selection.createRange()} + catch(e) {} + if (!range || range.parentElement() != te) { return false } + return range.compareEndPoints("StartToEnd", range) != 0 +} + +var hasCopyEvent = (function () { + var e = elt("div") + if ("oncopy" in e) { return true } + e.setAttribute("oncopy", "return;") + return typeof e.oncopy == "function" +})() + +var badZoomedRects = null +function hasBadZoomedRects(measure) { + if (badZoomedRects != null) { return badZoomedRects } + var node = removeChildrenAndAdd(measure, elt("span", "x")) + var normal = node.getBoundingClientRect() + var fromRange = range(node, 0, 1).getBoundingClientRect() + return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1 +} + +var modes = {}; +var mimeModes = {}; +// Extra arguments are stored as the mode's dependencies, which is +// used by (legacy) mechanisms like loadmode.js to automatically +// load a mode. (Preferred mechanism is the require/define calls.) +function defineMode(name, mode) { + if (arguments.length > 2) + { mode.dependencies = Array.prototype.slice.call(arguments, 2) } + modes[name] = mode +} + +function defineMIME(mime, spec) { + mimeModes[mime] = spec +} + +// Given a MIME type, a {name, ...options} config object, or a name +// string, return a mode config object. +function resolveMode(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec] + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name] + if (typeof found == "string") { found = {name: found} } + spec = createObj(found, spec) + spec.name = found.name + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return resolveMode("application/xml") + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) { + return resolveMode("application/json") + } + if (typeof spec == "string") { return {name: spec} } + else { return spec || {name: "null"} } +} + +// Given a mode spec (anything that resolveMode accepts), find and +// initialize an actual mode object. +function getMode(options, spec) { + spec = resolveMode(spec) + var mfactory = modes[spec.name] + if (!mfactory) { return getMode(options, "text/plain") } + var modeObj = mfactory(options, spec) + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name] + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) { continue } + if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop] } + modeObj[prop] = exts[prop] + } + } + modeObj.name = spec.name + if (spec.helperType) { modeObj.helperType = spec.helperType } + if (spec.modeProps) { for (var prop$1 in spec.modeProps) + { modeObj[prop$1] = spec.modeProps[prop$1] } } + + return modeObj +} + +// This can be used to attach properties to mode objects from +// outside the actual mode definition. +var modeExtensions = {} +function extendMode(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}) + copyObj(properties, exts) +} + +function copyState(mode, state) { + if (state === true) { return state } + if (mode.copyState) { return mode.copyState(state) } + var nstate = {} + for (var n in state) { + var val = state[n] + if (val instanceof Array) { val = val.concat([]) } + nstate[n] = val + } + return nstate +} + +// Given a mode and a state (for that mode), find the inner mode and +// state at the position that the state refers to. +function innerMode(mode, state) { + var info + while (mode.innerMode) { + info = mode.innerMode(state) + if (!info || info.mode == mode) { break } + state = info.state + mode = info.mode + } + return info || {mode: mode, state: state} +} + +function startState(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true +} + +// STRING STREAM + +// Fed to the mode parsers, provides helper functions to make +// parsers more succinct. + +var StringStream = function(string, tabSize) { + this.pos = this.start = 0 + this.string = string + this.tabSize = tabSize || 8 + this.lastColumnPos = this.lastColumnValue = 0 + this.lineStart = 0 +}; + +StringStream.prototype.eol = function () {return this.pos >= this.string.length}; +StringStream.prototype.sol = function () {return this.pos == this.lineStart}; +StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined}; +StringStream.prototype.next = function () { + if (this.pos < this.string.length) + { return this.string.charAt(this.pos++) } +}; +StringStream.prototype.eat = function (match) { + var ch = this.string.charAt(this.pos) + var ok + if (typeof match == "string") { ok = ch == match } + else { ok = ch && (match.test ? match.test(ch) : match(ch)) } + if (ok) {++this.pos; return ch} +}; +StringStream.prototype.eatWhile = function (match) { + var start = this.pos + while (this.eat(match)){} + return this.pos > start +}; +StringStream.prototype.eatSpace = function () { + var this$1 = this; + + var start = this.pos + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos } + return this.pos > start +}; +StringStream.prototype.skipToEnd = function () {this.pos = this.string.length}; +StringStream.prototype.skipTo = function (ch) { + var found = this.string.indexOf(ch, this.pos) + if (found > -1) {this.pos = found; return true} +}; +StringStream.prototype.backUp = function (n) {this.pos -= n}; +StringStream.prototype.column = function () { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue) + this.lastColumnPos = this.start + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) +}; +StringStream.prototype.indentation = function () { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) +}; +StringStream.prototype.match = function (pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; } + var substr = this.string.substr(this.pos, pattern.length) + if (cased(substr) == cased(pattern)) { + if (consume !== false) { this.pos += pattern.length } + return true + } + } else { + var match = this.string.slice(this.pos).match(pattern) + if (match && match.index > 0) { return null } + if (match && consume !== false) { this.pos += match[0].length } + return match + } +}; +StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)}; +StringStream.prototype.hideFirstChars = function (n, inner) { + this.lineStart += n + try { return inner() } + finally { this.lineStart -= n } +}; + +// Compute a style array (an array starting with a mode generation +// -- for invalidation -- followed by pairs of end positions and +// style strings), which is used to highlight the tokens on the +// line. +function highlightLine(cm, line, state, forceToEnd) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen], lineClasses = {} + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, state, function (end, style) { return st.push(end, style); }, + lineClasses, forceToEnd) + + // Run overlays, adjust style array. + var loop = function ( o ) { + var overlay = cm.state.overlays[o], i = 1, at = 0 + runMode(cm, line.text, overlay.mode, true, function (end, style) { + var start = i + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i] + if (i_end > end) + { st.splice(i, 1, end, st[i+1], i_end) } + i += 2 + at = Math.min(end, i_end) + } + if (!style) { return } + if (overlay.opaque) { + st.splice(start, i - start, end, "overlay " + style) + i = start + 2 + } else { + for (; start < i; start += 2) { + var cur = st[start+1] + st[start+1] = (cur ? cur + " " : "") + "overlay " + style + } + } + }, lineClasses) + }; + + for (var o = 0; o < cm.state.overlays.length; ++o) loop( o ); + + return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null} +} + +function getLineStyles(cm, line, updateFrontier) { + if (!line.styles || line.styles[0] != cm.state.modeGen) { + var state = getStateBefore(cm, lineNo(line)) + var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state) + line.stateAfter = state + line.styles = result.styles + if (result.classes) { line.styleClasses = result.classes } + else if (line.styleClasses) { line.styleClasses = null } + if (updateFrontier === cm.doc.frontier) { cm.doc.frontier++ } + } + return line.styles +} + +function getStateBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display + if (!doc.mode.startState) { return true } + var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter + if (!state) { state = startState(doc.mode) } + else { state = copyState(doc.mode, state) } + doc.iter(pos, n, function (line) { + processLine(cm, line.text, state) + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo + line.stateAfter = save ? copyState(doc.mode, state) : null + ++pos + }) + if (precise) { doc.frontier = pos } + return state +} + +// Lightweight form of highlight -- proceed over this line and +// update state, but don't save a style array. Used for lines that +// aren't currently visible. +function processLine(cm, text, state, startAt) { + var mode = cm.doc.mode + var stream = new StringStream(text, cm.options.tabSize) + stream.start = stream.pos = startAt || 0 + if (text == "") { callBlankLine(mode, state) } + while (!stream.eol()) { + readToken(mode, stream, state) + stream.start = stream.pos + } +} + +function callBlankLine(mode, state) { + if (mode.blankLine) { return mode.blankLine(state) } + if (!mode.innerMode) { return } + var inner = innerMode(mode, state) + if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) } +} + +function readToken(mode, stream, state, inner) { + for (var i = 0; i < 10; i++) { + if (inner) { inner[0] = innerMode(mode, state).mode } + var style = mode.token(stream, state) + if (stream.pos > stream.start) { return style } + } + throw new Error("Mode " + mode.name + " failed to advance stream.") +} + +// Utility for getTokenAt and getLineTokens +function takeToken(cm, pos, precise, asArray) { + var getObj = function (copy) { return ({ + start: stream.start, end: stream.pos, + string: stream.current(), + type: style || null, + state: copy ? copyState(doc.mode, state) : state + }); } + + var doc = cm.doc, mode = doc.mode, style + pos = clipPos(doc, pos) + var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise) + var stream = new StringStream(line.text, cm.options.tabSize), tokens + if (asArray) { tokens = [] } + while ((asArray || stream.pos < pos.ch) && !stream.eol()) { + stream.start = stream.pos + style = readToken(mode, stream, state) + if (asArray) { tokens.push(getObj(true)) } + } + return asArray ? tokens : getObj() +} + +function extractLineClasses(type, output) { + if (type) { for (;;) { + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/) + if (!lineClass) { break } + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length) + var prop = lineClass[1] ? "bgClass" : "textClass" + if (output[prop] == null) + { output[prop] = lineClass[2] } + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + { output[prop] += " " + lineClass[2] } + } } + return type +} + +// Run the given mode's parser over a line, calling f for each token. +function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { + var flattenSpans = mode.flattenSpans + if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans } + var curStart = 0, curStyle = null + var stream = new StringStream(text, cm.options.tabSize), style + var inner = cm.options.addModeClass && [null] + if (text == "") { extractLineClasses(callBlankLine(mode, state), lineClasses) } + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false + if (forceToEnd) { processLine(cm, text, state, stream.pos) } + stream.pos = text.length + style = null + } else { + style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses) + } + if (inner) { + var mName = inner[0].name + if (mName) { style = "m-" + (style ? mName + " " + style : mName) } + } + if (!flattenSpans || curStyle != style) { + while (curStart < stream.start) { + curStart = Math.min(stream.start, curStart + 5000) + f(curStart, curStyle) + } + curStyle = style + } + stream.start = stream.pos + } + while (curStart < stream.pos) { + // Webkit seems to refuse to render text nodes longer than 57444 + // characters, and returns inaccurate measurements in nodes + // starting around 5000 chars. + var pos = Math.min(stream.pos, curStart + 5000) + f(pos, curStyle) + curStart = pos + } +} + +// Finds the line to start with when starting a parse. Tries to +// find a line with a stateAfter, so that it can start with a +// valid state. If that fails, it returns the line with the +// smallest indentation, which tends to need the least context to +// parse correctly. +function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100) + for (var search = n; search > lim; --search) { + if (search <= doc.first) { return doc.first } + var line = getLine(doc, search - 1) + if (line.stateAfter && (!precise || search <= doc.frontier)) { return search } + var indented = countColumn(line.text, null, cm.options.tabSize) + if (minline == null || minindent > indented) { + minline = search - 1 + minindent = indented + } + } + return minline +} + +// LINE DATA STRUCTURE + +// Line objects. These hold state related to a line, including +// highlighting info (the styles array). +var Line = function(text, markedSpans, estimateHeight) { + this.text = text + attachMarkedSpans(this, markedSpans) + this.height = estimateHeight ? estimateHeight(this) : 1 +}; + +Line.prototype.lineNo = function () { return lineNo(this) }; +eventMixin(Line) + +// Change the content (text, markers) of a line. Automatically +// invalidates cached information and tries to re-estimate the +// line's height. +function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text + if (line.stateAfter) { line.stateAfter = null } + if (line.styles) { line.styles = null } + if (line.order != null) { line.order = null } + detachMarkedSpans(line) + attachMarkedSpans(line, markedSpans) + var estHeight = estimateHeight ? estimateHeight(line) : 1 + if (estHeight != line.height) { updateLineHeight(line, estHeight) } +} + +// Detach a line from the document tree and its markers. +function cleanUpLine(line) { + line.parent = null + detachMarkedSpans(line) +} + +// Convert a style as returned by a mode (either null, or a string +// containing one or more styles) to a CSS style. This is cached, +// and also looks for line-wide styles. +var styleToClassCache = {}; +var styleToClassCacheWithMode = {}; +function interpretTokenStyle(style, options) { + if (!style || /^\s*$/.test(style)) { return null } + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache + return cache[style] || + (cache[style] = style.replace(/\S+/g, "cm-$&")) +} + +// Render the DOM representation of the text of a line. Also builds +// up a 'line map', which points at the DOM nodes that represent +// specific stretches of text, and is used by the measuring code. +// The returned object contains the DOM node, this map, and +// information about line-wide styles that were set by the mode. +function buildLineContent(cm, lineView) { + // The padding-right forces the element to have a 'border', which + // is needed on Webkit to be able to get line-level bounding + // rectangles for it (in measureChar). + var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null) + var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content, + col: 0, pos: 0, cm: cm, + trailingSpace: false, + splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")} + lineView.measure = {} + + // Iterate over the logical lines that make up this visual line. + for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0) + builder.pos = 0 + builder.addToken = buildToken + // Optionally wire in some hacks into the token-rendering + // algorithm, to deal with browser quirks. + if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction))) + { builder.addToken = buildTokenBadBidi(builder.addToken, order) } + builder.map = [] + var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line) + insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)) + if (line.styleClasses) { + if (line.styleClasses.bgClass) + { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "") } + if (line.styleClasses.textClass) + { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "") } + } + + // Ensure at least a single node is present, for measuring. + if (builder.map.length == 0) + { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))) } + + // Store the map and a cache object for the current logical line + if (i == 0) { + lineView.measure.map = builder.map + lineView.measure.cache = {} + } else { + ;(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map) + ;(lineView.measure.caches || (lineView.measure.caches = [])).push({}) + } + } + + // See issue #2901 + if (webkit) { + var last = builder.content.lastChild + if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab"))) + { builder.content.className = "cm-tab-wrap-hack" } + } + + signal(cm, "renderLine", cm, lineView.line, builder.pre) + if (builder.pre.className) + { builder.textClass = joinClasses(builder.pre.className, builder.textClass || "") } + + return builder +} + +function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar") + token.title = "\\u" + ch.charCodeAt(0).toString(16) + token.setAttribute("aria-label", token.title) + return token +} + +// Build up the DOM representation for a single token, and add it to +// the line map. Takes care to render special characters separately. +function buildToken(builder, text, style, startStyle, endStyle, title, css) { + if (!text) { return } + var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text + var special = builder.cm.state.specialChars, mustWrap = false + var content + if (!special.test(text)) { + builder.col += text.length + content = document.createTextNode(displayText) + builder.map.push(builder.pos, builder.pos + text.length, content) + if (ie && ie_version < 9) { mustWrap = true } + builder.pos += text.length + } else { + content = document.createDocumentFragment() + var pos = 0 + while (true) { + special.lastIndex = pos + var m = special.exec(text) + var skipped = m ? m.index - pos : text.length - pos + if (skipped) { + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)) + if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])) } + else { content.appendChild(txt) } + builder.map.push(builder.pos, builder.pos + skipped, txt) + builder.col += skipped + builder.pos += skipped + } + if (!m) { break } + pos += skipped + 1 + var txt$1 = (void 0) + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize + txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")) + txt$1.setAttribute("role", "presentation") + txt$1.setAttribute("cm-text", "\t") + builder.col += tabWidth + } else if (m[0] == "\r" || m[0] == "\n") { + txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")) + txt$1.setAttribute("cm-text", m[0]) + builder.col += 1 + } else { + txt$1 = builder.cm.options.specialCharPlaceholder(m[0]) + txt$1.setAttribute("cm-text", m[0]) + if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])) } + else { content.appendChild(txt$1) } + builder.col += 1 + } + builder.map.push(builder.pos, builder.pos + 1, txt$1) + builder.pos++ + } + } + builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32 + if (style || startStyle || endStyle || mustWrap || css) { + var fullStyle = style || "" + if (startStyle) { fullStyle += startStyle } + if (endStyle) { fullStyle += endStyle } + var token = elt("span", [content], fullStyle, css) + if (title) { token.title = title } + return builder.content.appendChild(token) + } + builder.content.appendChild(content) +} + +function splitSpaces(text, trailingBefore) { + if (text.length > 1 && !/ /.test(text)) { return text } + var spaceBefore = trailingBefore, result = "" + for (var i = 0; i < text.length; i++) { + var ch = text.charAt(i) + if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32)) + { ch = "\u00a0" } + result += ch + spaceBefore = ch == " " + } + return result +} + +// Work around nonsense dimensions being reported for stretches of +// right-to-left text. +function buildTokenBadBidi(inner, order) { + return function (builder, text, style, startStyle, endStyle, title, css) { + style = style ? style + " cm-force-border" : "cm-force-border" + var start = builder.pos, end = start + text.length + for (;;) { + // Find the part that overlaps with the start of this text + var part = (void 0) + for (var i = 0; i < order.length; i++) { + part = order[i] + if (part.to > start && part.from <= start) { break } + } + if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) } + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css) + startStyle = null + text = text.slice(part.to - start) + start = part.to + } + } +} + +function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.widgetNode + if (widget) { builder.map.push(builder.pos, builder.pos + size, widget) } + if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { + if (!widget) + { widget = builder.content.appendChild(document.createElement("span")) } + widget.setAttribute("cm-marker", marker.id) + } + if (widget) { + builder.cm.display.input.setUneditable(widget) + builder.content.appendChild(widget) + } + builder.pos += size + builder.trailingSpace = false +} + +// Outputs a number of spans to make up a line, taking highlighting +// and marked text into account. +function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0 + if (!spans) { + for (var i$1 = 1; i$1 < styles.length; i$1+=2) + { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)) } + return + } + + var len = allText.length, pos = 0, i = 1, text = "", style, css + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed + for (;;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = title = css = "" + collapsed = null; nextChange = Infinity + var foundBookmarks = [], endStyles = (void 0) + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { + foundBookmarks.push(m) + } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { + if (sp.to != null && sp.to != pos && nextChange > sp.to) { + nextChange = sp.to + spanEndStyle = "" + } + if (m.className) { spanStyle += " " + m.className } + if (m.css) { css = (css ? css + ";" : "") + m.css } + if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle } + if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to) } + if (m.title && !title) { title = m.title } + if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) + { collapsed = sp } + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from + } + } + if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2) + { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1] } } } + + if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2) + { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]) } } + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, + collapsed.marker, collapsed.from == null) + if (collapsed.to == null) { return } + if (collapsed.to == pos) { collapsed = false } + } + } + if (pos >= len) { break } + + var upto = Math.min(len, nextChange) + while (true) { + if (text) { + var end = pos + text.length + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css) + } + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break} + pos = end + spanStartStyle = "" + } + text = allText.slice(at, at = styles[i++]) + style = interpretTokenStyle(styles[i++], builder.cm.options) + } + } +} + + +// These objects are used to represent the visible (currently drawn) +// part of the document. A LineView may correspond to multiple +// logical lines, if those are connected by collapsed ranges. +function LineView(doc, line, lineN) { + // The starting line + this.line = line + // Continuing lines, if any + this.rest = visualLineContinued(line) + // Number of logical lines in this visual line + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1 + this.node = this.text = null + this.hidden = lineIsHidden(doc, line) +} + +// Create a range of LineView objects for the given lines. +function buildViewArray(cm, from, to) { + var array = [], nextPos + for (var pos = from; pos < to; pos = nextPos) { + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos) + nextPos = pos + view.size + array.push(view) + } + return array +} + +var operationGroup = null + +function pushOperation(op) { + if (operationGroup) { + operationGroup.ops.push(op) + } else { + op.ownsGroup = operationGroup = { + ops: [op], + delayedCallbacks: [] + } + } +} + +function fireCallbacksForOps(group) { + // Calls delayed callbacks and cursorActivity handlers until no + // new ones appear + var callbacks = group.delayedCallbacks, i = 0 + do { + for (; i < callbacks.length; i++) + { callbacks[i].call(null) } + for (var j = 0; j < group.ops.length; j++) { + var op = group.ops[j] + if (op.cursorActivityHandlers) + { while (op.cursorActivityCalled < op.cursorActivityHandlers.length) + { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) } } + } + } while (i < callbacks.length) +} + +function finishOperation(op, endCb) { + var group = op.ownsGroup + if (!group) { return } + + try { fireCallbacksForOps(group) } + finally { + operationGroup = null + endCb(group) + } +} + +var orphanDelayedCallbacks = null + +// Often, we want to signal events at a point where we are in the +// middle of some work, but don't want the handler to start calling +// other methods on the editor, which might be in an inconsistent +// state or simply not expect any other events to happen. +// signalLater looks whether there are any handlers, and schedules +// them to be executed when the last operation ends, or, if no +// operation is active, when a timeout fires. +function signalLater(emitter, type /*, values...*/) { + var arr = getHandlers(emitter, type) + if (!arr.length) { return } + var args = Array.prototype.slice.call(arguments, 2), list + if (operationGroup) { + list = operationGroup.delayedCallbacks + } else if (orphanDelayedCallbacks) { + list = orphanDelayedCallbacks + } else { + list = orphanDelayedCallbacks = [] + setTimeout(fireOrphanDelayed, 0) + } + var loop = function ( i ) { + list.push(function () { return arr[i].apply(null, args); }) + }; + + for (var i = 0; i < arr.length; ++i) + loop( i ); +} + +function fireOrphanDelayed() { + var delayed = orphanDelayedCallbacks + orphanDelayedCallbacks = null + for (var i = 0; i < delayed.length; ++i) { delayed[i]() } +} + +// When an aspect of a line changes, a string is added to +// lineView.changes. This updates the relevant part of the line's +// DOM structure. +function updateLineForChanges(cm, lineView, lineN, dims) { + for (var j = 0; j < lineView.changes.length; j++) { + var type = lineView.changes[j] + if (type == "text") { updateLineText(cm, lineView) } + else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims) } + else if (type == "class") { updateLineClasses(cm, lineView) } + else if (type == "widget") { updateLineWidgets(cm, lineView, dims) } + } + lineView.changes = null +} + +// Lines with gutter elements, widgets or a background class need to +// be wrapped, and have the extra elements added to the wrapper div +function ensureLineWrapped(lineView) { + if (lineView.node == lineView.text) { + lineView.node = elt("div", null, null, "position: relative") + if (lineView.text.parentNode) + { lineView.text.parentNode.replaceChild(lineView.node, lineView.text) } + lineView.node.appendChild(lineView.text) + if (ie && ie_version < 8) { lineView.node.style.zIndex = 2 } + } + return lineView.node +} + +function updateLineBackground(cm, lineView) { + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass + if (cls) { cls += " CodeMirror-linebackground" } + if (lineView.background) { + if (cls) { lineView.background.className = cls } + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null } + } else if (cls) { + var wrap = ensureLineWrapped(lineView) + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild) + cm.display.input.setUneditable(lineView.background) + } +} + +// Wrapper around buildLineContent which will reuse the structure +// in display.externalMeasured when possible. +function getLineContent(cm, lineView) { + var ext = cm.display.externalMeasured + if (ext && ext.line == lineView.line) { + cm.display.externalMeasured = null + lineView.measure = ext.measure + return ext.built + } + return buildLineContent(cm, lineView) +} + +// Redraw the line's text. Interacts with the background and text +// classes because the mode may output tokens that influence these +// classes. +function updateLineText(cm, lineView) { + var cls = lineView.text.className + var built = getLineContent(cm, lineView) + if (lineView.text == lineView.node) { lineView.node = built.pre } + lineView.text.parentNode.replaceChild(built.pre, lineView.text) + lineView.text = built.pre + if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { + lineView.bgClass = built.bgClass + lineView.textClass = built.textClass + updateLineClasses(cm, lineView) + } else if (cls) { + lineView.text.className = cls + } +} + +function updateLineClasses(cm, lineView) { + updateLineBackground(cm, lineView) + if (lineView.line.wrapClass) + { ensureLineWrapped(lineView).className = lineView.line.wrapClass } + else if (lineView.node != lineView.text) + { lineView.node.className = "" } + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass + lineView.text.className = textClass || "" +} + +function updateLineGutter(cm, lineView, lineN, dims) { + if (lineView.gutter) { + lineView.node.removeChild(lineView.gutter) + lineView.gutter = null + } + if (lineView.gutterBackground) { + lineView.node.removeChild(lineView.gutterBackground) + lineView.gutterBackground = null + } + if (lineView.line.gutterClass) { + var wrap = ensureLineWrapped(lineView) + lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, + ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px")) + cm.display.input.setUneditable(lineView.gutterBackground) + wrap.insertBefore(lineView.gutterBackground, lineView.text) + } + var markers = lineView.line.gutterMarkers + if (cm.options.lineNumbers || markers) { + var wrap$1 = ensureLineWrapped(lineView) + var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px")) + cm.display.input.setUneditable(gutterWrap) + wrap$1.insertBefore(gutterWrap, lineView.text) + if (lineView.line.gutterClass) + { gutterWrap.className += " " + lineView.line.gutterClass } + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + { lineView.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineN), + "CodeMirror-linenumber CodeMirror-gutter-elt", + ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))) } + if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) { + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id] + if (found) + { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", + ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))) } + } } + } +} + +function updateLineWidgets(cm, lineView, dims) { + if (lineView.alignable) { lineView.alignable = null } + for (var node = lineView.node.firstChild, next = (void 0); node; node = next) { + next = node.nextSibling + if (node.className == "CodeMirror-linewidget") + { lineView.node.removeChild(node) } + } + insertLineWidgets(cm, lineView, dims) +} + +// Build a line's DOM representation from scratch +function buildLineElement(cm, lineView, lineN, dims) { + var built = getLineContent(cm, lineView) + lineView.text = lineView.node = built.pre + if (built.bgClass) { lineView.bgClass = built.bgClass } + if (built.textClass) { lineView.textClass = built.textClass } + + updateLineClasses(cm, lineView) + updateLineGutter(cm, lineView, lineN, dims) + insertLineWidgets(cm, lineView, dims) + return lineView.node +} + +// A lineView may contain multiple logical lines (when merged by +// collapsed spans). The widgets for all of them need to be drawn. +function insertLineWidgets(cm, lineView, dims) { + insertLineWidgetsFor(cm, lineView.line, lineView, dims, true) + if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) + { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false) } } +} + +function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { + if (!line.widgets) { return } + var wrap = ensureLineWrapped(lineView) + for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget") + if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true") } + positionLineWidget(widget, node, lineView, dims) + cm.display.input.setUneditable(node) + if (allowAbove && widget.above) + { wrap.insertBefore(node, lineView.gutter || lineView.text) } + else + { wrap.appendChild(node) } + signalLater(widget, "redraw") + } +} + +function positionLineWidget(widget, node, lineView, dims) { + if (widget.noHScroll) { + ;(lineView.alignable || (lineView.alignable = [])).push(node) + var width = dims.wrapperWidth + node.style.left = dims.fixedPos + "px" + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth + node.style.paddingLeft = dims.gutterTotalWidth + "px" + } + node.style.width = width + "px" + } + if (widget.coverGutter) { + node.style.zIndex = 5 + node.style.position = "relative" + if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px" } + } +} + +function widgetHeight(widget) { + if (widget.height != null) { return widget.height } + var cm = widget.doc.cm + if (!cm) { return 0 } + if (!contains(document.body, widget.node)) { + var parentStyle = "position: relative;" + if (widget.coverGutter) + { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;" } + if (widget.noHScroll) + { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;" } + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)) + } + return widget.height = widget.node.parentNode.offsetHeight +} + +// Return true when the given mouse event happened in a widget +function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || + (n.parentNode == display.sizer && n != display.mover)) + { return true } + } +} + +// POSITION MEASUREMENT + +function paddingTop(display) {return display.lineSpace.offsetTop} +function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight} +function paddingH(display) { + if (display.cachedPaddingH) { return display.cachedPaddingH } + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")) + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle + var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)} + if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data } + return data +} + +function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth } +function displayWidth(cm) { + return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth +} +function displayHeight(cm) { + return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight +} + +// Ensure the lineView.wrapping.heights array is populated. This is +// an array of bottom offsets for the lines that make up a drawn +// line. When lineWrapping is on, there might be more than one +// height. +function ensureLineHeights(cm, lineView, rect) { + var wrapping = cm.options.lineWrapping + var curWidth = wrapping && displayWidth(cm) + if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { + var heights = lineView.measure.heights = [] + if (wrapping) { + lineView.measure.width = curWidth + var rects = lineView.text.firstChild.getClientRects() + for (var i = 0; i < rects.length - 1; i++) { + var cur = rects[i], next = rects[i + 1] + if (Math.abs(cur.bottom - next.bottom) > 2) + { heights.push((cur.bottom + next.top) / 2 - rect.top) } + } + } + heights.push(rect.bottom - rect.top) + } +} + +// Find a line map (mapping character offsets to text nodes) and a +// measurement cache for the given line number. (A line view might +// contain multiple lines when collapsed ranges are present.) +function mapFromLineView(lineView, line, lineN) { + if (lineView.line == line) + { return {map: lineView.measure.map, cache: lineView.measure.cache} } + for (var i = 0; i < lineView.rest.length; i++) + { if (lineView.rest[i] == line) + { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } } + for (var i$1 = 0; i$1 < lineView.rest.length; i$1++) + { if (lineNo(lineView.rest[i$1]) > lineN) + { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } } +} + +// Render a line into the hidden node display.externalMeasured. Used +// when measurement is needed for a line that's not in the viewport. +function updateExternalMeasurement(cm, line) { + line = visualLine(line) + var lineN = lineNo(line) + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN) + view.lineN = lineN + var built = view.built = buildLineContent(cm, view) + view.text = built.pre + removeChildrenAndAdd(cm.display.lineMeasure, built.pre) + return view +} + +// Get a {top, bottom, left, right} box (in line-local coordinates) +// for a given character. +function measureChar(cm, line, ch, bias) { + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias) +} + +// Find a line view that corresponds to the given line number. +function findViewForLine(cm, lineN) { + if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) + { return cm.display.view[findViewIndex(cm, lineN)] } + var ext = cm.display.externalMeasured + if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) + { return ext } +} + +// Measurement can be split in two steps, the set-up work that +// applies to the whole line, and the measurement of the actual +// character. Functions like coordsChar, that need to do a lot of +// measurements in a row, can thus ensure that the set-up work is +// only done once. +function prepareMeasureForLine(cm, line) { + var lineN = lineNo(line) + var view = findViewForLine(cm, lineN) + if (view && !view.text) { + view = null + } else if (view && view.changes) { + updateLineForChanges(cm, view, lineN, getDimensions(cm)) + cm.curOp.forceUpdate = true + } + if (!view) + { view = updateExternalMeasurement(cm, line) } + + var info = mapFromLineView(view, line, lineN) + return { + line: line, view: view, rect: null, + map: info.map, cache: info.cache, before: info.before, + hasHeights: false + } +} + +// Given a prepared measurement object, measures the position of an +// actual character (or fetches it from the cache). +function measureCharPrepared(cm, prepared, ch, bias, varHeight) { + if (prepared.before) { ch = -1 } + var key = ch + (bias || ""), found + if (prepared.cache.hasOwnProperty(key)) { + found = prepared.cache[key] + } else { + if (!prepared.rect) + { prepared.rect = prepared.view.text.getBoundingClientRect() } + if (!prepared.hasHeights) { + ensureLineHeights(cm, prepared.view, prepared.rect) + prepared.hasHeights = true + } + found = measureCharInner(cm, prepared, ch, bias) + if (!found.bogus) { prepared.cache[key] = found } + } + return {left: found.left, right: found.right, + top: varHeight ? found.rtop : found.top, + bottom: varHeight ? found.rbottom : found.bottom} +} + +var nullRect = {left: 0, right: 0, top: 0, bottom: 0} + +function nodeAndOffsetInLineMap(map, ch, bias) { + var node, start, end, collapse, mStart, mEnd + // First, search the line map for the text node corresponding to, + // or closest to, the target character. + for (var i = 0; i < map.length; i += 3) { + mStart = map[i] + mEnd = map[i + 1] + if (ch < mStart) { + start = 0; end = 1 + collapse = "left" + } else if (ch < mEnd) { + start = ch - mStart + end = start + 1 + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { + end = mEnd - mStart + start = end - 1 + if (ch >= mEnd) { collapse = "right" } + } + if (start != null) { + node = map[i + 2] + if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) + { collapse = bias } + if (bias == "left" && start == 0) + { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2] + collapse = "left" + } } + if (bias == "right" && start == mEnd - mStart) + { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2] + collapse = "right" + } } + break + } + } + return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd} +} + +function getUsefulRect(rects, bias) { + var rect = nullRect + if (bias == "left") { for (var i = 0; i < rects.length; i++) { + if ((rect = rects[i]).left != rect.right) { break } + } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) { + if ((rect = rects[i$1]).left != rect.right) { break } + } } + return rect +} + +function measureCharInner(cm, prepared, ch, bias) { + var place = nodeAndOffsetInLineMap(prepared.map, ch, bias) + var node = place.node, start = place.start, end = place.end, collapse = place.collapse + + var rect + if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. + for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned + while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start } + while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end } + if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) + { rect = node.parentNode.getBoundingClientRect() } + else + { rect = getUsefulRect(range(node, start, end).getClientRects(), bias) } + if (rect.left || rect.right || start == 0) { break } + end = start + start = start - 1 + collapse = "right" + } + if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect) } + } else { // If it is a widget, simply get the box for the whole widget. + if (start > 0) { collapse = bias = "right" } + var rects + if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) + { rect = rects[bias == "right" ? rects.length - 1 : 0] } + else + { rect = node.getBoundingClientRect() } + } + if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { + var rSpan = node.parentNode.getClientRects()[0] + if (rSpan) + { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom} } + else + { rect = nullRect } + } + + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top + var mid = (rtop + rbot) / 2 + var heights = prepared.view.measure.heights + var i = 0 + for (; i < heights.length - 1; i++) + { if (mid < heights[i]) { break } } + var top = i ? heights[i - 1] : 0, bot = heights[i] + var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, + top: top, bottom: bot} + if (!rect.left && !rect.right) { result.bogus = true } + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot } + + return result +} + +// Work around problem with bounding client rects on ranges being +// returned incorrectly when zoomed on IE10 and below. +function maybeUpdateRectForZooming(measure, rect) { + if (!window.screen || screen.logicalXDPI == null || + screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) + { return rect } + var scaleX = screen.logicalXDPI / screen.deviceXDPI + var scaleY = screen.logicalYDPI / screen.deviceYDPI + return {left: rect.left * scaleX, right: rect.right * scaleX, + top: rect.top * scaleY, bottom: rect.bottom * scaleY} +} + +function clearLineMeasurementCacheFor(lineView) { + if (lineView.measure) { + lineView.measure.cache = {} + lineView.measure.heights = null + if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) + { lineView.measure.caches[i] = {} } } + } +} + +function clearLineMeasurementCache(cm) { + cm.display.externalMeasure = null + removeChildren(cm.display.lineMeasure) + for (var i = 0; i < cm.display.view.length; i++) + { clearLineMeasurementCacheFor(cm.display.view[i]) } +} + +function clearCaches(cm) { + clearLineMeasurementCache(cm) + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null + if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true } + cm.display.lineNumChars = null +} + +function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft } +function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop } + +// Converts a {top, bottom, left, right} box from line-local +// coordinates into another coordinate system. Context may be one of +// "line", "div" (display.lineDiv), "local"./null (editor), "window", +// or "page". +function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) { + if (!includeWidgets && lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) { + var size = widgetHeight(lineObj.widgets[i]) + rect.top += size; rect.bottom += size + } } } + if (context == "line") { return rect } + if (!context) { context = "local" } + var yOff = heightAtLine(lineObj) + if (context == "local") { yOff += paddingTop(cm.display) } + else { yOff -= cm.display.viewOffset } + if (context == "page" || context == "window") { + var lOff = cm.display.lineSpace.getBoundingClientRect() + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()) + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()) + rect.left += xOff; rect.right += xOff + } + rect.top += yOff; rect.bottom += yOff + return rect +} + +// Coverts a box from "div" coords to another coordinate system. +// Context may be "window", "page", "div", or "local"./null. +function fromCoordSystem(cm, coords, context) { + if (context == "div") { return coords } + var left = coords.left, top = coords.top + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX() + top -= pageScrollY() + } else if (context == "local" || !context) { + var localBox = cm.display.sizer.getBoundingClientRect() + left += localBox.left + top += localBox.top + } + + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect() + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top} +} + +function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) { lineObj = getLine(cm.doc, pos.line) } + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context) +} + +// Returns a box for a given cursor position, which may have an +// 'other' property containing the position of the secondary cursor +// on a bidi boundary. +// A cursor Pos(line, char, "before") is on the same visual line as `char - 1` +// and after `char - 1` in writing order of `char - 1` +// A cursor Pos(line, char, "after") is on the same visual line as `char` +// and before `char` in writing order of `char` +// Examples (upper-case letters are RTL, lower-case are LTR): +// Pos(0, 1, ...) +// before after +// ab a|b a|b +// aB a|B aB| +// Ab |Ab A|b +// AB B|A B|A +// Every position after the last character on a line is considered to stick +// to the last character on the line. +function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { + lineObj = lineObj || getLine(cm.doc, pos.line) + if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) } + function get(ch, right) { + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight) + if (right) { m.left = m.right; } else { m.right = m.left } + return intoCoordSystem(cm, lineObj, m, context) + } + var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky + if (ch >= lineObj.text.length) { + ch = lineObj.text.length + sticky = "before" + } else if (ch <= 0) { + ch = 0 + sticky = "after" + } + if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") } + + function getBidi(ch, partPos, invert) { + var part = order[partPos], right = (part.level % 2) != 0 + return get(invert ? ch - 1 : ch, right != invert) + } + var partPos = getBidiPartAt(order, ch, sticky) + var other = bidiOther + var val = getBidi(ch, partPos, sticky == "before") + if (other != null) { val.other = getBidi(ch, other, sticky != "before") } + return val +} + +// Used to cheaply estimate the coordinates for a position. Used for +// intermediate scroll updates. +function estimateCoords(cm, pos) { + var left = 0 + pos = clipPos(cm.doc, pos) + if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch } + var lineObj = getLine(cm.doc, pos.line) + var top = heightAtLine(lineObj) + paddingTop(cm.display) + return {left: left, right: left, top: top, bottom: top + lineObj.height} +} + +// Positions returned by coordsChar contain some extra information. +// xRel is the relative x position of the input coordinates compared +// to the found position (so xRel > 0 means the coordinates are to +// the right of the character position, for example). When outside +// is true, that means the coordinates lie outside the line's +// vertical range. +function PosWithInfo(line, ch, sticky, outside, xRel) { + var pos = Pos(line, ch, sticky) + pos.xRel = xRel + if (outside) { pos.outside = true } + return pos +} + +// Compute the character position closest to the given coordinates. +// Input must be lineSpace-local ("div" coordinate system). +function coordsChar(cm, x, y) { + var doc = cm.doc + y += cm.display.viewOffset + if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) } + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1 + if (lineN > last) + { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) } + if (x < 0) { x = 0 } + + var lineObj = getLine(doc, lineN) + for (;;) { + var found = coordsCharInner(cm, lineObj, lineN, x, y) + var merged = collapsedSpanAtEnd(lineObj) + var mergedPos = merged && merged.find(0, true) + if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) + { lineN = lineNo(lineObj = mergedPos.to.line) } + else + { return found } + } +} + +function wrappedLineExtent(cm, lineObj, preparedMeasure, y) { + var measure = function (ch) { return intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line"); } + var end = lineObj.text.length + var begin = findFirst(function (ch) { return measure(ch - 1).bottom <= y; }, end, 0) + end = findFirst(function (ch) { return measure(ch).top > y; }, begin, end) + return {begin: begin, end: end} +} + +function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) { + var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top + return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop) +} + +function coordsCharInner(cm, lineObj, lineNo, x, y) { + y -= heightAtLine(lineObj) + var begin = 0, end = lineObj.text.length + var preparedMeasure = prepareMeasureForLine(cm, lineObj) + var pos + var order = getOrder(lineObj, cm.doc.direction) + if (order) { + if (cm.options.lineWrapping) { + ;var assign; + ((assign = wrappedLineExtent(cm, lineObj, preparedMeasure, y), begin = assign.begin, end = assign.end, assign)) + } + pos = new Pos(lineNo, begin) + var beginLeft = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left + var dir = beginLeft < x ? 1 : -1 + var prevDiff, diff = beginLeft - x, prevPos + do { + prevDiff = diff + prevPos = pos + pos = moveVisually(cm, lineObj, pos, dir) + if (pos == null || pos.ch < begin || end <= (pos.sticky == "before" ? pos.ch - 1 : pos.ch)) { + pos = prevPos + break + } + diff = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left - x + } while ((dir < 0) != (diff < 0) && (Math.abs(diff) <= Math.abs(prevDiff))) + if (Math.abs(diff) > Math.abs(prevDiff)) { + if ((diff < 0) == (prevDiff < 0)) { throw new Error("Broke out of infinite loop in coordsCharInner") } + pos = prevPos + } + } else { + var ch = findFirst(function (ch) { + var box = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line") + if (box.top > y) { + // For the cursor stickiness + end = Math.min(ch, end) + return true + } + else if (box.bottom <= y) { return false } + else if (box.left > x) { return true } + else if (box.right < x) { return false } + else { return (x - box.left < box.right - x) } + }, begin, end) + ch = skipExtendingChars(lineObj.text, ch, 1) + pos = new Pos(lineNo, ch, ch == end ? "before" : "after") + } + var coords = cursorCoords(cm, pos, "line", lineObj, preparedMeasure) + if (y < coords.top || coords.bottom < y) { pos.outside = true } + pos.xRel = x < coords.left ? -1 : (x > coords.right ? 1 : 0) + return pos +} + +var measureText +// Compute the default text height. +function textHeight(display) { + if (display.cachedTextHeight != null) { return display.cachedTextHeight } + if (measureText == null) { + measureText = elt("pre") + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")) + measureText.appendChild(elt("br")) + } + measureText.appendChild(document.createTextNode("x")) + } + removeChildrenAndAdd(display.measure, measureText) + var height = measureText.offsetHeight / 50 + if (height > 3) { display.cachedTextHeight = height } + removeChildren(display.measure) + return height || 1 +} + +// Compute the default character width. +function charWidth(display) { + if (display.cachedCharWidth != null) { return display.cachedCharWidth } + var anchor = elt("span", "xxxxxxxxxx") + var pre = elt("pre", [anchor]) + removeChildrenAndAdd(display.measure, pre) + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10 + if (width > 2) { display.cachedCharWidth = width } + return width || 10 +} + +// Do a bulk-read of the DOM positions and sizes needed to draw the +// view, so that we don't interleave reading and writing to the DOM. +function getDimensions(cm) { + var d = cm.display, left = {}, width = {} + var gutterLeft = d.gutters.clientLeft + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft + width[cm.options.gutters[i]] = n.clientWidth + } + return {fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth} +} + +// Computes display.scroller.scrollLeft + display.gutters.offsetWidth, +// but using getBoundingClientRect to get a sub-pixel-accurate +// result. +function compensateForHScroll(display) { + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left +} + +// Returns a function that estimates the height of a line, to use as +// first approximation until the line becomes visible (and is thus +// properly measurable). +function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3) + return function (line) { + if (lineIsHidden(cm.doc, line)) { return 0 } + + var widgetsHeight = 0 + if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height } + } } + + if (wrapping) + { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th } + else + { return widgetsHeight + th } + } +} + +function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm) + doc.iter(function (line) { + var estHeight = est(line) + if (estHeight != line.height) { updateLineHeight(line, estHeight) } + }) +} + +// Given a mouse event, find the corresponding position. If liberal +// is false, it checks whether a gutter or scrollbar was clicked, +// and returns null if it was. forRect is used by rectangular +// selections, and tries to estimate a character position even for +// coordinates beyond the right of the text. +function posFromMouse(cm, e, liberal, forRect) { + var display = cm.display + if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null } + + var x, y, space = display.lineSpace.getBoundingClientRect() + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX - space.left; y = e.clientY - space.top } + catch (e) { return null } + var coords = coordsChar(cm, x, y), line + if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)) + } + return coords +} + +// Find the view element corresponding to a given line. Return null +// when the line isn't visible. +function findViewIndex(cm, n) { + if (n >= cm.display.viewTo) { return null } + n -= cm.display.viewFrom + if (n < 0) { return null } + var view = cm.display.view + for (var i = 0; i < view.length; i++) { + n -= view[i].size + if (n < 0) { return i } + } +} + +function updateSelection(cm) { + cm.display.input.showSelection(cm.display.input.prepareSelection()) +} + +function prepareSelection(cm, primary) { + var doc = cm.doc, result = {} + var curFragment = result.cursors = document.createDocumentFragment() + var selFragment = result.selection = document.createDocumentFragment() + + for (var i = 0; i < doc.sel.ranges.length; i++) { + if (primary === false && i == doc.sel.primIndex) { continue } + var range = doc.sel.ranges[i] + if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue } + var collapsed = range.empty() + if (collapsed || cm.options.showCursorWhenSelecting) + { drawSelectionCursor(cm, range.head, curFragment) } + if (!collapsed) + { drawSelectionRange(cm, range, selFragment) } + } + return result +} + +// Draws a cursor for the given range +function drawSelectionCursor(cm, head, output) { + var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine) + + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")) + cursor.style.left = pos.left + "px" + cursor.style.top = pos.top + "px" + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px" + + if (pos.other) { + // Secondary cursor, shown when on a 'jump' in bi-directional text + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")) + otherCursor.style.display = "" + otherCursor.style.left = pos.other.left + "px" + otherCursor.style.top = pos.other.top + "px" + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px" + } +} + +// Draws the given range as a highlighted selection +function drawSelectionRange(cm, range, output) { + var display = cm.display, doc = cm.doc + var fragment = document.createDocumentFragment() + var padding = paddingH(cm.display), leftSide = padding.left + var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right + + function add(left, top, width, bottom) { + if (top < 0) { top = 0 } + top = Math.round(top) + bottom = Math.round(bottom) + fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px"))) + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line) + var lineLen = lineObj.text.length + var start, end + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias) + } + + iterateBidiSections(getOrder(lineObj, doc.direction), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) { + var leftPos = coords(from, "left"), rightPos, left, right + if (from == to) { + rightPos = leftPos + left = right = leftPos.left + } else { + rightPos = coords(to - 1, "right") + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp } + left = leftPos.left + right = rightPos.right + } + if (fromArg == null && from == 0) { left = leftSide } + if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part + add(left, leftPos.top, null, leftPos.bottom) + left = leftSide + if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top) } + } + if (toArg == null && to == lineLen) { right = rightSide } + if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) + { start = leftPos } + if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) + { end = rightPos } + if (left < leftSide + 1) { left = leftSide } + add(left, rightPos.top, right - left, rightPos.bottom) + }) + return {start: start, end: end} + } + + var sFrom = range.from(), sTo = range.to() + if (sFrom.line == sTo.line) { + drawForLine(sFrom.line, sFrom.ch, sTo.ch) + } else { + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line) + var singleVLine = visualLine(fromLine) == visualLine(toLine) + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom) + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom) + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom) + } + } + if (leftEnd.bottom < rightStart.top) + { add(leftSide, leftEnd.bottom, null, rightStart.top) } + } + + output.appendChild(fragment) +} + +// Cursor-blinking +function restartBlink(cm) { + if (!cm.state.focused) { return } + var display = cm.display + clearInterval(display.blinker) + var on = true + display.cursorDiv.style.visibility = "" + if (cm.options.cursorBlinkRate > 0) + { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; }, + cm.options.cursorBlinkRate) } + else if (cm.options.cursorBlinkRate < 0) + { display.cursorDiv.style.visibility = "hidden" } +} + +function ensureFocus(cm) { + if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm) } +} + +function delayBlurEvent(cm) { + cm.state.delayingBlurEvent = true + setTimeout(function () { if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false + onBlur(cm) + } }, 100) +} + +function onFocus(cm, e) { + if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false } + + if (cm.options.readOnly == "nocursor") { return } + if (!cm.state.focused) { + signal(cm, "focus", cm, e) + cm.state.focused = true + addClass(cm.display.wrapper, "CodeMirror-focused") + // This test prevents this from firing when a context + // menu is closed (since the input reset would kill the + // select-all detection hack) + if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { + cm.display.input.reset() + if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20) } // Issue #1730 + } + cm.display.input.receivedFocus() + } + restartBlink(cm) +} +function onBlur(cm, e) { + if (cm.state.delayingBlurEvent) { return } + + if (cm.state.focused) { + signal(cm, "blur", cm, e) + cm.state.focused = false + rmClass(cm.display.wrapper, "CodeMirror-focused") + } + clearInterval(cm.display.blinker) + setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false } }, 150) +} + +// Re-align line numbers and gutter marks to compensate for +// horizontal scrolling. +function alignHorizontally(cm) { + var display = cm.display, view = display.view + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return } + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft + var gutterW = display.gutters.offsetWidth, left = comp + "px" + for (var i = 0; i < view.length; i++) { if (!view[i].hidden) { + if (cm.options.fixedGutter) { + if (view[i].gutter) + { view[i].gutter.style.left = left } + if (view[i].gutterBackground) + { view[i].gutterBackground.style.left = left } + } + var align = view[i].alignable + if (align) { for (var j = 0; j < align.length; j++) + { align[j].style.left = left } } + } } + if (cm.options.fixedGutter) + { display.gutters.style.left = (comp + gutterW) + "px" } +} + +// Used to ensure that the line number gutter is still the right +// size for the current document size. Returns true when an update +// is needed. +function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) { return false } + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")) + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW + display.lineGutter.style.width = "" + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1 + display.lineNumWidth = display.lineNumInnerWidth + padding + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1 + display.lineGutter.style.width = display.lineNumWidth + "px" + updateGutterSpace(cm) + return true + } + return false +} + +// Read the actual heights of the rendered lines, and update their +// stored heights to match. +function updateHeightsInViewport(cm) { + var display = cm.display + var prevBottom = display.lineDiv.offsetTop + for (var i = 0; i < display.view.length; i++) { + var cur = display.view[i], height = (void 0) + if (cur.hidden) { continue } + if (ie && ie_version < 8) { + var bot = cur.node.offsetTop + cur.node.offsetHeight + height = bot - prevBottom + prevBottom = bot + } else { + var box = cur.node.getBoundingClientRect() + height = box.bottom - box.top + } + var diff = cur.line.height - height + if (height < 2) { height = textHeight(display) } + if (diff > .001 || diff < -.001) { + updateLineHeight(cur.line, height) + updateWidgetHeight(cur.line) + if (cur.rest) { for (var j = 0; j < cur.rest.length; j++) + { updateWidgetHeight(cur.rest[j]) } } + } + } +} + +// Read and store the height of line widgets associated with the +// given line. +function updateWidgetHeight(line) { + if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) + { line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight } } +} + +// Compute the lines that are visible in a given viewport (defaults +// the the current scroll position). viewport may contain top, +// height, and ensure (see op.scrollToPos) properties. +function visibleLines(display, doc, viewport) { + var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop + top = Math.floor(top - paddingTop(display)) + var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight + + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom) + // Ensure is a {from: {line, ch}, to: {line, ch}} object, and + // forces those lines into the viewport (if possible). + if (viewport && viewport.ensure) { + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line + if (ensureFrom < from) { + from = ensureFrom + to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight) + } else if (Math.min(ensureTo, doc.lastLine()) >= to) { + from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight) + to = ensureTo + } + } + return {from: from, to: Math.max(to, from + 1)} +} + +// Sync the scrollable area and scrollbars, ensure the viewport +// covers the visible area. +function setScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) { return } + cm.doc.scrollTop = val + if (!gecko) { updateDisplaySimple(cm, {top: val}) } + if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val } + cm.display.scrollbars.setScrollTop(val) + if (gecko) { updateDisplaySimple(cm) } + startWorker(cm, 100) +} +// Sync scroller and scrollbar, ensure the gutter elements are +// aligned. +function setScrollLeft(cm, val, isScroller) { + if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) { return } + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth) + cm.doc.scrollLeft = val + alignHorizontally(cm) + if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val } + cm.display.scrollbars.setScrollLeft(val) +} + +// Since the delta values reported on mouse wheel events are +// unstandardized between browsers and even browser versions, and +// generally horribly unpredictable, this code starts by measuring +// the scroll effect that the first few mouse wheel events have, +// and, from that, detects the way it can convert deltas to pixel +// offsets afterwards. +// +// The reason we want to know the amount a wheel event will scroll +// is that it gives us a chance to update the display before the +// actual scrolling happens, reducing flickering. + +var wheelSamples = 0; +var wheelPixelsPerUnit = null; +// Fill in a browser-detected starting value on browsers where we +// know one. These don't have to be accurate -- the result of them +// being wrong would just be a slight flicker on the first wheel +// scroll (if it is large enough). +if (ie) { wheelPixelsPerUnit = -.53 } +else if (gecko) { wheelPixelsPerUnit = 15 } +else if (chrome) { wheelPixelsPerUnit = -.7 } +else if (safari) { wheelPixelsPerUnit = -1/3 } + +function wheelEventDelta(e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail } + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail } + else if (dy == null) { dy = e.wheelDelta } + return {x: dx, y: dy} +} +function wheelEventPixels(e) { + var delta = wheelEventDelta(e) + delta.x *= wheelPixelsPerUnit + delta.y *= wheelPixelsPerUnit + return delta +} + +function onScrollWheel(cm, e) { + var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y + + var display = cm.display, scroll = display.scroller + // Quit if there's nothing to scroll here + var canScrollX = scroll.scrollWidth > scroll.clientWidth + var canScrollY = scroll.scrollHeight > scroll.clientHeight + if (!(dx && canScrollX || dy && canScrollY)) { return } + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (var i = 0; i < view.length; i++) { + if (view[i].node == cur) { + cm.display.currentWheelTarget = cur + break outer + } + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dy && canScrollY) + { setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))) } + setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))) + // Only prevent default scrolling if vertical scrolling is + // actually possible. Otherwise, it causes vertical scroll + // jitter on OSX trackpads when deltaX is small and deltaY + // is large (issue #3579) + if (!dy || (dy && canScrollY)) + { e_preventDefault(e) } + display.wheelStartX = null // Abort measurement, if in progress + return + } + + // 'Project' the visible viewport to cover the area that is being + // scrolled into view (if we know enough to estimate it). + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight + if (pixels < 0) { top = Math.max(0, top + pixels - 50) } + else { bot = Math.min(cm.doc.height, bot + pixels + 50) } + updateDisplaySimple(cm, {top: top, bottom: bot}) + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop + display.wheelDX = dx; display.wheelDY = dy + setTimeout(function () { + if (display.wheelStartX == null) { return } + var movedX = scroll.scrollLeft - display.wheelStartX + var movedY = scroll.scrollTop - display.wheelStartY + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX) + display.wheelStartX = display.wheelStartY = null + if (!sample) { return } + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1) + ++wheelSamples + }, 200) + } else { + display.wheelDX += dx; display.wheelDY += dy + } + } +} + +// SCROLLBARS + +// Prepare DOM reads needed to update the scrollbars. Done in one +// shot to minimize update/measure roundtrips. +function measureForScrollbars(cm) { + var d = cm.display, gutterW = d.gutters.offsetWidth + var docH = Math.round(cm.doc.height + paddingVert(cm.display)) + return { + clientHeight: d.scroller.clientHeight, + viewHeight: d.wrapper.clientHeight, + scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, + viewWidth: d.wrapper.clientWidth, + barLeft: cm.options.fixedGutter ? gutterW : 0, + docHeight: docH, + scrollHeight: docH + scrollGap(cm) + d.barHeight, + nativeBarWidth: d.nativeBarWidth, + gutterWidth: gutterW + } +} + +var NativeScrollbars = function(place, scroll, cm) { + this.cm = cm + var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") + var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") + place(vert); place(horiz) + + on(vert, "scroll", function () { + if (vert.clientHeight) { scroll(vert.scrollTop, "vertical") } + }) + on(horiz, "scroll", function () { + if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal") } + }) + + this.checkedZeroWidth = false + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px" } +}; + +NativeScrollbars.prototype.update = function (measure) { + var needsH = measure.scrollWidth > measure.clientWidth + 1 + var needsV = measure.scrollHeight > measure.clientHeight + 1 + var sWidth = measure.nativeBarWidth + + if (needsV) { + this.vert.style.display = "block" + this.vert.style.bottom = needsH ? sWidth + "px" : "0" + var totalHeight = measure.viewHeight - (needsH ? sWidth : 0) + // A bug in IE8 can cause this value to be negative, so guard it. + this.vert.firstChild.style.height = + Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px" + } else { + this.vert.style.display = "" + this.vert.firstChild.style.height = "0" + } + + if (needsH) { + this.horiz.style.display = "block" + this.horiz.style.right = needsV ? sWidth + "px" : "0" + this.horiz.style.left = measure.barLeft + "px" + var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0) + this.horiz.firstChild.style.width = + Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px" + } else { + this.horiz.style.display = "" + this.horiz.firstChild.style.width = "0" + } + + if (!this.checkedZeroWidth && measure.clientHeight > 0) { + if (sWidth == 0) { this.zeroWidthHack() } + this.checkedZeroWidth = true + } + + return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0} +}; + +NativeScrollbars.prototype.setScrollLeft = function (pos) { + if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos } + if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz) } +}; + +NativeScrollbars.prototype.setScrollTop = function (pos) { + if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos } + if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert) } +}; + +NativeScrollbars.prototype.zeroWidthHack = function () { + var w = mac && !mac_geMountainLion ? "12px" : "18px" + this.horiz.style.height = this.vert.style.width = w + this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none" + this.disableHoriz = new Delayed + this.disableVert = new Delayed +}; + +NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay) { + bar.style.pointerEvents = "auto" + function maybeDisable() { + // To find out whether the scrollbar is still visible, we + // check whether the element under the pixel in the bottom + // left corner of the scrollbar box is the scrollbar box + // itself (when the bar is still visible) or its filler child + // (when the bar is hidden). If it is still visible, we keep + // it enabled, if it's hidden, we disable pointer events. + var box = bar.getBoundingClientRect() + var elt = document.elementFromPoint(box.left + 1, box.bottom - 1) + if (elt != bar) { bar.style.pointerEvents = "none" } + else { delay.set(1000, maybeDisable) } + } + delay.set(1000, maybeDisable) +}; + +NativeScrollbars.prototype.clear = function () { + var parent = this.horiz.parentNode + parent.removeChild(this.horiz) + parent.removeChild(this.vert) +}; + +var NullScrollbars = function () {}; + +NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} }; +NullScrollbars.prototype.setScrollLeft = function () {}; +NullScrollbars.prototype.setScrollTop = function () {}; +NullScrollbars.prototype.clear = function () {}; + +function updateScrollbars(cm, measure) { + if (!measure) { measure = measureForScrollbars(cm) } + var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight + updateScrollbarsInner(cm, measure) + for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { + if (startWidth != cm.display.barWidth && cm.options.lineWrapping) + { updateHeightsInViewport(cm) } + updateScrollbarsInner(cm, measureForScrollbars(cm)) + startWidth = cm.display.barWidth; startHeight = cm.display.barHeight + } +} + +// Re-synchronize the fake scrollbars with the actual size of the +// content. +function updateScrollbarsInner(cm, measure) { + var d = cm.display + var sizes = d.scrollbars.update(measure) + + d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px" + d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px" + d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent" + + if (sizes.right && sizes.bottom) { + d.scrollbarFiller.style.display = "block" + d.scrollbarFiller.style.height = sizes.bottom + "px" + d.scrollbarFiller.style.width = sizes.right + "px" + } else { d.scrollbarFiller.style.display = "" } + if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block" + d.gutterFiller.style.height = sizes.bottom + "px" + d.gutterFiller.style.width = measure.gutterWidth + "px" + } else { d.gutterFiller.style.display = "" } +} + +var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars} + +function initScrollbars(cm) { + if (cm.display.scrollbars) { + cm.display.scrollbars.clear() + if (cm.display.scrollbars.addClass) + { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass) } + } + + cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) { + cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller) + // Prevent clicks in the scrollbars from killing focus + on(node, "mousedown", function () { + if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0) } + }) + node.setAttribute("cm-not-content", "true") + }, function (pos, axis) { + if (axis == "horizontal") { setScrollLeft(cm, pos) } + else { setScrollTop(cm, pos) } + }, cm) + if (cm.display.scrollbars.addClass) + { addClass(cm.display.wrapper, cm.display.scrollbars.addClass) } +} + +// SCROLLING THINGS INTO VIEW + +// If an editor sits on the top or bottom of the window, partially +// scrolled out of view, this ensures that the cursor is visible. +function maybeScrollWindow(cm, rect) { + if (signalDOMEvent(cm, "scrollCursorIntoView")) { return } + + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null + if (rect.top + box.top < 0) { doScroll = true } + else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false } + if (doScroll != null && !phantom) { + var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;")) + cm.display.lineSpace.appendChild(scrollNode) + scrollNode.scrollIntoView(doScroll) + cm.display.lineSpace.removeChild(scrollNode) + } +} + +// Scroll a given position into view (immediately), verifying that +// it actually became visible (as line heights are accurately +// measured, the position of something may 'drift' during drawing). +function scrollPosIntoView(cm, pos, end, margin) { + if (margin == null) { margin = 0 } + var rect + for (var limit = 0; limit < 5; limit++) { + var changed = false + var coords = cursorCoords(cm, pos) + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end) + rect = {left: Math.min(coords.left, endCoords.left), + top: Math.min(coords.top, endCoords.top) - margin, + right: Math.max(coords.left, endCoords.left), + bottom: Math.max(coords.bottom, endCoords.bottom) + margin} + var scrollPos = calculateScrollPos(cm, rect) + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft + if (scrollPos.scrollTop != null) { + setScrollTop(cm, scrollPos.scrollTop) + if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true } + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft) + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true } + } + if (!changed) { break } + } + return rect +} + +// Scroll a given set of coordinates into view (immediately). +function scrollIntoView(cm, rect) { + var scrollPos = calculateScrollPos(cm, rect) + if (scrollPos.scrollTop != null) { setScrollTop(cm, scrollPos.scrollTop) } + if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft) } +} + +// Calculate a new scroll position needed to scroll the given +// rectangle into view. Returns an object with scrollTop and +// scrollLeft properties. When these are undefined, the +// vertical/horizontal position does not need to be adjusted. +function calculateScrollPos(cm, rect) { + var display = cm.display, snapMargin = textHeight(cm.display) + if (rect.top < 0) { rect.top = 0 } + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop + var screen = displayHeight(cm), result = {} + if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen } + var docBottom = cm.doc.height + paddingVert(display) + var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin + if (rect.top < screentop) { + result.scrollTop = atTop ? 0 : rect.top + } else if (rect.bottom > screentop + screen) { + var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen) + if (newTop != screentop) { result.scrollTop = newTop } + } + + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft + var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0) + var tooWide = rect.right - rect.left > screenw + if (tooWide) { rect.right = rect.left + screenw } + if (rect.left < 10) + { result.scrollLeft = 0 } + else if (rect.left < screenleft) + { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)) } + else if (rect.right > screenw + screenleft - 3) + { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw } + return result +} + +// Store a relative adjustment to the scroll position in the current +// operation (to be applied when the operation finishes). +function addToScrollPos(cm, left, top) { + if (left != null || top != null) { resolveScrollToPos(cm) } + if (left != null) + { cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left } + if (top != null) + { cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top } +} + +// Make sure that at the end of the operation the current cursor is +// shown. +function ensureCursorVisible(cm) { + resolveScrollToPos(cm) + var cur = cm.getCursor(), from = cur, to = cur + if (!cm.options.lineWrapping) { + from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur + to = Pos(cur.line, cur.ch + 1) + } + cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin} +} + +// When an operation has its scrollToPos property set, and another +// scroll action is applied before the end of the operation, this +// 'simulates' scrolling that position into view in a cheap way, so +// that the effect of intermediate scroll commands is not ignored. +function resolveScrollToPos(cm) { + var range = cm.curOp.scrollToPos + if (range) { + cm.curOp.scrollToPos = null + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to) + var sPos = calculateScrollPos(cm, { + left: Math.min(from.left, to.left), + top: Math.min(from.top, to.top) - range.margin, + right: Math.max(from.right, to.right), + bottom: Math.max(from.bottom, to.bottom) + range.margin + }) + cm.scrollTo(sPos.scrollLeft, sPos.scrollTop) + } +} + +// Operations are used to wrap a series of changes to the editor +// state in such a way that each change won't have to update the +// cursor and display (which would be awkward, slow, and +// error-prone). Instead, display updates are batched and then all +// combined and executed at once. + +var nextOpId = 0 +// Start a new operation. +function startOperation(cm) { + cm.curOp = { + cm: cm, + viewChanged: false, // Flag that indicates that lines might need to be redrawn + startHeight: cm.doc.height, // Used to detect need to update scrollbar + forceUpdate: false, // Used to force a redraw + updateInput: null, // Whether to reset the input textarea + typing: false, // Whether this reset should be careful to leave existing text (for compositing) + changeObjs: null, // Accumulated changes, for firing change events + cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already + selectionChanged: false, // Whether the selection needs to be redrawn + updateMaxLine: false, // Set when the widest line needs to be determined anew + scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet + scrollToPos: null, // Used to scroll to a specific position + focus: false, + id: ++nextOpId // Unique ID + } + pushOperation(cm.curOp) +} + +// Finish an operation, updating the display and signalling delayed events +function endOperation(cm) { + var op = cm.curOp + finishOperation(op, function (group) { + for (var i = 0; i < group.ops.length; i++) + { group.ops[i].cm.curOp = null } + endOperations(group) + }) +} + +// The DOM updates done when an operation finishes are batched so +// that the minimum number of relayouts are required. +function endOperations(group) { + var ops = group.ops + for (var i = 0; i < ops.length; i++) // Read DOM + { endOperation_R1(ops[i]) } + for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe) + { endOperation_W1(ops[i$1]) } + for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM + { endOperation_R2(ops[i$2]) } + for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe) + { endOperation_W2(ops[i$3]) } + for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM + { endOperation_finish(ops[i$4]) } +} + +function endOperation_R1(op) { + var cm = op.cm, display = cm.display + maybeClipScrollbars(cm) + if (op.updateMaxLine) { findMaxLine(cm) } + + op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || + op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || + op.scrollToPos.to.line >= display.viewTo) || + display.maxLineChanged && cm.options.lineWrapping + op.update = op.mustUpdate && + new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate) +} + +function endOperation_W1(op) { + op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update) +} + +function endOperation_R2(op) { + var cm = op.cm, display = cm.display + if (op.updatedDisplay) { updateHeightsInViewport(cm) } + + op.barMeasure = measureForScrollbars(cm) + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + // updateDisplay_W2 will use these properties to do the actual resizing + if (display.maxLineChanged && !cm.options.lineWrapping) { + op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3 + cm.display.sizerWidth = op.adjustWidthTo + op.barMeasure.scrollWidth = + Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth) + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)) + } + + if (op.updatedDisplay || op.selectionChanged) + { op.preparedSelection = display.input.prepareSelection(op.focus) } +} + +function endOperation_W2(op) { + var cm = op.cm + + if (op.adjustWidthTo != null) { + cm.display.sizer.style.minWidth = op.adjustWidthTo + "px" + if (op.maxScrollLeft < cm.doc.scrollLeft) + { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true) } + cm.display.maxLineChanged = false + } + + var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()) + if (op.preparedSelection) + { cm.display.input.showSelection(op.preparedSelection, takeFocus) } + if (op.updatedDisplay || op.startHeight != cm.doc.height) + { updateScrollbars(cm, op.barMeasure) } + if (op.updatedDisplay) + { setDocumentHeight(cm, op.barMeasure) } + + if (op.selectionChanged) { restartBlink(cm) } + + if (cm.state.focused && op.updateInput) + { cm.display.input.reset(op.typing) } + if (takeFocus) { ensureFocus(op.cm) } +} + +function endOperation_finish(op) { + var cm = op.cm, display = cm.display, doc = cm.doc + + if (op.updatedDisplay) { postUpdateDisplay(cm, op.update) } + + // Abort mouse wheel delta measurement, when scrolling explicitly + if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) + { display.wheelStartX = display.wheelStartY = null } + + // Propagate the scroll position to the actual DOM scroller + if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { + doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)) + display.scrollbars.setScrollTop(doc.scrollTop) + display.scroller.scrollTop = doc.scrollTop + } + if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { + doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)) + display.scrollbars.setScrollLeft(doc.scrollLeft) + display.scroller.scrollLeft = doc.scrollLeft + alignHorizontally(cm) + } + // If we need to scroll a specific position into view, do so. + if (op.scrollToPos) { + var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), + clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin) + maybeScrollWindow(cm, rect) + } + + // Fire events for markers that are hidden/unidden by editing or + // undoing + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers + if (hidden) { for (var i = 0; i < hidden.length; ++i) + { if (!hidden[i].lines.length) { signal(hidden[i], "hide") } } } + if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1) + { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide") } } } + + if (display.wrapper.offsetHeight) + { doc.scrollTop = cm.display.scroller.scrollTop } + + // Fire change events, and delayed event handlers + if (op.changeObjs) + { signal(cm, "changes", cm, op.changeObjs) } + if (op.update) + { op.update.finish() } +} + +// Run the given function in an operation +function runInOp(cm, f) { + if (cm.curOp) { return f() } + startOperation(cm) + try { return f() } + finally { endOperation(cm) } +} +// Wraps a function in an operation. Returns the wrapped function. +function operation(cm, f) { + return function() { + if (cm.curOp) { return f.apply(cm, arguments) } + startOperation(cm) + try { return f.apply(cm, arguments) } + finally { endOperation(cm) } + } +} +// Used to add methods to editor and doc instances, wrapping them in +// operations. +function methodOp(f) { + return function() { + if (this.curOp) { return f.apply(this, arguments) } + startOperation(this) + try { return f.apply(this, arguments) } + finally { endOperation(this) } + } +} +function docMethodOp(f) { + return function() { + var cm = this.cm + if (!cm || cm.curOp) { return f.apply(this, arguments) } + startOperation(cm) + try { return f.apply(this, arguments) } + finally { endOperation(cm) } + } +} + +// Updates the display.view data structure for a given change to the +// document. From and to are in pre-change coordinates. Lendiff is +// the amount of lines added or subtracted by the change. This is +// used for changes that span multiple lines, or change the way +// lines are divided into visual lines. regLineChange (below) +// registers single-line changes. +function regChange(cm, from, to, lendiff) { + if (from == null) { from = cm.doc.first } + if (to == null) { to = cm.doc.first + cm.doc.size } + if (!lendiff) { lendiff = 0 } + + var display = cm.display + if (lendiff && to < display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers > from)) + { display.updateLineNumbers = from } + + cm.curOp.viewChanged = true + + if (from >= display.viewTo) { // Change after + if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) + { resetView(cm) } + } else if (to <= display.viewFrom) { // Change before + if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { + resetView(cm) + } else { + display.viewFrom += lendiff + display.viewTo += lendiff + } + } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap + resetView(cm) + } else if (from <= display.viewFrom) { // Top overlap + var cut = viewCuttingPoint(cm, to, to + lendiff, 1) + if (cut) { + display.view = display.view.slice(cut.index) + display.viewFrom = cut.lineN + display.viewTo += lendiff + } else { + resetView(cm) + } + } else if (to >= display.viewTo) { // Bottom overlap + var cut$1 = viewCuttingPoint(cm, from, from, -1) + if (cut$1) { + display.view = display.view.slice(0, cut$1.index) + display.viewTo = cut$1.lineN + } else { + resetView(cm) + } + } else { // Gap in the middle + var cutTop = viewCuttingPoint(cm, from, from, -1) + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1) + if (cutTop && cutBot) { + display.view = display.view.slice(0, cutTop.index) + .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) + .concat(display.view.slice(cutBot.index)) + display.viewTo += lendiff + } else { + resetView(cm) + } + } + + var ext = display.externalMeasured + if (ext) { + if (to < ext.lineN) + { ext.lineN += lendiff } + else if (from < ext.lineN + ext.size) + { display.externalMeasured = null } + } +} + +// Register a change to a single line. Type must be one of "text", +// "gutter", "class", "widget" +function regLineChange(cm, line, type) { + cm.curOp.viewChanged = true + var display = cm.display, ext = cm.display.externalMeasured + if (ext && line >= ext.lineN && line < ext.lineN + ext.size) + { display.externalMeasured = null } + + if (line < display.viewFrom || line >= display.viewTo) { return } + var lineView = display.view[findViewIndex(cm, line)] + if (lineView.node == null) { return } + var arr = lineView.changes || (lineView.changes = []) + if (indexOf(arr, type) == -1) { arr.push(type) } +} + +// Clear the view. +function resetView(cm) { + cm.display.viewFrom = cm.display.viewTo = cm.doc.first + cm.display.view = [] + cm.display.viewOffset = 0 +} + +function viewCuttingPoint(cm, oldN, newN, dir) { + var index = findViewIndex(cm, oldN), diff, view = cm.display.view + if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) + { return {index: index, lineN: newN} } + var n = cm.display.viewFrom + for (var i = 0; i < index; i++) + { n += view[i].size } + if (n != oldN) { + if (dir > 0) { + if (index == view.length - 1) { return null } + diff = (n + view[index].size) - oldN + index++ + } else { + diff = n - oldN + } + oldN += diff; newN += diff + } + while (visualLineNo(cm.doc, newN) != newN) { + if (index == (dir < 0 ? 0 : view.length - 1)) { return null } + newN += dir * view[index - (dir < 0 ? 1 : 0)].size + index += dir + } + return {index: index, lineN: newN} +} + +// Force the view to cover a given range, adding empty view element +// or clipping off existing ones as needed. +function adjustView(cm, from, to) { + var display = cm.display, view = display.view + if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { + display.view = buildViewArray(cm, from, to) + display.viewFrom = from + } else { + if (display.viewFrom > from) + { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view) } + else if (display.viewFrom < from) + { display.view = display.view.slice(findViewIndex(cm, from)) } + display.viewFrom = from + if (display.viewTo < to) + { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)) } + else if (display.viewTo > to) + { display.view = display.view.slice(0, findViewIndex(cm, to)) } + } + display.viewTo = to +} + +// Count the number of lines in the view whose DOM representation is +// out of date (or nonexistent). +function countDirtyView(cm) { + var view = cm.display.view, dirty = 0 + for (var i = 0; i < view.length; i++) { + var lineView = view[i] + if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty } + } + return dirty +} + +// HIGHLIGHT WORKER + +function startWorker(cm, time) { + if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) + { cm.state.highlight.set(time, bind(highlightWorker, cm)) } +} + +function highlightWorker(cm) { + var doc = cm.doc + if (doc.frontier < doc.first) { doc.frontier = doc.first } + if (doc.frontier >= cm.display.viewTo) { return } + var end = +new Date + cm.options.workTime + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)) + var changedLines = [] + + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) { + if (doc.frontier >= cm.display.viewFrom) { // Visible + var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength + var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true) + line.styles = highlighted.styles + var oldCls = line.styleClasses, newCls = highlighted.classes + if (newCls) { line.styleClasses = newCls } + else if (oldCls) { line.styleClasses = null } + var ischange = !oldStyles || oldStyles.length != line.styles.length || + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass) + for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i] } + if (ischange) { changedLines.push(doc.frontier) } + line.stateAfter = tooLong ? state : copyState(doc.mode, state) + } else { + if (line.text.length <= cm.options.maxHighlightLength) + { processLine(cm, line.text, state) } + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null + } + ++doc.frontier + if (+new Date > end) { + startWorker(cm, cm.options.workDelay) + return true + } + }) + if (changedLines.length) { runInOp(cm, function () { + for (var i = 0; i < changedLines.length; i++) + { regLineChange(cm, changedLines[i], "text") } + }) } +} + +// DISPLAY DRAWING + +var DisplayUpdate = function(cm, viewport, force) { + var display = cm.display + + this.viewport = viewport + // Store some values that we'll need later (but don't want to force a relayout for) + this.visible = visibleLines(display, cm.doc, viewport) + this.editorIsHidden = !display.wrapper.offsetWidth + this.wrapperHeight = display.wrapper.clientHeight + this.wrapperWidth = display.wrapper.clientWidth + this.oldDisplayWidth = displayWidth(cm) + this.force = force + this.dims = getDimensions(cm) + this.events = [] +}; + +DisplayUpdate.prototype.signal = function (emitter, type) { + if (hasHandler(emitter, type)) + { this.events.push(arguments) } +}; +DisplayUpdate.prototype.finish = function () { + var this$1 = this; + + for (var i = 0; i < this.events.length; i++) + { signal.apply(null, this$1.events[i]) } +}; + +function maybeClipScrollbars(cm) { + var display = cm.display + if (!display.scrollbarsClipped && display.scroller.offsetWidth) { + display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth + display.heightForcer.style.height = scrollGap(cm) + "px" + display.sizer.style.marginBottom = -display.nativeBarWidth + "px" + display.sizer.style.borderRightWidth = scrollGap(cm) + "px" + display.scrollbarsClipped = true + } +} + +// Does the actual updating of the line display. Bails out +// (returning false) when there is nothing to be done and forced is +// false. +function updateDisplayIfNeeded(cm, update) { + var display = cm.display, doc = cm.doc + + if (update.editorIsHidden) { + resetView(cm) + return false + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!update.force && + update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && + display.renderedView == display.view && countDirtyView(cm) == 0) + { return false } + + if (maybeUpdateLineNumberWidth(cm)) { + resetView(cm) + update.dims = getDimensions(cm) + } + + // Compute a suitable new viewport (from & to) + var end = doc.first + doc.size + var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first) + var to = Math.min(end, update.visible.to + cm.options.viewportMargin) + if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom) } + if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo) } + if (sawCollapsedSpans) { + from = visualLineNo(cm.doc, from) + to = visualLineEndNo(cm.doc, to) + } + + var different = from != display.viewFrom || to != display.viewTo || + display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth + adjustView(cm, from, to) + + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)) + // Position the mover div to align with the current scroll position + cm.display.mover.style.top = display.viewOffset + "px" + + var toUpdate = countDirtyView(cm) + if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) + { return false } + + // For big changes, we hide the enclosing element during the + // update, since that speeds up the operations on most browsers. + var focused = activeElt() + if (toUpdate > 4) { display.lineDiv.style.display = "none" } + patchDisplay(cm, display.updateLineNumbers, update.dims) + if (toUpdate > 4) { display.lineDiv.style.display = "" } + display.renderedView = display.view + // There might have been a widget with a focused element that got + // hidden or updated, if so re-focus it. + if (focused && activeElt() != focused && focused.offsetHeight) { focused.focus() } + + // Prevent selection and cursors from interfering with the scroll + // width and height. + removeChildren(display.cursorDiv) + removeChildren(display.selectionDiv) + display.gutters.style.height = display.sizer.style.minHeight = 0 + + if (different) { + display.lastWrapHeight = update.wrapperHeight + display.lastWrapWidth = update.wrapperWidth + startWorker(cm, 400) + } + + display.updateLineNumbers = null + + return true +} + +function postUpdateDisplay(cm, update) { + var viewport = update.viewport + + for (var first = true;; first = false) { + if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { + // Clip forced viewport to actual scrollable area. + if (viewport && viewport.top != null) + { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)} } + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + update.visible = visibleLines(cm.display, cm.doc, viewport) + if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) + { break } + } + if (!updateDisplayIfNeeded(cm, update)) { break } + updateHeightsInViewport(cm) + var barMeasure = measureForScrollbars(cm) + updateSelection(cm) + updateScrollbars(cm, barMeasure) + setDocumentHeight(cm, barMeasure) + } + + update.signal(cm, "update", cm) + if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo) + cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo + } +} + +function updateDisplaySimple(cm, viewport) { + var update = new DisplayUpdate(cm, viewport) + if (updateDisplayIfNeeded(cm, update)) { + updateHeightsInViewport(cm) + postUpdateDisplay(cm, update) + var barMeasure = measureForScrollbars(cm) + updateSelection(cm) + updateScrollbars(cm, barMeasure) + setDocumentHeight(cm, barMeasure) + update.finish() + } +} + +// Sync the actual display DOM structure with display.view, removing +// nodes for lines that are no longer in view, and creating the ones +// that are not there yet, and updating the ones that are out of +// date. +function patchDisplay(cm, updateNumbersFrom, dims) { + var display = cm.display, lineNumbers = cm.options.lineNumbers + var container = display.lineDiv, cur = container.firstChild + + function rm(node) { + var next = node.nextSibling + // Works around a throw-scroll bug in OS X Webkit + if (webkit && mac && cm.display.currentWheelTarget == node) + { node.style.display = "none" } + else + { node.parentNode.removeChild(node) } + return next + } + + var view = display.view, lineN = display.viewFrom + // Loop over the elements in the view, syncing cur (the DOM nodes + // in display.lineDiv) with the view as we go. + for (var i = 0; i < view.length; i++) { + var lineView = view[i] + if (lineView.hidden) { + } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet + var node = buildLineElement(cm, lineView, lineN, dims) + container.insertBefore(node, cur) + } else { // Already drawn + while (cur != lineView.node) { cur = rm(cur) } + var updateNumber = lineNumbers && updateNumbersFrom != null && + updateNumbersFrom <= lineN && lineView.lineNumber + if (lineView.changes) { + if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false } + updateLineForChanges(cm, lineView, lineN, dims) + } + if (updateNumber) { + removeChildren(lineView.lineNumber) + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))) + } + cur = lineView.node.nextSibling + } + lineN += lineView.size + } + while (cur) { cur = rm(cur) } +} + +function updateGutterSpace(cm) { + var width = cm.display.gutters.offsetWidth + cm.display.sizer.style.marginLeft = width + "px" +} + +function setDocumentHeight(cm, measure) { + cm.display.sizer.style.minHeight = measure.docHeight + "px" + cm.display.heightForcer.style.top = measure.docHeight + "px" + cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px" +} + +// Rebuild the gutter elements, ensure the margin to the left of the +// code matches their width. +function updateGutters(cm) { + var gutters = cm.display.gutters, specs = cm.options.gutters + removeChildren(gutters) + var i = 0 + for (; i < specs.length; ++i) { + var gutterClass = specs[i] + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)) + if (gutterClass == "CodeMirror-linenumbers") { + cm.display.lineGutter = gElt + gElt.style.width = (cm.display.lineNumWidth || 1) + "px" + } + } + gutters.style.display = i ? "" : "none" + updateGutterSpace(cm) +} + +// Make sure the gutters options contains the element +// "CodeMirror-linenumbers" when the lineNumbers option is true. +function setGuttersForLineNumbers(options) { + var found = indexOf(options.gutters, "CodeMirror-linenumbers") + if (found == -1 && options.lineNumbers) { + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]) + } else if (found > -1 && !options.lineNumbers) { + options.gutters = options.gutters.slice(0) + options.gutters.splice(found, 1) + } +} + +// Selection objects are immutable. A new one is created every time +// the selection changes. A selection is one or more non-overlapping +// (and non-touching) ranges, sorted, and an integer that indicates +// which one is the primary selection (the one that's scrolled into +// view, that getCursor returns, etc). +var Selection = function(ranges, primIndex) { + this.ranges = ranges + this.primIndex = primIndex +}; + +Selection.prototype.primary = function () { return this.ranges[this.primIndex] }; + +Selection.prototype.equals = function (other) { + var this$1 = this; + + if (other == this) { return true } + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false } + for (var i = 0; i < this.ranges.length; i++) { + var here = this$1.ranges[i], there = other.ranges[i] + if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false } + } + return true +}; + +Selection.prototype.deepCopy = function () { + var this$1 = this; + + var out = [] + for (var i = 0; i < this.ranges.length; i++) + { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)) } + return new Selection(out, this.primIndex) +}; + +Selection.prototype.somethingSelected = function () { + var this$1 = this; + + for (var i = 0; i < this.ranges.length; i++) + { if (!this$1.ranges[i].empty()) { return true } } + return false +}; + +Selection.prototype.contains = function (pos, end) { + var this$1 = this; + + if (!end) { end = pos } + for (var i = 0; i < this.ranges.length; i++) { + var range = this$1.ranges[i] + if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) + { return i } + } + return -1 +}; + +var Range = function(anchor, head) { + this.anchor = anchor; this.head = head +}; + +Range.prototype.from = function () { return minPos(this.anchor, this.head) }; +Range.prototype.to = function () { return maxPos(this.anchor, this.head) }; +Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch }; + +// Take an unsorted, potentially overlapping set of ranges, and +// build a selection out of it. 'Consumes' ranges array (modifying +// it). +function normalizeSelection(ranges, primIndex) { + var prim = ranges[primIndex] + ranges.sort(function (a, b) { return cmp(a.from(), b.from()); }) + primIndex = indexOf(ranges, prim) + for (var i = 1; i < ranges.length; i++) { + var cur = ranges[i], prev = ranges[i - 1] + if (cmp(prev.to(), cur.from()) >= 0) { + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()) + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head + if (i <= primIndex) { --primIndex } + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)) + } + } + return new Selection(ranges, primIndex) +} + +function simpleSelection(anchor, head) { + return new Selection([new Range(anchor, head || anchor)], 0) +} + +// Compute the position of the end of a change (its 'to' property +// refers to the pre-change end). +function changeEnd(change) { + if (!change.text) { return change.to } + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)) +} + +// Adjust a position to refer to the post-change position of the +// same text, or the end of the change if the change covers it. +function adjustForChange(pos, change) { + if (cmp(pos, change.from) < 0) { return pos } + if (cmp(pos, change.to) <= 0) { return changeEnd(change) } + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch + if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch } + return Pos(line, ch) +} + +function computeSelAfterChange(doc, change) { + var out = [] + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i] + out.push(new Range(adjustForChange(range.anchor, change), + adjustForChange(range.head, change))) + } + return normalizeSelection(out, doc.sel.primIndex) +} + +function offsetPos(pos, old, nw) { + if (pos.line == old.line) + { return Pos(nw.line, pos.ch - old.ch + nw.ch) } + else + { return Pos(nw.line + (pos.line - old.line), pos.ch) } +} + +// Used by replaceSelections to allow moving the selection to the +// start or around the replaced test. Hint may be "start" or "around". +function computeReplacedSel(doc, changes, hint) { + var out = [] + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev + for (var i = 0; i < changes.length; i++) { + var change = changes[i] + var from = offsetPos(change.from, oldPrev, newPrev) + var to = offsetPos(changeEnd(change), oldPrev, newPrev) + oldPrev = change.to + newPrev = to + if (hint == "around") { + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0 + out[i] = new Range(inv ? to : from, inv ? from : to) + } else { + out[i] = new Range(from, from) + } + } + return new Selection(out, doc.sel.primIndex) +} + +// Used to get the editor into a consistent state again when options change. + +function loadMode(cm) { + cm.doc.mode = getMode(cm.options, cm.doc.modeOption) + resetModeState(cm) +} + +function resetModeState(cm) { + cm.doc.iter(function (line) { + if (line.stateAfter) { line.stateAfter = null } + if (line.styles) { line.styles = null } + }) + cm.doc.frontier = cm.doc.first + startWorker(cm, 100) + cm.state.modeGen++ + if (cm.curOp) { regChange(cm) } +} + +// DOCUMENT DATA STRUCTURE + +// By default, updates that start and end at the beginning of a line +// are treated specially, in order to make the association of line +// widgets and marker elements with the text behave more intuitive. +function isWholeLineUpdate(doc, change) { + return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore) +} + +// Perform a change on the document data structure. +function updateDoc(doc, change, markedSpans, estimateHeight) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight) + signalLater(line, "change", line, change) + } + function linesFor(start, end) { + var result = [] + for (var i = start; i < end; ++i) + { result.push(new Line(text[i], spansFor(i), estimateHeight)) } + return result + } + + var from = change.from, to = change.to, text = change.text + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line) + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line + + // Adjust the line structure + if (change.full) { + doc.insert(0, linesFor(0, text.length)) + doc.remove(text.length, doc.size - text.length) + } else if (isWholeLineUpdate(doc, change)) { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = linesFor(0, text.length - 1) + update(lastLine, lastLine.text, lastSpans) + if (nlines) { doc.remove(from.line, nlines) } + if (added.length) { doc.insert(from.line, added) } + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans) + } else { + var added$1 = linesFor(1, text.length - 1) + added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)) + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) + doc.insert(from.line + 1, added$1) + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)) + doc.remove(from.line + 1, nlines) + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans) + var added$2 = linesFor(1, text.length - 1) + if (nlines > 1) { doc.remove(from.line + 1, nlines - 1) } + doc.insert(from.line + 1, added$2) + } + + signalLater(doc, "change", doc, change) +} + +// Call f for all linked documents. +function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i] + if (rel.doc == skip) { continue } + var shared = sharedHist && rel.sharedHist + if (sharedHistOnly && !shared) { continue } + f(rel.doc, shared) + propagate(rel.doc, doc, shared) + } } + } + propagate(doc, null, true) +} + +// Attach a document to an editor. +function attachDoc(cm, doc) { + if (doc.cm) { throw new Error("This document is already in use.") } + cm.doc = doc + doc.cm = cm + estimateLineHeights(cm) + loadMode(cm) + setDirectionClass(cm) + if (!cm.options.lineWrapping) { findMaxLine(cm) } + cm.options.mode = doc.modeOption + regChange(cm) +} + +function setDirectionClass(cm) { + ;(cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl") +} + +function directionChanged(cm) { + runInOp(cm, function () { + setDirectionClass(cm) + regChange(cm) + }) +} + +function History(startGen) { + // Arrays of change events and selections. Doing something adds an + // event to done and clears undo. Undoing moves events from done + // to undone, redoing moves them in the other direction. + this.done = []; this.undone = [] + this.undoDepth = Infinity + // Used to track when changes can be merged into a single undo + // event + this.lastModTime = this.lastSelTime = 0 + this.lastOp = this.lastSelOp = null + this.lastOrigin = this.lastSelOrigin = null + // Used by the isClean() method + this.generation = this.maxGeneration = startGen || 1 +} + +// Create a history change event from an updateDoc-style change +// object. +function historyChangeFromChange(doc, change) { + var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)} + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1) + linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true) + return histChange +} + +// Pop all selection events off the end of a history array. Stop at +// a change event. +function clearSelectionEvents(array) { + while (array.length) { + var last = lst(array) + if (last.ranges) { array.pop() } + else { break } + } +} + +// Find the top change event in the history. Pop off selection +// events that are in the way. +function lastChangeEvent(hist, force) { + if (force) { + clearSelectionEvents(hist.done) + return lst(hist.done) + } else if (hist.done.length && !lst(hist.done).ranges) { + return lst(hist.done) + } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { + hist.done.pop() + return lst(hist.done) + } +} + +// Register a change in the history. Merges changes that are within +// a single operation, or are close together with an origin that +// allows merging (starting with "+") into a single event. +function addChangeToHistory(doc, change, selAfter, opId) { + var hist = doc.history + hist.undone.length = 0 + var time = +new Date, cur + var last + + if ((hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || + change.origin.charAt(0) == "*")) && + (cur = lastChangeEvent(hist, hist.lastOp == opId))) { + // Merge this change into the last event + last = lst(cur.changes) + if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change) + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)) + } + } else { + // Can not be merged, start a new event. + var before = lst(hist.done) + if (!before || !before.ranges) + { pushSelectionToHistory(doc.sel, hist.done) } + cur = {changes: [historyChangeFromChange(doc, change)], + generation: hist.generation} + hist.done.push(cur) + while (hist.done.length > hist.undoDepth) { + hist.done.shift() + if (!hist.done[0].ranges) { hist.done.shift() } + } + } + hist.done.push(selAfter) + hist.generation = ++hist.maxGeneration + hist.lastModTime = hist.lastSelTime = time + hist.lastOp = hist.lastSelOp = opId + hist.lastOrigin = hist.lastSelOrigin = change.origin + + if (!last) { signal(doc, "historyAdded") } +} + +function selectionEventCanBeMerged(doc, origin, prev, sel) { + var ch = origin.charAt(0) + return ch == "*" || + ch == "+" && + prev.ranges.length == sel.ranges.length && + prev.somethingSelected() == sel.somethingSelected() && + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500) +} + +// Called whenever the selection changes, sets the new selection as +// the pending selection in the history, and pushes the old pending +// selection into the 'done' array when it was significantly +// different (in number of selected ranges, emptiness, or time). +function addSelectionToHistory(doc, sel, opId, options) { + var hist = doc.history, origin = options && options.origin + + // A new event is started when the previous origin does not match + // the current, or the origins don't allow matching. Origins + // starting with * are always merged, those starting with + are + // merged when similar and close together in time. + if (opId == hist.lastSelOp || + (origin && hist.lastSelOrigin == origin && + (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || + selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) + { hist.done[hist.done.length - 1] = sel } + else + { pushSelectionToHistory(sel, hist.done) } + + hist.lastSelTime = +new Date + hist.lastSelOrigin = origin + hist.lastSelOp = opId + if (options && options.clearRedo !== false) + { clearSelectionEvents(hist.undone) } +} + +function pushSelectionToHistory(sel, dest) { + var top = lst(dest) + if (!(top && top.ranges && top.equals(sel))) + { dest.push(sel) } +} + +// Used to store marked span information in the history. +function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0 + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) { + if (line.markedSpans) + { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans } + ++n + }) +} + +// When un/re-doing restores text containing marked spans, those +// that have been explicitly cleared should not be restored. +function removeClearedSpans(spans) { + if (!spans) { return null } + var out + for (var i = 0; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i) } } + else if (out) { out.push(spans[i]) } + } + return !out ? spans : out.length ? out : null +} + +// Retrieve and filter the old marked spans stored in a change event. +function getOldSpans(doc, change) { + var found = change["spans_" + doc.id] + if (!found) { return null } + var nw = [] + for (var i = 0; i < change.text.length; ++i) + { nw.push(removeClearedSpans(found[i])) } + return nw +} + +// Used for un/re-doing changes from the history. Combines the +// result of computing the existing spans with the set of spans that +// existed in the history (so that deleting around a span and then +// undoing brings back the span). +function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change) + var stretched = stretchSpansOverChange(doc, change) + if (!old) { return stretched } + if (!stretched) { return old } + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i] + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j] + for (var k = 0; k < oldCur.length; ++k) + { if (oldCur[k].marker == span.marker) { continue spans } } + oldCur.push(span) + } + } else if (stretchCur) { + old[i] = stretchCur + } + } + return old +} + +// Used both to provide a JSON-safe object in .getHistory, and, when +// detaching a document, to split the history in two +function copyHistoryArray(events, newGroup, instantiateSel) { + var copy = [] + for (var i = 0; i < events.length; ++i) { + var event = events[i] + if (event.ranges) { + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event) + continue + } + var changes = event.changes, newChanges = [] + copy.push({changes: newChanges}) + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m = (void 0) + newChanges.push({from: change.from, to: change.to, text: change.text}) + if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop] + delete change[prop] + } + } } } + } + } + return copy +} + +// The 'scroll' parameter given to many of these indicated whether +// the new cursor position should be scrolled into view after +// modifying the selection. + +// If shift is held or the extend flag is set, extends a range to +// include a given position (and optionally a second position). +// Otherwise, simply returns the range between the given positions. +// Used for cursor motion and such. +function extendRange(doc, range, head, other) { + if (doc.cm && doc.cm.display.shift || doc.extend) { + var anchor = range.anchor + if (other) { + var posBefore = cmp(head, anchor) < 0 + if (posBefore != (cmp(other, anchor) < 0)) { + anchor = head + head = other + } else if (posBefore != (cmp(head, other) < 0)) { + head = other + } + } + return new Range(anchor, head) + } else { + return new Range(other || head, head) + } +} + +// Extend the primary selection range, discard the rest. +function extendSelection(doc, head, other, options) { + setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options) +} + +// Extend all selections (pos is an array of selections with length +// equal the number of selections) +function extendSelections(doc, heads, options) { + var out = [] + for (var i = 0; i < doc.sel.ranges.length; i++) + { out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null) } + var newSel = normalizeSelection(out, doc.sel.primIndex) + setSelection(doc, newSel, options) +} + +// Updates a single range in the selection. +function replaceOneSelection(doc, i, range, options) { + var ranges = doc.sel.ranges.slice(0) + ranges[i] = range + setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options) +} + +// Reset the selection to a single range. +function setSimpleSelection(doc, anchor, head, options) { + setSelection(doc, simpleSelection(anchor, head), options) +} + +// Give beforeSelectionChange handlers a change to influence a +// selection update. +function filterSelectionChange(doc, sel, options) { + var obj = { + ranges: sel.ranges, + update: function(ranges) { + var this$1 = this; + + this.ranges = [] + for (var i = 0; i < ranges.length; i++) + { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + clipPos(doc, ranges[i].head)) } + }, + origin: options && options.origin + } + signal(doc, "beforeSelectionChange", doc, obj) + if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj) } + if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) } + else { return sel } +} + +function setSelectionReplaceHistory(doc, sel, options) { + var done = doc.history.done, last = lst(done) + if (last && last.ranges) { + done[done.length - 1] = sel + setSelectionNoUndo(doc, sel, options) + } else { + setSelection(doc, sel, options) + } +} + +// Set a new selection. +function setSelection(doc, sel, options) { + setSelectionNoUndo(doc, sel, options) + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options) +} + +function setSelectionNoUndo(doc, sel, options) { + if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) + { sel = filterSelectionChange(doc, sel, options) } + + var bias = options && options.bias || + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1) + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)) + + if (!(options && options.scroll === false) && doc.cm) + { ensureCursorVisible(doc.cm) } +} + +function setSelectionInner(doc, sel) { + if (sel.equals(doc.sel)) { return } + + doc.sel = sel + + if (doc.cm) { + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true + signalCursorActivity(doc.cm) + } + signalLater(doc, "cursorActivity", doc) +} + +// Verify that the selection does not partially select any atomic +// marked ranges. +function reCheckSelection(doc) { + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll) +} + +// Return a selection that does not partially select any atomic +// ranges. +function skipAtomicInSelection(doc, sel, bias, mayClear) { + var out + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i] + var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i] + var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear) + var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear) + if (out || newAnchor != range.anchor || newHead != range.head) { + if (!out) { out = sel.ranges.slice(0, i) } + out[i] = new Range(newAnchor, newHead) + } + } + return out ? normalizeSelection(out, sel.primIndex) : sel +} + +function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { + var line = getLine(doc, pos.line) + if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter") + if (m.explicitlyCleared) { + if (!line.markedSpans) { break } + else {--i; continue} + } + } + if (!m.atomic) { continue } + + if (oldPos) { + var near = m.find(dir < 0 ? 1 : -1), diff = (void 0) + if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) + { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null) } + if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) + { return skipAtomicInner(doc, near, pos, dir, mayClear) } + } + + var far = m.find(dir < 0 ? -1 : 1) + if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) + { far = movePos(doc, far, dir, far.line == pos.line ? line : null) } + return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null + } + } } + return pos +} + +// Ensure a given position is not inside an atomic range. +function skipAtomic(doc, pos, oldPos, bias, mayClear) { + var dir = bias || 1 + var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || + skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)) + if (!found) { + doc.cantEdit = true + return Pos(doc.first, 0) + } + return found +} + +function movePos(doc, pos, dir, line) { + if (dir < 0 && pos.ch == 0) { + if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) } + else { return null } + } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { + if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) } + else { return null } + } else { + return new Pos(pos.line, pos.ch + dir) + } +} + +function selectAll(cm) { + cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll) +} + +// UPDATING + +// Allow "beforeChange" event handlers to influence a change +function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function () { return obj.canceled = true; } + } + if (update) { obj.update = function (from, to, text, origin) { + if (from) { obj.from = clipPos(doc, from) } + if (to) { obj.to = clipPos(doc, to) } + if (text) { obj.text = text } + if (origin !== undefined) { obj.origin = origin } + } } + signal(doc, "beforeChange", doc, obj) + if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj) } + + if (obj.canceled) { return null } + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin} +} + +// Apply a change to a document, and add it to the document's +// history, and propagating it to all linked documents. +function makeChange(doc, change, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) } + if (doc.cm.state.suppressEdits) { return } + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true) + if (!change) { return } + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to) + if (split) { + for (var i = split.length - 1; i >= 0; --i) + { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}) } + } else { + makeChangeInner(doc, change) + } +} + +function makeChangeInner(doc, change) { + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return } + var selAfter = computeSelAfterChange(doc, change) + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN) + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)) + var rebased = [] + + linkedDocs(doc, function (doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change) + rebased.push(doc.history) + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)) + }) +} + +// Revert a change stored in a document's history. +function makeChangeFromHistory(doc, type, allowSelectionOnly) { + if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return } + + var hist = doc.history, event, selAfter = doc.sel + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done + + // Verify that there is a useable event (so that ctrl-z won't + // needlessly clear selection events) + var i = 0 + for (; i < source.length; i++) { + event = source[i] + if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) + { break } + } + if (i == source.length) { return } + hist.lastOrigin = hist.lastSelOrigin = null + + for (;;) { + event = source.pop() + if (event.ranges) { + pushSelectionToHistory(event, dest) + if (allowSelectionOnly && !event.equals(doc.sel)) { + setSelection(doc, event, {clearRedo: false}) + return + } + selAfter = event + } + else { break } + } + + // Build up a reverse change object to add to the opposite history + // stack (redo when undoing, and vice versa). + var antiChanges = [] + pushSelectionToHistory(selAfter, dest) + dest.push({changes: antiChanges, generation: hist.generation}) + hist.generation = event.generation || ++hist.maxGeneration + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange") + + var loop = function ( i ) { + var change = event.changes[i] + change.origin = type + if (filter && !filterChange(doc, change, false)) { + source.length = 0 + return {} + } + + antiChanges.push(historyChangeFromChange(doc, change)) + + var after = i ? computeSelAfterChange(doc, change) : lst(source) + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)) + if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}) } + var rebased = [] + + // Propagate to the linked documents + linkedDocs(doc, function (doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change) + rebased.push(doc.history) + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)) + }) + }; + + for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) { + var returned = loop( i$1 ); + + if ( returned ) return returned.v; + } +} + +// Sub-views need their line numbers shifted when text is added +// above or below them in the parent document. +function shiftDoc(doc, distance) { + if (distance == 0) { return } + doc.first += distance + doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range( + Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch) + ); }), doc.sel.primIndex) + if (doc.cm) { + regChange(doc.cm, doc.first, doc.first - distance, distance) + for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + { regLineChange(doc.cm, l, "gutter") } + } +} + +// More lower-level change function, handling only a single document +// (not linked ones). +function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) } + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)) + return + } + if (change.from.line > doc.lastLine()) { return } + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line) + shiftDoc(doc, shift) + change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin} + } + var last = doc.lastLine() + if (change.to.line > last) { + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin} + } + + change.removed = getBetween(doc, change.from, change.to) + + if (!selAfter) { selAfter = computeSelAfterChange(doc, change) } + if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans) } + else { updateDoc(doc, change, spans) } + setSelectionNoUndo(doc, selAfter, sel_dontScroll) +} + +// Handle the interaction of a change to a document with the editor +// that this document is part of. +function makeChangeSingleDocInEditor(cm, change, spans) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to + + var recomputeMaxLength = false, checkWidthStart = from.line + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))) + doc.iter(checkWidthStart, to.line + 1, function (line) { + if (line == display.maxLine) { + recomputeMaxLength = true + return true + } + }) + } + + if (doc.sel.contains(change.from, change.to) > -1) + { signalCursorActivity(cm) } + + updateDoc(doc, change, spans, estimateHeight(cm)) + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function (line) { + var len = lineLength(line) + if (len > display.maxLineLength) { + display.maxLine = line + display.maxLineLength = len + display.maxLineChanged = true + recomputeMaxLength = false + } + }) + if (recomputeMaxLength) { cm.curOp.updateMaxLine = true } + } + + // Adjust frontier, schedule worker + doc.frontier = Math.min(doc.frontier, from.line) + startWorker(cm, 400) + + var lendiff = change.text.length - (to.line - from.line) - 1 + // Remember that these lines changed, for updating the display + if (change.full) + { regChange(cm) } + else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) + { regLineChange(cm, from.line, "text") } + else + { regChange(cm, from.line, to.line + 1, lendiff) } + + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change") + if (changeHandler || changesHandler) { + var obj = { + from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin + } + if (changeHandler) { signalLater(cm, "change", cm, obj) } + if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj) } + } + cm.display.selForContextMenu = null +} + +function replaceRange(doc, code, from, to, origin) { + if (!to) { to = from } + if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp } + if (typeof code == "string") { code = doc.splitLines(code) } + makeChange(doc, {from: from, to: to, text: code, origin: origin}) +} + +// Rebasing/resetting history to deal with externally-sourced changes + +function rebaseHistSelSingle(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff + } else if (from < pos.line) { + pos.line = from + pos.ch = 0 + } +} + +// Tries to rebase an array of history events given a change in the +// document. If the change touches the same lines as the event, the +// event, and everything 'behind' it, is discarded. If the change is +// before the event, the event's positions are updated. Uses a +// copy-on-write scheme for the positions, to avoid having to +// reallocate them all on every rebase, but also avoid problems with +// shared position objects being unsafely updated. +function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true + if (sub.ranges) { + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true } + for (var j = 0; j < sub.ranges.length; j++) { + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff) + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff) + } + continue + } + for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) { + var cur = sub.changes[j$1] + if (to < cur.from.line) { + cur.from = Pos(cur.from.line + diff, cur.from.ch) + cur.to = Pos(cur.to.line + diff, cur.to.ch) + } else if (from <= cur.to.line) { + ok = false + break + } + } + if (!ok) { + array.splice(0, i + 1) + i = 0 + } + } +} + +function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1 + rebaseHistArray(hist.done, from, to, diff) + rebaseHistArray(hist.undone, from, to, diff) +} + +// Utility for applying a change to a line by handle or number, +// returning the number and optionally registering the line as +// changed. +function changeLine(doc, handle, changeType, op) { + var no = handle, line = handle + if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)) } + else { no = lineNo(handle) } + if (no == null) { return null } + if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType) } + return line +} + +// The document is represented as a BTree consisting of leaves, with +// chunk of lines in them, and branches, with up to ten leaves or +// other branch nodes below them. The top node is always a branch +// node, and is the document object itself (meaning it has +// additional methods and properties). +// +// All nodes have parent links. The tree is used both to go from +// line numbers to line objects, and to go from objects to numbers. +// It also indexes by height, and is used to convert between height +// and line object, and to find the total height of the document. +// +// See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html + +var LeafChunk = function(lines) { + var this$1 = this; + + this.lines = lines + this.parent = null + var height = 0 + for (var i = 0; i < lines.length; ++i) { + lines[i].parent = this$1 + height += lines[i].height + } + this.height = height +}; + +LeafChunk.prototype.chunkSize = function () { return this.lines.length }; + +// Remove the n lines at offset 'at'. +LeafChunk.prototype.removeInner = function (at, n) { + var this$1 = this; + + for (var i = at, e = at + n; i < e; ++i) { + var line = this$1.lines[i] + this$1.height -= line.height + cleanUpLine(line) + signalLater(line, "delete") + } + this.lines.splice(at, n) +}; + +// Helper used to collapse a small branch into a single leaf. +LeafChunk.prototype.collapse = function (lines) { + lines.push.apply(lines, this.lines) +}; + +// Insert the given array of lines at offset 'at', count them as +// having the given height. +LeafChunk.prototype.insertInner = function (at, lines, height) { + var this$1 = this; + + this.height += height + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)) + for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1 } +}; + +// Used to iterate over a part of the tree. +LeafChunk.prototype.iterN = function (at, n, op) { + var this$1 = this; + + for (var e = at + n; at < e; ++at) + { if (op(this$1.lines[at])) { return true } } +}; + +var BranchChunk = function(children) { + var this$1 = this; + + this.children = children + var size = 0, height = 0 + for (var i = 0; i < children.length; ++i) { + var ch = children[i] + size += ch.chunkSize(); height += ch.height + ch.parent = this$1 + } + this.size = size + this.height = height + this.parent = null +}; + +BranchChunk.prototype.chunkSize = function () { return this.size }; + +BranchChunk.prototype.removeInner = function (at, n) { + var this$1 = this; + + this.size -= n + for (var i = 0; i < this.children.length; ++i) { + var child = this$1.children[i], sz = child.chunkSize() + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height + child.removeInner(at, rm) + this$1.height -= oldHeight - child.height + if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null } + if ((n -= rm) == 0) { break } + at = 0 + } else { at -= sz } + } + // If the result is smaller than 25 lines, ensure that it is a + // single leaf node. + if (this.size - n < 25 && + (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { + var lines = [] + this.collapse(lines) + this.children = [new LeafChunk(lines)] + this.children[0].parent = this + } +}; + +BranchChunk.prototype.collapse = function (lines) { + var this$1 = this; + + for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines) } +}; + +BranchChunk.prototype.insertInner = function (at, lines, height) { + var this$1 = this; + + this.size += lines.length + this.height += height + for (var i = 0; i < this.children.length; ++i) { + var child = this$1.children[i], sz = child.chunkSize() + if (at <= sz) { + child.insertInner(at, lines, height) + if (child.lines && child.lines.length > 50) { + // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced. + // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest. + var remaining = child.lines.length % 25 + 25 + for (var pos = remaining; pos < child.lines.length;) { + var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)) + child.height -= leaf.height + this$1.children.splice(++i, 0, leaf) + leaf.parent = this$1 + } + child.lines = child.lines.slice(0, remaining) + this$1.maybeSpill() + } + break + } + at -= sz + } +}; + +// When a node has grown, check whether it should be split. +BranchChunk.prototype.maybeSpill = function () { + if (this.children.length <= 10) { return } + var me = this + do { + var spilled = me.children.splice(me.children.length - 5, 5) + var sibling = new BranchChunk(spilled) + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children) + copy.parent = me + me.children = [copy, sibling] + me = copy + } else { + me.size -= sibling.size + me.height -= sibling.height + var myIndex = indexOf(me.parent.children, me) + me.parent.children.splice(myIndex + 1, 0, sibling) + } + sibling.parent = me.parent + } while (me.children.length > 10) + me.parent.maybeSpill() +}; + +BranchChunk.prototype.iterN = function (at, n, op) { + var this$1 = this; + + for (var i = 0; i < this.children.length; ++i) { + var child = this$1.children[i], sz = child.chunkSize() + if (at < sz) { + var used = Math.min(n, sz - at) + if (child.iterN(at, used, op)) { return true } + if ((n -= used) == 0) { break } + at = 0 + } else { at -= sz } + } +}; + +// Line widgets are block elements displayed above or below a line. + +var LineWidget = function(doc, node, options) { + var this$1 = this; + + if (options) { for (var opt in options) { if (options.hasOwnProperty(opt)) + { this$1[opt] = options[opt] } } } + this.doc = doc + this.node = node +}; + +LineWidget.prototype.clear = function () { + var this$1 = this; + + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line) + if (no == null || !ws) { return } + for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1) } } + if (!ws.length) { line.widgets = null } + var height = widgetHeight(this) + updateLineHeight(line, Math.max(0, line.height - height)) + if (cm) { + runInOp(cm, function () { + adjustScrollWhenAboveVisible(cm, line, -height) + regLineChange(cm, no, "widget") + }) + signalLater(cm, "lineWidgetCleared", cm, this, no) + } +}; + +LineWidget.prototype.changed = function () { + var this$1 = this; + + var oldH = this.height, cm = this.doc.cm, line = this.line + this.height = null + var diff = widgetHeight(this) - oldH + if (!diff) { return } + updateLineHeight(line, line.height + diff) + if (cm) { + runInOp(cm, function () { + cm.curOp.forceUpdate = true + adjustScrollWhenAboveVisible(cm, line, diff) + signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line)) + }) + } +}; +eventMixin(LineWidget) + +function adjustScrollWhenAboveVisible(cm, line, diff) { + if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) + { addToScrollPos(cm, null, diff) } +} + +function addLineWidget(doc, handle, node, options) { + var widget = new LineWidget(doc, node, options) + var cm = doc.cm + if (cm && widget.noHScroll) { cm.display.alignWidgets = true } + changeLine(doc, handle, "widget", function (line) { + var widgets = line.widgets || (line.widgets = []) + if (widget.insertAt == null) { widgets.push(widget) } + else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget) } + widget.line = line + if (cm && !lineIsHidden(doc, line)) { + var aboveVisible = heightAtLine(line) < doc.scrollTop + updateLineHeight(line, line.height + widgetHeight(widget)) + if (aboveVisible) { addToScrollPos(cm, null, widget.height) } + cm.curOp.forceUpdate = true + } + return true + }) + signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) + return widget +} + +// TEXTMARKERS + +// Created with markText and setBookmark methods. A TextMarker is a +// handle that can be used to clear or find a marked position in the +// document. Line objects hold arrays (markedSpans) containing +// {from, to, marker} object pointing to such marker objects, and +// indicating that such a marker is present on that line. Multiple +// lines may point to the same marker when it spans across lines. +// The spans will have null for their from/to properties when the +// marker continues beyond the start/end of the line. Markers have +// links back to the lines they currently touch. + +// Collapsed markers have unique ids, in order to be able to order +// them, which is needed for uniquely determining an outer marker +// when they overlap (they may nest, but not partially overlap). +var nextMarkerId = 0 + +var TextMarker = function(doc, type) { + this.lines = [] + this.type = type + this.doc = doc + this.id = ++nextMarkerId +}; + +// Clear the marker. +TextMarker.prototype.clear = function () { + var this$1 = this; + + if (this.explicitlyCleared) { return } + var cm = this.doc.cm, withOp = cm && !cm.curOp + if (withOp) { startOperation(cm) } + if (hasHandler(this, "clear")) { + var found = this.find() + if (found) { signalLater(this, "clear", found.from, found.to) } + } + var min = null, max = null + for (var i = 0; i < this.lines.length; ++i) { + var line = this$1.lines[i] + var span = getMarkedSpanFor(line.markedSpans, this$1) + if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text") } + else if (cm) { + if (span.to != null) { max = lineNo(line) } + if (span.from != null) { min = lineNo(line) } + } + line.markedSpans = removeMarkedSpan(line.markedSpans, span) + if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm) + { updateLineHeight(line, textHeight(cm.display)) } + } + if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) { + var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual) + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual + cm.display.maxLineLength = len + cm.display.maxLineChanged = true + } + } } + + if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1) } + this.lines.length = 0 + this.explicitlyCleared = true + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false + if (cm) { reCheckSelection(cm.doc) } + } + if (cm) { signalLater(cm, "markerCleared", cm, this, min, max) } + if (withOp) { endOperation(cm) } + if (this.parent) { this.parent.clear() } +}; + +// Find the position of the marker in the document. Returns a {from, +// to} object by default. Side can be passed to get a specific side +// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the +// Pos objects returned contain a line object, rather than a line +// number (used to prevent looking up the same line twice). +TextMarker.prototype.find = function (side, lineObj) { + var this$1 = this; + + if (side == null && this.type == "bookmark") { side = 1 } + var from, to + for (var i = 0; i < this.lines.length; ++i) { + var line = this$1.lines[i] + var span = getMarkedSpanFor(line.markedSpans, this$1) + if (span.from != null) { + from = Pos(lineObj ? line : lineNo(line), span.from) + if (side == -1) { return from } + } + if (span.to != null) { + to = Pos(lineObj ? line : lineNo(line), span.to) + if (side == 1) { return to } + } + } + return from && {from: from, to: to} +}; + +// Signals that the marker's widget changed, and surrounding layout +// should be recomputed. +TextMarker.prototype.changed = function () { + var this$1 = this; + + var pos = this.find(-1, true), widget = this, cm = this.doc.cm + if (!pos || !cm) { return } + runInOp(cm, function () { + var line = pos.line, lineN = lineNo(pos.line) + var view = findViewForLine(cm, lineN) + if (view) { + clearLineMeasurementCacheFor(view) + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true + } + cm.curOp.updateMaxLine = true + if (!lineIsHidden(widget.doc, line) && widget.height != null) { + var oldHeight = widget.height + widget.height = null + var dHeight = widgetHeight(widget) - oldHeight + if (dHeight) + { updateLineHeight(line, line.height + dHeight) } + } + signalLater(cm, "markerChanged", cm, this$1) + }) +}; + +TextMarker.prototype.attachLine = function (line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this) } + } + this.lines.push(line) +}; + +TextMarker.prototype.detachLine = function (line) { + this.lines.splice(indexOf(this.lines, line), 1) + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp + ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this) + } +}; +eventMixin(TextMarker) + +// Create a marker, wire it up to the right lines, and +function markText(doc, from, to, options, type) { + // Shared markers (across linked documents) are handled separately + // (markTextShared will call out to this again, once per + // document). + if (options && options.shared) { return markTextShared(doc, from, to, options, type) } + // Ensure we are in an operation. + if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) } + + var marker = new TextMarker(doc, type), diff = cmp(from, to) + if (options) { copyObj(options, marker, false) } + // Don't connect empty markers unless clearWhenEmpty is false + if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) + { return marker } + if (marker.replacedWith) { + // Showing up as a widget implies collapsed (widget replaces text) + marker.collapsed = true + marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget") + if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true") } + if (options.insertLeft) { marker.widgetNode.insertLeft = true } + } + if (marker.collapsed) { + if (conflictingCollapsedRange(doc, from.line, from, to, marker) || + from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) + { throw new Error("Inserting collapsed marker partially overlapping an existing one") } + seeCollapsedSpans() + } + + if (marker.addToHistory) + { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN) } + + var curLine = from.line, cm = doc.cm, updateMaxLine + doc.iter(curLine, to.line + 1, function (line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) + { updateMaxLine = true } + if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0) } + addMarkedSpan(line, new MarkedSpan(marker, + curLine == from.line ? from.ch : null, + curLine == to.line ? to.ch : null)) + ++curLine + }) + // lineIsHidden depends on the presence of the spans, so needs a second pass + if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) { + if (lineIsHidden(doc, line)) { updateLineHeight(line, 0) } + }) } + + if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }) } + + if (marker.readOnly) { + seeReadOnlySpans() + if (doc.history.done.length || doc.history.undone.length) + { doc.clearHistory() } + } + if (marker.collapsed) { + marker.id = ++nextMarkerId + marker.atomic = true + } + if (cm) { + // Sync editor state + if (updateMaxLine) { cm.curOp.updateMaxLine = true } + if (marker.collapsed) + { regChange(cm, from.line, to.line + 1) } + else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) + { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text") } } + if (marker.atomic) { reCheckSelection(cm.doc) } + signalLater(cm, "markerAdded", cm, marker) + } + return marker +} + +// SHARED TEXTMARKERS + +// A shared marker spans multiple linked documents. It is +// implemented as a meta-marker-object controlling multiple normal +// markers. +var SharedTextMarker = function(markers, primary) { + var this$1 = this; + + this.markers = markers + this.primary = primary + for (var i = 0; i < markers.length; ++i) + { markers[i].parent = this$1 } +}; + +SharedTextMarker.prototype.clear = function () { + var this$1 = this; + + if (this.explicitlyCleared) { return } + this.explicitlyCleared = true + for (var i = 0; i < this.markers.length; ++i) + { this$1.markers[i].clear() } + signalLater(this, "clear") +}; + +SharedTextMarker.prototype.find = function (side, lineObj) { + return this.primary.find(side, lineObj) +}; +eventMixin(SharedTextMarker) + +function markTextShared(doc, from, to, options, type) { + options = copyObj(options) + options.shared = false + var markers = [markText(doc, from, to, options, type)], primary = markers[0] + var widget = options.widgetNode + linkedDocs(doc, function (doc) { + if (widget) { options.widgetNode = widget.cloneNode(true) } + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)) + for (var i = 0; i < doc.linked.length; ++i) + { if (doc.linked[i].isParent) { return } } + primary = lst(markers) + }) + return new SharedTextMarker(markers, primary) +} + +function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; }) +} + +function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find() + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to) + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type) + marker.markers.push(subMark) + subMark.parent = marker + } + } +} + +function detachSharedMarkers(markers) { + var loop = function ( i ) { + var marker = markers[i], linked = [marker.primary.doc] + linkedDocs(marker.primary.doc, function (d) { return linked.push(d); }) + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j] + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null + marker.markers.splice(j--, 1) + } + } + }; + + for (var i = 0; i < markers.length; i++) loop( i ); +} + +var nextDocId = 0 +var Doc = function(text, mode, firstLine, lineSep, direction) { + if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) } + if (firstLine == null) { firstLine = 0 } + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]) + this.first = firstLine + this.scrollTop = this.scrollLeft = 0 + this.cantEdit = false + this.cleanGeneration = 1 + this.frontier = firstLine + var start = Pos(firstLine, 0) + this.sel = simpleSelection(start) + this.history = new History(null) + this.id = ++nextDocId + this.modeOption = mode + this.lineSep = lineSep + this.direction = (direction == "rtl") ? "rtl" : "ltr" + this.extend = false + + if (typeof text == "string") { text = this.splitLines(text) } + updateDoc(this, {from: start, to: start, text: text}) + setSelection(this, simpleSelection(start), sel_dontScroll) +} + +Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + // Iterate over the document. Supports two forms -- with only one + // argument, it calls that for each line in the document. With + // three, it iterates over the range given by the first two (with + // the second being non-inclusive). + iter: function(from, to, op) { + if (op) { this.iterN(from - this.first, to - from, op) } + else { this.iterN(this.first, this.first + this.size, from) } + }, + + // Non-public interface for adding and removing lines. + insert: function(at, lines) { + var height = 0 + for (var i = 0; i < lines.length; ++i) { height += lines[i].height } + this.insertInner(at - this.first, lines, height) + }, + remove: function(at, n) { this.removeInner(at - this.first, n) }, + + // From here, the methods are part of the public interface. Most + // are also available from CodeMirror (editor) instances. + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size) + if (lineSep === false) { return lines } + return lines.join(lineSep || this.lineSeparator()) + }, + setValue: docMethodOp(function(code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1 + makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), + text: this.splitLines(code), origin: "setValue", full: true}, true) + setSelection(this, simpleSelection(top)) + }), + replaceRange: function(code, from, to, origin) { + from = clipPos(this, from) + to = to ? clipPos(this, to) : from + replaceRange(this, code, from, to, origin) + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)) + if (lineSep === false) { return lines } + return lines.join(lineSep || this.lineSeparator()) + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text}, + + getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }}, + getLineNumber: function(line) {return lineNo(line)}, + + getLineHandleVisualStart: function(line) { + if (typeof line == "number") { line = getLine(this, line) } + return visualLine(line) + }, + + lineCount: function() {return this.size}, + firstLine: function() {return this.first}, + lastLine: function() {return this.first + this.size - 1}, + + clipPos: function(pos) {return clipPos(this, pos)}, + + getCursor: function(start) { + var range = this.sel.primary(), pos + if (start == null || start == "head") { pos = range.head } + else if (start == "anchor") { pos = range.anchor } + else if (start == "end" || start == "to" || start === false) { pos = range.to() } + else { pos = range.from() } + return pos + }, + listSelections: function() { return this.sel.ranges }, + somethingSelected: function() {return this.sel.somethingSelected()}, + + setCursor: docMethodOp(function(line, ch, options) { + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options) + }), + setSelection: docMethodOp(function(anchor, head, options) { + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options) + }), + extendSelection: docMethodOp(function(head, other, options) { + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options) + }), + extendSelections: docMethodOp(function(heads, options) { + extendSelections(this, clipPosArray(this, heads), options) + }), + extendSelectionsBy: docMethodOp(function(f, options) { + var heads = map(this.sel.ranges, f) + extendSelections(this, clipPosArray(this, heads), options) + }), + setSelections: docMethodOp(function(ranges, primary, options) { + var this$1 = this; + + if (!ranges.length) { return } + var out = [] + for (var i = 0; i < ranges.length; i++) + { out[i] = new Range(clipPos(this$1, ranges[i].anchor), + clipPos(this$1, ranges[i].head)) } + if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex) } + setSelection(this, normalizeSelection(out, primary), options) + }), + addSelection: docMethodOp(function(anchor, head, options) { + var ranges = this.sel.ranges.slice(0) + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))) + setSelection(this, normalizeSelection(ranges, ranges.length - 1), options) + }), + + getSelection: function(lineSep) { + var this$1 = this; + + var ranges = this.sel.ranges, lines + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()) + lines = lines ? lines.concat(sel) : sel + } + if (lineSep === false) { return lines } + else { return lines.join(lineSep || this.lineSeparator()) } + }, + getSelections: function(lineSep) { + var this$1 = this; + + var parts = [], ranges = this.sel.ranges + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()) + if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()) } + parts[i] = sel + } + return parts + }, + replaceSelection: function(code, collapse, origin) { + var dup = [] + for (var i = 0; i < this.sel.ranges.length; i++) + { dup[i] = code } + this.replaceSelections(dup, collapse, origin || "+input") + }, + replaceSelections: docMethodOp(function(code, collapse, origin) { + var this$1 = this; + + var changes = [], sel = this.sel + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i] + changes[i] = {from: range.from(), to: range.to(), text: this$1.splitLines(code[i]), origin: origin} + } + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse) + for (var i$1 = changes.length - 1; i$1 >= 0; i$1--) + { makeChange(this$1, changes[i$1]) } + if (newSel) { setSelectionReplaceHistory(this, newSel) } + else if (this.cm) { ensureCursorVisible(this.cm) } + }), + undo: docMethodOp(function() {makeChangeFromHistory(this, "undo")}), + redo: docMethodOp(function() {makeChangeFromHistory(this, "redo")}), + undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true)}), + redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true)}), + + setExtending: function(val) {this.extend = val}, + getExtending: function() {return this.extend}, + + historySize: function() { + var hist = this.history, done = 0, undone = 0 + for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done } } + for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone } } + return {undo: done, redo: undone} + }, + clearHistory: function() {this.history = new History(this.history.maxGeneration)}, + + markClean: function() { + this.cleanGeneration = this.changeGeneration(true) + }, + changeGeneration: function(forceSplit) { + if (forceSplit) + { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null } + return this.history.generation + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration) + }, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)} + }, + setHistory: function(histData) { + var hist = this.history = new History(this.history.maxGeneration) + hist.done = copyHistoryArray(histData.done.slice(0), null, true) + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true) + }, + + setGutterMarker: docMethodOp(function(line, gutterID, value) { + return changeLine(this, line, "gutter", function (line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}) + markers[gutterID] = value + if (!value && isEmpty(markers)) { line.gutterMarkers = null } + return true + }) + }), + + clearGutter: docMethodOp(function(gutterID) { + var this$1 = this; + + this.iter(function (line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + changeLine(this$1, line, "gutter", function () { + line.gutterMarkers[gutterID] = null + if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null } + return true + }) + } + }) + }), + + lineInfo: function(line) { + var n + if (typeof line == "number") { + if (!isLine(this, line)) { return null } + n = line + line = getLine(this, line) + if (!line) { return null } + } else { + n = lineNo(line) + if (n == null) { return null } + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets} + }, + + addLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass" + if (!line[prop]) { line[prop] = cls } + else if (classTest(cls).test(line[prop])) { return false } + else { line[prop] += " " + cls } + return true + }) + }), + removeLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass" + var cur = line[prop] + if (!cur) { return false } + else if (cls == null) { line[prop] = null } + else { + var found = cur.match(classTest(cls)) + if (!found) { return false } + var end = found.index + found[0].length + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null + } + return true + }) + }), + + addLineWidget: docMethodOp(function(handle, node, options) { + return addLineWidget(this, handle, node, options) + }), + removeLineWidget: function(widget) { widget.clear() }, + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range") + }, + setBookmark: function(pos, options) { + var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft, + clearWhenEmpty: false, shared: options && options.shared, + handleMouseEvents: options && options.handleMouseEvents} + pos = clipPos(this, pos) + return markText(this, pos, pos, realOpts, "bookmark") + }, + findMarksAt: function(pos) { + pos = clipPos(this, pos) + var markers = [], spans = getLine(this, pos.line).markedSpans + if (spans) { for (var i = 0; i < spans.length; ++i) { + var span = spans[i] + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + { markers.push(span.marker.parent || span.marker) } + } } + return markers + }, + findMarks: function(from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to) + var found = [], lineNo = from.line + this.iter(from.line, to.line + 1, function (line) { + var spans = line.markedSpans + if (spans) { for (var i = 0; i < spans.length; i++) { + var span = spans[i] + if (!(span.to != null && lineNo == from.line && from.ch >= span.to || + span.from == null && lineNo != from.line || + span.from != null && lineNo == to.line && span.from >= to.ch) && + (!filter || filter(span.marker))) + { found.push(span.marker.parent || span.marker) } + } } + ++lineNo + }) + return found + }, + getAllMarks: function() { + var markers = [] + this.iter(function (line) { + var sps = line.markedSpans + if (sps) { for (var i = 0; i < sps.length; ++i) + { if (sps[i].from != null) { markers.push(sps[i].marker) } } } + }) + return markers + }, + + posFromIndex: function(off) { + var ch, lineNo = this.first, sepSize = this.lineSeparator().length + this.iter(function (line) { + var sz = line.text.length + sepSize + if (sz > off) { ch = off; return true } + off -= sz + ++lineNo + }) + return clipPos(this, Pos(lineNo, ch)) + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords) + var index = coords.ch + if (coords.line < this.first || coords.ch < 0) { return 0 } + var sepSize = this.lineSeparator().length + this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value + index += line.text.length + sepSize + }) + return index + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), + this.modeOption, this.first, this.lineSep, this.direction) + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft + doc.sel = this.sel + doc.extend = false + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth + doc.setHistory(this.getHistory()) + } + return doc + }, + + linkedDoc: function(options) { + if (!options) { options = {} } + var from = this.first, to = this.first + this.size + if (options.from != null && options.from > from) { from = options.from } + if (options.to != null && options.to < to) { to = options.to } + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction) + if (options.sharedHist) { copy.history = this.history + ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}) + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}] + copySharedMarkers(copy, findSharedMarkers(this)) + return copy + }, + unlinkDoc: function(other) { + var this$1 = this; + + if (other instanceof CodeMirror) { other = other.doc } + if (this.linked) { for (var i = 0; i < this.linked.length; ++i) { + var link = this$1.linked[i] + if (link.doc != other) { continue } + this$1.linked.splice(i, 1) + other.unlinkDoc(this$1) + detachSharedMarkers(findSharedMarkers(this$1)) + break + } } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id] + linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true) + other.history = new History(null) + other.history.done = copyHistoryArray(this.history.done, splitIds) + other.history.undone = copyHistoryArray(this.history.undone, splitIds) + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f)}, + + getMode: function() {return this.mode}, + getEditor: function() {return this.cm}, + + splitLines: function(str) { + if (this.lineSep) { return str.split(this.lineSep) } + return splitLinesAuto(str) + }, + lineSeparator: function() { return this.lineSep || "\n" }, + + setDirection: docMethodOp(function (dir) { + if (dir != "rtl") { dir = "ltr" } + if (dir == this.direction) { return } + this.direction = dir + this.iter(function (line) { return line.order = null; }) + if (this.cm) { directionChanged(this.cm) } + }) +}) + +// Public alias. +Doc.prototype.eachLine = Doc.prototype.iter + +// Kludge to work around strange IE behavior where it'll sometimes +// re-fire a series of drag-related events right after the drop (#1551) +var lastDrop = 0 + +function onDrop(e) { + var cm = this + clearDragCursor(cm) + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) + { return } + e_preventDefault(e) + if (ie) { lastDrop = +new Date } + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files + if (!pos || cm.isReadOnly()) { return } + // Might be a file drop, in which case we simply extract the text + // and insert it. + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0 + var loadFile = function (file, i) { + if (cm.options.allowDropFileTypes && + indexOf(cm.options.allowDropFileTypes, file.type) == -1) + { return } + + var reader = new FileReader + reader.onload = operation(cm, function () { + var content = reader.result + if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = "" } + text[i] = content + if (++read == n) { + pos = clipPos(cm.doc, pos) + var change = {from: pos, to: pos, + text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), + origin: "paste"} + makeChange(cm.doc, change) + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))) + } + }) + reader.readAsText(file) + } + for (var i = 0; i < n; ++i) { loadFile(files[i], i) } + } else { // Normal drop + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { + cm.state.draggingText(e) + // Ensure the editor is re-focused + setTimeout(function () { return cm.display.input.focus(); }, 20) + return + } + try { + var text$1 = e.dataTransfer.getData("Text") + if (text$1) { + var selected + if (cm.state.draggingText && !cm.state.draggingText.copy) + { selected = cm.listSelections() } + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)) + if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1) + { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag") } } + cm.replaceSelection(text$1, "around", "paste") + cm.display.input.focus() + } + } + catch(e){} + } +} + +function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return } + + e.dataTransfer.setData("Text", cm.getSelection()) + e.dataTransfer.effectAllowed = "copyMove" + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;") + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" + if (presto) { + img.width = img.height = 1 + cm.display.wrapper.appendChild(img) + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop + } + e.dataTransfer.setDragImage(img, 0, 0) + if (presto) { img.parentNode.removeChild(img) } + } +} + +function onDragOver(cm, e) { + var pos = posFromMouse(cm, e) + if (!pos) { return } + var frag = document.createDocumentFragment() + drawSelectionCursor(cm, pos, frag) + if (!cm.display.dragCursor) { + cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors") + cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv) + } + removeChildrenAndAdd(cm.display.dragCursor, frag) +} + +function clearDragCursor(cm) { + if (cm.display.dragCursor) { + cm.display.lineSpace.removeChild(cm.display.dragCursor) + cm.display.dragCursor = null + } +} + +// These must be handled carefully, because naively registering a +// handler for each editor will cause the editors to never be +// garbage collected. + +function forEachCodeMirror(f) { + if (!document.body.getElementsByClassName) { return } + var byClass = document.body.getElementsByClassName("CodeMirror") + for (var i = 0; i < byClass.length; i++) { + var cm = byClass[i].CodeMirror + if (cm) { f(cm) } + } +} + +var globalsRegistered = false +function ensureGlobalHandlers() { + if (globalsRegistered) { return } + registerGlobalHandlers() + globalsRegistered = true +} +function registerGlobalHandlers() { + // When the window resizes, we need to refresh active editors. + var resizeTimer + on(window, "resize", function () { + if (resizeTimer == null) { resizeTimer = setTimeout(function () { + resizeTimer = null + forEachCodeMirror(onResize) + }, 100) } + }) + // When the window loses focus, we want to show the editor as blurred + on(window, "blur", function () { return forEachCodeMirror(onBlur); }) +} +// Called when the window resizes +function onResize(cm) { + var d = cm.display + if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) + { return } + // Might be a text scaling operation, clear size caches. + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null + d.scrollbarsClipped = false + cm.setSize() +} + +var keyNames = { + 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", + 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" +} + +// Number keys +for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i) } +// Alphabetic keys +for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1) } +// Function keys +for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2 } + +var keyMap = {} + +keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", + "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", + "Esc": "singleSelection" +} +// Note that the save and find-related commands aren't defined by +// default. User code or addons can define them. Unknown commands +// are simply ignored. +keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", + fallthrough: "basic" +} +// Very basic readline/emacs-style bindings, which are standard on Mac. +keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars", + "Ctrl-O": "openLine" +} +keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", + fallthrough: ["basic", "emacsy"] +} +keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault + +// KEYMAP DISPATCH + +function normalizeKeyName(name) { + var parts = name.split(/-(?!$)/) + name = parts[parts.length - 1] + var alt, ctrl, shift, cmd + for (var i = 0; i < parts.length - 1; i++) { + var mod = parts[i] + if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true } + else if (/^a(lt)?$/i.test(mod)) { alt = true } + else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true } + else if (/^s(hift)?$/i.test(mod)) { shift = true } + else { throw new Error("Unrecognized modifier name: " + mod) } + } + if (alt) { name = "Alt-" + name } + if (ctrl) { name = "Ctrl-" + name } + if (cmd) { name = "Cmd-" + name } + if (shift) { name = "Shift-" + name } + return name +} + +// This is a kludge to keep keymaps mostly working as raw objects +// (backwards compatibility) while at the same time support features +// like normalization and multi-stroke key bindings. It compiles a +// new normalized keymap, and then updates the old object to reflect +// this. +function normalizeKeyMap(keymap) { + var copy = {} + for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) { + var value = keymap[keyname] + if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue } + if (value == "...") { delete keymap[keyname]; continue } + + var keys = map(keyname.split(" "), normalizeKeyName) + for (var i = 0; i < keys.length; i++) { + var val = (void 0), name = (void 0) + if (i == keys.length - 1) { + name = keys.join(" ") + val = value + } else { + name = keys.slice(0, i + 1).join(" ") + val = "..." + } + var prev = copy[name] + if (!prev) { copy[name] = val } + else if (prev != val) { throw new Error("Inconsistent bindings for " + name) } + } + delete keymap[keyname] + } } + for (var prop in copy) { keymap[prop] = copy[prop] } + return keymap +} + +function lookupKey(key, map, handle, context) { + map = getKeyMap(map) + var found = map.call ? map.call(key, context) : map[key] + if (found === false) { return "nothing" } + if (found === "...") { return "multi" } + if (found != null && handle(found)) { return "handled" } + + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + { return lookupKey(key, map.fallthrough, handle, context) } + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context) + if (result) { return result } + } + } +} + +// Modifier key presses don't count as 'real' key presses for the +// purpose of keymap fallthrough. +function isModifierKey(value) { + var name = typeof value == "string" ? value : keyNames[value.keyCode] + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod" +} + +// Look up the name of a key as indicated by an event object. +function keyName(event, noShift) { + if (presto && event.keyCode == 34 && event["char"]) { return false } + var base = keyNames[event.keyCode], name = base + if (name == null || event.altGraphKey) { return false } + if (event.altKey && base != "Alt") { name = "Alt-" + name } + if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name } + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name } + if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name } + return name +} + +function getKeyMap(val) { + return typeof val == "string" ? keyMap[val] : val +} + +// Helper for deleting text near the selection(s), used to implement +// backspace, delete, and similar functionality. +function deleteNearSelection(cm, compute) { + var ranges = cm.doc.sel.ranges, kill = [] + // Build up a set of ranges to kill first, merging overlapping + // ranges. + for (var i = 0; i < ranges.length; i++) { + var toKill = compute(ranges[i]) + while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { + var replaced = kill.pop() + if (cmp(replaced.from, toKill.from) < 0) { + toKill.from = replaced.from + break + } + } + kill.push(toKill) + } + // Next, remove those actual ranges. + runInOp(cm, function () { + for (var i = kill.length - 1; i >= 0; i--) + { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete") } + ensureCursorVisible(cm) + }) +} + +// Commands are parameter-less actions that can be performed on an +// editor, mostly used for keybindings. +var commands = { + selectAll: selectAll, + singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); }, + killLine: function (cm) { return deleteNearSelection(cm, function (range) { + if (range.empty()) { + var len = getLine(cm.doc, range.head.line).text.length + if (range.head.ch == len && range.head.line < cm.lastLine()) + { return {from: range.head, to: Pos(range.head.line + 1, 0)} } + else + { return {from: range.head, to: Pos(range.head.line, len)} } + } else { + return {from: range.from(), to: range.to()} + } + }); }, + deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({ + from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0)) + }); }); }, + delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({ + from: Pos(range.from().line, 0), to: range.from() + }); }); }, + delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { + var top = cm.charCoords(range.head, "div").top + 5 + var leftPos = cm.coordsChar({left: 0, top: top}, "div") + return {from: leftPos, to: range.from()} + }); }, + delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) { + var top = cm.charCoords(range.head, "div").top + 5 + var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + return {from: range.from(), to: rightPos } + }); }, + undo: function (cm) { return cm.undo(); }, + redo: function (cm) { return cm.redo(); }, + undoSelection: function (cm) { return cm.undoSelection(); }, + redoSelection: function (cm) { return cm.redoSelection(); }, + goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); }, + goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); }, + goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); }, + {origin: "+move", bias: 1} + ); }, + goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); }, + {origin: "+move", bias: 1} + ); }, + goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); }, + {origin: "+move", bias: -1} + ); }, + goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) { + var top = cm.charCoords(range.head, "div").top + 5 + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + }, sel_move); }, + goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) { + var top = cm.charCoords(range.head, "div").top + 5 + return cm.coordsChar({left: 0, top: top}, "div") + }, sel_move); }, + goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) { + var top = cm.charCoords(range.head, "div").top + 5 + var pos = cm.coordsChar({left: 0, top: top}, "div") + if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) } + return pos + }, sel_move); }, + goLineUp: function (cm) { return cm.moveV(-1, "line"); }, + goLineDown: function (cm) { return cm.moveV(1, "line"); }, + goPageUp: function (cm) { return cm.moveV(-1, "page"); }, + goPageDown: function (cm) { return cm.moveV(1, "page"); }, + goCharLeft: function (cm) { return cm.moveH(-1, "char"); }, + goCharRight: function (cm) { return cm.moveH(1, "char"); }, + goColumnLeft: function (cm) { return cm.moveH(-1, "column"); }, + goColumnRight: function (cm) { return cm.moveH(1, "column"); }, + goWordLeft: function (cm) { return cm.moveH(-1, "word"); }, + goGroupRight: function (cm) { return cm.moveH(1, "group"); }, + goGroupLeft: function (cm) { return cm.moveH(-1, "group"); }, + goWordRight: function (cm) { return cm.moveH(1, "word"); }, + delCharBefore: function (cm) { return cm.deleteH(-1, "char"); }, + delCharAfter: function (cm) { return cm.deleteH(1, "char"); }, + delWordBefore: function (cm) { return cm.deleteH(-1, "word"); }, + delWordAfter: function (cm) { return cm.deleteH(1, "word"); }, + delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); }, + delGroupAfter: function (cm) { return cm.deleteH(1, "group"); }, + indentAuto: function (cm) { return cm.indentSelection("smart"); }, + indentMore: function (cm) { return cm.indentSelection("add"); }, + indentLess: function (cm) { return cm.indentSelection("subtract"); }, + insertTab: function (cm) { return cm.replaceSelection("\t"); }, + insertSoftTab: function (cm) { + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].from() + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize) + spaces.push(spaceStr(tabSize - col % tabSize)) + } + cm.replaceSelections(spaces) + }, + defaultTab: function (cm) { + if (cm.somethingSelected()) { cm.indentSelection("add") } + else { cm.execCommand("insertTab") } + }, + // Swap the two chars left and right of each selection's head. + // Move cursor behind the two swapped characters afterwards. + // + // Doesn't consider line feeds a character. + // Doesn't scan more than one line above to find a character. + // Doesn't do anything on an empty line. + // Doesn't do anything with non-empty selections. + transposeChars: function (cm) { return runInOp(cm, function () { + var ranges = cm.listSelections(), newSel = [] + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) { continue } + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text + if (line) { + if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1) } + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1) + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose") + } else if (cur.line > cm.doc.first) { + var prev = getLine(cm.doc, cur.line - 1).text + if (prev) { + cur = new Pos(cur.line, 1) + cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), cur, "+transpose") + } + } + } + newSel.push(new Range(cur, cur)) + } + cm.setSelections(newSel) + }); }, + newlineAndIndent: function (cm) { return runInOp(cm, function () { + var sels = cm.listSelections() + for (var i = sels.length - 1; i >= 0; i--) + { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input") } + sels = cm.listSelections() + for (var i$1 = 0; i$1 < sels.length; i$1++) + { cm.indentLine(sels[i$1].from().line, null, true) } + ensureCursorVisible(cm) + }); }, + openLine: function (cm) { return cm.replaceSelection("\n", "start"); }, + toggleOverwrite: function (cm) { return cm.toggleOverwrite(); } +} + + +function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN) + var visual = visualLine(line) + if (visual != line) { lineN = lineNo(visual) } + return endOfLine(true, cm, visual, lineN, 1) +} +function lineEnd(cm, lineN) { + var line = getLine(cm.doc, lineN) + var visual = visualLineEnd(line) + if (visual != line) { lineN = lineNo(visual) } + return endOfLine(true, cm, line, lineN, -1) +} +function lineStartSmart(cm, pos) { + var start = lineStart(cm, pos.line) + var line = getLine(cm.doc, start.line) + var order = getOrder(line, cm.doc.direction) + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)) + var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch + return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky) + } + return start +} + +// Run a handler that was bound to a key. +function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound] + if (!bound) { return false } + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + cm.display.input.ensurePolled() + var prevShift = cm.display.shift, done = false + try { + if (cm.isReadOnly()) { cm.state.suppressEdits = true } + if (dropShift) { cm.display.shift = false } + done = bound(cm) != Pass + } finally { + cm.display.shift = prevShift + cm.state.suppressEdits = false + } + return done +} + +function lookupKeyForEditor(cm, name, handle) { + for (var i = 0; i < cm.state.keyMaps.length; i++) { + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm) + if (result) { return result } + } + return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) + || lookupKey(name, cm.options.keyMap, handle, cm) +} + +var stopSeq = new Delayed +function dispatchKey(cm, name, e, handle) { + var seq = cm.state.keySeq + if (seq) { + if (isModifierKey(name)) { return "handled" } + stopSeq.set(50, function () { + if (cm.state.keySeq == seq) { + cm.state.keySeq = null + cm.display.input.reset() + } + }) + name = seq + " " + name + } + var result = lookupKeyForEditor(cm, name, handle) + + if (result == "multi") + { cm.state.keySeq = name } + if (result == "handled") + { signalLater(cm, "keyHandled", cm, name, e) } + + if (result == "handled" || result == "multi") { + e_preventDefault(e) + restartBlink(cm) + } + + if (seq && !result && /\'$/.test(name)) { + e_preventDefault(e) + return true + } + return !!result +} + +// Handle a key from the keydown event. +function handleKeyBinding(cm, e) { + var name = keyName(e, true) + if (!name) { return false } + + if (e.shiftKey && !cm.state.keySeq) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); }) + || dispatchKey(cm, name, e, function (b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + { return doHandleBinding(cm, b) } + }) + } else { + return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); }) + } +} + +// Handle a key from the keypress event +function handleCharBinding(cm, e, ch) { + return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); }) +} + +var lastStoppedKey = null +function onKeyDown(e) { + var cm = this + cm.curOp.focus = activeElt() + if (signalDOMEvent(cm, e)) { return } + // IE does strange things with escape. + if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false } + var code = e.keyCode + cm.display.shift = code == 16 || e.shiftKey + var handled = handleKeyBinding(cm, e) + if (presto) { + lastStoppedKey = handled ? code : null + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + { cm.replaceSelection("", null, "cut") } + } + + // Turn mouse into crosshair when Alt is held on Mac. + if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) + { showCrossHair(cm) } +} + +function showCrossHair(cm) { + var lineDiv = cm.display.lineDiv + addClass(lineDiv, "CodeMirror-crosshair") + + function up(e) { + if (e.keyCode == 18 || !e.altKey) { + rmClass(lineDiv, "CodeMirror-crosshair") + off(document, "keyup", up) + off(document, "mouseover", up) + } + } + on(document, "keyup", up) + on(document, "mouseover", up) +} + +function onKeyUp(e) { + if (e.keyCode == 16) { this.doc.sel.shift = false } + signalDOMEvent(this, e) +} + +function onKeyPress(e) { + var cm = this + if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return } + var keyCode = e.keyCode, charCode = e.charCode + if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} + if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return } + var ch = String.fromCharCode(charCode == null ? keyCode : charCode) + // Some browsers fire keypress events for backspace + if (ch == "\x08") { return } + if (handleCharBinding(cm, e, ch)) { return } + cm.display.input.onKeyPress(e) +} + +// A mouse down can be a single click, double click, triple click, +// start of selection drag, start of text drag, new cursor +// (ctrl-click), rectangle drag (alt-drag), or xwin +// middle-click-paste. Or it might be a click on something we should +// not interfere with, such as a scrollbar or widget. +function onMouseDown(e) { + var cm = this, display = cm.display + if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return } + display.input.ensurePolled() + display.shift = e.shiftKey + + if (eventInWidget(display, e)) { + if (!webkit) { + // Briefly turn off draggability, to allow widgets to do + // normal dragging things. + display.scroller.draggable = false + setTimeout(function () { return display.scroller.draggable = true; }, 100) + } + return + } + if (clickInGutter(cm, e)) { return } + var start = posFromMouse(cm, e) + window.focus() + + switch (e_button(e)) { + case 1: + // #3261: make sure, that we're not starting a second selection + if (cm.state.selectingText) + { cm.state.selectingText(e) } + else if (start) + { leftButtonDown(cm, e, start) } + else if (e_target(e) == display.scroller) + { e_preventDefault(e) } + break + case 2: + if (webkit) { cm.state.lastMiddleDown = +new Date } + if (start) { extendSelection(cm.doc, start) } + setTimeout(function () { return display.input.focus(); }, 20) + e_preventDefault(e) + break + case 3: + if (captureRightClick) { onContextMenu(cm, e) } + else { delayBlurEvent(cm) } + break + } +} + +var lastClick; +var lastDoubleClick; +function leftButtonDown(cm, e, start) { + if (ie) { setTimeout(bind(ensureFocus, cm), 0) } + else { cm.curOp.focus = activeElt() } + + var now = +new Date, type + if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { + type = "triple" + } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { + type = "double" + lastDoubleClick = {time: now, pos: start} + } else { + type = "single" + lastClick = {time: now, pos: start} + } + + var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained + if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && + type == "single" && (contained = sel.contains(start)) > -1 && + (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && + (cmp(contained.to(), start) > 0 || start.xRel < 0)) + { leftButtonStartDrag(cm, e, start, modifier) } + else + { leftButtonSelect(cm, e, start, type, modifier) } +} + +// Start a text drag. When it ends, see if any dragging actually +// happen, and treat as a click if it didn't. +function leftButtonStartDrag(cm, e, start, modifier) { + var display = cm.display, startTime = +new Date + var dragEnd = operation(cm, function (e2) { + if (webkit) { display.scroller.draggable = false } + cm.state.draggingText = false + off(document, "mouseup", dragEnd) + off(display.scroller, "drop", dragEnd) + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2) + if (!modifier && +new Date - 200 < startTime) + { extendSelection(cm.doc, start) } + // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) + if (webkit || ie && ie_version == 9) + { setTimeout(function () {document.body.focus(); display.input.focus()}, 20) } + else + { display.input.focus() } + } + }) + // Let the drag handler handle this. + if (webkit) { display.scroller.draggable = true } + cm.state.draggingText = dragEnd + dragEnd.copy = mac ? e.altKey : e.ctrlKey + // IE's approach to draggable + if (display.scroller.dragDrop) { display.scroller.dragDrop() } + on(document, "mouseup", dragEnd) + on(display.scroller, "drop", dragEnd) +} + +// Normal selection, as opposed to text dragging. +function leftButtonSelect(cm, e, start, type, addNew) { + var display = cm.display, doc = cm.doc + e_preventDefault(e) + + var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges + if (addNew && !e.shiftKey) { + ourIndex = doc.sel.contains(start) + if (ourIndex > -1) + { ourRange = ranges[ourIndex] } + else + { ourRange = new Range(start, start) } + } else { + ourRange = doc.sel.primary() + ourIndex = doc.sel.primIndex + } + + if (chromeOS ? e.shiftKey && e.metaKey : e.altKey) { + type = "rect" + if (!addNew) { ourRange = new Range(start, start) } + start = posFromMouse(cm, e, true, true) + ourIndex = -1 + } else if (type == "double") { + var word = cm.findWordAt(start) + if (cm.display.shift || doc.extend) + { ourRange = extendRange(doc, ourRange, word.anchor, word.head) } + else + { ourRange = word } + } else if (type == "triple") { + var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))) + if (cm.display.shift || doc.extend) + { ourRange = extendRange(doc, ourRange, line.anchor, line.head) } + else + { ourRange = line } + } else { + ourRange = extendRange(doc, ourRange, start) + } + + if (!addNew) { + ourIndex = 0 + setSelection(doc, new Selection([ourRange], 0), sel_mouse) + startSel = doc.sel + } else if (ourIndex == -1) { + ourIndex = ranges.length + setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), + {scroll: false, origin: "*mouse"}) + } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { + setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), + {scroll: false, origin: "*mouse"}) + startSel = doc.sel + } else { + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse) + } + + var lastPos = start + function extendTo(pos) { + if (cmp(lastPos, pos) == 0) { return } + lastPos = pos + + if (type == "rect") { + var ranges = [], tabSize = cm.options.tabSize + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize) + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize) + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol) + for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + line <= end; line++) { + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize) + if (left == right) + { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))) } + else if (text.length > leftPos) + { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))) } + } + if (!ranges.length) { ranges.push(new Range(start, start)) } + setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + {origin: "*mouse", scroll: false}) + cm.scrollIntoView(pos) + } else { + var oldRange = ourRange + var anchor = oldRange.anchor, head = pos + if (type != "single") { + var range + if (type == "double") + { range = cm.findWordAt(pos) } + else + { range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))) } + if (cmp(range.anchor, anchor) > 0) { + head = range.head + anchor = minPos(oldRange.from(), range.anchor) + } else { + head = range.anchor + anchor = maxPos(oldRange.to(), range.head) + } + } + var ranges$1 = startSel.ranges.slice(0) + ranges$1[ourIndex] = new Range(clipPos(doc, anchor), head) + setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse) + } + } + + var editorSize = display.wrapper.getBoundingClientRect() + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0 + + function extend(e) { + var curCount = ++counter + var cur = posFromMouse(cm, e, true, type == "rect") + if (!cur) { return } + if (cmp(cur, lastPos) != 0) { + cm.curOp.focus = activeElt() + extendTo(cur) + var visible = visibleLines(display, doc) + if (cur.line >= visible.to || cur.line < visible.from) + { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e) }}), 150) } + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0 + if (outside) { setTimeout(operation(cm, function () { + if (counter != curCount) { return } + display.scroller.scrollTop += outside + extend(e) + }), 50) } + } + } + + function done(e) { + cm.state.selectingText = false + counter = Infinity + e_preventDefault(e) + display.input.focus() + off(document, "mousemove", move) + off(document, "mouseup", up) + doc.history.lastSelOrigin = null + } + + var move = operation(cm, function (e) { + if (!e_button(e)) { done(e) } + else { extend(e) } + }) + var up = operation(cm, done) + cm.state.selectingText = up + on(document, "mousemove", move) + on(document, "mouseup", up) +} + + +// Determines whether an event happened in the gutter, and fires the +// handlers for the corresponding event. +function gutterEvent(cm, e, type, prevent) { + var mX, mY + try { mX = e.clientX; mY = e.clientY } + catch(e) { return false } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false } + if (prevent) { e_preventDefault(e) } + + var display = cm.display + var lineBox = display.lineDiv.getBoundingClientRect() + + if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) } + mY -= lineBox.top - display.viewOffset + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i] + if (g && g.getBoundingClientRect().right >= mX) { + var line = lineAtHeight(cm.doc, mY) + var gutter = cm.options.gutters[i] + signal(cm, type, cm, line, gutter, e) + return e_defaultPrevented(e) + } + } +} + +function clickInGutter(cm, e) { + return gutterEvent(cm, e, "gutterClick", true) +} + +// CONTEXT MENU HANDLING + +// To make the context menu work, we need to briefly unhide the +// textarea (making it as unobtrusive as possible) to let the +// right-click take effect on it. +function onContextMenu(cm, e) { + if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return } + if (signalDOMEvent(cm, e, "contextmenu")) { return } + cm.display.input.onContextMenu(e) +} + +function contextMenuInGutter(cm, e) { + if (!hasHandler(cm, "gutterContextMenu")) { return false } + return gutterEvent(cm, e, "gutterContextMenu", false) +} + +function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-") + clearCaches(cm) +} + +var Init = {toString: function(){return "CodeMirror.Init"}} + +var defaults = {} +var optionHandlers = {} + +function defineOptions(CodeMirror) { + var optionHandlers = CodeMirror.optionHandlers + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt + if (handle) { optionHandlers[name] = + notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old) }} : handle } + } + + CodeMirror.defineOption = option + + // Passed to option handlers when there is no old value. + CodeMirror.Init = Init + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function (cm, val) { return cm.setValue(val); }, true) + option("mode", null, function (cm, val) { + cm.doc.modeOption = val + loadMode(cm) + }, true) + + option("indentUnit", 2, loadMode, true) + option("indentWithTabs", false) + option("smartIndent", true) + option("tabSize", 4, function (cm) { + resetModeState(cm) + clearCaches(cm) + regChange(cm) + }, true) + option("lineSeparator", null, function (cm, val) { + cm.doc.lineSep = val + if (!val) { return } + var newBreaks = [], lineNo = cm.doc.first + cm.doc.iter(function (line) { + for (var pos = 0;;) { + var found = line.text.indexOf(val, pos) + if (found == -1) { break } + pos = found + val.length + newBreaks.push(Pos(lineNo, found)) + } + lineNo++ + }) + for (var i = newBreaks.length - 1; i >= 0; i--) + { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) } + }) + option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) { + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g") + if (old != Init) { cm.refresh() } + }) + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true) + option("electricChars", true) + option("inputStyle", mobile ? "contenteditable" : "textarea", function () { + throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME + }, true) + option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true) + option("rtlMoveVisually", !windows) + option("wholeLineUpdateBefore", true) + + option("theme", "default", function (cm) { + themeChanged(cm) + guttersChanged(cm) + }, true) + option("keyMap", "default", function (cm, val, old) { + var next = getKeyMap(val) + var prev = old != Init && getKeyMap(old) + if (prev && prev.detach) { prev.detach(cm, next) } + if (next.attach) { next.attach(cm, prev || null) } + }) + option("extraKeys", null) + + option("lineWrapping", false, wrappingChanged, true) + option("gutters", [], function (cm) { + setGuttersForLineNumbers(cm.options) + guttersChanged(cm) + }, true) + option("fixedGutter", true, function (cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0" + cm.refresh() + }, true) + option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true) + option("scrollbarStyle", "native", function (cm) { + initScrollbars(cm) + updateScrollbars(cm) + cm.display.scrollbars.setScrollTop(cm.doc.scrollTop) + cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft) + }, true) + option("lineNumbers", false, function (cm) { + setGuttersForLineNumbers(cm.options) + guttersChanged(cm) + }, true) + option("firstLineNumber", 1, guttersChanged, true) + option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true) + option("showCursorWhenSelecting", false, updateSelection, true) + + option("resetSelectionOnContextMenu", true) + option("lineWiseCopyCut", true) + + option("readOnly", false, function (cm, val) { + if (val == "nocursor") { + onBlur(cm) + cm.display.input.blur() + cm.display.disabled = true + } else { + cm.display.disabled = false + } + cm.display.input.readOnlyChanged(val) + }) + option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset() }}, true) + option("dragDrop", true, dragDropChanged) + option("allowDropFileTypes", null) + + option("cursorBlinkRate", 530) + option("cursorScrollMargin", 0) + option("cursorHeight", 1, updateSelection, true) + option("singleCursorHeightPerLine", true, updateSelection, true) + option("workTime", 100) + option("workDelay", 100) + option("flattenSpans", true, resetModeState, true) + option("addModeClass", false, resetModeState, true) + option("pollInterval", 100) + option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; }) + option("historyEventDelay", 1250) + option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true) + option("maxHighlightLength", 10000, resetModeState, true) + option("moveInputWithCursor", true, function (cm, val) { + if (!val) { cm.display.input.resetPosition() } + }) + + option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; }) + option("autofocus", null) + option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true) +} + +function guttersChanged(cm) { + updateGutters(cm) + regChange(cm) + alignHorizontally(cm) +} + +function dragDropChanged(cm, value, old) { + var wasOn = old && old != Init + if (!value != !wasOn) { + var funcs = cm.display.dragFunctions + var toggle = value ? on : off + toggle(cm.display.scroller, "dragstart", funcs.start) + toggle(cm.display.scroller, "dragenter", funcs.enter) + toggle(cm.display.scroller, "dragover", funcs.over) + toggle(cm.display.scroller, "dragleave", funcs.leave) + toggle(cm.display.scroller, "drop", funcs.drop) + } +} + +function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + addClass(cm.display.wrapper, "CodeMirror-wrap") + cm.display.sizer.style.minWidth = "" + cm.display.sizerWidth = null + } else { + rmClass(cm.display.wrapper, "CodeMirror-wrap") + findMaxLine(cm) + } + estimateLineHeights(cm) + regChange(cm) + clearCaches(cm) + setTimeout(function () { return updateScrollbars(cm); }, 100) +} + +// A CodeMirror instance represents an editor. This is the object +// that user code is usually dealing with. + +function CodeMirror(place, options) { + var this$1 = this; + + if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) } + + this.options = options = options ? copyObj(options) : {} + // Determine effective options based on given values and defaults. + copyObj(defaults, options, false) + setGuttersForLineNumbers(options) + + var doc = options.value + if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction) } + this.doc = doc + + var input = new CodeMirror.inputStyles[options.inputStyle](this) + var display = this.display = new Display(place, doc, input) + display.wrapper.CodeMirror = this + updateGutters(this) + themeChanged(this) + if (options.lineWrapping) + { this.display.wrapper.className += " CodeMirror-wrap" } + initScrollbars(this) + + this.state = { + keyMaps: [], // stores maps added by addKeyMap + overlays: [], // highlighting overlays, as added by addOverlay + modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info + overwrite: false, + delayingBlurEvent: false, + focused: false, + suppressEdits: false, // used to disable editing during key handlers when in readOnly mode + pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll + selectingText: false, + draggingText: false, + highlight: new Delayed(), // stores highlight worker timeout + keySeq: null, // Unfinished key sequence + specialChars: null + } + + if (options.autofocus && !mobile) { display.input.focus() } + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20) } + + registerEventHandlers(this) + ensureGlobalHandlers() + + startOperation(this) + this.curOp.forceUpdate = true + attachDoc(this, doc) + + if ((options.autofocus && !mobile) || this.hasFocus()) + { setTimeout(bind(onFocus, this), 20) } + else + { onBlur(this) } + + for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt)) + { optionHandlers[opt](this$1, options[opt], Init) } } + maybeUpdateLineNumberWidth(this) + if (options.finishInit) { options.finishInit(this) } + for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1) } + endOperation(this) + // Suppress optimizelegibility in Webkit, since it breaks text + // measuring on line wrapping boundaries. + if (webkit && options.lineWrapping && + getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") + { display.lineDiv.style.textRendering = "auto" } +} + +// The default configuration options. +CodeMirror.defaults = defaults +// Functions to run when options are changed. +CodeMirror.optionHandlers = optionHandlers + +// Attach the necessary event handlers when initializing the editor +function registerEventHandlers(cm) { + var d = cm.display + on(d.scroller, "mousedown", operation(cm, onMouseDown)) + // Older IE's will not fire a second mousedown for a double click + if (ie && ie_version < 11) + { on(d.scroller, "dblclick", operation(cm, function (e) { + if (signalDOMEvent(cm, e)) { return } + var pos = posFromMouse(cm, e) + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return } + e_preventDefault(e) + var word = cm.findWordAt(pos) + extendSelection(cm.doc, word.anchor, word.head) + })) } + else + { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }) } + // Some browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for these browsers. + if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }) } + + // Used to suppress mouse event handling when a touch happens + var touchFinished, prevTouch = {end: 0} + function finishTouch() { + if (d.activeTouch) { + touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000) + prevTouch = d.activeTouch + prevTouch.end = +new Date + } + } + function isMouseLikeTouchEvent(e) { + if (e.touches.length != 1) { return false } + var touch = e.touches[0] + return touch.radiusX <= 1 && touch.radiusY <= 1 + } + function farAway(touch, other) { + if (other.left == null) { return true } + var dx = other.left - touch.left, dy = other.top - touch.top + return dx * dx + dy * dy > 20 * 20 + } + on(d.scroller, "touchstart", function (e) { + if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { + d.input.ensurePolled() + clearTimeout(touchFinished) + var now = +new Date + d.activeTouch = {start: now, moved: false, + prev: now - prevTouch.end <= 300 ? prevTouch : null} + if (e.touches.length == 1) { + d.activeTouch.left = e.touches[0].pageX + d.activeTouch.top = e.touches[0].pageY + } + } + }) + on(d.scroller, "touchmove", function () { + if (d.activeTouch) { d.activeTouch.moved = true } + }) + on(d.scroller, "touchend", function (e) { + var touch = d.activeTouch + if (touch && !eventInWidget(d, e) && touch.left != null && + !touch.moved && new Date - touch.start < 300) { + var pos = cm.coordsChar(d.activeTouch, "page"), range + if (!touch.prev || farAway(touch, touch.prev)) // Single tap + { range = new Range(pos, pos) } + else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap + { range = cm.findWordAt(pos) } + else // Triple tap + { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) } + cm.setSelection(range.anchor, range.head) + cm.focus() + e_preventDefault(e) + } + finishTouch() + }) + on(d.scroller, "touchcancel", finishTouch) + + // Sync scrolling between fake scrollbars and real scrollable + // area, ensure viewport is updated when scrolling. + on(d.scroller, "scroll", function () { + if (d.scroller.clientHeight) { + setScrollTop(cm, d.scroller.scrollTop) + setScrollLeft(cm, d.scroller.scrollLeft, true) + signal(cm, "scroll", cm) + } + }) + + // Listen to wheel events in order to try and update the viewport on time. + on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); }) + on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); }) + + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }) + + d.dragFunctions = { + enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e) }}, + over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e) }}, + start: function (e) { return onDragStart(cm, e); }, + drop: operation(cm, onDrop), + leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm) }} + } + + var inp = d.input.getField() + on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); }) + on(inp, "keydown", operation(cm, onKeyDown)) + on(inp, "keypress", operation(cm, onKeyPress)) + on(inp, "focus", function (e) { return onFocus(cm, e); }) + on(inp, "blur", function (e) { return onBlur(cm, e); }) +} + +var initHooks = [] +CodeMirror.defineInitHook = function (f) { return initHooks.push(f); } + +// Indent the given line. The how parameter can be "smart", +// "add"/null, "subtract", or "prev". When aggressive is false +// (typically set to true for forced single-line indents), empty +// lines are not indented, and places where the mode returns Pass +// are left alone. +function indentLine(cm, n, how, aggressive) { + var doc = cm.doc, state + if (how == null) { how = "add" } + if (how == "smart") { + // Fall back to "prev" when the mode doesn't have an indentation + // method. + if (!doc.mode.indent) { how = "prev" } + else { state = getStateBefore(cm, n) } + } + + var tabSize = cm.options.tabSize + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize) + if (line.stateAfter) { line.stateAfter = null } + var curSpaceString = line.text.match(/^\s*/)[0], indentation + if (!aggressive && !/\S/.test(line.text)) { + indentation = 0 + how = "not" + } else if (how == "smart") { + indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text) + if (indentation == Pass || indentation > 150) { + if (!aggressive) { return } + how = "prev" + } + } + if (how == "prev") { + if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize) } + else { indentation = 0 } + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit + } else if (typeof how == "number") { + indentation = curSpace + how + } + indentation = Math.max(0, indentation) + + var indentString = "", pos = 0 + if (cm.options.indentWithTabs) + { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"} } + if (pos < indentation) { indentString += spaceStr(indentation - pos) } + + if (indentString != curSpaceString) { + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input") + line.stateAfter = null + return true + } else { + // Ensure that, if the cursor was in the whitespace at the start + // of the line, it is moved to the end of that space. + for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) { + var range = doc.sel.ranges[i$1] + if (range.head.line == n && range.head.ch < curSpaceString.length) { + var pos$1 = Pos(n, curSpaceString.length) + replaceOneSelection(doc, i$1, new Range(pos$1, pos$1)) + break + } + } + } +} + +// This will be set to a {lineWise: bool, text: [string]} object, so +// that, when pasting, we know what kind of selections the copied +// text was made out of. +var lastCopied = null + +function setLastCopied(newLastCopied) { + lastCopied = newLastCopied +} + +function applyTextInput(cm, inserted, deleted, sel, origin) { + var doc = cm.doc + cm.display.shift = false + if (!sel) { sel = doc.sel } + + var paste = cm.state.pasteIncoming || origin == "paste" + var textLines = splitLinesAuto(inserted), multiPaste = null + // When pasing N lines into N selections, insert one line per selection + if (paste && sel.ranges.length > 1) { + if (lastCopied && lastCopied.text.join("\n") == inserted) { + if (sel.ranges.length % lastCopied.text.length == 0) { + multiPaste = [] + for (var i = 0; i < lastCopied.text.length; i++) + { multiPaste.push(doc.splitLines(lastCopied.text[i])) } + } + } else if (textLines.length == sel.ranges.length) { + multiPaste = map(textLines, function (l) { return [l]; }) + } + } + + var updateInput + // Normal behavior is to insert the new text into every selection + for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) { + var range = sel.ranges[i$1] + var from = range.from(), to = range.to() + if (range.empty()) { + if (deleted && deleted > 0) // Handle deletion + { from = Pos(from.line, from.ch - deleted) } + else if (cm.state.overwrite && !paste) // Handle overwrite + { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)) } + else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) + { from = to = Pos(from.line, 0) } + } + updateInput = cm.curOp.updateInput + var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines, + origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")} + makeChange(cm.doc, changeEvent) + signalLater(cm, "inputRead", cm, changeEvent) + } + if (inserted && !paste) + { triggerElectric(cm, inserted) } + + ensureCursorVisible(cm) + cm.curOp.updateInput = updateInput + cm.curOp.typing = true + cm.state.pasteIncoming = cm.state.cutIncoming = false +} + +function handlePaste(e, cm) { + var pasted = e.clipboardData && e.clipboardData.getData("Text") + if (pasted) { + e.preventDefault() + if (!cm.isReadOnly() && !cm.options.disableInput) + { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }) } + return true + } +} + +function triggerElectric(cm, inserted) { + // When an 'electric' character is inserted, immediately trigger a reindent + if (!cm.options.electricChars || !cm.options.smartIndent) { return } + var sel = cm.doc.sel + + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i] + if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue } + var mode = cm.getModeAt(range.head) + var indented = false + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indented = indentLine(cm, range.head.line, "smart") + break + } } + } else if (mode.electricInput) { + if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) + { indented = indentLine(cm, range.head.line, "smart") } + } + if (indented) { signalLater(cm, "electricInput", cm, range.head.line) } + } +} + +function copyableRanges(cm) { + var text = [], ranges = [] + for (var i = 0; i < cm.doc.sel.ranges.length; i++) { + var line = cm.doc.sel.ranges[i].head.line + var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)} + ranges.push(lineRange) + text.push(cm.getRange(lineRange.anchor, lineRange.head)) + } + return {text: text, ranges: ranges} +} + +function disableBrowserMagic(field, spellcheck) { + field.setAttribute("autocorrect", "off") + field.setAttribute("autocapitalize", "off") + field.setAttribute("spellcheck", !!spellcheck) +} + +function hiddenTextarea() { + var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none") + var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;") + // The textarea is kept positioned near the cursor to prevent the + // fact that it'll be scrolled into view on input from scrolling + // our fake cursor out of view. On webkit, when wrap=off, paste is + // very slow. So make the area wide instead. + if (webkit) { te.style.width = "1000px" } + else { te.setAttribute("wrap", "off") } + // If border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) { te.style.border = "1px solid black" } + disableBrowserMagic(te) + return div +} + +// The publicly visible API. Note that methodOp(f) means +// 'wrap f in an operation, performed on its `this` parameter'. + +// This is not the complete set of editor methods. Most of the +// methods defined on the Doc type are also injected into +// CodeMirror.prototype, for backwards compatibility and +// convenience. + +function addEditorMethods(CodeMirror) { + var optionHandlers = CodeMirror.optionHandlers + + var helpers = CodeMirror.helpers = {} + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function(){window.focus(); this.display.input.focus()}, + + setOption: function(option, value) { + var options = this.options, old = options[option] + if (options[option] == value && option != "mode") { return } + options[option] = value + if (optionHandlers.hasOwnProperty(option)) + { operation(this, optionHandlers[option])(this, value, old) } + signal(this, "optionChange", this, option) + }, + + getOption: function(option) {return this.options[option]}, + getDoc: function() {return this.doc}, + + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)) + }, + removeKeyMap: function(map) { + var maps = this.state.keyMaps + for (var i = 0; i < maps.length; ++i) + { if (maps[i] == map || maps[i].name == map) { + maps.splice(i, 1) + return true + } } + }, + + addOverlay: methodOp(function(spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec) + if (mode.startState) { throw new Error("Overlays may not be stateful.") } + insertSorted(this.state.overlays, + {mode: mode, modeSpec: spec, opaque: options && options.opaque, + priority: (options && options.priority) || 0}, + function (overlay) { return overlay.priority; }) + this.state.modeGen++ + regChange(this) + }), + removeOverlay: methodOp(function(spec) { + var this$1 = this; + + var overlays = this.state.overlays + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1) + this$1.state.modeGen++ + regChange(this$1) + return + } + } + }), + + indentLine: methodOp(function(n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev" } + else { dir = dir ? "add" : "subtract" } + } + if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive) } + }), + indentSelection: methodOp(function(how) { + var this$1 = this; + + var ranges = this.doc.sel.ranges, end = -1 + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i] + if (!range.empty()) { + var from = range.from(), to = range.to() + var start = Math.max(end, from.line) + end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1 + for (var j = start; j < end; ++j) + { indentLine(this$1, j, how) } + var newRanges = this$1.doc.sel.ranges + if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) + { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll) } + } else if (range.head.line > end) { + indentLine(this$1, range.head.line, how, true) + end = range.head.line + if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1) } + } + } + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(pos, precise) { + return takeToken(this, pos, precise) + }, + + getLineTokens: function(line, precise) { + return takeToken(this, Pos(line), precise, true) + }, + + getTokenTypeAt: function(pos) { + pos = clipPos(this.doc, pos) + var styles = getLineStyles(this, getLine(this.doc, pos.line)) + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch + var type + if (ch == 0) { type = styles[2] } + else { for (;;) { + var mid = (before + after) >> 1 + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid } + else if (styles[mid * 2 + 1] < ch) { before = mid + 1 } + else { type = styles[mid * 2 + 2]; break } + } } + var cut = type ? type.indexOf("overlay ") : -1 + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1) + }, + + getModeAt: function(pos) { + var mode = this.doc.mode + if (!mode.innerMode) { return mode } + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode + }, + + getHelper: function(pos, type) { + return this.getHelpers(pos, type)[0] + }, + + getHelpers: function(pos, type) { + var this$1 = this; + + var found = [] + if (!helpers.hasOwnProperty(type)) { return found } + var help = helpers[type], mode = this.getModeAt(pos) + if (typeof mode[type] == "string") { + if (help[mode[type]]) { found.push(help[mode[type]]) } + } else if (mode[type]) { + for (var i = 0; i < mode[type].length; i++) { + var val = help[mode[type][i]] + if (val) { found.push(val) } + } + } else if (mode.helperType && help[mode.helperType]) { + found.push(help[mode.helperType]) + } else if (help[mode.name]) { + found.push(help[mode.name]) + } + for (var i$1 = 0; i$1 < help._global.length; i$1++) { + var cur = help._global[i$1] + if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1) + { found.push(cur.val) } + } + return found + }, + + getStateAfter: function(line, precise) { + var doc = this.doc + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line) + return getStateBefore(this, line + 1, precise) + }, + + cursorCoords: function(start, mode) { + var pos, range = this.doc.sel.primary() + if (start == null) { pos = range.head } + else if (typeof start == "object") { pos = clipPos(this.doc, start) } + else { pos = start ? range.from() : range.to() } + return cursorCoords(this, pos, mode || "page") + }, + + charCoords: function(pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page") + }, + + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page") + return coordsChar(this, coords.left, coords.top) + }, + + lineAtHeight: function(height, mode) { + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top + return lineAtHeight(this.doc, height + this.display.viewOffset) + }, + heightAtLine: function(line, mode, includeWidgets) { + var end = false, lineObj + if (typeof line == "number") { + var last = this.doc.first + this.doc.size - 1 + if (line < this.doc.first) { line = this.doc.first } + else if (line > last) { line = last; end = true } + lineObj = getLine(this.doc, line) + } else { + lineObj = line + } + return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top + + (end ? this.doc.height - heightAtLine(lineObj) : 0) + }, + + defaultTextHeight: function() { return textHeight(this.display) }, + defaultCharWidth: function() { return charWidth(this.display) }, + + getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}}, + + addWidget: function(pos, node, scroll, vert, horiz) { + var display = this.display + pos = cursorCoords(this, clipPos(this.doc, pos)) + var top = pos.bottom, left = pos.left + node.style.position = "absolute" + node.setAttribute("cm-ignore-events", "true") + this.display.input.setUneditable(node) + display.sizer.appendChild(node) + if (vert == "over") { + top = pos.top + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth) + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + { top = pos.top - node.offsetHeight } + else if (pos.bottom + node.offsetHeight <= vspace) + { top = pos.bottom } + if (left + node.offsetWidth > hspace) + { left = hspace - node.offsetWidth } + } + node.style.top = top + "px" + node.style.left = node.style.right = "" + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth + node.style.right = "0px" + } else { + if (horiz == "left") { left = 0 } + else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2 } + node.style.left = left + "px" + } + if (scroll) + { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}) } + }, + + triggerOnKeyDown: methodOp(onKeyDown), + triggerOnKeyPress: methodOp(onKeyPress), + triggerOnKeyUp: onKeyUp, + + execCommand: function(cmd) { + if (commands.hasOwnProperty(cmd)) + { return commands[cmd].call(null, this) } + }, + + triggerElectric: methodOp(function(text) { triggerElectric(this, text) }), + + findPosH: function(from, amount, unit, visually) { + var this$1 = this; + + var dir = 1 + if (amount < 0) { dir = -1; amount = -amount } + var cur = clipPos(this.doc, from) + for (var i = 0; i < amount; ++i) { + cur = findPosH(this$1.doc, cur, dir, unit, visually) + if (cur.hitSide) { break } + } + return cur + }, + + moveH: methodOp(function(dir, unit) { + var this$1 = this; + + this.extendSelectionsBy(function (range) { + if (this$1.display.shift || this$1.doc.extend || range.empty()) + { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) } + else + { return dir < 0 ? range.from() : range.to() } + }, sel_move) + }), + + deleteH: methodOp(function(dir, unit) { + var sel = this.doc.sel, doc = this.doc + if (sel.somethingSelected()) + { doc.replaceSelection("", null, "+delete") } + else + { deleteNearSelection(this, function (range) { + var other = findPosH(doc, range.head, dir, unit, false) + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} + }) } + }), + + findPosV: function(from, amount, unit, goalColumn) { + var this$1 = this; + + var dir = 1, x = goalColumn + if (amount < 0) { dir = -1; amount = -amount } + var cur = clipPos(this.doc, from) + for (var i = 0; i < amount; ++i) { + var coords = cursorCoords(this$1, cur, "div") + if (x == null) { x = coords.left } + else { coords.left = x } + cur = findPosV(this$1, coords, dir, unit) + if (cur.hitSide) { break } + } + return cur + }, + + moveV: methodOp(function(dir, unit) { + var this$1 = this; + + var doc = this.doc, goals = [] + var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected() + doc.extendSelectionsBy(function (range) { + if (collapse) + { return dir < 0 ? range.from() : range.to() } + var headPos = cursorCoords(this$1, range.head, "div") + if (range.goalColumn != null) { headPos.left = range.goalColumn } + goals.push(headPos.left) + var pos = findPosV(this$1, headPos, dir, unit) + if (unit == "page" && range == doc.sel.primary()) + { addToScrollPos(this$1, null, charCoords(this$1, pos, "div").top - headPos.top) } + return pos + }, sel_move) + if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++) + { doc.sel.ranges[i].goalColumn = goals[i] } } + }), + + // Find the word at the given position (as returned by coordsChar). + findWordAt: function(pos) { + var doc = this.doc, line = getLine(doc, pos.line).text + var start = pos.ch, end = pos.ch + if (line) { + var helper = this.getHelper(pos, "wordChars") + if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end } + var startChar = line.charAt(start) + var check = isWordChar(startChar, helper) + ? function (ch) { return isWordChar(ch, helper); } + : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); } + : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); } + while (start > 0 && check(line.charAt(start - 1))) { --start } + while (end < line.length && check(line.charAt(end))) { ++end } + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)) + }, + + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) { return } + if (this.state.overwrite = !this.state.overwrite) + { addClass(this.display.cursorDiv, "CodeMirror-overwrite") } + else + { rmClass(this.display.cursorDiv, "CodeMirror-overwrite") } + + signal(this, "overwriteToggle", this, this.state.overwrite) + }, + hasFocus: function() { return this.display.input.getField() == activeElt() }, + isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) }, + + scrollTo: methodOp(function(x, y) { + if (x != null || y != null) { resolveScrollToPos(this) } + if (x != null) { this.curOp.scrollLeft = x } + if (y != null) { this.curOp.scrollTop = y } + }), + getScrollInfo: function() { + var scroller = this.display.scroller + return {left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, + width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, + clientHeight: displayHeight(this), clientWidth: displayWidth(this)} + }, + + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null} + if (margin == null) { margin = this.options.cursorScrollMargin } + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null} + } else if (range.from == null) { + range = {from: range, to: null} + } + if (!range.to) { range.to = range.from } + range.margin = margin || 0 + + if (range.from.line != null) { + resolveScrollToPos(this) + this.curOp.scrollToPos = range + } else { + var sPos = calculateScrollPos(this, { + left: Math.min(range.from.left, range.to.left), + top: Math.min(range.from.top, range.to.top) - range.margin, + right: Math.max(range.from.right, range.to.right), + bottom: Math.max(range.from.bottom, range.to.bottom) + range.margin + }) + this.scrollTo(sPos.scrollLeft, sPos.scrollTop) + } + }), + + setSize: methodOp(function(width, height) { + var this$1 = this; + + var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; } + if (width != null) { this.display.wrapper.style.width = interpret(width) } + if (height != null) { this.display.wrapper.style.height = interpret(height) } + if (this.options.lineWrapping) { clearLineMeasurementCache(this) } + var lineNo = this.display.viewFrom + this.doc.iter(lineNo, this.display.viewTo, function (line) { + if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) + { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } } + ++lineNo + }) + this.curOp.forceUpdate = true + signal(this, "refresh", this) + }), + + operation: function(f){return runInOp(this, f)}, + + refresh: methodOp(function() { + var oldHeight = this.display.cachedTextHeight + regChange(this) + this.curOp.forceUpdate = true + clearCaches(this) + this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop) + updateGutterSpace(this) + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + { estimateLineHeights(this) } + signal(this, "refresh", this) + }), + + swapDoc: methodOp(function(doc) { + var old = this.doc + old.cm = null + attachDoc(this, doc) + clearCaches(this) + this.display.input.reset() + this.scrollTo(doc.scrollLeft, doc.scrollTop) + this.curOp.forceScroll = true + signalLater(this, "swapDoc", this, old) + return old + }), + + getInputField: function(){return this.display.input.getField()}, + getWrapperElement: function(){return this.display.wrapper}, + getScrollerElement: function(){return this.display.scroller}, + getGutterElement: function(){return this.display.gutters} + } + eventMixin(CodeMirror) + + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []} } + helpers[type][name] = value + } + CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { + CodeMirror.registerHelper(type, name, value) + helpers[type]._global.push({pred: predicate, val: value}) + } +} + +// Used for horizontal relative motion. Dir is -1 or 1 (left or +// right), unit can be "char", "column" (like char, but doesn't +// cross line boundaries), "word" (across next word), or "group" (to +// the start of next group of word or non-word-non-whitespace +// chars). The visually param controls whether, in right-to-left +// text, direction 1 means to move towards the next index in the +// string, or towards the character to the right of the current +// position. The resulting position will have a hitSide=true +// property if it reached the end of the document. +function findPosH(doc, pos, dir, unit, visually) { + var oldPos = pos + var origDir = dir + var lineObj = getLine(doc, pos.line) + function findNextLine() { + var l = pos.line + dir + if (l < doc.first || l >= doc.first + doc.size) { return false } + pos = new Pos(l, pos.ch, pos.sticky) + return lineObj = getLine(doc, l) + } + function moveOnce(boundToLine) { + var next + if (visually) { + next = moveVisually(doc.cm, lineObj, pos, dir) + } else { + next = moveLogically(lineObj, pos, dir) + } + if (next == null) { + if (!boundToLine && findNextLine()) + { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir) } + else + { return false } + } else { + pos = next + } + return true + } + + if (unit == "char") { + moveOnce() + } else if (unit == "column") { + moveOnce(true) + } else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group" + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars") + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) { break } + var cur = lineObj.text.charAt(pos.ch) || "\n" + var type = isWordChar(cur, helper) ? "w" + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null + : "p" + if (group && !first && !type) { type = "s" } + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after"} + break + } + + if (type) { sawType = type } + if (dir > 0 && !moveOnce(!first)) { break } + } + } + var result = skipAtomic(doc, pos, oldPos, origDir, true) + if (equalCursorPos(oldPos, result)) { result.hitSide = true } + return result +} + +// For relative vertical movement. Dir may be -1 or 1. Unit can be +// "page" or "line". The resulting position will have a hitSide=true +// property if it reached the end of the document. +function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight) + var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3) + y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount + + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3 + } + var target + for (;;) { + target = coordsChar(cm, x, y) + if (!target.outside) { break } + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break } + y += dir * 5 + } + return target +} + +// CONTENTEDITABLE INPUT STYLE + +var ContentEditableInput = function(cm) { + this.cm = cm + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null + this.polling = new Delayed() + this.composing = null + this.gracePeriod = false + this.readDOMTimeout = null +}; + +ContentEditableInput.prototype.init = function (display) { + var this$1 = this; + + var input = this, cm = input.cm + var div = input.div = display.lineDiv + disableBrowserMagic(div, cm.options.spellcheck) + + on(div, "paste", function (e) { + if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } + // IE doesn't fire input events, so we schedule a read for the pasted content in this way + if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20) } + }) + + on(div, "compositionstart", function (e) { + this$1.composing = {data: e.data, done: false} + }) + on(div, "compositionupdate", function (e) { + if (!this$1.composing) { this$1.composing = {data: e.data, done: false} } + }) + on(div, "compositionend", function (e) { + if (this$1.composing) { + if (e.data != this$1.composing.data) { this$1.readFromDOMSoon() } + this$1.composing.done = true + } + }) + + on(div, "touchstart", function () { return input.forceCompositionEnd(); }) + + on(div, "input", function () { + if (!this$1.composing) { this$1.readFromDOMSoon() } + }) + + function onCopyCut(e) { + if (signalDOMEvent(cm, e)) { return } + if (cm.somethingSelected()) { + setLastCopied({lineWise: false, text: cm.getSelections()}) + if (e.type == "cut") { cm.replaceSelection("", null, "cut") } + } else if (!cm.options.lineWiseCopyCut) { + return + } else { + var ranges = copyableRanges(cm) + setLastCopied({lineWise: true, text: ranges.text}) + if (e.type == "cut") { + cm.operation(function () { + cm.setSelections(ranges.ranges, 0, sel_dontScroll) + cm.replaceSelection("", null, "cut") + }) + } + } + if (e.clipboardData) { + e.clipboardData.clearData() + var content = lastCopied.text.join("\n") + // iOS exposes the clipboard API, but seems to discard content inserted into it + e.clipboardData.setData("Text", content) + if (e.clipboardData.getData("Text") == content) { + e.preventDefault() + return + } + } + // Old-fashioned briefly-focus-a-textarea hack + var kludge = hiddenTextarea(), te = kludge.firstChild + cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild) + te.value = lastCopied.text.join("\n") + var hadFocus = document.activeElement + selectInput(te) + setTimeout(function () { + cm.display.lineSpace.removeChild(kludge) + hadFocus.focus() + if (hadFocus == div) { input.showPrimarySelection() } + }, 50) + } + on(div, "copy", onCopyCut) + on(div, "cut", onCopyCut) +}; + +ContentEditableInput.prototype.prepareSelection = function () { + var result = prepareSelection(this.cm, false) + result.focus = this.cm.state.focused + return result +}; + +ContentEditableInput.prototype.showSelection = function (info, takeFocus) { + if (!info || !this.cm.display.view.length) { return } + if (info.focus || takeFocus) { this.showPrimarySelection() } + this.showMultipleSelections(info) +}; + +ContentEditableInput.prototype.showPrimarySelection = function () { + var sel = window.getSelection(), prim = this.cm.doc.sel.primary() + var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset) + var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset) + if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && + cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && + cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) + { return } + + var start = posToDOM(this.cm, prim.from()) + var end = posToDOM(this.cm, prim.to()) + if (!start && !end) { + sel.removeAllRanges() + return + } + + var view = this.cm.display.view + var old = sel.rangeCount && sel.getRangeAt(0) + if (!start) { + start = {node: view[0].measure.map[2], offset: 0} + } else if (!end) { // FIXME dangerously hacky + var measure = view[view.length - 1].measure + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]} + } + + var rng + try { rng = range(start.node, start.offset, end.offset, end.node) } + catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible + if (rng) { + if (!gecko && this.cm.state.focused) { + sel.collapse(start.node, start.offset) + if (!rng.collapsed) { + sel.removeAllRanges() + sel.addRange(rng) + } + } else { + sel.removeAllRanges() + sel.addRange(rng) + } + if (old && sel.anchorNode == null) { sel.addRange(old) } + else if (gecko) { this.startGracePeriod() } + } + this.rememberSelection() +}; + +ContentEditableInput.prototype.startGracePeriod = function () { + var this$1 = this; + + clearTimeout(this.gracePeriod) + this.gracePeriod = setTimeout(function () { + this$1.gracePeriod = false + if (this$1.selectionChanged()) + { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }) } + }, 20) +}; + +ContentEditableInput.prototype.showMultipleSelections = function (info) { + removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors) + removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection) +}; + +ContentEditableInput.prototype.rememberSelection = function () { + var sel = window.getSelection() + this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset + this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset +}; + +ContentEditableInput.prototype.selectionInEditor = function () { + var sel = window.getSelection() + if (!sel.rangeCount) { return false } + var node = sel.getRangeAt(0).commonAncestorContainer + return contains(this.div, node) +}; + +ContentEditableInput.prototype.focus = function () { + if (this.cm.options.readOnly != "nocursor") { + if (!this.selectionInEditor()) + { this.showSelection(this.prepareSelection(), true) } + this.div.focus() + } +}; +ContentEditableInput.prototype.blur = function () { this.div.blur() }; +ContentEditableInput.prototype.getField = function () { return this.div }; + +ContentEditableInput.prototype.supportsTouch = function () { return true }; + +ContentEditableInput.prototype.receivedFocus = function () { + var input = this + if (this.selectionInEditor()) + { this.pollSelection() } + else + { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }) } + + function poll() { + if (input.cm.state.focused) { + input.pollSelection() + input.polling.set(input.cm.options.pollInterval, poll) + } + } + this.polling.set(this.cm.options.pollInterval, poll) +}; + +ContentEditableInput.prototype.selectionChanged = function () { + var sel = window.getSelection() + return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset +}; + +ContentEditableInput.prototype.pollSelection = function () { + if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return } + var sel = window.getSelection(), cm = this.cm + // On Android Chrome (version 56, at least), backspacing into an + // uneditable block element will put the cursor in that element, + // and then, because it's not editable, hide the virtual keyboard. + // Because Android doesn't allow us to actually detect backspace + // presses in a sane way, this code checks for when that happens + // and simulates a backspace press in this case. + if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) { + this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs}) + this.blur() + this.focus() + return + } + if (this.composing) { return } + this.rememberSelection() + var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) + var head = domToPos(cm, sel.focusNode, sel.focusOffset) + if (anchor && head) { runInOp(cm, function () { + setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll) + if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true } + }) } +}; + +ContentEditableInput.prototype.pollContent = function () { + if (this.readDOMTimeout != null) { + clearTimeout(this.readDOMTimeout) + this.readDOMTimeout = null + } + + var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary() + var from = sel.from(), to = sel.to() + if (from.ch == 0 && from.line > cm.firstLine()) + { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length) } + if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine()) + { to = Pos(to.line + 1, 0) } + if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false } + + var fromIndex, fromLine, fromNode + if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { + fromLine = lineNo(display.view[0].line) + fromNode = display.view[0].node + } else { + fromLine = lineNo(display.view[fromIndex].line) + fromNode = display.view[fromIndex - 1].node.nextSibling + } + var toIndex = findViewIndex(cm, to.line) + var toLine, toNode + if (toIndex == display.view.length - 1) { + toLine = display.viewTo - 1 + toNode = display.lineDiv.lastChild + } else { + toLine = lineNo(display.view[toIndex + 1].line) - 1 + toNode = display.view[toIndex + 1].node.previousSibling + } + + if (!fromNode) { return false } + var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)) + var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)) + while (newText.length > 1 && oldText.length > 1) { + if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- } + else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ } + else { break } + } + + var cutFront = 0, cutEnd = 0 + var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length) + while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) + { ++cutFront } + var newBot = lst(newText), oldBot = lst(oldText) + var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), + oldBot.length - (oldText.length == 1 ? cutFront : 0)) + while (cutEnd < maxCutEnd && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) + { ++cutEnd } + // Try to move start of change to start of selection if ambiguous + if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) { + while (cutFront && cutFront > from.ch && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) { + cutFront-- + cutEnd++ + } + } + + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "") + newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "") + + var chFrom = Pos(fromLine, cutFront) + var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0) + if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { + replaceRange(cm.doc, newText, chFrom, chTo, "+input") + return true + } +}; + +ContentEditableInput.prototype.ensurePolled = function () { + this.forceCompositionEnd() +}; +ContentEditableInput.prototype.reset = function () { + this.forceCompositionEnd() +}; +ContentEditableInput.prototype.forceCompositionEnd = function () { + if (!this.composing) { return } + clearTimeout(this.readDOMTimeout) + this.composing = null + this.updateFromDOM() + this.div.blur() + this.div.focus() +}; +ContentEditableInput.prototype.readFromDOMSoon = function () { + var this$1 = this; + + if (this.readDOMTimeout != null) { return } + this.readDOMTimeout = setTimeout(function () { + this$1.readDOMTimeout = null + if (this$1.composing) { + if (this$1.composing.done) { this$1.composing = null } + else { return } + } + this$1.updateFromDOM() + }, 80) +}; + +ContentEditableInput.prototype.updateFromDOM = function () { + var this$1 = this; + + if (this.cm.isReadOnly() || !this.pollContent()) + { runInOp(this.cm, function () { return regChange(this$1.cm); }) } +}; + +ContentEditableInput.prototype.setUneditable = function (node) { + node.contentEditable = "false" +}; + +ContentEditableInput.prototype.onKeyPress = function (e) { + if (e.charCode == 0) { return } + e.preventDefault() + if (!this.cm.isReadOnly()) + { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) } +}; + +ContentEditableInput.prototype.readOnlyChanged = function (val) { + this.div.contentEditable = String(val != "nocursor") +}; + +ContentEditableInput.prototype.onContextMenu = function () {}; +ContentEditableInput.prototype.resetPosition = function () {}; + +ContentEditableInput.prototype.needsContentAttribute = true + +function posToDOM(cm, pos) { + var view = findViewForLine(cm, pos.line) + if (!view || view.hidden) { return null } + var line = getLine(cm.doc, pos.line) + var info = mapFromLineView(view, line, pos.line) + + var order = getOrder(line, cm.doc.direction), side = "left" + if (order) { + var partPos = getBidiPartAt(order, pos.ch) + side = partPos % 2 ? "right" : "left" + } + var result = nodeAndOffsetInLineMap(info.map, pos.ch, side) + result.offset = result.collapse == "right" ? result.end : result.start + return result +} + +function isInGutter(node) { + for (var scan = node; scan; scan = scan.parentNode) + { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } } + return false +} + +function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos } + +function domTextBetween(cm, from, to, fromLine, toLine) { + var text = "", closing = false, lineSep = cm.doc.lineSeparator() + function recognizeMarker(id) { return function (marker) { return marker.id == id; } } + function close() { + if (closing) { + text += lineSep + closing = false + } + } + function addText(str) { + if (str) { + close() + text += str + } + } + function walk(node) { + if (node.nodeType == 1) { + var cmText = node.getAttribute("cm-text") + if (cmText != null) { + addText(cmText || node.textContent.replace(/\u200b/g, "")) + return + } + var markerID = node.getAttribute("cm-marker"), range + if (markerID) { + var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)) + if (found.length && (range = found[0].find())) + { addText(getBetween(cm.doc, range.from, range.to).join(lineSep)) } + return + } + if (node.getAttribute("contenteditable") == "false") { return } + var isBlock = /^(pre|div|p)$/i.test(node.nodeName) + if (isBlock) { close() } + for (var i = 0; i < node.childNodes.length; i++) + { walk(node.childNodes[i]) } + if (isBlock) { closing = true } + } else if (node.nodeType == 3) { + addText(node.nodeValue) + } + } + for (;;) { + walk(from) + if (from == to) { break } + from = from.nextSibling + } + return text +} + +function domToPos(cm, node, offset) { + var lineNode + if (node == cm.display.lineDiv) { + lineNode = cm.display.lineDiv.childNodes[offset] + if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) } + node = null; offset = 0 + } else { + for (lineNode = node;; lineNode = lineNode.parentNode) { + if (!lineNode || lineNode == cm.display.lineDiv) { return null } + if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break } + } + } + for (var i = 0; i < cm.display.view.length; i++) { + var lineView = cm.display.view[i] + if (lineView.node == lineNode) + { return locateNodeInLineView(lineView, node, offset) } + } +} + +function locateNodeInLineView(lineView, node, offset) { + var wrapper = lineView.text.firstChild, bad = false + if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) } + if (node == wrapper) { + bad = true + node = wrapper.childNodes[offset] + offset = 0 + if (!node) { + var line = lineView.rest ? lst(lineView.rest) : lineView.line + return badPos(Pos(lineNo(line), line.text.length), bad) + } + } + + var textNode = node.nodeType == 3 ? node : null, topNode = node + if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { + textNode = node.firstChild + if (offset) { offset = textNode.nodeValue.length } + } + while (topNode.parentNode != wrapper) { topNode = topNode.parentNode } + var measure = lineView.measure, maps = measure.maps + + function find(textNode, topNode, offset) { + for (var i = -1; i < (maps ? maps.length : 0); i++) { + var map = i < 0 ? measure.map : maps[i] + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2] + if (curNode == textNode || curNode == topNode) { + var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]) + var ch = map[j] + offset + if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)] } + return Pos(line, ch) + } + } + } + } + var found = find(textNode, topNode, offset) + if (found) { return badPos(found, bad) } + + // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems + for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { + found = find(after, after.firstChild, 0) + if (found) + { return badPos(Pos(found.line, found.ch - dist), bad) } + else + { dist += after.textContent.length } + } + for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) { + found = find(before, before.firstChild, -1) + if (found) + { return badPos(Pos(found.line, found.ch + dist$1), bad) } + else + { dist$1 += before.textContent.length } + } +} + +// TEXTAREA INPUT STYLE + +var TextareaInput = function(cm) { + this.cm = cm + // See input.poll and input.reset + this.prevInput = "" + + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + this.pollingFast = false + // Self-resetting timeout for the poller + this.polling = new Delayed() + // Tracks when input.reset has punted to just putting a short + // string into the textarea instead of the full selection. + this.inaccurateSelection = false + // Used to work around IE issue with selection being forgotten when focus moves away from textarea + this.hasSelection = false + this.composing = null +}; + +TextareaInput.prototype.init = function (display) { + var this$1 = this; + + var input = this, cm = this.cm + + // Wraps and hides input textarea + var div = this.wrapper = hiddenTextarea() + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + var te = this.textarea = div.firstChild + display.wrapper.insertBefore(div, display.wrapper.firstChild) + + // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) + if (ios) { te.style.width = "0px" } + + on(te, "input", function () { + if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null } + input.poll() + }) + + on(te, "paste", function (e) { + if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } + + cm.state.pasteIncoming = true + input.fastPoll() + }) + + function prepareCopyCut(e) { + if (signalDOMEvent(cm, e)) { return } + if (cm.somethingSelected()) { + setLastCopied({lineWise: false, text: cm.getSelections()}) + if (input.inaccurateSelection) { + input.prevInput = "" + input.inaccurateSelection = false + te.value = lastCopied.text.join("\n") + selectInput(te) + } + } else if (!cm.options.lineWiseCopyCut) { + return + } else { + var ranges = copyableRanges(cm) + setLastCopied({lineWise: true, text: ranges.text}) + if (e.type == "cut") { + cm.setSelections(ranges.ranges, null, sel_dontScroll) + } else { + input.prevInput = "" + te.value = ranges.text.join("\n") + selectInput(te) + } + } + if (e.type == "cut") { cm.state.cutIncoming = true } + } + on(te, "cut", prepareCopyCut) + on(te, "copy", prepareCopyCut) + + on(display.scroller, "paste", function (e) { + if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return } + cm.state.pasteIncoming = true + input.focus() + }) + + // Prevent normal selection in the editor (we handle our own) + on(display.lineSpace, "selectstart", function (e) { + if (!eventInWidget(display, e)) { e_preventDefault(e) } + }) + + on(te, "compositionstart", function () { + var start = cm.getCursor("from") + if (input.composing) { input.composing.range.clear() } + input.composing = { + start: start, + range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) + } + }) + on(te, "compositionend", function () { + if (input.composing) { + input.poll() + input.composing.range.clear() + input.composing = null + } + }) +}; + +TextareaInput.prototype.prepareSelection = function () { + // Redraw the selection and/or cursor + var cm = this.cm, display = cm.display, doc = cm.doc + var result = prepareSelection(cm) + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, doc.sel.primary().head, "div") + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect() + result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)) + result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)) + } + + return result +}; + +TextareaInput.prototype.showSelection = function (drawn) { + var cm = this.cm, display = cm.display + removeChildrenAndAdd(display.cursorDiv, drawn.cursors) + removeChildrenAndAdd(display.selectionDiv, drawn.selection) + if (drawn.teTop != null) { + this.wrapper.style.top = drawn.teTop + "px" + this.wrapper.style.left = drawn.teLeft + "px" + } +}; + +// Reset the input to correspond to the selection (or to be empty, +// when not typing and nothing is selected) +TextareaInput.prototype.reset = function (typing) { + if (this.contextMenuPending) { return } + var minimal, selected, cm = this.cm, doc = cm.doc + if (cm.somethingSelected()) { + this.prevInput = "" + var range = doc.sel.primary() + minimal = hasCopyEvent && + (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000) + var content = minimal ? "-" : selected || cm.getSelection() + this.textarea.value = content + if (cm.state.focused) { selectInput(this.textarea) } + if (ie && ie_version >= 9) { this.hasSelection = content } + } else if (!typing) { + this.prevInput = this.textarea.value = "" + if (ie && ie_version >= 9) { this.hasSelection = null } + } + this.inaccurateSelection = minimal +}; + +TextareaInput.prototype.getField = function () { return this.textarea }; + +TextareaInput.prototype.supportsTouch = function () { return false }; + +TextareaInput.prototype.focus = function () { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { + try { this.textarea.focus() } + catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM + } +}; + +TextareaInput.prototype.blur = function () { this.textarea.blur() }; + +TextareaInput.prototype.resetPosition = function () { + this.wrapper.style.top = this.wrapper.style.left = 0 +}; + +TextareaInput.prototype.receivedFocus = function () { this.slowPoll() }; + +// Poll for input changes, using the normal rate of polling. This +// runs as long as the editor is focused. +TextareaInput.prototype.slowPoll = function () { + var this$1 = this; + + if (this.pollingFast) { return } + this.polling.set(this.cm.options.pollInterval, function () { + this$1.poll() + if (this$1.cm.state.focused) { this$1.slowPoll() } + }) +}; + +// When an event has just come in that is likely to add or change +// something in the input textarea, we poll faster, to ensure that +// the change appears on the screen quickly. +TextareaInput.prototype.fastPoll = function () { + var missed = false, input = this + input.pollingFast = true + function p() { + var changed = input.poll() + if (!changed && !missed) {missed = true; input.polling.set(60, p)} + else {input.pollingFast = false; input.slowPoll()} + } + input.polling.set(20, p) +}; + +// Read input from the textarea, and update the document to match. +// When something is selected, it is present in the textarea, and +// selected (unless it is huge, in which case a placeholder is +// used). When nothing is selected, the cursor sits after previously +// seen text (can be empty), which is stored in prevInput (we must +// not reset the textarea when typing, because that breaks IME). +TextareaInput.prototype.poll = function () { + var this$1 = this; + + var cm = this.cm, input = this.textarea, prevInput = this.prevInput + // Since this is called a *lot*, try to bail out as cheaply as + // possible when it is clear that nothing happened. hasSelection + // will be the case when there is a lot of text in the textarea, + // in which case reading its value would be expensive. + if (this.contextMenuPending || !cm.state.focused || + (hasSelection(input) && !prevInput && !this.composing) || + cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) + { return false } + + var text = input.value + // If nothing changed, bail. + if (text == prevInput && !cm.somethingSelected()) { return false } + // Work around nonsensical selection resetting in IE9/10, and + // inexplicable appearance of private area unicode characters on + // some key combos in Mac (#2689). + if (ie && ie_version >= 9 && this.hasSelection === text || + mac && /[\uf700-\uf7ff]/.test(text)) { + cm.display.input.reset() + return false + } + + if (cm.doc.sel == cm.display.selForContextMenu) { + var first = text.charCodeAt(0) + if (first == 0x200b && !prevInput) { prevInput = "\u200b" } + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") } + } + // Find the part of the input that is actually new + var same = 0, l = Math.min(prevInput.length, text.length) + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same } + + runInOp(cm, function () { + applyTextInput(cm, text.slice(same), prevInput.length - same, + null, this$1.composing ? "*compose" : null) + + // Don't leave long text in the textarea, since it makes further polling slow + if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = "" } + else { this$1.prevInput = text } + + if (this$1.composing) { + this$1.composing.range.clear() + this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"), + {className: "CodeMirror-composing"}) + } + }) + return true +}; + +TextareaInput.prototype.ensurePolled = function () { + if (this.pollingFast && this.poll()) { this.pollingFast = false } +}; + +TextareaInput.prototype.onKeyPress = function () { + if (ie && ie_version >= 9) { this.hasSelection = null } + this.fastPoll() +}; + +TextareaInput.prototype.onContextMenu = function (e) { + var input = this, cm = input.cm, display = cm.display, te = input.textarea + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop + if (!pos || presto) { return } // Opera is difficult. + + // Reset the current text selection only if the click is done outside of the selection + // and 'resetSelectionOnContextMenu' option is true. + var reset = cm.options.resetSelectionOnContextMenu + if (reset && cm.doc.sel.contains(pos) == -1) + { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll) } + + var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText + input.wrapper.style.cssText = "position: absolute" + var wrapperBox = input.wrapper.getBoundingClientRect() + te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);" + var oldScrollY + if (webkit) { oldScrollY = window.scrollY } // Work around Chrome issue (#2712) + display.input.focus() + if (webkit) { window.scrollTo(null, oldScrollY) } + display.input.reset() + // Adds "Select all" to context menu in FF + if (!cm.somethingSelected()) { te.value = input.prevInput = " " } + input.contextMenuPending = true + display.selForContextMenu = cm.doc.sel + clearTimeout(display.detectingSelectAll) + + // Select-all will be greyed out if there's nothing to select, so + // this adds a zero-width space so that we can later check whether + // it got selected. + function prepareSelectAllHack() { + if (te.selectionStart != null) { + var selected = cm.somethingSelected() + var extval = "\u200b" + (selected ? te.value : "") + te.value = "\u21da" // Used to catch context-menu undo + te.value = extval + input.prevInput = selected ? "" : "\u200b" + te.selectionStart = 1; te.selectionEnd = extval.length + // Re-set this, in case some other handler touched the + // selection in the meantime. + display.selForContextMenu = cm.doc.sel + } + } + function rehide() { + input.contextMenuPending = false + input.wrapper.style.cssText = oldWrapperCSS + te.style.cssText = oldCSS + if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos) } + + // Try to detect the user choosing select-all + if (te.selectionStart != null) { + if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack() } + var i = 0, poll = function () { + if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && + te.selectionEnd > 0 && input.prevInput == "\u200b") { + operation(cm, selectAll)(cm) + } else if (i++ < 10) { + display.detectingSelectAll = setTimeout(poll, 500) + } else { + display.selForContextMenu = null + display.input.reset() + } + } + display.detectingSelectAll = setTimeout(poll, 200) + } + } + + if (ie && ie_version >= 9) { prepareSelectAllHack() } + if (captureRightClick) { + e_stop(e) + var mouseup = function () { + off(window, "mouseup", mouseup) + setTimeout(rehide, 20) + } + on(window, "mouseup", mouseup) + } else { + setTimeout(rehide, 50) + } +}; + +TextareaInput.prototype.readOnlyChanged = function (val) { + if (!val) { this.reset() } +}; + +TextareaInput.prototype.setUneditable = function () {}; + +TextareaInput.prototype.needsContentAttribute = false + +function fromTextArea(textarea, options) { + options = options ? copyObj(options) : {} + options.value = textarea.value + if (!options.tabindex && textarea.tabIndex) + { options.tabindex = textarea.tabIndex } + if (!options.placeholder && textarea.placeholder) + { options.placeholder = textarea.placeholder } + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = activeElt() + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body + } + + function save() {textarea.value = cm.getValue()} + + var realSubmit + if (textarea.form) { + on(textarea.form, "submit", save) + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form + realSubmit = form.submit + try { + var wrappedSubmit = form.submit = function () { + save() + form.submit = realSubmit + form.submit() + form.submit = wrappedSubmit + } + } catch(e) {} + } + } + + options.finishInit = function (cm) { + cm.save = save + cm.getTextArea = function () { return textarea; } + cm.toTextArea = function () { + cm.toTextArea = isNaN // Prevent this from being ran twice + save() + textarea.parentNode.removeChild(cm.getWrapperElement()) + textarea.style.display = "" + if (textarea.form) { + off(textarea.form, "submit", save) + if (typeof textarea.form.submit == "function") + { textarea.form.submit = realSubmit } + } + } + } + + textarea.style.display = "none" + var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); }, + options) + return cm +} + +function addLegacyProps(CodeMirror) { + CodeMirror.off = off + CodeMirror.on = on + CodeMirror.wheelEventPixels = wheelEventPixels + CodeMirror.Doc = Doc + CodeMirror.splitLines = splitLinesAuto + CodeMirror.countColumn = countColumn + CodeMirror.findColumn = findColumn + CodeMirror.isWordChar = isWordCharBasic + CodeMirror.Pass = Pass + CodeMirror.signal = signal + CodeMirror.Line = Line + CodeMirror.changeEnd = changeEnd + CodeMirror.scrollbarModel = scrollbarModel + CodeMirror.Pos = Pos + CodeMirror.cmpPos = cmp + CodeMirror.modes = modes + CodeMirror.mimeModes = mimeModes + CodeMirror.resolveMode = resolveMode + CodeMirror.getMode = getMode + CodeMirror.modeExtensions = modeExtensions + CodeMirror.extendMode = extendMode + CodeMirror.copyState = copyState + CodeMirror.startState = startState + CodeMirror.innerMode = innerMode + CodeMirror.commands = commands + CodeMirror.keyMap = keyMap + CodeMirror.keyName = keyName + CodeMirror.isModifierKey = isModifierKey + CodeMirror.lookupKey = lookupKey + CodeMirror.normalizeKeyMap = normalizeKeyMap + CodeMirror.StringStream = StringStream + CodeMirror.SharedTextMarker = SharedTextMarker + CodeMirror.TextMarker = TextMarker + CodeMirror.LineWidget = LineWidget + CodeMirror.e_preventDefault = e_preventDefault + CodeMirror.e_stopPropagation = e_stopPropagation + CodeMirror.e_stop = e_stop + CodeMirror.addClass = addClass + CodeMirror.contains = contains + CodeMirror.rmClass = rmClass + CodeMirror.keyNames = keyNames +} + +// EDITOR CONSTRUCTOR + +defineOptions(CodeMirror) + +addEditorMethods(CodeMirror) + +// Set up methods on CodeMirror's prototype to redirect to the editor's document. +var dontDelegate = "iter insert remove copy getEditor constructor".split(" ") +for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + { CodeMirror.prototype[prop] = (function(method) { + return function() {return method.apply(this.doc, arguments)} + })(Doc.prototype[prop]) } } + +eventMixin(Doc) + +// INPUT HANDLING + +CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput} + +// MODE DEFINITION AND QUERYING + +// Extra arguments are stored as the mode's dependencies, which is +// used by (legacy) mechanisms like loadmode.js to automatically +// load a mode. (Preferred mechanism is the require/define calls.) +CodeMirror.defineMode = function(name/*, mode, …*/) { + if (!CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode = name } + defineMode.apply(this, arguments) +} + +CodeMirror.defineMIME = defineMIME + +// Minimal default mode. +CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); }) +CodeMirror.defineMIME("text/plain", "null") + +// EXTENSIONS + +CodeMirror.defineExtension = function (name, func) { + CodeMirror.prototype[name] = func +} +CodeMirror.defineDocExtension = function (name, func) { + Doc.prototype[name] = func +} + +CodeMirror.fromTextArea = fromTextArea + +addLegacyProps(CodeMirror) + +CodeMirror.version = "5.25.0" + +return CodeMirror; + +}))); \ No newline at end of file diff --git a/public/react/public/js/codemirror/lib/fuzzysort.js b/public/react/public/js/codemirror/lib/fuzzysort.js new file mode 100755 index 000000000..18e197c47 --- /dev/null +++ b/public/react/public/js/codemirror/lib/fuzzysort.js @@ -0,0 +1,603 @@ +/* +WHAT: SublimeText-like Fuzzy Search +USAGE: + fuzzysort.single('fs', 'Fuzzy Search') // {score: -16} + fuzzysort.single('test', 'test') // {score: 0} + fuzzysort.single('doesnt exist', 'target') // null + fuzzysort.go('mr', ['Monitor.cpp', 'MeshRenderer.cpp']) + // [{score: -18, target: "MeshRenderer.cpp"}, {score: -6009, target: "Monitor.cpp"}] + fuzzysort.highlight(fuzzysort.single('fs', 'Fuzzy Search'), '', '') + // Fuzzy Search + + https://github.com/farzher/fuzzysort +*/ + +// UMD (Universal Module Definition) for fuzzysort +;(function(root, UMD) { + if(typeof define === 'function' && define.amd) define([], UMD) + else if(typeof module === 'object' && module.exports) module.exports = UMD() + else root.fuzzysort = UMD() +})(this, function UMD() { function fuzzysortNew(instanceOptions) { + + var fuzzysort = { + + single: function(search, target, options) { + if(!search) return null + if(!isObj(search)) search = fuzzysort.getPreparedSearch(search) + + if(!target) return null + if(!isObj(target)) target = fuzzysort.getPrepared(target) + + var allowTypo = options && options.allowTypo!==undefined ? options.allowTypo + : instanceOptions && instanceOptions.allowTypo!==undefined ? instanceOptions.allowTypo + : true + var algorithm = allowTypo ? fuzzysort.algorithm : fuzzysort.algorithmNoTypo + return algorithm(search, target, search[0]) + // var threshold = options && options.threshold || instanceOptions && instanceOptions.threshold || -9007199254740991 + // var result = algorithm(search, target, search[0]) + // if(result === null) return null + // if(result.score < threshold) return null + // return result + }, + + go: function(search, targets, options) { + if(!search) return noResults + search = fuzzysort.prepareSearch(search) + var searchLowerCode = search[0] + + var threshold = options && options.threshold || instanceOptions && instanceOptions.threshold || -9007199254740991 + var limit = options && options.limit || instanceOptions && instanceOptions.limit || 9007199254740991 + var allowTypo = options && options.allowTypo!==undefined ? options.allowTypo + : instanceOptions && instanceOptions.allowTypo!==undefined ? instanceOptions.allowTypo + : true + var algorithm = allowTypo ? fuzzysort.algorithm : fuzzysort.algorithmNoTypo + var resultsLen = 0; var limitedCount = 0 + var targetsLen = targets.length + + // This code is copy/pasted 3 times for performance reasons [options.keys, options.key, no keys] + + // options.keys + if(options && options.keys) { + var scoreFn = options.scoreFn || defaultScoreFn + var keys = options.keys + var keysLen = keys.length + for(var i = targetsLen - 1; i >= 0; --i) { var obj = targets[i] + var objResults = new Array(keysLen) + for (var keyI = keysLen - 1; keyI >= 0; --keyI) { + var key = keys[keyI] + var target = getValue(obj, key) + if(!target) { objResults[keyI] = null; continue } + if(!isObj(target)) target = fuzzysort.getPrepared(target) + + objResults[keyI] = algorithm(search, target, searchLowerCode) + } + objResults.obj = obj // before scoreFn so scoreFn can use it + var score = scoreFn(objResults) + if(score === null) continue + if(score < threshold) continue + objResults.score = score + if(resultsLen < limit) { q.add(objResults); ++resultsLen } + else { + ++limitedCount + if(score > q.peek().score) q.replaceTop(objResults) + } + } + + // options.key + } else if(options && options.key) { + var key = options.key + for(var i = targetsLen - 1; i >= 0; --i) { var obj = targets[i] + var target = getValue(obj, key) + if(!target) continue + if(!isObj(target)) target = fuzzysort.getPrepared(target) + + var result = algorithm(search, target, searchLowerCode) + if(result === null) continue + if(result.score < threshold) continue + + // have to clone result so duplicate targets from different obj can each reference the correct obj + result = {target:result.target, _targetLowerCodes:null, _nextBeginningIndexes:null, score:result.score, indexes:result.indexes, obj:obj} // hidden + + if(resultsLen < limit) { q.add(result); ++resultsLen } + else { + ++limitedCount + if(result.score > q.peek().score) q.replaceTop(result) + } + } + + // no keys + } else { + for(var i = targetsLen - 1; i >= 0; --i) { var target = targets[i] + if(!target) continue + if(!isObj(target)) target = fuzzysort.getPrepared(target) + + var result = algorithm(search, target, searchLowerCode) + if(result === null) continue + if(result.score < threshold) continue + if(resultsLen < limit) { q.add(result); ++resultsLen } + else { + ++limitedCount + if(result.score > q.peek().score) q.replaceTop(result) + } + } + } + + if(resultsLen === 0) return noResults + var results = new Array(resultsLen) + for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll() + results.total = resultsLen + limitedCount + return results + }, + + goAsync: function(search, targets, options) { + var canceled = false + var p = new Promise(function(resolve, reject) { + if(!search) return resolve(noResults) + search = fuzzysort.prepareSearch(search) + var searchLowerCode = search[0] + + var q = fastpriorityqueue() + var iCurrent = targets.length - 1 + var threshold = options && options.threshold || instanceOptions && instanceOptions.threshold || -9007199254740991 + var limit = options && options.limit || instanceOptions && instanceOptions.limit || 9007199254740991 + var allowTypo = options && options.allowTypo!==undefined ? options.allowTypo + : instanceOptions && instanceOptions.allowTypo!==undefined ? instanceOptions.allowTypo + : true + var algorithm = allowTypo ? fuzzysort.algorithm : fuzzysort.algorithmNoTypo + var resultsLen = 0; var limitedCount = 0 + function step() { + if(canceled) return reject('canceled') + + var startMs = Date.now() + + // This code is copy/pasted 3 times for performance reasons [options.keys, options.key, no keys] + + // options.keys + if(options && options.keys) { + var scoreFn = options.scoreFn || defaultScoreFn + var keys = options.keys + var keysLen = keys.length + for(; iCurrent >= 0; --iCurrent) { var obj = targets[iCurrent] + var objResults = new Array(keysLen) + for (var keyI = keysLen - 1; keyI >= 0; --keyI) { + var key = keys[keyI] + var target = getValue(obj, key) + if(!target) { objResults[keyI] = null; continue } + if(!isObj(target)) target = fuzzysort.getPrepared(target) + + objResults[keyI] = algorithm(search, target, searchLowerCode) + } + objResults.obj = obj // before scoreFn so scoreFn can use it + var score = scoreFn(objResults) + if(score === null) continue + if(score < threshold) continue + objResults.score = score + if(resultsLen < limit) { q.add(objResults); ++resultsLen } + else { + ++limitedCount + if(score > q.peek().score) q.replaceTop(objResults) + } + + if(iCurrent%1000/*itemsPerCheck*/ === 0) { + if(Date.now() - startMs >= 10/*asyncInterval*/) { + isNode?setImmediate(step):setTimeout(step) + return + } + } + } + + // options.key + } else if(options && options.key) { + var key = options.key + for(; iCurrent >= 0; --iCurrent) { var obj = targets[iCurrent] + var target = getValue(obj, key) + if(!target) continue + if(!isObj(target)) target = fuzzysort.getPrepared(target) + + var result = algorithm(search, target, searchLowerCode) + if(result === null) continue + if(result.score < threshold) continue + + // have to clone result so duplicate targets from different obj can each reference the correct obj + result = {target:result.target, _targetLowerCodes:null, _nextBeginningIndexes:null, score:result.score, indexes:result.indexes, obj:obj} // hidden + + if(resultsLen < limit) { q.add(result); ++resultsLen } + else { + ++limitedCount + if(result.score > q.peek().score) q.replaceTop(result) + } + + if(iCurrent%1000/*itemsPerCheck*/ === 0) { + if(Date.now() - startMs >= 10/*asyncInterval*/) { + isNode?setImmediate(step):setTimeout(step) + return + } + } + } + + // no keys + } else { + for(; iCurrent >= 0; --iCurrent) { var target = targets[iCurrent] + if(!target) continue + if(!isObj(target)) target = fuzzysort.getPrepared(target) + + var result = algorithm(search, target, searchLowerCode) + if(result === null) continue + if(result.score < threshold) continue + if(resultsLen < limit) { q.add(result); ++resultsLen } + else { + ++limitedCount + if(result.score > q.peek().score) q.replaceTop(result) + } + + if(iCurrent%1000/*itemsPerCheck*/ === 0) { + if(Date.now() - startMs >= 10/*asyncInterval*/) { + isNode?setImmediate(step):setTimeout(step) + return + } + } + } + } + + if(resultsLen === 0) return resolve(noResults) + var results = new Array(resultsLen) + for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll() + results.total = resultsLen + limitedCount + resolve(results) + } + + isNode?setImmediate(step):step() + }) + p.cancel = function() { canceled = true } + return p + }, + + highlight: function(result, hOpen, hClose) { + if(result === null) return null + if(hOpen === undefined) hOpen = '' + if(hClose === undefined) hClose = '' + var highlighted = '' + var matchesIndex = 0 + var opened = false + var target = result.target + var targetLen = target.length + var matchesBest = result.indexes + for(var i = 0; i < targetLen; ++i) { var char = target[i] + if(matchesBest[matchesIndex] === i) { + ++matchesIndex + if(!opened) { opened = true + highlighted += hOpen + } + + if(matchesIndex === matchesBest.length) { + highlighted += char + hClose + target.substr(i+1) + break + } + } else { + if(opened) { opened = false + highlighted += hClose + } + } + highlighted += char + } + + return highlighted + }, + + prepare: function(target) { + if(!target) return + return {target:target, _targetLowerCodes:fuzzysort.prepareLowerCodes(target), _nextBeginningIndexes:null, score:null, indexes:null, obj:null} // hidden + }, + prepareSlow: function(target) { + if(!target) return + return {target:target, _targetLowerCodes:fuzzysort.prepareLowerCodes(target), _nextBeginningIndexes:fuzzysort.prepareNextBeginningIndexes(target), score:null, indexes:null, obj:null} // hidden + }, + prepareSearch: function(search) { + if(!search) return + return fuzzysort.prepareLowerCodes(search) + }, + + + + // Below this point is only internal code + // Below this point is only internal code + // Below this point is only internal code + // Below this point is only internal code + + + + getPrepared: function(target) { + if(target.length > 999) return fuzzysort.prepare(target) // don't cache huge targets + var targetPrepared = preparedCache.get(target) + if(targetPrepared !== undefined) return targetPrepared + targetPrepared = fuzzysort.prepare(target) + preparedCache.set(target, targetPrepared) + return targetPrepared + }, + getPreparedSearch: function(search) { + if(search.length > 999) return fuzzysort.prepareSearch(search) // don't cache huge searches + var searchPrepared = preparedSearchCache.get(search) + if(searchPrepared !== undefined) return searchPrepared + searchPrepared = fuzzysort.prepareSearch(search) + preparedSearchCache.set(search, searchPrepared) + return searchPrepared + }, + + algorithm: function(searchLowerCodes, prepared, searchLowerCode) { + var targetLowerCodes = prepared._targetLowerCodes + var searchLen = searchLowerCodes.length + var targetLen = targetLowerCodes.length + var searchI = 0 // where we at + var targetI = 0 // where you at + var typoSimpleI = 0 + var matchesSimpleLen = 0 + + // very basic fuzzy match; to remove non-matching targets ASAP! + // walk through target. find sequential matches. + // if all chars aren't found then exit + for(;;) { + var isMatch = searchLowerCode === targetLowerCodes[targetI] + if(isMatch) { + matchesSimple[matchesSimpleLen++] = targetI + ++searchI; if(searchI === searchLen) break + searchLowerCode = searchLowerCodes[typoSimpleI===0?searchI : (typoSimpleI===searchI?searchI+1 : (typoSimpleI===searchI-1?searchI-1 : searchI))] + } + + ++targetI; if(targetI >= targetLen) { // Failed to find searchI + // Check for typo or exit + // we go as far as possible before trying to transpose + // then we transpose backwards until we reach the beginning + for(;;) { + if(searchI <= 1) return null // not allowed to transpose first char + if(typoSimpleI === 0) { // we haven't tried to transpose yet + --searchI + var searchLowerCodeNew = searchLowerCodes[searchI] + if(searchLowerCode === searchLowerCodeNew) continue // doesn't make sense to transpose a repeat char + typoSimpleI = searchI + } else { + if(typoSimpleI === 1) return null // reached the end of the line for transposing + --typoSimpleI + searchI = typoSimpleI + searchLowerCode = searchLowerCodes[searchI + 1] + var searchLowerCodeNew = searchLowerCodes[searchI] + if(searchLowerCode === searchLowerCodeNew) continue // doesn't make sense to transpose a repeat char + } + matchesSimpleLen = searchI + targetI = matchesSimple[matchesSimpleLen - 1] + 1 + break + } + } + } + + var searchI = 0 + var typoStrictI = 0 + var successStrict = false + var matchesStrictLen = 0 + + var nextBeginningIndexes = prepared._nextBeginningIndexes + if(nextBeginningIndexes === null) nextBeginningIndexes = prepared._nextBeginningIndexes = fuzzysort.prepareNextBeginningIndexes(prepared.target) + var firstPossibleI = targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1] + + // Our target string successfully matched all characters in sequence! + // Let's try a more advanced and strict test to improve the score + // only count it as a match if it's consecutive or a beginning character! + if(targetI !== targetLen) for(;;) { + if(targetI >= targetLen) { + // We failed to find a good spot for this search char, go back to the previous search char and force it forward + if(searchI <= 0) { // We failed to push chars forward for a better match + // transpose, starting from the beginning + ++typoStrictI; if(typoStrictI > searchLen-2) break + if(searchLowerCodes[typoStrictI] === searchLowerCodes[typoStrictI+1]) continue // doesn't make sense to transpose a repeat char + targetI = firstPossibleI + continue + } + + --searchI + var lastMatch = matchesStrict[--matchesStrictLen] + targetI = nextBeginningIndexes[lastMatch] + + } else { + var isMatch = searchLowerCodes[typoStrictI===0?searchI : (typoStrictI===searchI?searchI+1 : (typoStrictI===searchI-1?searchI-1 : searchI))] === targetLowerCodes[targetI] + if(isMatch) { + matchesStrict[matchesStrictLen++] = targetI + ++searchI; if(searchI === searchLen) { successStrict = true; break } + ++targetI + } else { + targetI = nextBeginningIndexes[targetI] + } + } + } + + { // tally up the score & keep track of matches for highlighting later + if(successStrict) { var matchesBest = matchesStrict; var matchesBestLen = matchesStrictLen } + else { var matchesBest = matchesSimple; var matchesBestLen = matchesSimpleLen } + var score = 0 + var lastTargetI = -1 + for(var i = 0; i < searchLen; ++i) { var targetI = matchesBest[i] + // score only goes down if they're not consecutive + if(lastTargetI !== targetI - 1) score -= targetI + lastTargetI = targetI + } + if(!successStrict) { + score *= 1000 + if(typoSimpleI !== 0) score += -20/*typoPenalty*/ + } else { + if(typoStrictI !== 0) score += -20/*typoPenalty*/ + } + score -= targetLen - searchLen + prepared.score = score + prepared.indexes = new Array(matchesBestLen); for(var i = matchesBestLen - 1; i >= 0; --i) prepared.indexes[i] = matchesBest[i] + + return prepared + } + }, + + algorithmNoTypo: function(searchLowerCodes, prepared, searchLowerCode) { + var targetLowerCodes = prepared._targetLowerCodes + var searchLen = searchLowerCodes.length + var targetLen = targetLowerCodes.length + var searchI = 0 // where we at + var targetI = 0 // where you at + var matchesSimpleLen = 0 + + // very basic fuzzy match; to remove non-matching targets ASAP! + // walk through target. find sequential matches. + // if all chars aren't found then exit + for(;;) { + var isMatch = searchLowerCode === targetLowerCodes[targetI] + if(isMatch) { + matchesSimple[matchesSimpleLen++] = targetI + ++searchI; if(searchI === searchLen) break + searchLowerCode = searchLowerCodes[searchI] + } + ++targetI; if(targetI >= targetLen) return null // Failed to find searchI + } + + var searchI = 0 + var successStrict = false + var matchesStrictLen = 0 + + var nextBeginningIndexes = prepared._nextBeginningIndexes + if(nextBeginningIndexes === null) nextBeginningIndexes = prepared._nextBeginningIndexes = fuzzysort.prepareNextBeginningIndexes(prepared.target) + var firstPossibleI = targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1] + + // Our target string successfully matched all characters in sequence! + // Let's try a more advanced and strict test to improve the score + // only count it as a match if it's consecutive or a beginning character! + if(targetI !== targetLen) for(;;) { + if(targetI >= targetLen) { + // We failed to find a good spot for this search char, go back to the previous search char and force it forward + if(searchI <= 0) break // We failed to push chars forward for a better match + + --searchI + var lastMatch = matchesStrict[--matchesStrictLen] + targetI = nextBeginningIndexes[lastMatch] + + } else { + var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI] + if(isMatch) { + matchesStrict[matchesStrictLen++] = targetI + ++searchI; if(searchI === searchLen) { successStrict = true; break } + ++targetI + } else { + targetI = nextBeginningIndexes[targetI] + } + } + } + + { // tally up the score & keep track of matches for highlighting later + if(successStrict) { var matchesBest = matchesStrict; var matchesBestLen = matchesStrictLen } + else { var matchesBest = matchesSimple; var matchesBestLen = matchesSimpleLen } + var score = 0 + var lastTargetI = -1 + for(var i = 0; i < searchLen; ++i) { var targetI = matchesBest[i] + // score only goes down if they're not consecutive + if(lastTargetI !== targetI - 1) score -= targetI + lastTargetI = targetI + } + if(!successStrict) score *= 1000 + score -= targetLen - searchLen + prepared.score = score + prepared.indexes = new Array(matchesBestLen); for(var i = matchesBestLen - 1; i >= 0; --i) prepared.indexes[i] = matchesBest[i] + + return prepared + } + }, + + prepareLowerCodes: function(str) { + var strLen = str.length + var lowerCodes = [] // new Array(strLen) sparse array is too slow + var lower = str.toLowerCase() + for(var i = 0; i < strLen; ++i) lowerCodes[i] = lower.charCodeAt(i) + return lowerCodes + }, + prepareBeginningIndexes: function(target) { + var targetLen = target.length + var beginningIndexes = []; var beginningIndexesLen = 0 + var wasUpper = false + var wasAlphanum = false + for(var i = 0; i < targetLen; ++i) { + var targetCode = target.charCodeAt(i) + var isUpper = targetCode>=65&&targetCode<=90 + var isAlphanum = isUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57 + var isBeginning = isUpper && !wasUpper || !wasAlphanum || !isAlphanum + wasUpper = isUpper + wasAlphanum = isAlphanum + if(isBeginning) beginningIndexes[beginningIndexesLen++] = i + } + return beginningIndexes + }, + prepareNextBeginningIndexes: function(target) { + var targetLen = target.length + var beginningIndexes = fuzzysort.prepareBeginningIndexes(target) + var nextBeginningIndexes = [] // new Array(targetLen) sparse array is too slow + var lastIsBeginning = beginningIndexes[0] + var lastIsBeginningI = 0 + for(var i = 0; i < targetLen; ++i) { + if(lastIsBeginning > i) { + nextBeginningIndexes[i] = lastIsBeginning + } else { + lastIsBeginning = beginningIndexes[++lastIsBeginningI] + nextBeginningIndexes[i] = lastIsBeginning===undefined ? targetLen : lastIsBeginning + } + } + return nextBeginningIndexes + }, + + cleanup: cleanup, + new: fuzzysortNew, + } + return fuzzysort +} // fuzzysortNew + +// This stuff is outside fuzzysortNew, because it's shared with instances of fuzzysort.new() +var isNode = typeof require !== 'undefined' && typeof window === 'undefined' +// var MAX_INT = Number.MAX_SAFE_INTEGER +// var MIN_INT = Number.MIN_VALUE +var preparedCache = new Map() +var preparedSearchCache = new Map() +var noResults = []; noResults.total = 0 +var matchesSimple = []; var matchesStrict = [] +function cleanup() { preparedCache.clear(); preparedSearchCache.clear(); matchesSimple = []; matchesStrict = [] } +function defaultScoreFn(a) { + var max = -9007199254740991 + for (var i = a.length - 1; i >= 0; --i) { + var result = a[i]; if(result === null) continue + var score = result.score + if(score > max) max = score + } + if(max === -9007199254740991) return null + return max +} + +// prop = 'key' 2.5ms optimized for this case, seems to be about as fast as direct obj[prop] +// prop = 'key1.key2' 10ms +// prop = ['key1', 'key2'] 27ms +function getValue(obj, prop) { + var tmp = obj[prop]; if(tmp !== undefined) return tmp + var segs = prop + if(!Array.isArray(prop)) segs = prop.split('.') + var len = segs.length + var i = -1 + while (obj && (++i < len)) obj = obj[segs[i]] + return obj +} + +function isObj(x) { return typeof x === 'object' } // faster as a function + +// Hacked version of https://github.com/lemire/FastPriorityQueue.js +var fastpriorityqueue=function(){var r=[],o=0,e={};function n(){for(var e=0,n=r[e],c=1;c>1]=r[e],c=1+(e<<1)}for(var a=e-1>>1;e>0&&n.score>1)r[e]=r[a];r[e]=n}return e.add=function(e){var n=o;r[o++]=e;for(var c=n-1>>1;n>0&&e.score>1)r[n]=r[c];r[n]=e},e.poll=function(){if(0!==o){var e=r[0];return r[0]=r[--o],n(),e}},e.peek=function(e){if(0!==o)return r[0]},e.replaceTop=function(o){r[0]=o,n()},e}; +var q = fastpriorityqueue() // reuse this, except for async, it needs to make its own + +return fuzzysortNew() +}) // UMD + +// TODO: (performance) wasm version!? + +// TODO: (performance) layout memory in an optimal way to go fast by avoiding cache misses + +// TODO: (performance) preparedCache is a memory leak + +// TODO: (like sublime) backslash === forwardslash + +// TODO: (performance) i have no idea how well optizmied the allowing typos algorithm is \ No newline at end of file diff --git a/public/react/public/js/codemirror/merge/merge.css b/public/react/public/js/codemirror/merge/merge.css new file mode 100755 index 000000000..b6d923ced --- /dev/null +++ b/public/react/public/js/codemirror/merge/merge.css @@ -0,0 +1,111 @@ + +.CodeMirror-merge { + position: relative; + white-space: pre; +} + +.CodeMirror-merge, .CodeMirror-merge .CodeMirror { + min-height:50px; +} + +.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 48%; } +.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 4%; } +.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } +.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } + +.CodeMirror-merge-pane { + display: inline-block; + white-space: normal; + vertical-align: top; +} +.CodeMirror-merge-pane-rightmost { + position: absolute; + right: 0px; + z-index: 1; +} + +.CodeMirror-merge-gap { + z-index: 2; + display: inline-block; + height: 100%; + -moz-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; + position: relative; + background: #515151; +} + +.CodeMirror-merge-scrolllock-wrap { + position: absolute; + bottom: 0; left: 50%; +} +.CodeMirror-merge-scrolllock { + position: relative; + left: -50%; + cursor: pointer; + color: #d8d8d8; + line-height: 1; +} + +.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { + position: absolute; + left: 0; top: 0; + right: 0; bottom: 0; + line-height: 1; +} + +.CodeMirror-merge-copy { + position: absolute; + cursor: pointer; + color: #ce374b; + z-index: 3; +} + +.CodeMirror-merge-copy-reverse { + position: absolute; + cursor: pointer; + color: #44c; +} + +.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } +.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } + +.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-chunk { background: #9a6868; } +.CodeMirror-merge-r-chunk-start { /*border-top: 1px solid #ee8; */} +.CodeMirror-merge-r-chunk-end {/* border-bottom: 1px solid #ee8; */} +.CodeMirror-merge-r-connect { fill:#9a6868;} + +.CodeMirror-merge-l-chunk { background: #eef; } +.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } +.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } +.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } + +.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } +.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } +.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } + +.CodeMirror-merge-collapsed-widget:before { + content: "(...)"; +} +.CodeMirror-merge-collapsed-widget { + cursor: pointer; + color: #88b; + background: #eef; + border: 1px solid #ddf; + font-size: 90%; + padding: 0 3px; + border-radius: 4px; +} +.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; } diff --git a/public/react/public/js/codemirror/merge/merge.js b/public/react/public/js/codemirror/merge/merge.js new file mode 100755 index 000000000..25b44e513 --- /dev/null +++ b/public/react/public/js/codemirror/merge/merge.js @@ -0,0 +1,1040 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); // Note non-packaged dependency diff_match_patch + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "diff_match_patch"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var Pos = CodeMirror.Pos; + var svgNS = "http://www.w3.org/2000/svg"; + + var value, orig1, orig2, dv, panes = 2, highlight = true, connect = null, collapse = false; + CodeMirror.k_init=function(id,newData,oldData){ + value=oldData;//左侧 老文件 + orig1 = ''; + orig2=newData;//右侧 新文件 + var dv = initUI(); + + // 滚轮按钮被注释了---- (setScrollLock) + function initUI() { + if (value == null) return; + var target = document.getElementById(id); + target.innerHTML = ""; + dv = CodeMirror.MergeView(target, { + value: value, + origLeft: panes == 3 && !collapse && !connect ? orig1 : null, + orig: orig2, + lineNumbers: true, //行号 + mode: "text/html", + theme:'blackboard',//修改主题 + //styleActiveLine: true, + matchBrackets: true, + highlightDifferences: highlight, + connect: connect, + collapseIdentical: collapse, + readOnly: "nocursor", + revertButtons:true//事件比较替换 + }); + console.log(dv.edit); + return dv + } + return dv; + }; + + function DiffView(mv, type) { + this.mv = mv; + this.type = type; + this.classes = type == "left" + ? {chunk: "CodeMirror-merge-l-chunk", + start: "CodeMirror-merge-l-chunk-start", + end: "CodeMirror-merge-l-chunk-end", + insert: "CodeMirror-merge-l-inserted", + del: "CodeMirror-merge-l-deleted", + connect: "CodeMirror-merge-l-connect"} + : {chunk: "CodeMirror-merge-r-chunk", + start: "CodeMirror-merge-r-chunk-start", + end: "CodeMirror-merge-r-chunk-end", + insert: "CodeMirror-merge-r-inserted", + del: "CodeMirror-merge-r-deleted", + connect: "CodeMirror-merge-r-connect"}; + } + + DiffView.prototype = { + constructor: DiffView, + init: function(pane, orig, options) { + this.edit = this.mv.edit; + ;(this.edit.state.diffViews || (this.edit.state.diffViews = [])).push(this); + this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options))); + if (this.mv.options.connect == "align") { + if (!this.edit.state.trackAlignable) this.edit.state.trackAlignable = new TrackAlignable(this.edit) + this.orig.state.trackAlignable = new TrackAlignable(this.orig) + } + + this.orig.state.diffViews = [this]; + var classLocation = options.chunkClassLocation || "background"; + if (Object.prototype.toString.call(classLocation) != "[object Array]") classLocation = [classLocation] + this.classes.classLocation = classLocation + + this.diff = getDiff(asString(orig), asString(options.value), this.mv.options.ignoreWhitespace); + this.chunks = getChunks(this.diff); + this.diffOutOfDate = this.dealigned = false; + this.needsScrollSync = null + + this.showDifferences = options.showDifferences !== false; + }, + registerEvents: function(otherDv) { + this.forceUpdate = registerUpdate(this); + setScrollLock(this, true, false); + registerScroll(this, otherDv); + }, + setShowDifferences: function(val) { + val = val !== false; + if (val != this.showDifferences) { + this.showDifferences = val; + this.forceUpdate("full"); + } + } + }; + + function ensureDiff(dv) { + if (dv.diffOutOfDate) { + dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue(), dv.mv.options.ignoreWhitespace); + dv.chunks = getChunks(dv.diff); + dv.diffOutOfDate = false; + CodeMirror.signal(dv.edit, "updateDiff", dv.diff); + } + } + + var updating = false; + function registerUpdate(dv) { + var edit = {from: 0, to: 0, marked: []}; + var orig = {from: 0, to: 0, marked: []}; + var debounceChange, updatingFast = false; + function update(mode) { + updating = true; + updatingFast = false; + if (mode == "full") { + if (dv.svg) clear(dv.svg); + if (dv.copyButtons) clear(dv.copyButtons); + clearMarks(dv.edit, edit.marked, dv.classes); + clearMarks(dv.orig, orig.marked, dv.classes); + edit.from = edit.to = orig.from = orig.to = 0; + } + ensureDiff(dv); + if (dv.showDifferences) { + updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); + updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); + } + + if (dv.mv.options.connect == "align") + alignChunks(dv); + makeConnections(dv); + if (dv.needsScrollSync != null) syncScroll(dv, dv.needsScrollSync) + + updating = false; + } + function setDealign(fast) { + if (updating) return; + dv.dealigned = true; + set(fast); + } + function set(fast) { + if (updating || updatingFast) return; + clearTimeout(debounceChange); + if (fast === true) updatingFast = true; + debounceChange = setTimeout(update, fast === true ? 20 : 250); + } + function change(_cm, change) { + if (!dv.diffOutOfDate) { + dv.diffOutOfDate = true; + edit.from = edit.to = orig.from = orig.to = 0; + } + // Update faster when a line was added/removed + setDealign(change.text.length - 1 != change.to.line - change.from.line); + } + function swapDoc() { + dv.diffOutOfDate = true; + dv.dealigned = true; + update("full"); + } + dv.edit.on("change", change); + dv.orig.on("change", change); + dv.edit.on("swapDoc", swapDoc); + dv.orig.on("swapDoc", swapDoc); + if (dv.mv.options.connect == "align") { + CodeMirror.on(dv.edit.state.trackAlignable, "realign", setDealign) + CodeMirror.on(dv.orig.state.trackAlignable, "realign", setDealign) + } + dv.edit.on("viewportChange", function() { set(false); }); + dv.orig.on("viewportChange", function() { set(false); }); + update(); + return update; + } + + function registerScroll(dv, otherDv) { + dv.edit.on("scroll", function() { + syncScroll(dv, true) && makeConnections(dv); + }); + dv.orig.on("scroll", function() { + syncScroll(dv, false) && makeConnections(dv); + if (otherDv) syncScroll(otherDv, true) && makeConnections(otherDv); + }); + } + + function syncScroll(dv, toOrig) { + // Change handler will do a refresh after a timeout when diff is out of date + if (dv.diffOutOfDate) { + if (dv.lockScroll && dv.needsScrollSync == null) dv.needsScrollSync = toOrig + return false + } + dv.needsScrollSync = null + if (!dv.lockScroll) return true; + var editor, other, now = +new Date; + if (toOrig) { editor = dv.edit; other = dv.orig; } + else { editor = dv.orig; other = dv.edit; } + // Don't take action if the position of this editor was recently set + // (to prevent feedback loops) + if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 250 > now) return false; + + var sInfo = editor.getScrollInfo(); + if (dv.mv.options.connect == "align") { + targetPos = sInfo.top; + } else { + var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen; + var mid = editor.lineAtHeight(midY, "local"); + var around = chunkBoundariesAround(dv.chunks, mid, toOrig); + var off = getOffsets(editor, toOrig ? around.edit : around.orig); + var offOther = getOffsets(other, toOrig ? around.orig : around.edit); + var ratio = (midY - off.top) / (off.bot - off.top); + var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top); + + var botDist, mix; + // Some careful tweaking to make sure no space is left out of view + // when scrolling to top or bottom. + if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) { + targetPos = targetPos * mix + sInfo.top * (1 - mix); + } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) { + var otherInfo = other.getScrollInfo(); + var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos; + if (botDistOther > botDist && (mix = botDist / halfScreen) < 1) + targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix); + } + } + + other.scrollTo(sInfo.left, targetPos); + other.state.scrollSetAt = now; + other.state.scrollSetBy = dv; + return true; + } + + function getOffsets(editor, around) { + var bot = around.after; + if (bot == null) bot = editor.lastLine() + 1; + return {top: editor.heightAtLine(around.before || 0, "local"), + bot: editor.heightAtLine(bot, "local")}; + } + + function setScrollLock(dv, val, action) { + dv.lockScroll = val; + if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv); + // 对比滚轮Toggle locked scrolling的样式 + //dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db  \u21da"; + } + + // Updating the marks for editor content + + function removeClass(editor, line, classes) { + var locs = classes.classLocation + for (var i = 0; i < locs.length; i++) { + editor.removeLineClass(line, locs[i], classes.chunk); + editor.removeLineClass(line, locs[i], classes.start); + editor.removeLineClass(line, locs[i], classes.end); + } + } + + function clearMarks(editor, arr, classes) { + for (var i = 0; i < arr.length; ++i) { + var mark = arr[i]; + if (mark instanceof CodeMirror.TextMarker) + mark.clear(); + else if (mark.parent) + removeClass(editor, mark, classes); + } + arr.length = 0; + } + + // FIXME maybe add a margin around viewport to prevent too many updates + function updateMarks(editor, diff, state, type, classes) { + var vp = editor.getViewport(); + editor.operation(function() { + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + clearMarks(editor, state.marked, classes); + markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes); + state.from = vp.from; state.to = vp.to; + } else { + if (vp.from < state.from) { + markChanges(editor, diff, type, state.marked, vp.from, state.from, classes); + state.from = vp.from; + } + if (vp.to > state.to) { + markChanges(editor, diff, type, state.marked, state.to, vp.to, classes); + state.to = vp.to; + } + } + }); + } + + function addClass(editor, lineNr, classes, main, start, end) { + var locs = classes.classLocation, line = editor.getLineHandle(lineNr); + for (var i = 0; i < locs.length; i++) { + if (main) editor.addLineClass(line, locs[i], classes.chunk); + if (start) editor.addLineClass(line, locs[i], classes.start); + if (end) editor.addLineClass(line, locs[i], classes.end); + } + return line; + } + + function markChanges(editor, diff, type, marks, from, to, classes) { + var pos = Pos(0, 0); + var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); + var cls = type == DIFF_DELETE ? classes.del : classes.insert; + function markChunk(start, end) { + var bfrom = Math.max(from, start), bto = Math.min(to, end); + for (var i = bfrom; i < bto; ++i) + marks.push(addClass(editor, i, classes, true, i == start, i == end - 1)); + // When the chunk is empty, make sure a horizontal line shows up + if (start == end && bfrom == end && bto == end) { + if (bfrom) + marks.push(addClass(editor, bfrom - 1, classes, false, false, true)); + else + marks.push(addClass(editor, bfrom, classes, false, true, false)); + } + } + + var chunkStart = 0, pending = false; + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0], str = part[1]; + if (tp == DIFF_EQUAL) { + var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1); + moveOver(pos, str); + var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0); + if (cleanTo > cleanFrom) { + if (pending) { markChunk(chunkStart, cleanFrom); pending = false } + chunkStart = cleanTo; + } + } else { + pending = true + if (tp == type) { + var end = moveOver(pos, str, true); + var a = posMax(top, pos), b = posMin(bot, end); + if (!posEq(a, b)) + marks.push(editor.markText(a, b, {className: cls})); + pos = end; + } + } + } + if (pending) markChunk(chunkStart, pos.line + 1); + } + + // Updating the gap between editor and original + + function makeConnections(dv) { + if (!dv.showDifferences) return; + + if (dv.svg) { + clear(dv.svg); + var w = dv.gap.offsetWidth; + attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight); + } + if (dv.copyButtons) clear(dv.copyButtons); + + var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport(); + var outerTop = dv.mv.wrap.getBoundingClientRect().top + var sTopEdit = outerTop - dv.edit.getScrollerElement().getBoundingClientRect().top + dv.edit.getScrollInfo().top + var sTopOrig = outerTop - dv.orig.getScrollerElement().getBoundingClientRect().top + dv.orig.getScrollInfo().top; + for (var i = 0; i < dv.chunks.length; i++) { + var ch = dv.chunks[i]; + if (ch.editFrom <= vpEdit.to && ch.editTo >= vpEdit.from && + ch.origFrom <= vpOrig.to && ch.origTo >= vpOrig.from) + drawConnectorsForChunk(dv, ch, sTopOrig, sTopEdit, w); + } + } + + function getMatchingOrigLine(editLine, chunks) { + var editStart = 0, origStart = 0; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + if (chunk.editTo > editLine && chunk.editFrom <= editLine) return null; + if (chunk.editFrom > editLine) break; + editStart = chunk.editTo; + origStart = chunk.origTo; + } + return origStart + (editLine - editStart); + } + + // Combines information about chunks and widgets/markers to return + // an array of lines, in a single editor, that probably need to be + // aligned with their counterparts in the editor next to it. + function alignableFor(cm, chunks, isOrig) { + var tracker = cm.state.trackAlignable + var start = cm.firstLine(), trackI = 0 + var result = [] + for (var i = 0;; i++) { + var chunk = chunks[i] + var chunkStart = !chunk ? 1e9 : isOrig ? chunk.origFrom : chunk.editFrom + for (; trackI < tracker.alignable.length; trackI += 2) { + var n = tracker.alignable[trackI] + 1 + if (n <= start) continue + if (n <= chunkStart) result.push(n) + else break + } + if (!chunk) break + result.push(start = isOrig ? chunk.origTo : chunk.editTo) + } + return result + } + + // Given information about alignable lines in two editors, fill in + // the result (an array of three-element arrays) to reflect the + // lines that need to be aligned with each other. + function mergeAlignable(result, origAlignable, chunks, setIndex) { + var rI = 0, origI = 0, chunkI = 0, diff = 0 + outer: for (;; rI++) { + var nextR = result[rI], nextO = origAlignable[origI] + if (!nextR && nextO == null) break + + var rLine = nextR ? nextR[0] : 1e9, oLine = nextO == null ? 1e9 : nextO + while (chunkI < chunks.length) { + var chunk = chunks[chunkI] + if (chunk.origFrom <= oLine && chunk.origTo > oLine) { + origI++ + rI-- + continue outer; + } + if (chunk.editTo > rLine) { + if (chunk.editFrom <= rLine) continue outer; + break + } + diff += (chunk.origTo - chunk.origFrom) - (chunk.editTo - chunk.editFrom) + chunkI++ + } + if (rLine == oLine - diff) { + nextR[setIndex] = oLine + origI++ + } else if (rLine < oLine - diff) { + nextR[setIndex] = rLine + diff + } else { + var record = [oLine - diff, null, null] + record[setIndex] = oLine + result.splice(rI, 0, record) + origI++ + } + } + } + + function findAlignedLines(dv, other) { + var alignable = alignableFor(dv.edit, dv.chunks, false), result = [] + if (other) for (var i = 0, j = 0; i < other.chunks.length; i++) { + var n = other.chunks[i].editTo + while (j < alignable.length && alignable[j] < n) j++ + if (j == alignable.length || alignable[j] != n) alignable.splice(j++, 0, n) + } + for (var i = 0; i < alignable.length; i++) + result.push([alignable[i], null, null]) + + mergeAlignable(result, alignableFor(dv.orig, dv.chunks, true), dv.chunks, 1) + if (other) + mergeAlignable(result, alignableFor(other.orig, other.chunks, true), other.chunks, 2) + + return result + } + + function alignChunks(dv, force) { + if (!dv.dealigned && !force) return; + if (!dv.orig.curOp) return dv.orig.operation(function() { + alignChunks(dv, force); + }); + + dv.dealigned = false; + var other = dv.mv.left == dv ? dv.mv.right : dv.mv.left; + if (other) { + ensureDiff(other); + other.dealigned = false; + } + var linesToAlign = findAlignedLines(dv, other); + + // Clear old aligners + var aligners = dv.mv.aligners; + for (var i = 0; i < aligners.length; i++) + aligners[i].clear(); + aligners.length = 0; + + var cm = [dv.edit, dv.orig], scroll = []; + if (other) cm.push(other.orig); + for (var i = 0; i < cm.length; i++) + scroll.push(cm[i].getScrollInfo().top); + + for (var ln = 0; ln < linesToAlign.length; ln++) + alignLines(cm, linesToAlign[ln], aligners); + + for (var i = 0; i < cm.length; i++) + cm[i].scrollTo(null, scroll[i]); + } + + function alignLines(cm, lines, aligners) { + var maxOffset = 0, offset = []; + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var off = cm[i].heightAtLine(lines[i], "local"); + offset[i] = off; + maxOffset = Math.max(maxOffset, off); + } + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var diff = maxOffset - offset[i]; + if (diff > 1) + aligners.push(padAbove(cm[i], lines[i], diff)); + } + } + + function padAbove(cm, line, size) { + var above = true; + if (line > cm.lastLine()) { + line--; + above = false; + } + var elt = document.createElement("div"); + elt.className = "CodeMirror-merge-spacer"; + elt.style.height = size + "px"; elt.style.minWidth = "1px"; + return cm.addLineWidget(line, elt, {height: size, above: above, mergeSpacer: true, handleMouseEvents: true}); + } + + function drawConnectorsForChunk(dv, chunk, sTopOrig, sTopEdit, w) { + var flip = dv.type == "left"; + var top = dv.orig.heightAtLine(chunk.origFrom, "local", true) - sTopOrig; + if (dv.svg) { + var topLpx = top; + var topRpx = dv.edit.heightAtLine(chunk.editFrom, "local", true) - sTopEdit; + if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; } + var botLpx = dv.orig.heightAtLine(chunk.origTo, "local", true) - sTopOrig; + var botRpx = dv.edit.heightAtLine(chunk.editTo, "local", true) - sTopEdit; + if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; } + var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx; + var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx; + attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")), + "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z", + "class", dv.classes.connect); + } + if (dv.copyButtons) { + var copy = dv.copyButtons.appendChild(elt1("div", dv.type == "left" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy")); + var editOriginals = dv.mv.options.allowEditingOriginals; + copy.title = editOriginals ? "Push to left" : "Revert chunk"; + copy.chunk = chunk; + copy.style.top = (chunk.origTo > chunk.origFrom ? top : dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit) + "px"; + + if (editOriginals) { + var topReverse = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit; + var copyReverse = dv.copyButtons.appendChild(elt1("div", dv.type == "right" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy-reverse")); + copyReverse.title = "Push to right"; + copyReverse.chunk = {editFrom: chunk.origFrom, editTo: chunk.origTo, + origFrom: chunk.editFrom, origTo: chunk.editTo}; + copyReverse.style.top = topReverse + "px"; + dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px"; + } + } + } + + function copyChunk(dv, to, from, chunk) { + if (dv.diffOutOfDate) return; + var origStart = chunk.origTo > from.lastLine() ? Pos(chunk.origFrom - 1) : Pos(chunk.origFrom, 0) + var origEnd = Pos(chunk.origTo, 0) + var editStart = chunk.editTo > to.lastLine() ? Pos(chunk.editFrom - 1) : Pos(chunk.editFrom, 0) + var editEnd = Pos(chunk.editTo, 0) + var handler = dv.mv.options.revertChunk + if (handler) + handler(dv.mv, from, origStart, origEnd, to, editStart, editEnd) + else + to.replaceRange(from.getRange(origStart, origEnd), editStart, editEnd) + } + + // Merge view, containing 0, 1, or 2 diff views. + + var MergeView = CodeMirror.MergeView = function(node, options) { + if (!(this instanceof MergeView)) return new MergeView(node, options); + + this.options = options; + var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight; + + var hasLeft = origLeft != null, hasRight = origRight != null; + var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0); + var wrap = [], left = this.left = null, right = this.right = null; + var self = this; + + if (hasLeft) { + left = this.left = new DiffView(this, "left"); + var leftPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-left"); + wrap.push(leftPane); + wrap.push(buildGap(left)); + } + + var editPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-editor"); + wrap.push(editPane); + + if (hasRight) { + right = this.right = new DiffView(this, "right"); + wrap.push(buildGap(right)); + var rightPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-right"); + wrap.push(rightPane); + } + + (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost"; + + wrap.push(elt("div", null, null, "height: 0; clear: both;")); + + var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane")); + this.edit = CodeMirror(editPane, copyObj(options)); + + if (left) left.init(leftPane, origLeft, options); + if (right) right.init(rightPane, origRight, options); + if (options.collapseIdentical) + this.editor().operation(function() { + collapseIdenticalStretches(self, options.collapseIdentical); + }); + if (options.connect == "align") { + this.aligners = []; + alignChunks(this.left || this.right, true); + } + if (left) left.registerEvents(right) + if (right) right.registerEvents(left) + + + var onResize = function() { + if (left) makeConnections(left); + if (right) makeConnections(right); + }; + CodeMirror.on(window, "resize", onResize); + var resizeInterval = setInterval(function() { + for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {} + if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); } + }, 5000); + }; + + function buildGap(dv) { + var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock"); + lock.title = "Toggle locked scrolling"; + var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); + CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); + var gapElts = [lockWrap]; + if (dv.mv.options.revertButtons !== false) { + dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); + CodeMirror.on(dv.copyButtons, "click", function(e) { + var node = e.target || e.srcElement; + if (!node.chunk) return; + if (node.className == "CodeMirror-merge-copy-reverse") { + copyChunk(dv, dv.orig, dv.edit, node.chunk); + return; + } + copyChunk(dv, dv.edit, dv.orig, node.chunk); + }); + gapElts.unshift(dv.copyButtons); + } + if (dv.mv.options.connect != "align") { + var svg = document.createElementNS && document.createElementNS(svgNS, "svg"); + if (svg && !svg.createSVGRect) svg = null; + dv.svg = svg; + if (svg) gapElts.push(svg); + } + + return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap"); + } + + MergeView.prototype = { + constructor: MergeView, + editor: function() { return this.edit; }, + rightOriginal: function() { return this.right && this.right.orig; }, + leftOriginal: function() { return this.left && this.left.orig; }, + setShowDifferences: function(val) { + if (this.right) this.right.setShowDifferences(val); + if (this.left) this.left.setShowDifferences(val); + }, + rightChunks: function() { + if (this.right) { ensureDiff(this.right); return this.right.chunks; } + }, + leftChunks: function() { + if (this.left) { ensureDiff(this.left); return this.left.chunks; } + } + }; + + function asString(obj) { + if (typeof obj == "string") return obj; + else return obj.getValue(); + } + + // Operations on diffs + + var dmp = new diff_match_patch(); + function getDiff(a, b, ignoreWhitespace) { + var diff = dmp.diff_main(a, b); + // The library sometimes leaves in empty parts, which confuse the algorithm + for (var i = 0; i < diff.length; ++i) { + var part = diff[i]; + if (ignoreWhitespace ? !/[^ \t]/.test(part[1]) : !part[1]) { + diff.splice(i--, 1); + } else if (i && diff[i - 1][0] == part[0]) { + diff.splice(i--, 1); + diff[i][1] += part[1]; + } + } + return diff; + } + + function getChunks(diff) { + var chunks = []; + var startEdit = 0, startOrig = 0; + var edit = Pos(0, 0), orig = Pos(0, 0); + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0]; + if (tp == DIFF_EQUAL) { + var startOff = !startOfLineClean(diff, i) || edit.line < startEdit || orig.line < startOrig ? 1 : 0; + var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff; + moveOver(edit, part[1], null, orig); + var endOff = endOfLineClean(diff, i) ? 1 : 0; + var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff; + if (cleanToEdit > cleanFromEdit) { + if (i) chunks.push({origFrom: startOrig, origTo: cleanFromOrig, + editFrom: startEdit, editTo: cleanFromEdit}); + startEdit = cleanToEdit; startOrig = cleanToOrig; + } + } else { + moveOver(tp == DIFF_INSERT ? edit : orig, part[1]); + } + } + if (startEdit <= edit.line || startOrig <= orig.line) + chunks.push({origFrom: startOrig, origTo: orig.line + 1, + editFrom: startEdit, editTo: edit.line + 1}); + return chunks; + } + + function endOfLineClean(diff, i) { + if (i == diff.length - 1) return true; + var next = diff[i + 1][1]; + if ((next.length == 1 && i < diff.length - 2) || next.charCodeAt(0) != 10) return false; + if (i == diff.length - 2) return true; + next = diff[i + 2][1]; + return (next.length > 1 || i == diff.length - 3) && next.charCodeAt(0) == 10; + } + + function startOfLineClean(diff, i) { + if (i == 0) return true; + var last = diff[i - 1][1]; + if (last.charCodeAt(last.length - 1) != 10) return false; + if (i == 1) return true; + last = diff[i - 2][1]; + return last.charCodeAt(last.length - 1) == 10; + } + + function chunkBoundariesAround(chunks, n, nInEdit) { + var beforeE, afterE, beforeO, afterO; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + var fromLocal = nInEdit ? chunk.editFrom : chunk.origFrom; + var toLocal = nInEdit ? chunk.editTo : chunk.origTo; + if (afterE == null) { + if (fromLocal > n) { afterE = chunk.editFrom; afterO = chunk.origFrom; } + else if (toLocal > n) { afterE = chunk.editTo; afterO = chunk.origTo; } + } + if (toLocal <= n) { beforeE = chunk.editTo; beforeO = chunk.origTo; } + else if (fromLocal <= n) { beforeE = chunk.editFrom; beforeO = chunk.origFrom; } + } + return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}}; + } + + function collapseSingle(cm, from, to) { + cm.addLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + var widget = document.createElement("span"); + widget.className = "CodeMirror-merge-collapsed-widget"; + widget.title = "Identical text collapsed. Click to expand."; + var mark = cm.markText(Pos(from, 0), Pos(to - 1), { + inclusiveLeft: true, + inclusiveRight: true, + replacedWith: widget, + clearOnEnter: true + }); + function clear() { + mark.clear(); + cm.removeLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + } + CodeMirror.on(widget, "click", clear); + return {mark: mark, clear: clear}; + } + + function collapseStretch(size, editors) { + var marks = []; + function clear() { + for (var i = 0; i < marks.length; i++) marks[i].clear(); + } + for (var i = 0; i < editors.length; i++) { + var editor = editors[i]; + var mark = collapseSingle(editor.cm, editor.line, editor.line + size); + marks.push(mark); + mark.mark.on("clear", clear); + } + return marks[0].mark; + } + + function unclearNearChunks(dv, margin, off, clear) { + for (var i = 0; i < dv.chunks.length; i++) { + var chunk = dv.chunks[i]; + for (var l = chunk.editFrom - margin; l < chunk.editTo + margin; l++) { + var pos = l + off; + if (pos >= 0 && pos < clear.length) clear[pos] = false; + } + } + } + + function collapseIdenticalStretches(mv, margin) { + if (typeof margin != "number") margin = 2; + var clear = [], edit = mv.editor(), off = edit.firstLine(); + for (var l = off, e = edit.lastLine(); l <= e; l++) clear.push(true); + if (mv.left) unclearNearChunks(mv.left, margin, off, clear); + if (mv.right) unclearNearChunks(mv.right, margin, off, clear); + + for (var i = 0; i < clear.length; i++) { + if (clear[i]) { + var line = i + off; + for (var size = 1; i < clear.length - 1 && clear[i + 1]; i++, size++) {} + if (size > margin) { + var editors = [{line: line, cm: edit}]; + if (mv.left) editors.push({line: getMatchingOrigLine(line, mv.left.chunks), cm: mv.left.orig}); + if (mv.right) editors.push({line: getMatchingOrigLine(line, mv.right.chunks), cm: mv.right.orig}); + var mark = collapseStretch(size, editors); + if (mv.options.onCollapse) mv.options.onCollapse(mv, line, size, mark); + } + } + } + } + + // General utilities + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + function elt1(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + function clear(node) { + for (var count = node.childNodes.length; count > 0; --count) + node.removeChild(node.firstChild); + } + + function attrs(elt) { + for (var i = 1; i < arguments.length; i += 2) + elt.setAttribute(arguments[i], arguments[i+1]); + } + + function copyObj(obj, target) { + if (!target) target = {}; + for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop]; + return target; + } + + function moveOver(pos, str, copy, other) { + var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0; + for (;;) { + var nl = str.indexOf("\n", at); + if (nl == -1) break; + ++out.line; + if (other) ++other.line; + at = nl + 1; + } + out.ch = (at ? 0 : out.ch) + (str.length - at); + if (other) other.ch = (at ? 0 : other.ch) + (str.length - at); + return out; + } + + // Tracks collapsed markers and line widgets, in order to be able to + // accurately align the content of two editors. + + var F_WIDGET = 1, F_WIDGET_BELOW = 2, F_MARKER = 4 + + function TrackAlignable(cm) { + this.cm = cm + this.alignable = [] + this.height = cm.doc.height + var self = this + cm.on("markerAdded", function(_, marker) { + if (!marker.collapsed) return + var found = marker.find(1) + if (found != null) self.set(found.line, F_MARKER) + }) + cm.on("markerCleared", function(_, marker, _min, max) { + if (max != null && marker.collapsed) + self.check(max, F_MARKER, self.hasMarker) + }) + cm.on("markerChanged", this.signal.bind(this)) + cm.on("lineWidgetAdded", function(_, widget, lineNo) { + if (widget.mergeSpacer) return + if (widget.above) self.set(lineNo - 1, F_WIDGET_BELOW) + else self.set(lineNo, F_WIDGET) + }) + cm.on("lineWidgetCleared", function(_, widget, lineNo) { + if (widget.mergeSpacer) return + if (widget.above) self.check(lineNo - 1, F_WIDGET_BELOW, self.hasWidgetBelow) + else self.check(lineNo, F_WIDGET, self.hasWidget) + }) + cm.on("lineWidgetChanged", this.signal.bind(this)) + cm.on("change", function(_, change) { + var start = change.from.line, nBefore = change.to.line - change.from.line + var nAfter = change.text.length - 1, end = start + nAfter + if (nBefore || nAfter) self.map(start, nBefore, nAfter) + self.check(end, F_MARKER, self.hasMarker) + if (nBefore || nAfter) self.check(change.from.line, F_MARKER, self.hasMarker) + }) + cm.on("viewportChange", function() { + if (self.cm.doc.height != self.height) self.signal() + }) + } + + TrackAlignable.prototype = { + signal: function() { + CodeMirror.signal(this, "realign") + this.height = this.cm.doc.height + }, + + set: function(n, flags) { + var pos = -1 + for (; pos < this.alignable.length; pos += 2) { + var diff = this.alignable[pos] - n + if (diff == 0) { + if ((this.alignable[pos + 1] & flags) == flags) return + this.alignable[pos + 1] |= flags + this.signal() + return + } + if (diff > 0) break + } + this.signal() + this.alignable.splice(pos, 0, n, flags) + }, + + find: function(n) { + for (var i = 0; i < this.alignable.length; i += 2) + if (this.alignable[i] == n) return i + return -1 + }, + + check: function(n, flag, pred) { + var found = this.find(n) + if (found == -1 || !(this.alignable[found + 1] & flag)) return + if (!pred.call(this, n)) { + this.signal() + var flags = this.alignable[found + 1] & ~flag + if (flags) this.alignable[found + 1] = flags + else this.alignable.splice(found, 2) + } + }, + + hasMarker: function(n) { + var handle = this.cm.getLineHandle(n) + if (handle.markedSpans) for (var i = 0; i < handle.markedSpans.length; i++) + if (handle.markedSpans[i].mark.collapsed && handle.markedSpans[i].to != null) + return true + return false + }, + + hasWidget: function(n) { + var handle = this.cm.getLineHandle(n) + if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++) + if (!handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true + return false + }, + + hasWidgetBelow: function(n) { + if (n == this.cm.lastLine()) return false + var handle = this.cm.getLineHandle(n + 1) + if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++) + if (handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true + return false + }, + + map: function(from, nBefore, nAfter) { + var diff = nAfter - nBefore, to = from + nBefore, widgetFrom = -1, widgetTo = -1 + for (var i = 0; i < this.alignable.length; i += 2) { + var n = this.alignable[i] + if (n == from && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetFrom = i + if (n == to && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetTo = i + if (n <= from) continue + else if (n < to) this.alignable.splice(i--, 2) + else this.alignable[i] += diff + } + if (widgetFrom > -1) { + var flags = this.alignable[widgetFrom + 1] + if (flags == F_WIDGET_BELOW) this.alignable.splice(widgetFrom, 2) + else this.alignable[widgetFrom + 1] = flags & ~F_WIDGET_BELOW + } + if (widgetTo > -1 && nAfter) + this.set(from + nAfter, F_WIDGET_BELOW) + } + } + + function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; } + function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; } + function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } + + function findPrevDiff(chunks, start, isOrig) { + for (var i = chunks.length - 1; i >= 0; i--) { + var chunk = chunks[i]; + var to = (isOrig ? chunk.origTo : chunk.editTo) - 1; + if (to < start) return to; + } + } + + function findNextDiff(chunks, start, isOrig) { + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + var from = (isOrig ? chunk.origFrom : chunk.editFrom); + if (from > start) return from; + } + } + + function goNearbyDiff(cm, dir) { + var found = null, views = cm.state.diffViews, line = cm.getCursor().line; + if (views) for (var i = 0; i < views.length; i++) { + var dv = views[i], isOrig = cm == dv.orig; + ensureDiff(dv); + var pos = dir < 0 ? findPrevDiff(dv.chunks, line, isOrig) : findNextDiff(dv.chunks, line, isOrig); + if (pos != null && (found == null || (dir < 0 ? pos > found : pos < found))) + found = pos; + } + if (found != null) + cm.setCursor(found, 0); + else + return CodeMirror.Pass; + } + + CodeMirror.commands.goNextDiff = function(cm) { + return goNearbyDiff(cm, 1); + }; + CodeMirror.commands.goPrevDiff = function(cm) { + return goNearbyDiff(cm, -1); + }; +}); diff --git a/public/react/public/js/codemirror/mode/javascript.js b/public/react/public/js/codemirror/mode/javascript.js new file mode 100755 index 000000000..dcefdca34 --- /dev/null +++ b/public/react/public/js/codemirror/mode/javascript.js @@ -0,0 +1,692 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE +// mode javascript +// TODO actually recognize syntax of TypeScript constructs + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("javascript", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var statementIndent = parserConfig.statementIndent; + var jsonldMode = parserConfig.jsonld; + var jsonMode = parserConfig.json || jsonldMode; + var isTS = parserConfig.typescript; + var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; + + // Tokenizer + + var keywords = function(){ + function kw(type) {return {type: type, style: "keyword"};} + var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); + var operator = kw("operator"), atom = {type: "atom", style: "atom"}; + + var jsKeywords = { + "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, + "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C, + "var": kw("var"), "const": kw("var"), "let": kw("var"), + "function": kw("function"), "catch": kw("catch"), + "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), + "in": operator, "typeof": operator, "instanceof": operator, + "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, + "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"), + "yield": C, "export": kw("export"), "import": kw("import"), "extends": C + }; + + // Extend the 'normal' keywords with the TypeScript language extensions + if (isTS) { + var type = {type: "variable", style: "variable-3"}; + var tsKeywords = { + // object-like things + "interface": kw("interface"), + "extends": kw("extends"), + "constructor": kw("constructor"), + + // scope modifiers + "public": kw("public"), + "private": kw("private"), + "protected": kw("protected"), + "static": kw("static"), + + // types + "string": type, "number": type, "bool": type, "any": type + }; + + for (var attr in tsKeywords) { + jsKeywords[attr] = tsKeywords[attr]; + } + } + + return jsKeywords; + }(); + + var isOperatorChar = /[+\-*&%=<>!?|~^]/; + var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; + + function readRegexp(stream) { + var escaped = false, next, inSet = false; + while ((next = stream.next()) != null) { + if (!escaped) { + if (next == "/" && !inSet) return; + if (next == "[") inSet = true; + else if (inSet && next == "]") inSet = false; + } + escaped = !escaped && next == "\\"; + } + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + function ret(tp, style, cont) { + type = tp; content = cont; + return style; + } + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { + return ret("number", "number"); + } else if (ch == "." && stream.match("..")) { + return ret("spread", "meta"); + } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + return ret(ch); + } else if (ch == "=" && stream.eat(">")) { + return ret("=>", "operator"); + } else if (ch == "0" && stream.eat(/x/i)) { + stream.eatWhile(/[\da-f]/i); + return ret("number", "number"); + } else if (/\d/.test(ch)) { + stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); + return ret("number", "number"); + } else if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } else if (stream.eat("/")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } else if (state.lastType == "operator" || state.lastType == "keyword c" || + state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) { + readRegexp(stream); + stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); + return ret("regexp", "string-2"); + } else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } + } else if (ch == "`") { + state.tokenize = tokenQuasi; + return tokenQuasi(stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return ret("error", "error"); + } else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } else if (wordRE.test(ch)) { + stream.eatWhile(wordRE); + var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; + return (known && state.lastType != ".") ? ret(known.type, known.style, word) : + ret("variable", "variable", word); + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next; + if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ + state.tokenize = tokenBase; + return ret("jsonld-keyword", "meta"); + } + while ((next = stream.next()) != null) { + if (next == quote && !escaped) break; + escaped = !escaped && next == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return ret("string", "string"); + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenQuasi(stream, state) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && next == "\\"; + } + return ret("quasi", "string-2", stream.current()); + } + + var brackets = "([{}])"; + // This is a crude lookahead trick to try and notice that we're + // parsing the argument patterns for a fat-arrow function before we + // actually hit the arrow token. It only works if the arrow is on + // the same line as the arguments and there's no strange noise + // (comments) in between. Fallback is to only notice when we hit the + // arrow, and not declare the arguments as locals for the arrow + // body. + function findFatArrow(stream, state) { + if (state.fatArrowAt) state.fatArrowAt = null; + var arrow = stream.string.indexOf("=>", stream.start); + if (arrow < 0) return; + + var depth = 0, sawSomething = false; + for (var pos = arrow - 1; pos >= 0; --pos) { + var ch = stream.string.charAt(pos); + var bracket = brackets.indexOf(ch); + if (bracket >= 0 && bracket < 3) { + if (!depth) { ++pos; break; } + if (--depth == 0) break; + } else if (bracket >= 3 && bracket < 6) { + ++depth; + } else if (wordRE.test(ch)) { + sawSomething = true; + } else if (/["'\/]/.test(ch)) { + return; + } else if (sawSomething && !depth) { + ++pos; + break; + } + } + if (sawSomething && !depth) state.fatArrowAt = pos; + } + + // Parser + + var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; + + function JSLexical(indented, column, type, align, prev, info) { + this.indented = indented; + this.column = column; + this.type = type; + this.prev = prev; + this.info = info; + if (align != null) this.align = align; + } + + function inScope(state, varname) { + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return true; + for (var cx = state.context; cx; cx = cx.prev) { + for (var v = cx.vars; v; v = v.next) + if (v.name == varname) return true; + } + } + + function parseJS(state, style, type, content, stream) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; + + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + + while(true) { + var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; + if (combinator(type, content)) { + while(cc.length && cc[cc.length - 1].lex) + cc.pop()(); + if (cx.marked) return cx.marked; + if (type == "variable" && inScope(state, content)) return "variable-2"; + return style; + } + } + } + + // Combinator utils + + var cx = {state: null, column: null, marked: null, cc: null}; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + function register(varname) { + function inList(list) { + for (var v = list; v; v = v.next) + if (v.name == varname) return true; + return false; + } + var state = cx.state; + if (state.context) { + cx.marked = "def"; + if (inList(state.localVars)) return; + state.localVars = {name: varname, next: state.localVars}; + } else { + if (inList(state.globalVars)) return; + if (parserConfig.globalVars) + state.globalVars = {name: varname, next: state.globalVars}; + } + } + + // Combinators + + var defaultVars = {name: "this", next: {name: "arguments"}}; + function pushcontext() { + cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; + cx.state.localVars = defaultVars; + } + function popcontext() { + cx.state.localVars = cx.state.context.vars; + cx.state.context = cx.state.context.prev; + } + function pushlex(type, info) { + var result = function() { + var state = cx.state, indent = state.indented; + if (state.lexical.type == "stat") indent = state.lexical.indented; + else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) + indent = outer.indented; + state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + poplex.lex = true; + + function expect(wanted) { + function exp(type) { + if (type == wanted) return cont(); + else if (wanted == ";") return pass(); + else return cont(exp); + }; + return exp; + } + + function statement(type, value) { + if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); + if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); + if (type == "keyword b") return cont(pushlex("form"), statement, poplex); + if (type == "{") return cont(pushlex("}"), block, poplex); + if (type == ";") return cont(); + if (type == "if") { + if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) + cx.state.cc.pop()(); + return cont(pushlex("form"), expression, statement, poplex, maybeelse); + } + if (type == "function") return cont(functiondef); + if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); + if (type == "variable") return cont(pushlex("stat"), maybelabel); + if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), + block, poplex, poplex); + if (type == "case") return cont(expression, expect(":")); + if (type == "default") return cont(expect(":")); + if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), + statement, poplex, popcontext); + if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex); + if (type == "class") return cont(pushlex("form"), className, poplex); + if (type == "export") return cont(pushlex("form"), afterExport, poplex); + if (type == "import") return cont(pushlex("form"), afterImport, poplex); + return pass(pushlex("stat"), expression, expect(";"), poplex); + } + function expression(type) { + return expressionInner(type, false); + } + function expressionNoComma(type) { + return expressionInner(type, true); + } + function expressionInner(type, noComma) { + if (cx.state.fatArrowAt == cx.stream.start) { + var body = noComma ? arrowBodyNoComma : arrowBody; + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext); + else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); + } + + var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; + if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); + if (type == "function") return cont(functiondef, maybeop); + if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); + if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop); + if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); + if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); + if (type == "{") return contCommasep(objprop, "}", null, maybeop); + if (type == "quasi") { return pass(quasi, maybeop); } + return cont(); + } + function maybeexpression(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expression); + } + function maybeexpressionNoComma(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expressionNoComma); + } + + function maybeoperatorComma(type, value) { + if (type == ",") return cont(expression); + return maybeoperatorNoComma(type, value, false); + } + function maybeoperatorNoComma(type, value, noComma) { + var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; + var expr = noComma == false ? expression : expressionNoComma; + if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); + if (type == "operator") { + if (/\+\+|--/.test(value)) return cont(me); + if (value == "?") return cont(expression, expect(":"), expr); + return cont(expr); + } + if (type == "quasi") { return pass(quasi, me); } + if (type == ";") return; + if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); + if (type == ".") return cont(property, me); + if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); + } + function quasi(type, value) { + if (type != "quasi") return pass(); + if (value.slice(value.length - 2) != "${") return cont(quasi); + return cont(expression, continueQuasi); + } + function continueQuasi(type) { + if (type == "}") { + cx.marked = "string-2"; + cx.state.tokenize = tokenQuasi; + return cont(quasi); + } + } + function arrowBody(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expression); + } + function arrowBodyNoComma(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expressionNoComma); + } + function maybelabel(type) { + if (type == ":") return cont(poplex, statement); + return pass(maybeoperatorComma, expect(";"), poplex); + } + function property(type) { + if (type == "variable") {cx.marked = "property"; return cont();} + } + function objprop(type, value) { + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + if (value == "get" || value == "set") return cont(getterSetter); + return cont(afterprop); + } else if (type == "number" || type == "string") { + cx.marked = jsonldMode ? "property" : (cx.style + " property"); + return cont(afterprop); + } else if (type == "jsonld-keyword") { + return cont(afterprop); + } else if (type == "[") { + return cont(expression, expect("]"), afterprop); + } + } + function getterSetter(type) { + if (type != "variable") return pass(afterprop); + cx.marked = "property"; + return cont(functiondef); + } + function afterprop(type) { + if (type == ":") return cont(expressionNoComma); + if (type == "(") return pass(functiondef); + } + function commasep(what, end) { + function proceed(type) { + if (type == ",") { + var lex = cx.state.lexical; + if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; + return cont(what, proceed); + } + if (type == end) return cont(); + return cont(expect(end)); + } + return function(type) { + if (type == end) return cont(); + return pass(what, proceed); + }; + } + function contCommasep(what, end, info) { + for (var i = 3; i < arguments.length; i++) + cx.cc.push(arguments[i]); + return cont(pushlex(end, info), commasep(what, end), poplex); + } + function block(type) { + if (type == "}") return cont(); + return pass(statement, block); + } + function maybetype(type) { + if (isTS && type == ":") return cont(typedef); + } + function typedef(type) { + if (type == "variable"){cx.marked = "variable-3"; return cont();} + } + function vardef() { + return pass(pattern, maybetype, maybeAssign, vardefCont); + } + function pattern(type, value) { + if (type == "variable") { register(value); return cont(); } + if (type == "[") return contCommasep(pattern, "]"); + if (type == "{") return contCommasep(proppattern, "}"); + } + function proppattern(type, value) { + if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { + register(value); + return cont(maybeAssign); + } + if (type == "variable") cx.marked = "property"; + return cont(expect(":"), pattern, maybeAssign); + } + function maybeAssign(_type, value) { + if (value == "=") return cont(expressionNoComma); + } + function vardefCont(type) { + if (type == ",") return cont(vardef); + } + function maybeelse(type, value) { + if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); + } + function forspec(type) { + if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); + } + function forspec1(type) { + if (type == "var") return cont(vardef, expect(";"), forspec2); + if (type == ";") return cont(forspec2); + if (type == "variable") return cont(formaybeinof); + return pass(expression, expect(";"), forspec2); + } + function formaybeinof(_type, value) { + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return cont(maybeoperatorComma, forspec2); + } + function forspec2(type, value) { + if (type == ";") return cont(forspec3); + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return pass(expression, expect(";"), forspec3); + } + function forspec3(type) { + if (type != ")") cont(expression); + } + function functiondef(type, value) { + if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} + if (type == "variable") {register(value); return cont(functiondef);} + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext); + } + function funarg(type) { + if (type == "spread") return cont(funarg); + return pass(pattern, maybetype); + } + function className(type, value) { + if (type == "variable") {register(value); return cont(classNameAfter);} + } + function classNameAfter(type, value) { + if (value == "extends") return cont(expression, classNameAfter); + if (type == "{") return cont(pushlex("}"), classBody, poplex); + } + function classBody(type, value) { + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); + return cont(functiondef, classBody); + } + if (value == "*") { + cx.marked = "keyword"; + return cont(classBody); + } + if (type == ";") return cont(classBody); + if (type == "}") return cont(); + } + function classGetterSetter(type) { + if (type != "variable") return pass(); + cx.marked = "property"; + return cont(); + } + function afterModule(type, value) { + if (type == "string") return cont(statement); + if (type == "variable") { register(value); return cont(maybeFrom); } + } + function afterExport(_type, value) { + if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } + if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } + return pass(statement); + } + function afterImport(type) { + if (type == "string") return cont(); + return pass(importSpec, maybeFrom); + } + function importSpec(type, value) { + if (type == "{") return contCommasep(importSpec, "}"); + if (type == "variable") register(value); + return cont(); + } + function maybeFrom(_type, value) { + if (value == "from") { cx.marked = "keyword"; return cont(expression); } + } + function arrayLiteral(type) { + if (type == "]") return cont(); + return pass(expressionNoComma, maybeArrayComprehension); + } + function maybeArrayComprehension(type) { + if (type == "for") return pass(comprehension, expect("]")); + if (type == ",") return cont(commasep(maybeexpressionNoComma, "]")); + return pass(commasep(expressionNoComma, "]")); + } + function comprehension(type) { + if (type == "for") return cont(forspec, comprehension); + if (type == "if") return cont(expression, comprehension); + } + + function isContinuedStatement(state, textAfter) { + return state.lastType == "operator" || state.lastType == "," || + isOperatorChar.test(textAfter.charAt(0)) || + /[,.]/.test(textAfter.charAt(0)); + } + + // Interface + + return { + startState: function(basecolumn) { + var state = { + tokenize: tokenBase, + lastType: "sof", + cc: [], + lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), + localVars: parserConfig.localVars, + context: parserConfig.localVars && {vars: parserConfig.localVars}, + indented: 0 + }; + if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") + state.globalVars = parserConfig.globalVars; + return state; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + findFatArrow(stream, state); + } + if (state.tokenize != tokenComment && stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (type == "comment") return style; + state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; + return parseJS(state, style, type, content, stream); + }, + + indent: function(state, textAfter) { + if (state.tokenize == tokenComment) return CodeMirror.Pass; + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; + // Kludge to prevent 'maybelse' from blocking lexical scope pops + if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { + var c = state.cc[i]; + if (c == poplex) lexical = lexical.prev; + else if (c != maybeelse) break; + } + if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; + if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") + lexical = lexical.prev; + var type = lexical.type, closing = firstChar == type; + + if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); + else if (type == "form" && firstChar == "{") return lexical.indented; + else if (type == "form") return lexical.indented + indentUnit; + else if (type == "stat") + return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); + else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) + return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); + else if (lexical.align) return lexical.column + (closing ? 0 : 1); + else return lexical.indented + (closing ? 0 : indentUnit); + }, + + electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, + blockCommentStart: jsonMode ? null : "/*", + blockCommentEnd: jsonMode ? null : "*/", + lineComment: jsonMode ? null : "//", + fold: "brace", + + helperType: jsonMode ? "json" : "javascript", + jsonldMode: jsonldMode, + jsonMode: jsonMode + }; +}); + +CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); + +CodeMirror.defineMIME("text/javascript", "javascript"); +CodeMirror.defineMIME("text/ecmascript", "javascript"); +CodeMirror.defineMIME("application/javascript", "javascript"); +CodeMirror.defineMIME("application/x-javascript", "javascript"); +CodeMirror.defineMIME("application/ecmascript", "javascript"); +CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); +CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); +CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); + +}); \ No newline at end of file diff --git a/public/react/public/js/create_kindeditor.js b/public/react/public/js/create_kindeditor.js new file mode 100755 index 000000000..66f97665e --- /dev/null +++ b/public/react/public/js/create_kindeditor.js @@ -0,0 +1,429 @@ +//需求:表情栏可以隐藏显示,高度只要一点高 +function sd_create_editor(params){ + // var minHeight; //最小高度 + var paramsHeight = params.height; //设定的高度 + var id = arguments[1] ? arguments[1] : undefined; + var type = arguments[2] ? arguments[2] : ''; + var paramsWidth = params.width == undefined ? "100%" : params.width; + + var editor = params.kindutil.create(params.textarea, { + resizeType : 1,minWidth:"1px",width:"94%", + height:"33px",// == undefined ? "30px":paramsHeight+"px", + minHeight:"33px",// == undefined ? "30px":paramsHeight+"px", + width:params.width, + /* + items:['emoticons','fontname', + 'forecolor', 'hilitecolor', 'bold', '|', 'justifyleft', 'justifycenter', 'insertorderedlist','insertunorderedlist', '|', + 'formatblock', 'fontsize', '|','indent', 'outdent', + '|','imagedirectupload','more'],*/ + items : ['code','emoticons','fontname', + 'forecolor', 'hilitecolor', 'bold', '|', 'justifyleft', 'justifycenter', 'insertorderedlist','insertunorderedlist', '|', + 'formatblock', 'fontsize', '|','indent', 'outdent', + '|','imagedirectupload','table', 'media', 'preview',"more" + ], + afterChange:function(){//按键事件 + var edit = this.edit; + var body = edit.doc.body; + edit.iframe.height(paramsHeight); + this.resize(null, Math.max((params.kindutil.IE ? body.scrollHeight : (params.kindutil.GECKO ? body.offsetHeight+26:body.offsetHeight+7)) , paramsHeight)); + }, + afterBlur:function(){ + //params.toolbar_container.hide(); + params.textarea.blur(); + sd_check_editor_form_field({content:this,contentmsg:params.contentmsg,textarea:params.textarea}); + if(this.isEmpty()) { + this.edit.html("我要回复"); + } + //params.toolbar_container.hide(); + $('#reply_image_' + id).addClass('imageFuzzy'); + if(/^\s*<\w*\s*\w*\=\"\w*\"\s*\w*\=\"\w*\:\s*\#\d*\;\s*\w*\-\w*\:\s*\w*\;\"\>[\u4e00-\u9fa5]*<\/\w*\>\s*$/.test(this.edit.html())){ + params.submit_btn.hide(); + params.toolbar_container.hide(); + this.resize("100%", null); + }else if(this.edit.html().trim() != ""){ + params.submit_btn.show(); + params.toolbar_container.show(); + } + + //params.submit_btn.css("display","none"); + + }, + afterFocus: function(){ + var edit = this.edit; + var body = edit.doc.body; + if(/^\s*<\w*\s*\w*\=\"\w*\"\s*\w*\=\"\w*\:\s*\#\d*\;\s*\w*\-\w*\:\s*\w*\;\"\>[\u4e00-\u9fa5]*<\/\w*\>\s*$/.test(edit.html())){ + edit.html(''); + } + params.submit_btn.show(); + params.contentmsg.hide(); + params.toolbar_container.show(); + // params.toolbar_container.show(); + $('#reply_image_' + id).removeClass('imageFuzzy'); + //edit.iframe.width(paramsWidth); + + this.resize("100%", null); + this.resize(paramsWidth, null); + //params.submit_btn.show(); + + }, + + afterCreate:function(){ + //params.submit_btn.hide(); + var toolbar = $("div[class='ke-toolbar']",params.div_form); + toolbar.css('display','inline'); + toolbar.css('padding',0); + $(".ke-outline>.ke-toolbar-icon",toolbar).append('表情'); + params.toolbar_container.append(toolbar); + params.toolbar_container.hide(); + params.submit_btn.hide(); + //init + var edit = this.edit; + var body = edit.doc.body; + edit.iframe[0].scroll = 'no'; + body.style.overflowY = 'hidden'; + //reset height + paramsHeight = paramsHeight == undefined ? params.kindutil.removeUnit(this.height) : paramsHeight; + edit.iframe.height(paramsHeight); + edit.html("我要回复"); + this.resize(null,paramsHeight);// Math.max((params.kindutil.IE ? body.scrollHeight : body.offsetHeight)+ paramsHeight , paramsHeight) + // params.toolbar_container.hide(); + if(typeof enableAt === 'function'){ + enableAt(this, id, type); + } + } + }).loadPlugin('paste'); + return editor; +} + +function sd_create_shixun_editor(params){ + // var minHeight; //最小高度 + var paramsHeight = params.height; //设定的高度 + var id = arguments[1] ? arguments[1] : undefined; + var type = arguments[2] ? arguments[2] : ''; + var paramsWidth = params.width == undefined ? "100%" : params.width; + + var editor = params.kindutil.create(params.textarea, { + resizeType : 1,minWidth:"1px",width:"94%", + height:"33px",// == undefined ? "30px":paramsHeight+"px", + minHeight:"33px",// == undefined ? "30px":paramsHeight+"px", + width:params.width, + /* + items:['emoticons','fontname', + 'forecolor', 'hilitecolor', 'bold', '|', 'justifyleft', 'justifycenter', 'insertorderedlist','insertunorderedlist', '|', + 'formatblock', 'fontsize', '|','indent', 'outdent', + '|','imagedirectupload','more'],*/ + items : ['imagedirectupload'], + afterChange:function(){//按键事件 + if(this.isEmpty() || this.edit.doc.body.innerText == '说点什么') { + $('#mini_comment_section').height('auto') + } else { + var edit = this.edit; + var body = edit.doc.body; + var newHeight = 0; + + var FF = !(window.mozInnerScreenX == null); + if (FF) { // 火狐下处理方式不一样 + newHeight = $(body).height() + } else { + $(body).children().each(function(){newHeight+=$(this).height()}); + } + // var newHeight = $(body).height() + + var maxHeight = 357 // $(window).height() - 150 - 57; // 150 上部距离 57 下部距离 + + newHeight = newHeight <= maxHeight ? newHeight : maxHeight + + + if (newHeight > 150) { + if (FF) { // 火狐下处理方式不一样 + this.resize("100%", (newHeight + 20) + 'px'); + } else { + this.resize("100%", newHeight + 'px'); + } + $('#mini_comment_section').height(newHeight+57) + } else { + this.resize("100%", '150px'); + $('#mini_comment_section').height('auto') + } + } + + //edit.iframe.height(paramsHeight); + //this.resize(null, Math.max((params.kindutil.IE ? body.scrollHeight : (params.kindutil.GECKO ? body.offsetHeight+26:body.offsetHeight+7)) , 15)); + }, + afterBlur:function(){ + //params.toolbar_container.hide(); + params.textarea.blur(); + sd_check_editor_form_field({content:this,contentmsg:params.contentmsg,textarea:params.textarea}); + if(this.isEmpty()) { + $('#mini_comment_section').height('auto') + this.edit.html("说点什么"); + params.submit_btn.hide(); + params.toolbar_container.hide(); + this.resize("100%", "30px"); + $("#dis_reply_id").val(""); + if($("#editor_panel").length>0){ + $("#editor_panel").attr("style","margin-top:9px;flex: 1;"); + $("#editor_panel").parents("form").addClass("df") + } + } + //params.toolbar_container.hide(); + /*$('#reply_image_' + id).addClass('imageFuzzy'); + if(/^\s*<\w*\s*\w*\=\"\w*\"\s*\w*\=\"\w*\:\s*\#\d*\;\s*\w*\-\w*\:\s*\w*\;\"\>[\u4e00-\u9fa5]*<\/\w*\>\s*$/.test(this.edit.html())){ + params.submit_btn.hide(); + params.toolbar_container.hide(); + this.resize("100%", "30px"); + }else if(this.edit.html().trim() != ""){ + params.submit_btn.show(); + params.toolbar_container.show(); + }*/ + //params.submit_btn.css("display","none"); + + // $('#mini_comment_section').height('auto') + }, + afterFocus: function(){ + var edit = this.edit; + var body = edit.doc.body; + if(/^\s*<\w*\s*\w*\=\"\w*\"\s*\w*\=\"\w*\:\s*\#\d*\;\s*\w*\-\w*\:\s*\w*\;\"\>[\u4e00-\u9fa5]*<\/\w*\>\s*$/.test(edit.html())){ + edit.html(""); + } + params.submit_btn.show(); + params.contentmsg.hide(); + params.toolbar_container.show(); + // params.toolbar_container.show(); + $('#reply_image_' + id).removeClass('imageFuzzy'); + //edit.iframe.width(paramsWidth); + + var newHeight = $(body).height() + if (newHeight < 150) { + this.resize("100%", "150px"); + this.resize(paramsWidth, "150px"); + } + if($("#editor_panel").length>0){ + $("#editor_panel").attr("style","width:100%;margin-top:9px;"); + $("#editor_panel").parents("form").removeClass("df") + } + //params.submit_btn.show(); + + // $('#mini_comment_section').height('244px') + }, + + afterCreate:function(){ + //params.submit_btn.hide(); + var toolbar = $("div[class='ke-toolbar']",params.div_form); + toolbar.css('display','inline'); + toolbar.css('padding',0); + $(".ke-outline>.ke-toolbar-icon",toolbar).append('表情'); + params.toolbar_container.append(toolbar); + params.toolbar_container.hide(); + params.submit_btn.hide(); + //init + var edit = this.edit; + var body = edit.doc.body; + edit.iframe[0].scroll = 'no'; + // body.style.overflowY = 'hidden'; + body.style['padding-top']= '2px'; + body.style['padding-left']= '5px'; + // + //reset height + paramsHeight = paramsHeight == undefined ? params.kindutil.removeUnit(this.height) : paramsHeight; + edit.iframe.height(paramsHeight); + edit.html("说点什么"); + this.resize(null,paramsHeight);// Math.max((params.kindutil.IE ? body.scrollHeight : body.offsetHeight)+ paramsHeight , paramsHeight) + // params.toolbar_container.hide(); + if(typeof enableAt === 'function'){ + enableAt(this, id, type); + } + + var iframe = edit.iframe[0] + $(iframe.contentDocument.head).append( + $("")); + } + }).loadPlugin('paste'); + return editor; +} + +function sd_check_editor_form_field(params){ + var result=true; + if(params.content!=undefined){ + if(params.content.isEmpty()){ + result=false; + } + if(params.content.html()!=params.textarea.html() || params.issubmit==true){ + params.textarea.html(params.content.html()); + params.content.sync(); + if(params.content.isEmpty() || /^\s*<\w*\s*\w*\=\"\w*\"\s*\w*\=\"\w*\:\s*\#\d*\;\s*\w*\-\w*\:\s*\w*\;\"\>[\u4e00-\u9fa5]*<\/\w*\>\s*$/.test(params.textarea.html())){ + params.contentmsg.html('内容不能为空'); + params.contentmsg.css({color:'#ff0000'}); + }else{ + params.contentmsg.html('填写正确'); + params.contentmsg.css({color:'#008000'}); + } + params.contentmsg.show(); + } + } + return result; +} +function sd_create_form(params){ + params.form.submit(function(){ + var flag = false; + if(params.form.attr('data-remote') != undefined ){ + flag = true + } + var is_checked = sd_check_editor_form_field({ + issubmit:true, + content:params.editor, + contentmsg:params.contentmsg, + textarea:params.textarea + }); + if(is_checked){ + if(flag){ + return true; + }else{ + $(this)[0].submit(); + return false; + } + } + return false; + }); +} +function sd_reset_editor_form(params){ + params.form[0].reset(); + params.textarea.empty(); + if(params.editor != undefined){ + params.editor.html(params.textarea.html()); + } + params.contentmsg.hide(); +} +//第二个参数是高度,可以传,可以不传 +function sd_create_editor_from_data(id){ + var height = arguments[1] ? arguments[1] : undefined; + var width = arguments[2] ? arguments[2] : undefined; + var type = arguments[3] ? arguments[3] : undefined; + // KindEditor.ready(function (K) { + // react 环境不需要ready方法,页面已经加载完了才执行sd_create_editor_from_data + var K = KindEditor; + $("div[nhname='new_message_" + id + "']").each(function () { + var params = {}; + params.kindutil = K; + params.div_form = $(this); + params.form = $("form", params.div_form); + if (params.form == undefined || params.form.length == 0) { + return; + } + params.textarea = $("textarea[nhname='new_message_textarea_" + id + "']", params.div_form); + params.contentmsg = $("span[nhname='contentmsg_" + id + "']", params.div_form); + params.toolbar_container = $("div[nhname='toolbar_container_" + id + "']", params.div_form); + params.cancel_btn = $("#new_message_cancel_btn_" + id); + params.submit_btn = $("#new_message_submit_btn_" + id); + params.height = height; + params.width = width; + if (params.textarea.data('init') == undefined) { + params.editor = sd_create_editor(params,id, type); + sd_create_form(params); + params.cancel_btn.click(function () { + sd_reset_editor_form(params); + }); + params.submit_btn.click(function () { + var tContents = $("#comment_news_" + id).val(); + if(tContents != undefined){ + var beforeImage = tContents.split(""); + if(beforeImage[0] == "" && afterImage[1] == ""){ + notice_box('不支持纯图片评论
                                请在评论中增加文字信息'); + return; + } + + if (tContents.startsWith('<') && tContents.endsWith('>') + && (tContents.indexOf('"); + if(beforeImage[0] == "" && afterImage[1] == ""){ + notice_box('不支持纯图片评论
                                请在评论中增加文字信息'); + return; + } + } + params.form.submit(); + }); + params.textarea.focus(function (){ + params.editor.focus(); + }); + params.textarea.data('init', 1); + $(this).show(); + } + }); + // }); + + div_form = $("div[nhname='new_message_" + id + "']"); + $(".ke-edit", div_form).css("height","33px"); + $(".ke-edit-iframe",div_form).css("height","33px"); +} \ No newline at end of file diff --git a/public/react/public/js/diff_match_patch.js b/public/react/public/js/diff_match_patch.js new file mode 100755 index 000000000..300b0f85e --- /dev/null +++ b/public/react/public/js/diff_match_patch.js @@ -0,0 +1,49 @@ +(function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32} +diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);var f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,b.length-f);a=this.diff_compute_(a, +b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a}; +diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c):1==f.length?[[-1,a],[1,b]]:(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100c);v++){for(var n=-v+r;n<=v-t;n+=2){var l=g+n,m;m=n==-v||n!=v&&j[l-1]d)t+=2;else if(s>e)r+=2;else if(q&&(l=g+k-n,0<=l&&l= +u)return this.diff_bisectSplit_(a,b,m,s,c)}}for(n=-v+p;n<=v-w;n+=2){l=g+n;u=n==-v||n!=v&&i[l-1]d)w+=2;else if(m>e)p+=2;else if(!q&&(l=g+k-n,0<=l&&(l=u)))return this.diff_bisectSplit_(a,b,m,s,c)}}return[[-1,a],[1,b]]}; +diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d);a=a.substring(c);b=b.substring(d);f=this.diff_main(f,g,!1,e);e=this.diff_main(a,b,!1,e);return f.concat(e)}; +diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;fd?a=a.substring(c-d):c=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null; +var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.lengthd[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]}; +diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}}; +diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_); +return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]= +h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/; +diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;fb)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)}; +diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=//g,f=/\n/g,g=0;g");switch(h){case 1:b[g]=''+j+"";break;case -1:b[g]=''+j+"";break;case 0:b[g]=""+j+""}}return b.join("")}; +diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;cthis.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<=i;p--){var w=e[a.charAt(p-1)];k[p]=0===t?(k[p+1]<<1|1)&w:(k[p+1]<<1|1)&w|((r[p+1]|r[p])<<1|1)|r[p+1];if(k[p]&j&&(w=d(t,p-1),w<=g))if(g=w,h=p-1,h>c)i=Math.max(1,2*c-h);else break}if(d(t+1,c)>g)break;r=k}return h}; +diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c=2*this.Patch_Margin&& +e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;cthis.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g); +if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;ie[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0, +c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c}; +diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&& +(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c Using fontAwesome icon web fonts; + // Support Editor.md logo icon emoji :editormd-logo: :editormd-logo-1x: > 1~8x; + tex : false, // TeX(LaTeX), based on KaTeX + flowChart : false, // flowChart.js only support IE9+ + sequenceDiagram : false, // sequenceDiagram.js only support IE9+ + previewCodeHighlight : true, + + toolbar : true, // show/hide toolbar + toolbarAutoFixed : true, // on window scroll auto fixed position + toolbarIcons : "full", + toolbarTitles : {}, + toolbarHandlers : { + ucwords : function() { + return editormd.toolbarHandlers.ucwords; + }, + lowercase : function() { + return editormd.toolbarHandlers.lowercase; + } + }, + toolbarCustomIcons : { // using html tag create toolbar icon, unused default tag. + lowercase : "a", + "ucwords" : "Aa" + }, + toolbarIconsClass : { + undo : "fa-undo", + redo : "fa-repeat", + bold : "fa-bold", + del : "fa-strikethrough", + italic : "fa-italic", + quote : "fa-quote-left", + uppercase : "fa-font", + h1 : editormd.classPrefix + "bold", + h2 : editormd.classPrefix + "bold", + h3 : editormd.classPrefix + "bold", + h4 : editormd.classPrefix + "bold", + h5 : editormd.classPrefix + "bold", + h6 : editormd.classPrefix + "bold", + "list-ul" : "fa-list-ul", + "list-ol" : "fa-list-ol", + hr : "fa-minus", + link : "fa-link", + "reference-link" : "fa-anchor", + image : "fa-picture-o", + code : "fa-code", + "preformatted-text" : "fa-file-code-o", + "code-block" : "fa-file-code-o", + table : "fa-table", + datetime : "fa-clock-o", + emoji : "fa-smile-o", + "html-entities" : "fa-copyright", + pagebreak : "fa-newspaper-o", + "goto-line" : "fa-terminal", // fa-crosshairs + watch : "fa-eye-slash", + unwatch : "fa-eye", + preview : "fa-desktop", + search : "fa-search", + fullscreen : "fa-arrows-alt", + clear : "fa-eraser", + help : "fa-question-circle", + info : "fa-info-circle" + }, + toolbarIconTexts : {}, + + lang : { + name : "zh-cn", + description : "开源在线Markdown编辑器
                                Open source online Markdown editor.", + tocTitle : "目录", + toolbar : { + undo : "撤销(Ctrl+Z)", + redo : "重做(Ctrl+Y)", + bold : "粗体", + del : "删除线", + italic : "斜体", + quote : "引用", + ucwords : "将每个单词首字母转成大写", + uppercase : "将所选转换成大写", + lowercase : "将所选转换成小写", + h1 : "标题1", + h2 : "标题2", + h3 : "标题3", + h4 : "标题4", + h5 : "标题5", + h6 : "标题6", + "list-ul" : "无序列表", + "list-ol" : "有序列表", + hr : "横线", + link : "链接", + "reference-link" : "引用链接", + image : "添加图片", + code : "行内代码", + "preformatted-text" : "预格式文本 / 代码块(缩进风格)", + "code-block" : "代码块(多语言风格)", + table : "添加表格", + datetime : "日期时间", + emoji : "Emoji表情", + "html-entities" : "HTML实体字符", + pagebreak : "插入分页符", + "goto-line" : "跳转到行", + watch : "关闭实时预览", + unwatch : "开启实时预览", + preview : "全窗口预览HTML(按 Shift + ESC还原)", + fullscreen : "全屏(按ESC还原)", + clear : "清空", + search : "搜索", + help : "使用帮助", + info : "关于" + editormd.title + }, + buttons : { + enter : "确定", + cancel : "取消", + close : "关闭" + }, + dialog : { + link : { + title : "添加链接", + url : "链接地址", + urlTitle : "链接标题", + urlEmpty : "错误:请填写链接地址。" + }, + referenceLink : { + title : "添加引用链接", + name : "引用名称", + url : "链接地址", + urlId : "链接ID", + urlTitle : "链接标题", + nameEmpty: "错误:引用链接的名称不能为空。", + idEmpty : "错误:请填写引用链接的ID。", + urlEmpty : "错误:请填写引用链接的URL地址。" + }, + image : { + title : "添加图片", + url : "图片地址", + link : "图片链接", + alt : "图片描述", + uploadButton : "本地上传", + imageURLEmpty : "错误:图片地址不能为空。", + uploadFileEmpty : "错误:上传的图片不能为空。", + formatNotAllowed : "错误:只允许上传图片文件,允许上传的图片文件格式有:" + }, + preformattedText : { + title : "添加预格式文本或代码块", + emptyAlert : "错误:请填写预格式文本或代码的内容。" + }, + codeBlock : { + title : "添加代码块", + selectLabel : "代码语言:", + selectDefaultText : "请选择代码语言", + otherLanguage : "其他语言", + unselectedLanguageAlert : "错误:请选择代码所属的语言类型。", + codeEmptyAlert : "错误:请填写代码内容。" + }, + htmlEntities : { + title : "HTML 实体字符" + }, + help : { + title : "使用帮助" + } + } + } + }; + + editormd.classNames = { + tex : editormd.classPrefix + "tex" + }; + + editormd.dialogZindex = 99999; + + editormd.$katex = null; + editormd.$marked = null; + editormd.$CodeMirror = null; + editormd.$prettyPrint = null; + + var timer, flowchartTimer; + var settingNew; + editormd.prototype = editormd.fn = { + state : { + watching : false, + loaded : false, + preview : false, + fullscreen : false + }, + + /** + * 构造函数/实例初始化 + * Constructor / instance initialization + * + * @param {String} id 编辑器的ID + * @param {Object} [options={}] 配置选项 Key/Value + * @returns {editormd} 返回editormd的实例对象 + */ + + init : function (id, options) { + + options = options || {}; + + if (typeof id === "object") + { + options = id; + } + + var _this = this; + var classPrefix = this.classPrefix = editormd.classPrefix; + var settings = settingNew = $.extend(true, editormd.defaults, options); + this.settings = settings; + + id = (typeof id === "object") ? settings.id : id; + + var editor = this.editor = $("#" + id); + + this.id = id; + this.lang = settings.lang; + + var classNames = this.classNames = { + textarea : { + html : classPrefix + "html-textarea", + markdown : classPrefix + "markdown-textarea" + } + }; + + settings.pluginPath = (settings.pluginPath === "") ? settings.path + "../plugins/" : settings.pluginPath; + + this.state.watching = (settings.watch) ? true : false; + + if ( !editor.hasClass("editormd") ) { + editor.addClass("editormd"); + } + + editor.css({ + width : (typeof settings.width === "number") ? settings.width + "px" : settings.width, + height : (typeof settings.height === "number") ? settings.height + "px" : settings.height + }); + + if (settings.autoHeight) + { + editor.css("height", "auto"); + } + + var markdownTextarea = this.markdownTextarea = editor.children("textarea"); + + if (markdownTextarea.length < 1) + { + editor.append(""); + markdownTextarea = this.markdownTextarea = editor.children("textarea"); + } + + markdownTextarea.addClass(classNames.textarea.markdown).attr("placeholder", settings.placeholder); + + if (typeof markdownTextarea.attr("name") === "undefined" || markdownTextarea.attr("name") === "") + { + markdownTextarea.attr("name", (settings.name !== "") ? settings.name : id + "-markdown-doc"); + } + + var appendElements = [ + (!settings.readOnly) ? "" : "", + ( (settings.saveHTMLToTextarea) ? "" : "" ), + "
                                ", + "
                                ", + "
                                " + ].join("\n"); + + editor.append(appendElements).addClass(classPrefix + "vertical"); + + if (settings.theme !== "") + { + editor.addClass(classPrefix + "theme-" + settings.theme); + } + + this.mask = editor.children("." + classPrefix + "mask"); + this.containerMask = editor.children("." + classPrefix + "container-mask"); + + if (settings.markdown !== "") + { + markdownTextarea.val(settings.markdown); + } + + if (settings.appendMarkdown !== "") + { + markdownTextarea.val(markdownTextarea.val() + settings.appendMarkdown); + } + + this.htmlTextarea = editor.children("." + classNames.textarea.html); + this.preview = editor.children("." + classPrefix + "preview"); + this.previewContainer = this.preview.children("." + classPrefix + "preview-container"); + + if (settings.previewTheme !== "") + { + this.preview.addClass(classPrefix + "preview-theme-" + settings.previewTheme); + } + + if (typeof define === "function" && define.amd) + { + if (typeof katex !== "undefined") + { + editormd.$katex = katex; + } + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(settings.path + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(settings.path + "codemirror/addon/search/matchesonscrollbar"); + } + } + + if ((typeof define === "function" && define.amd) || !settings.autoLoadModules) + { + if (typeof CodeMirror !== "undefined") { + editormd.$CodeMirror = CodeMirror; + } + + if (typeof marked !== "undefined") { + editormd.$marked = marked; + } + + this.setCodeMirror().setToolbar().loadedDisplay(); + } + else + { + this.loadQueues(); + } + + return this; + }, + + /** + * 所需组件加载队列 + * Required components loading queue + * + * @returns {editormd} 返回editormd的实例对象 + */ + + loadQueues : function() { + var _this = this; + var settings = settingNew; + var loadPath = settings.path; + + var loadFlowChartOrSequenceDiagram = function() { + + if (editormd.isIE8) + { + _this.loadedDisplay(); + + return ; + } + + if (settings.flowChart || settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "raphael.min", function() { + + editormd.loadScript(loadPath + "underscore.min", function() { + + if (!settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + } + else if (settings.flowChart && !settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + _this.loadedDisplay(); + }); + }); + } + else if (settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + }); + }); + } + }); + + }); + } + else + { + _this.loadedDisplay(); + } + }; + + // codemirror 已经加载了 + // editormd.loadCSS(loadPath + "codemirror/codemirror.min"); + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(loadPath + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(loadPath + "codemirror/addon/search/matchesonscrollbar"); + } + + if (settings.codeFold) + { + editormd.loadCSS(loadPath + "codemirror/addon/fold/foldgutter"); + } + + // codemirror 已经加载了,codemirror会有插件,重复加载会使得之前加载的插件失效 + + // editormd.loadScript(loadPath + "codemirror/codemirror.min", function() { + editormd.$CodeMirror = CodeMirror; + + editormd.loadScript(loadPath + "codemirror/modes.min", function() { + + editormd.loadScript(loadPath + "codemirror/addons.min", function() { + + _this.setCodeMirror(); + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + _this.loadedDisplay(); + + return false; + } + + _this.setToolbar(); + + editormd.loadScript(loadPath + "marked.min", function() { + + editormd.$marked = marked; + + if (settings.previewCodeHighlight) + { + editormd.loadScript(loadPath + "prettify.min", function() { + loadFlowChartOrSequenceDiagram(); + }); + } + else + { + loadFlowChartOrSequenceDiagram(); + } + }); + + }); + + }); + + // }); + + return this; + }, + + /** + * 设置 Editor.md 的整体主题,主要是工具栏 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setTheme : function(theme) { + var editor = this.editor; + var oldTheme = settingNew.theme; + var themePrefix = this.classPrefix + "theme-"; + + editor.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + settingNew.theme = theme; + + return this; + }, + + /** + * 设置 CodeMirror(编辑区)的主题 + * Setting CodeMirror (Editor area) theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setEditorTheme : function(theme) { + var settings = settingNew; + settings.editorTheme = theme; + + if (theme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + this.cm.setOption("theme", theme); + + return this; + }, + + /** + * setEditorTheme() 的别名 + * setEditorTheme() alias + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorTheme : function (theme) { + this.setEditorTheme(theme); + + return this; + }, + + /** + * 设置 Editor.md 的主题 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setPreviewTheme : function(theme) { + var preview = this.preview; + var oldTheme = settingNew.previewTheme; + var themePrefix = this.classPrefix + "preview-theme-"; + + preview.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + settingNew.previewTheme = theme; + + return this; + }, + + /** + * 配置和初始化CodeMirror组件 + * CodeMirror initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirror : function() { + var settings = settingNew; + var editor = this.editor; + + if (settings.editorTheme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + var codeMirrorConfig = { + mode : settings.mode, + theme : settings.editorTheme, + tabSize : settings.tabSize, + dragDrop : false, + autofocus : settings.autoFocus, + autoCloseTags : settings.autoCloseTags, + readOnly : (settings.readOnly) ? "nocursor" : false, + indentUnit : settings.indentUnit, + lineNumbers : settings.lineNumbers, + lineWrapping : settings.lineWrapping, + extraKeys : { + "Ctrl-Q": function(cm) { + cm.foldCode(cm.getCursor()); + } + }, + foldGutter : settings.codeFold, + gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + matchBrackets : settings.matchBrackets, + indentWithTabs : settings.indentWithTabs, + styleActiveLine : settings.styleActiveLine, + styleSelectedText : settings.styleSelectedText, + autoCloseBrackets : settings.autoCloseBrackets, + showTrailingSpace : settings.showTrailingSpace, + highlightSelectionMatches : ( (!settings.matchWordHighlight) ? false : { showToken: (settings.matchWordHighlight === "onselected") ? false : /\w/ } ) + }; + + this.codeEditor = this.cm = editormd.$CodeMirror.fromTextArea(this.markdownTextarea[0], codeMirrorConfig); + this.codeMirror = this.cmElement = editor.children(".CodeMirror"); + + if (settings.value !== "") + { + this.cm.setValue(settings.value); + } + + this.codeMirror.css({ + fontSize : settings.fontSize, + width : (!settings.watch) ? "100%" : "50%" + }); + + if (settings.autoHeight) + { + this.codeMirror.css("height", "auto"); + this.cm.setOption("viewportMargin", Infinity); + } + + if (!settings.lineNumbers) + { + this.codeMirror.find(".CodeMirror-gutters").css("border-right", "none"); + } + + return this; + }, + + /** + * 获取CodeMirror的配置选项 + * Get CodeMirror setting options + * + * @returns {Mixed} return CodeMirror setting option value + */ + + getCodeMirrorOption : function(key) { + return this.cm.getOption(key); + }, + + /** + * 配置和重配置CodeMirror的选项 + * CodeMirror setting options / resettings + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorOption : function(key, value) { + + this.cm.setOption(key, value); + + return this; + }, + + /** + * 添加 CodeMirror 键盘快捷键 + * Add CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + addKeyMap : function(map, bottom) { + this.cm.addKeyMap(map, bottom); + + return this; + }, + + /** + * 移除 CodeMirror 键盘快捷键 + * Remove CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + removeKeyMap : function(map) { + this.cm.removeKeyMap(map); + + return this; + }, + + /** + * 跳转到指定的行 + * Goto CodeMirror line + * + * @param {String|Intiger} line line number or "first"|"last" + * @returns {editormd} 返回editormd的实例对象 + */ + + gotoLine : function (line) { + + var settings = settingNew; + + if (!settings.gotoLine) + { + return this; + } + + var cm = this.cm; + var editor = this.editor; + var count = cm.lineCount(); + var preview = this.preview; + + if (typeof line === "string") + { + if(line === "last") + { + line = count; + } + + if (line === "first") + { + line = 1; + } + } + + if (typeof line !== "number") + { + alert("Error: The line number must be an integer."); + return this; + } + + line = parseInt(line) - 1; + + if (line > count) + { + alert("Error: The line number range 1-" + count); + + return this; + } + + cm.setCursor( {line : line, ch : 0} ); + + var scrollInfo = cm.getScrollInfo(); + var clientHeight = scrollInfo.clientHeight; + var coords = cm.charCoords({line : line, ch : 0}, "local"); + + cm.scrollTo(null, (coords.top + coords.bottom - clientHeight) / 2); + + if (settings.watch) + { + var cmScroll = this.codeMirror.find(".CodeMirror-scroll")[0]; + var height = $(cmScroll).height(); + var scrollTop = cmScroll.scrollTop; + var percent = (scrollTop / cmScroll.scrollHeight); + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= cmScroll.scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop(preview[0].scrollHeight * percent); + } + } + + cm.focus(); + + return this; + }, + + /** + * 扩展当前实例对象,可同时设置多个或者只设置一个 + * Extend editormd instance object, can mutil setting. + * + * @returns {editormd} this(editormd instance object.) + */ + + extend : function() { + if (typeof arguments[1] !== "undefined") + { + if (typeof arguments[1] === "function") + { + arguments[1] = $.proxy(arguments[1], this); + } + + this[arguments[0]] = arguments[1]; + } + + if (typeof arguments[0] === "object" && typeof arguments[0].length === "undefined") + { + $.extend(true, this, arguments[0]); + } + + return this; + }, + + /** + * 设置或扩展当前实例对象,单个设置 + * Extend editormd instance object, one by one + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + set : function (key, value) { + + if (typeof value !== "undefined" && typeof value === "function") + { + value = $.proxy(value, this); + } + + this[key] = value; + + return this; + }, + + /** + * 重新配置 + * Resetting editor options + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + config : function(key, value) { + var settings = settingNew; + + if (typeof key === "object") + { + settings = $.extend(true, settings, key); + } + + if (typeof key === "string") + { + settings[key] = value; + } + + settingNew = settings; + this.recreate(); + + return this; + }, + + /** + * 注册事件处理方法 + * Bind editor event handle + * + * @param {String} eventType event type + * @param {Function} callback 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + on : function(eventType, callback) { + var settings = settingNew; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = $.proxy(callback, this); + } + + return this; + }, + + /** + * 解除事件处理方法 + * Unbind editor event handle + * + * @param {String} eventType event type + * @returns {editormd} this(editormd instance object.) + */ + + off : function(eventType) { + var settings = settingNew; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = function(){}; + } + + return this; + }, + + /** + * 显示工具栏 + * Display toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + showToolbar : function(callback) { + var settings = settingNew; + + if(settings.readOnly) { + return this; + } + + if (settings.toolbar && (this.toolbar.length < 1 || this.toolbar.find("." + this.classPrefix + "menu").html() === "") ) + { + this.setToolbar(); + } + + settings.toolbar = true; + + this.toolbar.show(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 隐藏工具栏 + * Hide toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + hideToolbar : function(callback) { + var settings = settingNew; + + settings.toolbar = false; + this.toolbar.hide(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 页面滚动时工具栏的固定定位 + * Set toolbar in window scroll auto fixed position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarAutoFixed : function(fixed) { + + var state = this.state; + var editor = this.editor; + var toolbar = this.toolbar; + var settings = settingNew; + + if (typeof fixed !== "undefined") + { + settings.toolbarAutoFixed = fixed; + } + + var autoFixedHandle = function(){ + var $window = $(window); + var top = $window.scrollTop(); + + if (!settings.toolbarAutoFixed) + { + return false; + } + + if (top - editor.offset().top > 10 && top < editor.height()) + { + toolbar.css({ + position : "fixed", + width : editor.width() + "px", + left : ($window.width() - editor.width()) / 2 + "px" + }); + } + else + { + toolbar.css({ + position : "absolute", + width : "100%", + left : 0 + }); + } + }; + + if (!state.fullscreen && !state.preview && settings.toolbar && settings.toolbarAutoFixed) + { + $(window).bind("scroll", autoFixedHandle); + } + + return this; + }, + + /** + * 配置和初始化工具栏 + * Set toolbar and Initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbar : function() { + var settings = settingNew; + + if(settings.readOnly) { + return this; + } + + var editor = this.editor; + var preview = this.preview; + var classPrefix = this.classPrefix; + + var toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + + if (settings.toolbar && toolbar.length < 1) + { + var toolbarHTML = "
                                  "; + + editor.append(toolbarHTML); + toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + } + + if (!settings.toolbar) + { + toolbar.hide(); + + return this; + } + + toolbar.show(); + + var icons = (typeof settings.toolbarIcons === "function") ? settings.toolbarIcons(this) + : ((typeof settings.toolbarIcons === "string") ? editormd.toolbarModes[settings.toolbarIcons] : settings.toolbarIcons); + + var toolbarMenu = toolbar.find("." + this.classPrefix + "menu"), menu = ""; + var pullRight = false; + + for (var i = 0, len = icons.length; i < len; i++) + { + var name = icons[i]; + + if (name === "||") + { + pullRight = true; + } + else if (name === "|") + { + menu += "
                                • |
                                • "; + } + else + { + var isHeader = (/h(\d)/.test(name)); + var index = name; + + if (name === "watch" && !settings.watch) { + index = "unwatch"; + } + + var title = settings.lang.toolbar[index]; + var iconTexts = settings.toolbarIconTexts[index]; + var iconClass = settings.toolbarIconsClass[index]; + + title = (typeof title === "undefined") ? "" : title; + iconTexts = (typeof iconTexts === "undefined") ? "" : iconTexts; + iconClass = (typeof iconClass === "undefined") ? "" : iconClass; + + var menuItem = pullRight ? "
                                • " : "
                                • "; + + if (typeof settings.toolbarCustomIcons[name] !== "undefined" && typeof settings.toolbarCustomIcons[name] !== "function") + { + menuItem += settings.toolbarCustomIcons[name]; + } + else + { + menuItem += ""; + menuItem += ""+((isHeader) ? name.toUpperCase() : ( (iconClass === "") ? iconTexts : "") ) + ""; + menuItem += ""; + } + + menuItem += "
                                • "; + + menu = pullRight ? menuItem + menu : menu + menuItem; + } + } + + toolbarMenu.html(menu); + + toolbarMenu.find("[title=\"Lowercase\"]").attr("title", settings.lang.toolbar.lowercase); + toolbarMenu.find("[title=\"ucwords\"]").attr("title", settings.lang.toolbar.ucwords); + + this.setToolbarHandler(); + this.setToolbarAutoFixed(); + + return this; + }, + + /** + * 工具栏图标事件处理对象序列 + * Get toolbar icons event handlers + * + * @param {Object} cm CodeMirror的实例对象 + * @param {String} name 要获取的事件处理器名称 + * @returns {Object} 返回处理对象序列 + */ + + dialogLockScreen : function() { + $.proxy(editormd.dialogLockScreen, this)(); + + return this; + }, + + dialogShowMask : function(dialog) { + $.proxy(editormd.dialogShowMask, this)(dialog); + + return this; + }, + + getToolbarHandles : function(name) { + var toolbarHandlers = this.toolbarHandlers = editormd.toolbarHandlers; + + return (name && typeof toolbarIconHandlers[name] !== "undefined") ? toolbarHandlers[name] : toolbarHandlers; + }, + + /** + * 工具栏图标事件处理器 + * Bind toolbar icons event handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarHandler : function() { + var _this = this; + var settings = settingNew; + + if (!settings.toolbar || settings.readOnly) { + return this; + } + + var toolbar = this.toolbar; + var cm = this.cm; + var classPrefix = this.classPrefix; + var toolbarIcons = this.toolbarIcons = toolbar.find("." + classPrefix + "menu > li > a"); + var toolbarIconHandlers = this.getToolbarHandles(); + + toolbarIcons.bind(editormd.mouseOrTouch("click", "touchend"), function(event) { + + var icon = $(this).children(".fa"); + var name = icon.attr("name"); + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (name === "") { + return ; + } + + _this.activeIcon = icon; + + if (typeof toolbarIconHandlers[name] !== "undefined") + { + $.proxy(toolbarIconHandlers[name], _this)(cm); + } + else + { + if (typeof settings.toolbarHandlers[name] !== "undefined") + { + $.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection); + } + } + + if (name !== "link" && name !== "reference-link" && name !== "image" && name !== "code-block" && + name !== "preformatted-text" && name !== "watch" && name !== "preview" && name !== "search" && name !== "fullscreen" && name !== "info") + { + cm.focus(); + } + + return false; + + }); + + return this; + }, + + /** + * 动态创建对话框 + * Creating custom dialogs + * + * @param {Object} options 配置项键值对 Key/Value + * @returns {dialog} 返回创建的dialog的jQuery实例对象 + */ + + createDialog : function(options) { + return $.proxy(editormd.createDialog, this)(options); + }, + + /** + * 创建关于Editor.md的对话框 + * Create about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + createInfoDialog : function() { + var _this = this; + var editor = this.editor; + var classPrefix = this.classPrefix; + + var infoDialogHTML = [ + "
                                  ", + "
                                  ", + "

                                  " + editormd.title + "v" + editormd.version + "

                                  ", + "

                                  " + this.lang.description + "

                                  ", + "

                                  " + editormd.homePage + "

                                  ", + "

                                  Copyright © 2015 Pandao, The MIT License.

                                  ", + "
                                  ", + "", + "
                                  " + ].join("\n"); + + editor.append(infoDialogHTML); + + var infoDialog = this.infoDialog = editor.children("." + classPrefix + "dialog-info"); + + infoDialog.find("." + classPrefix + "dialog-close").bind(editormd.mouseOrTouch("click", "touchend"), function() { + _this.hideInfoDialog(); + }); + + infoDialog.css("border", (editormd.isIE8) ? "1px solid #ddd" : "").css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 关于Editor.md对话居中定位 + * Editor.md dialog position handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + infoDialogPosition : function() { + var infoDialog = this.infoDialog; + + var _infoDialogPosition = function() { + infoDialog.css({ + top : ($(window).height() - infoDialog.height()) / 2 + "px", + left : ($(window).width() - infoDialog.width()) / 2 + "px" + }); + }; + + _infoDialogPosition(); + + $(window).resize(_infoDialogPosition); + + return this; + }, + + /** + * 显示关于Editor.md + * Display about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + showInfoDialog : function() { + + $("html,body").css("overflow-x", "hidden"); + + var _this = this; + var editor = this.editor; + var settings = settingNew; + var infoDialog = this.infoDialog = editor.children("." + this.classPrefix + "dialog-info"); + + if (infoDialog.length < 1) + { + this.createInfoDialog(); + } + + this.lockScreen(true); + + this.mask.css({ + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }).show(); + + infoDialog.css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 隐藏关于Editor.md + * Hide about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + hideInfoDialog : function() { + $("html,body").css("overflow-x", ""); + this.infoDialog.hide(); + this.mask.hide(); + this.lockScreen(false); + + return this; + }, + + /** + * 锁屏 + * lock screen + * + * @param {Boolean} lock Boolean 布尔值,是否锁屏 + * @returns {editormd} 返回editormd的实例对象 + */ + + lockScreen : function(lock) { + editormd.lockScreen(lock); + this.resize(); + + return this; + }, + + /** + * 编辑器界面重建,用于动态语言包或模块加载等 + * Recreate editor + * + * @returns {editormd} 返回editormd的实例对象 + */ + + recreate : function() { + var _this = this; + var editor = this.editor; + var settings = settingNew; + + this.codeMirror.remove(); + + this.setCodeMirror(); + + if (!settings.readOnly) + { + if (editor.find(".editormd-dialog").length > 0) { + editor.find(".editormd-dialog").remove(); + } + + if (settings.toolbar) + { + this.getToolbarHandles(); + this.setToolbar(); + } + } + + this.loadedDisplay(true); + + return this; + }, + + /** + * 高亮预览HTML的pre代码部分 + * highlight of preview codes + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewCodeHighlight : function() { + var settings = settingNew; + var previewContainer = this.previewContainer; + + if (settings.previewCodeHighlight) + { + previewContainer.find("pre").addClass("prettyprint linenums"); + + if (typeof prettyPrint !== "undefined") + { + prettyPrint(); + } + } + + return this; + }, + + /** + * 解析TeX(KaTeX)科学公式 + * TeX(KaTeX) Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + katexRender : function() { + + if (timer === null) + { + return this; + } + + this.previewContainer.find("." + editormd.classNames.tex).each(function(){ + var tex = $(this); + editormd.$katex.render(tex.text(), tex[0]); + + tex.find(".katex").css("font-size", "1.0em"); + }); + + return this; + }, + + /** + * 解析和渲染流程图及时序图 + * FlowChart and SequenceDiagram Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + flowChartAndSequenceDiagramRender : function() { + var $this = this; + var settings = settingNew; + var previewContainer = this.previewContainer; + + if (editormd.isIE8) { + return this; + } + + if (settings.flowChart) { + if (flowchartTimer === null) { + return this; + } + + previewContainer.find(".flowchart").flowChart(); + } + + if (settings.sequenceDiagram) { + previewContainer.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); + } + + var preview = $this.preview; + var codeMirror = $this.codeMirror; + var codeView = codeMirror.find(".CodeMirror-scroll"); + + var height = codeView.height(); + var scrollTop = codeView.scrollTop(); + var percent = (scrollTop / codeView[0].scrollHeight); + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= codeView[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + return this; + }, + + /** + * 注册键盘快捷键处理 + * Register CodeMirror keyMaps (keyboard shortcuts). + * + * @param {Object} keyMap KeyMap key/value {"(Ctrl/Shift/Alt)-Key" : function(){}} + * @returns {editormd} return this + */ + + registerKeyMaps : function(keyMap) { + + var _this = this; + var cm = this.cm; + var settings = settingNew; + var toolbarHandlers = editormd.toolbarHandlers; + var disabledKeyMaps = settings.disabledKeyMaps; + + keyMap = keyMap || null; + + if (keyMap) + { + for (var i in keyMap) + { + if ($.inArray(i, disabledKeyMaps) < 0) + { + var map = {}; + map[i] = keyMap[i]; + + cm.addKeyMap(keyMap); + } + } + } + else + { + for (var k in editormd.keyMaps) + { + var _keyMap = editormd.keyMaps[k]; + var handle = (typeof _keyMap === "string") ? $.proxy(toolbarHandlers[_keyMap], _this) : $.proxy(_keyMap, _this); + + if ($.inArray(k, ["F9", "F10", "F11"]) < 0 && $.inArray(k, disabledKeyMaps) < 0) + { + var _map = {}; + _map[k] = handle; + + cm.addKeyMap(_map); + } + } + + $(window).keydown(function(event) { + + var keymaps = { + "120" : "F9", + "121" : "F10", + "122" : "F11" + }; + + if ( $.inArray(keymaps[event.keyCode], disabledKeyMaps) < 0 ) + { + switch (event.keyCode) + { + case 120: + $.proxy(toolbarHandlers["watch"], _this)(); + return false; + break; + + case 121: + $.proxy(toolbarHandlers["preview"], _this)(); + return false; + break; + + case 122: + $.proxy(toolbarHandlers["fullscreen"], _this)(); + return false; + break; + + default: + break; + } + } + }); + } + + return this; + }, + + /** + * 绑定同步滚动 + * + * @returns {editormd} return this + */ + + bindScrollEvent : function() { + + var _this = this; + var preview = this.preview; + var settings = settingNew; + var codeMirror = this.codeMirror; + var mouseOrTouch = editormd.mouseOrTouch; + + if (!settings.syncScrolling) { + return this; + } + + var cmBindScroll = function() { + codeMirror.find(".CodeMirror-scroll").bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + $.proxy(settings.onscroll, _this)(event); + }); + }; + + var cmUnbindScroll = function() { + codeMirror.find(".CodeMirror-scroll").unbind(mouseOrTouch("scroll", "touchmove")); + }; + + var previewBindScroll = function() { + + preview.bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + var codeView = codeMirror.find(".CodeMirror-scroll"); + + if(scrollTop === 0) + { + codeView.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight) + { + codeView.scrollTop(codeView[0].scrollHeight); + } + else + { + codeView.scrollTop(codeView[0].scrollHeight * percent); + } + + $.proxy(settings.onpreviewscroll, _this)(event); + }); + + }; + + var previewUnbindScroll = function() { + preview.unbind(mouseOrTouch("scroll", "touchmove")); + }; + + codeMirror.bind({ + mouseover : cmBindScroll, + mouseout : cmUnbindScroll, + touchstart : cmBindScroll, + touchend : cmUnbindScroll + }); + + if (settings.syncScrolling === "single") { + return this; + } + + preview.bind({ + mouseover : previewBindScroll, + mouseout : previewUnbindScroll, + touchstart : previewBindScroll, + touchend : previewUnbindScroll + }); + + return this; + }, + + bindChangeEvent : function() { + + var _this = this; + var cm = this.cm; + var settings = settingNew; + + if (!settings.syncScrolling) { + return this; + } + + cm.on("change", function(_cm, changeObj) { + + if (settings.watch) + { + _this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + } + + timer = setTimeout(function() { + clearTimeout(timer); + _this.save(); + timer = null; + }, settings.delay); + }); + + return this; + }, + + /** + * 加载队列完成之后的显示处理 + * Display handle of the module queues loaded after. + * + * @param {Boolean} recreate 是否为重建编辑器 + * @returns {editormd} 返回editormd的实例对象 + */ + + loadedDisplay : function(recreate) { + + recreate = recreate || false; + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var settings = settingNew; + + this.containerMask.hide(); + + this.save(); + + if (settings.watch) { + preview.show(); + } + + editor.data("oldWidth", editor.width()).data("oldHeight", editor.height()); // 为了兼容Zepto + + this.resize(); + this.registerKeyMaps(); + + $(window).resize(function(){ + _this.resize(); + }); + + this.bindScrollEvent().bindChangeEvent(); + + if (!recreate) + { + // TODO url完善 + settings.imageUploadURL && initEditormdPasteUpload( this , settings.imageUploadURL) + $.proxy(settings.onload, this)(); + } + + this.state.loaded = true; + + return this; + }, + + /** + * 设置编辑器的宽度 + * Set editor width + * + * @param {Number|String} width 编辑器宽度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + width : function(width) { + + this.editor.css("width", (typeof width === "number") ? width + "px" : width); + this.resize(); + + return this; + }, + + /** + * 设置编辑器的高度 + * Set editor height + * + * @param {Number|String} height 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + height : function(height) { + + this.editor.css("height", (typeof height === "number") ? height + "px" : height); + this.resize(); + + return this; + }, + + /** + * 调整编辑器的尺寸和布局 + * Resize editor layout + * + * @param {Number|String} [width=null] 编辑器宽度值 + * @param {Number|String} [height=null] 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + resize : function(width, height) { + + width = width || null; + height = height || null; + + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = settingNew; + var codeMirror = this.codeMirror; + + if (width) + { + editor.css("width", (typeof width === "number") ? width + "px" : width); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + editor.css("height", "auto"); + codeMirror.css("height", "auto"); + } + else + { + if (height) + { + editor.css("height", (typeof height === "number") ? height + "px" : height); + } + + if (state.fullscreen) + { + editor.height($(window).height()); + } + + if (settings.toolbar && !settings.readOnly) + { + codeMirror.css("margin-top", toolbar.height() + 1).height(editor.height() - toolbar.height()); + } + else + { + codeMirror.css("margin-top", 0).height(editor.height()); + } + } + + if(settings.watch) + { + codeMirror.width(editor.width() / 2); + preview.width((!state.preview) ? editor.width() / 2 : editor.width()); + + this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + + if (settings.toolbar && !settings.readOnly) + { + preview.css("top", toolbar.height() + 1); + } + else + { + preview.css("top", 0); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + preview.height(""); + } + else + { + var previewHeight = (settings.toolbar && !settings.readOnly) ? editor.height() - toolbar.height() : editor.height(); + + preview.height(previewHeight); + } + } + else + { + codeMirror.width(editor.width()); + preview.hide(); + } + + if (state.loaded) + { + $.proxy(settings.onresize, this)(); + } + + return this; + }, + + /** + * 解析和保存Markdown代码 + * Parse & Saving Markdown source code + * + * @returns {editormd} 返回editormd的实例对象 + */ + + save : function() { + + if (timer === null) + { + return this; + } + + var _this = this; + var state = this.state; + var settings = settingNew; + var cm = this.cm; + var cmValue = cm.getValue(); + var previewContainer = this.previewContainer; + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + this.markdownTextarea.val(cmValue); + + return this; + } + + var marked = editormd.$marked; + var markdownToC = this.markdownToC = []; + var rendererOptions = this.markedRendererOptions = { + toc : settings.toc, + tocm : settings.tocm, + tocStartLevel : settings.tocStartLevel, + pageBreak : settings.pageBreak, + taskList : settings.taskList, + emoji : settings.emoji, + tex : settings.tex, + atLink : settings.atLink, // for @link + emailLink : settings.emailLink, // for mail address auto link + flowChart : settings.flowChart, + sequenceDiagram : settings.sequenceDiagram, + previewCodeHighlight : settings.previewCodeHighlight, + }; + + var markedOptions = this.markedOptions = { + renderer : editormd.markedRenderer(markdownToC, rendererOptions), + gfm : true, + tables : true, + breaks : true, + pedantic : false, + sanitize : (settings.htmlDecode) ? false : true, // 关闭忽略HTML标签,即开启识别HTML标签,默认为false + smartLists : true, + smartypants : true + }; + + marked.setOptions(markedOptions); + + var newMarkdownDoc = editormd.$marked(cmValue, markedOptions); + + //console.info("cmValue", cmValue, newMarkdownDoc); + + newMarkdownDoc = editormd.filterHTMLTags(newMarkdownDoc, settings.htmlDecode); + + //console.error("cmValue", cmValue, newMarkdownDoc); + + this.markdownTextarea.text(cmValue); + + cm.save(); + + if (settings.saveHTMLToTextarea) + { + this.htmlTextarea.text(newMarkdownDoc); + } + + if(settings.watch || (!settings.watch && state.preview)) + { + previewContainer.html(newMarkdownDoc); + + this.previewCodeHighlight(); + + if (settings.toc) + { + var tocContainer = (settings.tocContainer === "") ? previewContainer : $(settings.tocContainer); + var tocMenu = tocContainer.find("." + this.classPrefix + "toc-menu"); + + tocContainer.attr("previewContainer", (settings.tocContainer === "") ? "true" : "false"); + + if (settings.tocContainer !== "" && tocMenu.length > 0) + { + tocMenu.remove(); + } + + editormd.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); + + if (settings.tocDropdown || tocContainer.find("." + this.classPrefix + "toc-menu").length > 0) + { + editormd.tocDropdownMenu(tocContainer, (settings.tocTitle !== "") ? settings.tocTitle : this.lang.tocTitle); + } + + if (settings.tocContainer !== "") + { + previewContainer.find(".markdown-toc").css("border", "none"); + } + } + + if (settings.tex) + { + if (!editormd.kaTeXLoaded && settings.autoLoadModules) + { + editormd.loadKaTeX(function() { + editormd.$katex = katex; + editormd.kaTeXLoaded = true; + _this.katexRender(); + }); + } + else + { + editormd.$katex = katex; + this.katexRender(); + } + } + + if (settings.flowChart || settings.sequenceDiagram) + { + flowchartTimer = setTimeout(function(){ + clearTimeout(flowchartTimer); + _this.flowChartAndSequenceDiagramRender(); + flowchartTimer = null; + }, 10); + } + + if (state.loaded) + { + $.proxy(settings.onchange, this)(); + } + } + + return this; + }, + + /** + * 聚焦光标位置 + * Focusing the cursor position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + focus : function() { + this.cm.focus(); + + return this; + }, + + /** + * 设置光标的位置 + * Set cursor position + * + * @param {Object} cursor 要设置的光标位置键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setCursor : function(cursor) { + this.cm.setCursor(cursor); + + return this; + }, + + /** + * 获取当前光标的位置 + * Get the current position of the cursor + * + * @returns {Cursor} 返回一个光标Cursor对象 + */ + + getCursor : function() { + return this.cm.getCursor(); + }, + + /** + * 设置光标选中的范围 + * Set cursor selected ranges + * + * @param {Object} from 开始位置的光标键值对象,例:{line:1, ch:0} + * @param {Object} to 结束位置的光标键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setSelection : function(from, to) { + + this.cm.setSelection(from, to); + + return this; + }, + + /** + * 获取光标选中的文本 + * Get the texts from cursor selected + * + * @returns {String} 返回选中文本的字符串形式 + */ + + getSelection : function() { + return this.cm.getSelection(); + }, + + /** + * 设置光标选中的文本范围 + * Set the cursor selection ranges + * + * @param {Array} ranges cursor selection ranges array + * @returns {Array} return this + */ + + setSelections : function(ranges) { + this.cm.setSelections(ranges); + + return this; + }, + + /** + * 获取光标选中的文本范围 + * Get the cursor selection ranges + * + * @returns {Array} return selection ranges array + */ + + getSelections : function() { + return this.cm.getSelections(); + }, + + /** + * 替换当前光标选中的文本或在当前光标处插入新字符 + * Replace the text at the current cursor selected or insert a new character at the current cursor position + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + replaceSelection : function(value) { + this.cm.replaceSelection(value); + + return this; + }, + + /** + * 在当前光标处插入新字符 + * Insert a new character at the current cursor position + * + * 同replaceSelection()方法 + * With the replaceSelection() method + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + insertValue : function(value) { + this.replaceSelection(value); + + return this; + }, + + /** + * 追加markdown + * append Markdown to editor + * + * @param {String} md 要追加的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + appendMarkdown : function(md) { + var settings = settingNew; + var cm = this.cm; + + cm.setValue(cm.getValue() + md); + + return this; + }, + + /** + * 设置和传入编辑器的markdown源文档 + * Set Markdown source document + * + * @param {String} md 要传入的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + setMarkdown : function(md) { + this.cm.setValue(md || settingNew.markdown); + + return this; + }, + + /** + * 获取编辑器的markdown源文档 + * Set Editor.md markdown/CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getMarkdown : function() { + return this.cm.getValue(); + }, + + /** + * 获取编辑器的源文档 + * Get CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getValue : function() { + return this.cm.getValue(); + }, + + /** + * 设置编辑器的源文档 + * Set CodeMirror value + * + * @param {String} value set code/value/string/text + * @returns {editormd} 返回editormd的实例对象 + */ + + setValue : function(value) { + this.cm.setValue(value); + + return this; + }, + + /** + * 清空编辑器 + * Empty CodeMirror editor container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + clear : function() { + this.cm.setValue(""); + + return this; + }, + + /** + * 获取解析后存放在Textarea的HTML源码 + * Get parsed html code from Textarea + * + * @returns {String} 返回HTML源码 + */ + + getHTML : function() { + if (!settingNew.saveHTMLToTextarea) + { + alert("Error: settings.saveHTMLToTextarea == false"); + + return false; + } + + return this.htmlTextarea.val(); + }, + + /** + * getHTML()的别名 + * getHTML (alias) + * + * @returns {String} Return html code 返回HTML源码 + */ + + getTextareaSavedHTML : function() { + return this.getHTML(); + }, + + /** + * 获取预览窗口的HTML源码 + * Get html from preview container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getPreviewedHTML : function() { + if (!settingNew.watch) + { + alert("Error: settings.watch == false"); + + return false; + } + + return this.previewContainer.html(); + }, + + /** + * 开启实时预览 + * Enable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + watch : function(callback) { + var settings = settingNew; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) + { + return this; + } + + this.state.watching = settings.watch = true; + this.preview.show(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.watch); + icon.removeClass(unWatchIcon).addClass(watchIcon); + } + + this.codeMirror.css("border-right", "1px solid #ddd").width(this.editor.width() / 2); + + timer = 0; + + this.save().resize(); + + if (!settings.onwatch) + { + settings.onwatch = callback || function() {}; + } + + $.proxy(settings.onwatch, this)(); + + return this; + }, + + /** + * 关闭实时预览 + * Disable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + unwatch : function(callback) { + var settings = settingNew; + this.state.watching = settings.watch = false; + this.preview.hide(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.unwatch); + icon.removeClass(watchIcon).addClass(unWatchIcon); + } + + this.codeMirror.css("border-right", "none").width(this.editor.width()); + + this.resize(); + + if (!settings.onunwatch) + { + settings.onunwatch = callback || function() {}; + } + + $.proxy(settings.onunwatch, this)(); + + return this; + }, + + /** + * 显示编辑器 + * Show editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + show : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.show(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器 + * Hide editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + hide : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.hide(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器部分,只预览HTML + * Enter preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewing : function() { + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = settingNew; + var codeMirror = this.codeMirror; + var previewContainer = this.previewContainer; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) { + return this; + } + + if (settings.toolbar && toolbar) { + toolbar.toggle(); + toolbar.find(".fa[name=preview]").toggleClass("active"); + } + + codeMirror.toggle(); + + var escHandle = function(event) { + if (event.shiftKey && event.keyCode === 27) { + _this.previewed(); + } + }; + + if (codeMirror.css("display") === "none") // 为了兼容Zepto,而不使用codeMirror.is(":hidden") + { + this.state.preview = true; + + if (this.state.fullscreen) { + preview.css("background", "#fff"); + } + + editor.find("." + this.classPrefix + "preview-close-btn").show().bind(editormd.mouseOrTouch("click", "touchend"), function(){ + _this.previewed(); + }); + + if (!settings.watch) + { + this.save(); + } + else + { + previewContainer.css("padding", ""); + } + + previewContainer.addClass(this.classPrefix + "preview-active"); + + preview.show().css({ + position : "", + top : 0, + width : editor.width(), + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewing, this)(); + } + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.previewed(); + } + }, + + /** + * 显示编辑器部分,退出只预览HTML + * Exit preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewed : function() { + + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = settingNew; + var previewContainer = this.previewContainer; + var previewCloseBtn = editor.find("." + this.classPrefix + "preview-close-btn"); + + this.state.preview = false; + + this.codeMirror.show(); + + if (settings.toolbar) { + toolbar.show(); + } + + preview[(settings.watch) ? "show" : "hide"](); + + previewCloseBtn.hide().unbind(editormd.mouseOrTouch("click", "touchend")); + + previewContainer.removeClass(this.classPrefix + "preview-active"); + + if (settings.watch) + { + previewContainer.css("padding", "20px"); + } + + preview.css({ + background : null, + position : "absolute", + width : editor.width() / 2, + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() - toolbar.height(), + top : (settings.toolbar) ? toolbar.height() : 0 + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewed, this)(); + } + + return this; + }, + + /** + * 编辑器全屏显示 + * Fullscreen show + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreen : function() { + + var _this = this; + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = settingNew; + var fullscreenClass = this.classPrefix + "fullscreen"; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().toggleClass("active"); + } + + var escHandle = function(event) { + if (!event.shiftKey && event.keyCode === 27) + { + if (state.fullscreen) + { + _this.fullscreenExit(); + } + } + }; + + if (!editor.hasClass(fullscreenClass)) + { + state.fullscreen = true; + + $("html,body").css("overflow", "hidden"); + + editor.css({ + width : $(window).width(), + height : $(window).height() + }).addClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreen, this)(); + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.fullscreenExit(); + } + + return this; + }, + + /** + * 编辑器退出全屏显示 + * Exit fullscreen state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreenExit : function() { + + var editor = this.editor; + var settings = settingNew; + var toolbar = this.toolbar; + var fullscreenClass = this.classPrefix + "fullscreen"; + + this.state.fullscreen = false; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().removeClass("active"); + } + + $("html,body").css("overflow", ""); + + editor.css({ + width : editor.data("oldWidth"), + height : editor.data("oldHeight") + }).removeClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreenExit, this)(); + + return this; + }, + + /** + * 加载并执行插件 + * Load and execute the plugin + * + * @param {String} name plugin name / function name + * @param {String} path plugin load path + * @returns {editormd} 返回editormd的实例对象 + */ + + executePlugin : function(name, path) { + + var _this = this; + var cm = this.cm; + var settings = settingNew; + + path = settings.pluginPath + path; + + if (typeof define === "function") + { + if (typeof this[name] === "undefined") + { + alert("Error: " + name + " plugin is not found, you are not load this plugin."); + + return this; + } + + this[name](cm); + + return this; + } + + if ($.inArray(path, editormd.loadFiles.plugin) < 0) + { + editormd.loadPlugin(path, function() { + editormd.loadPlugins[name] = _this[name]; + _this[name](cm); + }); + } + else + { + $.proxy(editormd.loadPlugins[name], this)(cm); + } + + return this; + }, + + /** + * 搜索替换 + * Search & replace + * + * @param {String} command CodeMirror serach commands, "find, fintNext, fintPrev, clearSearch, replace, replaceAll" + * @returns {editormd} return this + */ + + search : function(command) { + var settings = settingNew; + + if (!settings.searchReplace) + { + alert("Error: settings.searchReplace == false"); + return this; + } + + if (!settings.readOnly) + { + this.cm.execCommand(command || "find"); + } + + return this; + }, + + searchReplace : function() { + this.search("replace"); + + return this; + }, + + searchReplaceAll : function() { + this.search("replaceAll"); + + return this; + } + }; + + editormd.fn.init.prototype = editormd.fn; + + /** + * 锁屏 + * lock screen when dialog opening + * + * @returns {void} + */ + + editormd.dialogLockScreen = function() { + var settings = settingNew || {dialogLockScreen : true}; + + if (settings.dialogLockScreen) + { + $("html,body").css("overflow", "hidden"); + this.resize(); + } + }; + + /** + * 显示透明背景层 + * Display mask layer when dialog opening + * + * @param {Object} dialog dialog jQuery object + * @returns {void} + */ + + editormd.dialogShowMask = function(dialog) { + var editor = this.editor; + var settings = settingNew || {dialogShowMask : true}; + + dialog.css({ + top : ($(window).height() - dialog.height()) / 2 + "px", + left : ($(window).width() - dialog.width()) / 2 + "px" + }); + + if (settings.dialogShowMask) { + editor.children("." + this.classPrefix + "mask").css("z-index", parseInt(dialog.css("z-index")) - 1).show(); + } + }; + + editormd.toolbarHandlers = { + undo : function() { + this.cm.undo(); + }, + + redo : function() { + this.cm.redo(); + }, + + bold : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("**" + selection + "**"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + del : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("~~" + selection + "~~"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + italic : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("*" + selection + "*"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + quote : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("> " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("> " + selection); + } + + //cm.replaceSelection("> " + selection); + //cm.setCursor(cursor.line, (selection === "") ? cursor.ch + 2 : cursor.ch + selection.length + 2); + }, + + ucfirst : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.firstUpperCase(selection)); + cm.setSelections(selections); + }, + + ucwords : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.wordsFirstUpperCase(selection)); + cm.setSelections(selections); + }, + + uppercase : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toUpperCase()); + cm.setSelections(selections); + }, + + lowercase : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toLowerCase()); + cm.setSelections(selections); + }, + + h1 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("# " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("# " + selection); + } + }, + + h2 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("## " + selection); + cm.setCursor(cursor.line, cursor.ch + 3); + } + else + { + cm.replaceSelection("## " + selection); + } + }, + + h3 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("### " + selection); + cm.setCursor(cursor.line, cursor.ch + 4); + } + else + { + cm.replaceSelection("### " + selection); + } + }, + + h4 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("#### " + selection); + cm.setCursor(cursor.line, cursor.ch + 5); + } + else + { + cm.replaceSelection("#### " + selection); + } + }, + + h5 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("##### " + selection); + cm.setCursor(cursor.line, cursor.ch + 6); + } + else + { + cm.replaceSelection("##### " + selection); + } + }, + + h6 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("###### " + selection); + cm.setCursor(cursor.line, cursor.ch + 7); + } + else + { + cm.replaceSelection("###### " + selection); + } + }, + + "list-ul" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (selection === "") + { + cm.replaceSelection("- " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : "- " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + "list-ol" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if(selection === "") + { + cm.replaceSelection("1. " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : (i+1) + ". " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + hr : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(((cursor.ch !== 0) ? "\n\n" : "\n") + "------------\n\n"); + }, + + tex : function() { + if (!settingNew.tex) + { + alert("settings.tex === false"); + return this; + } + + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("$$" + selection + "$$"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + link : function() { + this.executePlugin("linkDialog", "link-dialog/link-dialog"); + }, + + "reference-link" : function() { + this.executePlugin("referenceLinkDialog", "reference-link-dialog/reference-link-dialog"); + }, + + pagebreak : function() { + if (!settingNew.pageBreak) + { + alert("settings.pageBreak === false"); + return this; + } + + var cm = this.cm; + var selection = cm.getSelection(); + + cm.replaceSelection("\r\n[========]\r\n"); + }, + + image : function() { + this.executePlugin("imageDialog", "image-dialog/image-dialog"); + }, + + code : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("`" + selection + "`"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "code-block" : function() { + this.executePlugin("codeBlockDialog", "code-block-dialog/code-block-dialog"); + }, + + "preformatted-text" : function() { + this.executePlugin("preformattedTextDialog", "preformatted-text-dialog/preformatted-text-dialog"); + }, + + table : function() { + this.executePlugin("tableDialog", "table-dialog/table-dialog"); + }, + + datetime : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var date = new Date(); + var langName = settingNew.lang.name; + var datefmt = editormd.dateFormat() + " " + editormd.dateFormat((langName === "zh-cn" || langName === "zh-tw") ? "cn-week-day" : "week-day"); + + cm.replaceSelection(datefmt); + }, + + emoji : function() { + this.executePlugin("emojiDialog", "emoji-dialog/emoji-dialog"); + }, + + "html-entities" : function() { + this.executePlugin("htmlEntitiesDialog", "html-entities-dialog/html-entities-dialog"); + }, + + "goto-line" : function() { + this.executePlugin("gotoLineDialog", "goto-line-dialog/goto-line-dialog"); + }, + + watch : function() { + this[settingNew.watch ? "unwatch" : "watch"](); + }, + + preview : function() { + this.previewing(); + }, + + fullscreen : function() { + this.fullscreen(); + }, + + clear : function() { + this.clear(); + }, + + search : function() { + this.search(); + }, + + help : function() { + this.executePlugin("helpDialog", "help-dialog/help-dialog"); + }, + + info : function() { + this.showInfoDialog(); + } + }; + + editormd.keyMaps = { + "Ctrl-1" : "h1", + "Ctrl-2" : "h2", + "Ctrl-3" : "h3", + "Ctrl-4" : "h4", + "Ctrl-5" : "h5", + "Ctrl-6" : "h6", + "Ctrl-B" : "bold", // if this is string == editormd.toolbarHandlers.xxxx + "Ctrl-D" : "datetime", + + "Ctrl-E" : function() { // emoji + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!settingNew.emoji) + { + alert("Error: settings.emoji == false"); + return ; + } + + cm.replaceSelection(":" + selection + ":"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-Alt-G" : "goto-line", + "Ctrl-H" : "hr", + "Ctrl-I" : "italic", + "Ctrl-K" : "code", + + "Ctrl-L" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("[" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-U" : "list-ul", + + "Shift-Ctrl-A" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!settingNew.atLink) + { + alert("Error: settings.atLink == false"); + return ; + } + + cm.replaceSelection("@" + selection); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "Shift-Ctrl-C" : "code", + "Shift-Ctrl-Q" : "quote", + "Shift-Ctrl-S" : "del", + "Shift-Ctrl-K" : "tex", // KaTeX + + "Shift-Alt-C" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(["```", selection, "```"].join("\n")); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 3); + } + }, + + "Shift-Ctrl-Alt-C" : "code-block", + "Shift-Ctrl-H" : "html-entities", + "Shift-Alt-H" : "help", + "Shift-Ctrl-E" : "emoji", + "Shift-Ctrl-U" : "uppercase", + "Shift-Alt-U" : "ucwords", + "Shift-Ctrl-Alt-U" : "ucfirst", + "Shift-Alt-L" : "lowercase", + + "Shift-Ctrl-I" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("![" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 4); + } + }, + + "Shift-Ctrl-Alt-I" : "image", + "Shift-Ctrl-L" : "link", + "Shift-Ctrl-O" : "list-ol", + "Shift-Ctrl-P" : "preformatted-text", + "Shift-Ctrl-T" : "table", + "Shift-Alt-P" : "pagebreak", + "F9" : "watch", + "F10" : "preview", + "F11" : "fullscreen", + }; + + /** + * 清除字符串两边的空格 + * Clear the space of strings both sides. + * + * @param {String} str string + * @returns {String} trimed string + */ + + var trim = function(str) { + return (!String.prototype.trim) ? str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "") : str.trim(); + }; + + editormd.trim = trim; + + /** + * 所有单词首字母大写 + * Words first to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var ucwords = function (str) { + return str.toLowerCase().replace(/\b(\w)|\s(\w)/g, function($1) { + return $1.toUpperCase(); + }); + }; + + editormd.ucwords = editormd.wordsFirstUpperCase = ucwords; + + /** + * 字符串首字母大写 + * Only string first char to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var firstUpperCase = function(str) { + return str.toLowerCase().replace(/\b(\w)/, function($1){ + return $1.toUpperCase(); + }); + }; + + var ucfirst = firstUpperCase; + + editormd.firstUpperCase = editormd.ucfirst = firstUpperCase; + + editormd.urls = { + atLinkBase : "https://github.com/" + }; + + editormd.regexs = { + atLink : /@(\w+)/g, + email : /(\w+)@(\w+)\.(\w+)\.?(\w+)?/g, + emailLink : /(mailto:)?([\w\.\_]+)@(\w+)\.(\w+)\.?(\w+)?/g, + emoji : /:([\w\+-]+):/g, + emojiDatetime : /(\d{2}:\d{2}:\d{2})/g, + twemoji : /:(tw-([\w]+)-?(\w+)?):/g, + fontAwesome : /:(fa-([\w]+)(-(\w+)){0,}):/g, + editormdLogo : /:(editormd-logo-?(\w+)?):/g, + pageBreak : /^\[[=]{8,}\]$/ + }; + + // Emoji graphics files url path + editormd.emoji = { + // path : "http://www.emoji-cheat-sheet.com/graphics/emojis/", + path : "/editormd/emoji/", + + ext : ".png" + }; + + // Twitter Emoji (Twemoji) graphics files url path + editormd.twemoji = { + path : "http://twemoji.maxcdn.com/36x36/", + ext : ".png" + }; + + /** + * 自定义marked的解析器 + * Custom Marked renderer rules + * + * @param {Array} markdownToC 传入用于接收TOC的数组 + * @returns {Renderer} markedRenderer 返回marked的Renderer自定义对象 + */ + + editormd.markedRenderer = function(markdownToC, options) { + var defaults = { + toc : true, // Table of contents + tocm : false, + tocStartLevel : 1, // Said from H1 to create ToC + pageBreak : true, + atLink : true, // for @link + emailLink : true, // for mail address auto link + taskList : false, // Enable Github Flavored Markdown task lists + emoji : false, // :emoji: , Support Twemoji, fontAwesome, Editor.md logo emojis. + tex : false, // TeX(LaTeX), based on KaTeX + flowChart : false, // flowChart.js only support IE9+ + sequenceDiagram : false, // sequenceDiagram.js only support IE9+ + }; + + var settings = $.extend(defaults, options || {}); + var marked = editormd.$marked; + var markedRenderer = new marked.Renderer(); + markdownToC = markdownToC || []; + + var regexs = editormd.regexs; + var atLinkReg = regexs.atLink; + var emojiReg = regexs.emoji; + var emailReg = regexs.email; + var emailLinkReg = regexs.emailLink; + var twemojiReg = regexs.twemoji; + var faIconReg = regexs.fontAwesome; + var editormdLogoReg = regexs.editormdLogo; + var pageBreakReg = regexs.pageBreak; + + markedRenderer.emoji = function(text) { + + text = text.replace(editormd.regexs.emojiDatetime, function($1) { + return $1.replace(/:/g, ":"); + }); + + var matchs = text.match(emojiReg); + + if (!matchs || !settings.emoji) { + return text; + } + + for (var i = 0, len = matchs.length; i < len; i++) + { + if (matchs[i] === ":+1:") { + matchs[i] = ":\\+1:"; + } + + text = text.replace(new RegExp(matchs[i]), function($1, $2){ + var faMatchs = $1.match(faIconReg); + var name = $1.replace(/:/g, ""); + + if (faMatchs) + { + for (var fa = 0, len1 = faMatchs.length; fa < len1; fa++) + { + var faName = faMatchs[fa].replace(/:/g, ""); + + return ""; + } + } + else + { + var emdlogoMathcs = $1.match(editormdLogoReg); + var twemojiMatchs = $1.match(twemojiReg); + + if (emdlogoMathcs) + { + for (var x = 0, len2 = emdlogoMathcs.length; x < len2; x++) + { + var logoName = emdlogoMathcs[x].replace(/:/g, ""); + return ""; + } + } + else if (twemojiMatchs) + { + for (var t = 0, len3 = twemojiMatchs.length; t < len3; t++) + { + var twe = twemojiMatchs[t].replace(/:/g, "").replace("tw-", ""); + return "\"twemoji-""; + } + } + else + { + var src = (name === "+1") ? "plus1" : name; + src = (src === "black_large_square") ? "black_square" : src; + src = (src === "moon") ? "waxing_gibbous_moon" : src; + + return "\":""; + } + } + }); + } + + return text; + }; + + markedRenderer.atLink = function(text) { + + if (atLinkReg.test(text)) + { + if (settings.atLink) + { + text = text.replace(emailReg, function($1, $2, $3, $4) { + return $1.replace(/@/g, "_#_@_#_"); + }); + + text = text.replace(atLinkReg, function($1, $2) { + return "" + $1 + ""; + }).replace(/_#_@_#_/g, "@"); + } + + if (settings.emailLink) + { + text = text.replace(emailLinkReg, function($1, $2, $3, $4, $5) { + return (!$2 && $.inArray($5, "jpg|jpeg|png|gif|webp|ico|icon|pdf".split("|")) < 0) ? ""+$1+"" : $1; + }); + } + + return text; + } + + return text; + }; + + markedRenderer.link = function (href, title, text) { + + if (this.options.sanitize) { + try { + var prot = decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase(); + } catch(e) { + return ""; + } + + if (prot.indexOf("javascript:") === 0) { + return ""; + } + } + + var out = "" + text.replace(/@/g, "@") + ""; + } + + if (title) { + out += " title=\"" + title + "\""; + } + + out += ">" + text + ""; + + return out; + }; + + markedRenderer.heading = function(text, level, raw) { + + var linkText = text; + var hasLinkReg = /\s*\]*)\>(.*)\<\/a\>\s*/; + var getLinkTextReg = /\s*\]+)\>([^\>]*)\<\/a\>\s*/g; + + if (hasLinkReg.test(text)) + { + var tempText = []; + text = text.split(/\]+)\>([^\>]*)\<\/a\>/); + + for (var i = 0, len = text.length; i < len; i++) + { + tempText.push(text[i].replace(/\s*href\=\"(.*)\"\s*/g, "")); + } + + text = tempText.join(" "); + } + + text = trim(text); + + var escapedText = text.toLowerCase().replace(/[^\w]+/g, "-"); + var toc = { + text : text, + level : level, + slug : escapedText + }; + + var isChinese = /^[\u4e00-\u9fa5]+$/.test(text); + var id = (isChinese) ? escape(text).replace(/\%/g, "") : text.toLowerCase().replace(/[^\w]+/g, "-"); + + markdownToC.push(toc); + + var headingHTML = ""; + + headingHTML += ""; + headingHTML += ""; + headingHTML += (hasLinkReg) ? this.atLink(this.emoji(linkText)) : this.atLink(this.emoji(text)); + headingHTML += ""; + + return headingHTML; + }; + + markedRenderer.pageBreak = function(text) { + if (pageBreakReg.test(text) && settings.pageBreak) + { + text = "
                                  "; + } + + return text; + }; + + markedRenderer.paragraph = function(text) { + var isTeXInline = /\$\$(.*)\$\$/g.test(text); + var isTeXLine = /^\$\$(.*)\$\$$/.test(text); + var isTeXAddClass = (isTeXLine) ? " class=\"" + editormd.classNames.tex + "\"" : ""; + var isToC = (settings.tocm) ? /^(\[TOC\]|\[TOCM\])$/.test(text) : /^\[TOC\]$/.test(text); + var isToCMenu = /^\[TOCM\]$/.test(text); + + if (!isTeXLine && isTeXInline) + { + text = text.replace(/(\$\$([^\$]*)\$\$)+/g, function($1, $2) { + return "" + $2.replace(/\$/g, "") + ""; + }); + } + else + { + text = (isTeXLine) ? text.replace(/\$/g, "") : text; + } + + var tocHTML = "
                                  " + text + "
                                  "; + + return (isToC) ? ( (isToCMenu) ? "
                                  " + tocHTML + "

                                  " : tocHTML ) + : ( (pageBreakReg.test(text)) ? this.pageBreak(text) : "" + this.atLink(this.emoji(text)) + "

                                  \n" ); + }; + + markedRenderer.code = function (code, lang, escaped) { + + if (lang === "seq" || lang === "sequence") + { + return "
                                  " + code + "
                                  "; + } + else if ( lang === "flow") + { + return "
                                  " + code + "
                                  "; + } + else if ( lang === "math" || lang === "latex" || lang === "katex") + { + return "

                                  " + code + "

                                  "; + } + else + { + + return marked.Renderer.prototype.code.apply(this, arguments); + } + }; + + markedRenderer.tablecell = function(content, flags) { + var type = (flags.header) ? "th" : "td"; + var tag = (flags.align) ? "<" + type +" style=\"text-align:" + flags.align + "\">" : "<" + type + ">"; + + return tag + this.atLink(this.emoji(content)) + "\n"; + }; + + markedRenderer.listitem = function(text) { + if (settings.taskList && /^\s*\[[x\s]\]\s*/.test(text)) + { + text = text.replace(/^\s*\[\s\]\s*/, " ") + .replace(/^\s*\[x\]\s*/, " "); + + return "
                                • " + this.atLink(this.emoji(text)) + "
                                • "; + } + else + { + return "
                                • " + this.atLink(this.emoji(text)) + "
                                • "; + } + }; + + return markedRenderer; + }; + + /** + * + * 生成TOC(Table of Contents) + * Creating ToC (Table of Contents) + * + * @param {Array} toc 从marked获取的TOC数组列表 + * @param {Element} container 插入TOC的容器元素 + * @param {Integer} startLevel Hx 起始层级 + * @returns {Object} tocContainer 返回ToC列表容器层的jQuery对象元素 + */ + + editormd.markdownToCRenderer = function(toc, container, tocDropdown, startLevel) { + + var html = ""; + var lastLevel = 0; + var classPrefix = this.classPrefix; + + startLevel = startLevel || 1; + + for (var i = 0, len = toc.length; i < len; i++) + { + var text = toc[i].text; + var level = toc[i].level; + + if (level < startLevel) { + continue; + } + + if (level > lastLevel) + { + html += ""; + } + else if (level < lastLevel) + { + html += (new Array(lastLevel - level + 2)).join(""); + } + else + { + html += ""; + } + + html += "
                                • " + text + "
                                • ",r+='
                                • '+c+"
                                • ",i+='
                                • '+c+"
                                    ",o=u)}var h=e.find(".markdown-toc");if(h.length<1&&"false"===e.attr("previewContainer")){var f='
                                    ';f=n?'
                                    '+f+"
                                    ":f,e.html(f),h=e.find(".markdown-toc")}return n&&h.wrap('

                                    '),h.html('
                                      ').children(".markdown-toc-list").html(i.replace(/\r?\n?\\<\/ul\>/g,"")),h},r.tocDropdownMenu=function(e,n){n=n||"Table of Contents";var r=400,i=e.find("."+this.classPrefix+"toc-menu");return i.each(function(){var e=t(this),i=e.children(".markdown-toc"),o='',s=''+o+n+"",a=i.children("ul"),l=a.find("li");i.append(s),l.first().before("
                                    • "+n+" "+o+"

                                    • "),e.mouseover(function(){a.show(),l.each(function(){var e=t(this),n=e.children("ul");if(""===n.html()&&n.remove(),n.length>0&&""!==n.html()){var i=e.children("a").first();i.children(".fa").length<1&&i.append(t(o).css({float:"right",paddingTop:"4px"}))}e.mouseover(function(){n.css("z-index",r).show(),r+=1}).mouseleave(function(){n.hide()})})}).mouseleave(function(){a.hide()})}),i},r.filterHTMLTags=function(e,n){if("string"!=typeof e&&(e=new String(e)),"string"!=typeof n)return e;for(var r=n.split("|"),i=r[0].split(","),o=r[1],s=0,a=i.length;s]*)>([^>]*)","igm"),"")}if(void 0!==o){var c=/\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/gi;e="*"===o?e.replace(c,function(t,e,n,r,i){return"<"+e+">"+r+""}):"on*"===o?e.replace(c,function(e,n,r,i,o){var s=t("<"+n+">"+i+""),a=t(e)[0].attributes,l={};t.each(a,function(t,e){'"'!==e.nodeName&&(l[e.nodeName]=e.nodeValue)}),t.each(l,function(t){0===t.indexOf("on")&&delete l[t]}),s.attr(l);var c=void 0!==s[1]?t(s[1]).text():"";return s[0].outerHTML+c}):e.replace(c,function(e,n,r,i){var s=o.split(","),a=t(e);return a.html(i),t.each(s,function(t){a.attr(s[t],null)}),a[0].outerHTML})}return e},r.markdownToHTML=function(e,n){r.$marked=marked;var i=t("#"+e),o=i.settings=t.extend(!0,{gfm:!0,toc:!0,tocm:!1,tocStartLevel:1,tocTitle:"目录",tocDropdown:!1,tocContainer:"",markdown:"",markdownSourceCode:!1,htmlDecode:!1,autoLoadKaTeX:!0,pageBreak:!0,atLink:!0,emailLink:!0,tex:!1,taskList:!1,emoji:!1,flowChart:!1,sequenceDiagram:!1,previewCodeHighlight:!0},n||{}),s=i.find("textarea");s.length<1&&(i.append(""),s=i.find("textarea"));var a=""===o.markdown?s.val():o.markdown,l=[],c={toc:o.toc,tocm:o.tocm,tocStartLevel:o.tocStartLevel,taskList:o.taskList,emoji:o.emoji,tex:o.tex,pageBreak:o.pageBreak,atLink:o.atLink,emailLink:o.emailLink,flowChart:o.flowChart,sequenceDiagram:o.sequenceDiagram,previewCodeHighlight:o.previewCodeHighlight},u={renderer:r.markedRenderer(l,c),gfm:o.gfm,tables:!0,breaks:!0,pedantic:!1,sanitize:!o.htmlDecode,smartLists:!0,smartypants:!0};a=new String(a);var h=marked(a,u);h=r.filterHTMLTags(h,o.htmlDecode),o.markdownSourceCode?s.text(a):s.remove(),i.addClass("markdown-body "+this.classPrefix+"html-preview").append(h);var f=""!==o.tocContainer?t(o.tocContainer):i;if(""!==o.tocContainer&&f.attr("previewContainer",!1),o.toc&&(i.tocContainer=this.markdownToCRenderer(l,f,o.tocDropdown,o.tocStartLevel),(o.tocDropdown||i.find("."+this.classPrefix+"toc-menu").length>0)&&this.tocDropdownMenu(i,o.tocTitle),""!==o.tocContainer&&i.find(".editormd-toc-menu, .editormd-markdown-toc").remove()),o.previewCodeHighlight&&(i.find("pre").addClass("prettyprint linenums"),prettyPrint()),r.isIE8||(o.flowChart&&i.find(".flowchart").flowChart(),o.sequenceDiagram&&i.find(".sequence-diagram").sequenceDiagram({theme:"simple"})),o.tex){var d=function(){i.find("."+r.classNames.tex).each(function(){var e=t(this);katex.render(e.text(),e[0]),e.find(".katex").css("font-size","1.0em")})};!o.autoLoadKaTeX||r.$katex||r.kaTeXLoaded?d():this.loadKaTeX(function(){r.$katex=katex,r.kaTeXLoaded=!0,d()})}return i.getMarkdown=function(){return s.val()},i},r.themes=["default","dark"],r.previewThemes=["default","dark"],r.editorThemes=["default","3024-day","3024-night","ambiance","ambiance-mobile","base16-dark","base16-light","blackboard","cobalt","eclipse","elegant","erlang-dark","lesser-dark","mbo","mdn-like","midnight","monokai","neat","neo","night","paraiso-dark","paraiso-light","pastel-on-dark","rubyblue","solarized","the-matrix","tomorrow-night-eighties","twilight","vibrant-ink","xq-dark","xq-light"],r.loadPlugins={},r.loadFiles={js:[],css:[],plugin:[]},r.loadPlugin=function(t,e,n){e=e||function(){},this.loadScript(t,function(){r.loadFiles.plugin.push(t),e()},n)},r.loadCSS=function(t,e,n){n=n||"head",e=e||function(){};var i=document.createElement("link");i.type="text/css",i.rel="stylesheet",i.onload=i.onreadystatechange=function(){r.loadFiles.css.push(t),e()},i.href=t+".css","head"===n?document.getElementsByTagName("head")[0].appendChild(i):document.body.appendChild(i)},r.isIE="Microsoft Internet Explorer"==navigator.appName,r.isIE8=r.isIE&&"8."==navigator.appVersion.match(/8./i),r.loadScript=function(t,e,n){n=n||"head",e=e||function(){};var i=null;(i=document.createElement("script")).id=t.replace(/[\./]+/g,"-"),i.type="text/javascript",i.src=t+".js",r.isIE8?i.onreadystatechange=function(){i.readyState&&("loaded"!==i.readyState&&"complete"!==i.readyState||(i.onreadystatechange=null,r.loadFiles.js.push(t),e()))}:i.onload=function(){r.loadFiles.js.push(t),e()},"head"===n?document.getElementsByTagName("head")[0].appendChild(i):document.body.appendChild(i)},r.katexURL={css:"/katex/katex.min",js:"/katex/katex.min"},r.kaTeXLoaded=!1,r.loadKaTeX=function(t){r.loadCSS(r.katexURL.css,function(){r.loadScript(r.katexURL.js,t||function(){})})},r.lockScreen=function(e){t("html,body").css("overflow",e?"hidden":"")},r.createDialog=function(e){e=t.extend(!0,{name:"",width:420,height:240,title:"",drag:!0,closed:!0,content:"",mask:!0,maskStyle:{backgroundColor:"#fff",opacity:.1},lockScreen:!0,footer:!0,buttons:!1},e);var n=this,i=this.editor,o=r.classPrefix,s=(new Date).getTime(),a=""===e.name?o+"dialog-"+s:e.name,l=r.mouseOrTouch,c='
                                      ';""!==e.title&&(c+='
                                      ",c+=''+e.title+"",c+="
                                      "),e.closed&&(c+=''),c+='
                                      '+e.content,(e.footer||"string"==typeof e.footer)&&(c+='"),c+="
                                      ",c+='
                                      ',c+='
                                      ',c+="
                                      ",i.append(c);var u=i.find("."+a);u.lockScreen=function(r){return e.lockScreen&&(t("html,body").css("overflow",r?"hidden":""),n.resize()),u},u.showMask=function(){return e.mask&&i.find("."+o+"mask").css(e.maskStyle).css("z-index",r.dialogZindex-1).show(),u},u.hideMask=function(){return e.mask&&i.find("."+o+"mask").hide(),u},u.loading=function(t){return u.find("."+o+"dialog-mask")[t?"show":"hide"](),u},u.lockScreen(!0).showMask(),u.show().css({zIndex:r.dialogZindex,border:r.isIE8?"1px solid #ddd":"",width:"number"==typeof e.width?e.width+"px":e.width,height:"number"==typeof e.height?e.height+"px":e.height});var h=function(){u.css({top:(t(window).height()-u.height())/2+"px",left:(t(window).width()-u.width())/2+"px"})};if(h(),t(window).resize(h),u.children("."+o+"dialog-close").bind(l("click","touchend"),function(){u.hide().lockScreen(!1).hideMask()}),"object"==typeof e.buttons){var f=u.footer=u.find("."+o+"dialog-footer");for(var d in e.buttons){var p=e.buttons[d],v=o+d+"-btn";f.append('"),p[1]=t.proxy(p[1],u),f.children("."+v).bind(l("click","touchend"),p[1])}}if(""!==e.title&&e.drag){var g,m,y=u.children("."+o+"dialog-header");e.mask||y.bind(l("click","touchend"),function(){r.dialogZindex+=2,u.css("z-index",r.dialogZindex)}),y.mousedown(function(t){t=t||window.event,g=t.clientX-parseInt(u[0].style.left),m=t.clientY-parseInt(u[0].style.top),document.onmousemove=w});var x=function(t){t.removeClass(o+"user-unselect").off("selectstart")},b=function(t){t.addClass(o+"user-unselect").on("selectstart",function(t){return!1})},w=function(e){e=e||window.event;var n,r,i=parseInt(u[0].style.left),o=parseInt(u[0].style.top);i>=0?i+u.width()<=t(window).width()?n=e.clientX-g:(n=t(window).width()-u.width(),document.onmousemove=null):(n=0,document.onmousemove=null),o>=0?r=e.clientY-m:(r=0,document.onmousemove=null),document.onselectstart=function(){return!1},b(t("body")),b(u),u[0].style.left=n+"px",u[0].style.top=r+"px"};document.onmouseup=function(){x(t("body")),x(u),document.onselectstart=null,document.onmousemove=null},y.touchDraggable=function(){var e=null;this.bind("touchstart",function(n){var r=n.originalEvent,i=t(this).parent().position();e={x:r.changedTouches[0].pageX-i.left,y:r.changedTouches[0].pageY-i.top}}).bind("touchmove",function(n){n.preventDefault();var r=n.originalEvent;t(this).parent().css({top:r.changedTouches[0].pageY-e.y,left:r.changedTouches[0].pageX-e.x})})},y.touchDraggable()}return r.dialogZindex+=2,t("body").removeAttr("style"),u},r.mouseOrTouch=function(t,e){e=e||"touchend";var n=t=t||"click";try{document.createEvent("TouchEvent"),n=e}catch(t){}return n},r.dateFormat=function(t){t=t||"";var e=function(t){return t<10?"0"+t:t},n=new Date,r=n.getFullYear(),i=r.toString().slice(2,4),o=e(n.getMonth()+1),s=e(n.getDate()),a=n.getDay(),l=e(n.getHours()),c=e(n.getMinutes()),u=e(n.getSeconds()),h=e(n.getMilliseconds()),f="",d=i+"-"+o+"-"+s,p=r+"-"+o+"-"+s,v=l+":"+c+":"+u;switch(t){case"UNIX Time":f=n.getTime();break;case"UTC":f=n.toUTCString();break;case"yy":f=i;break;case"year":case"yyyy":f=r;break;case"month":case"mm":f=o;break;case"cn-week-day":case"cn-wd":f="星期"+["日","一","二","三","四","五","六"][a];break;case"week-day":case"wd":f=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][a];break;case"day":case"dd":f=s;break;case"hour":case"hh":f=l;break;case"min":case"ii":f=c;break;case"second":case"ss":f=u;break;case"ms":f=h;break;case"yy-mm-dd":f=d;break;case"yyyy-mm-dd":f=p;break;case"yyyy-mm-dd h:i:s ms":case"full + ms":f=p+" "+v+" "+h;break;case"full":case"yyyy-mm-dd h:i:s":default:f=p+" "+v}return f},r}}),window._whenPasterDoUpload=function(t,e,n){var r,i,o,s=t.clipboardData,a=0;if(s){if(!(r=s.items))return;for(i=r[0],o=s.types||[];a=15&&(h=!1,l=!0);var k=y&&(c||h&&(null==w||w<12.11)),C=n||s&&a>=9;function _(t){return new RegExp("(^|\\s)"+t+"(?:$|\\s)\\s*")}var S,T=function(t,e){var n=t.className,r=_(e).exec(n);if(r){var i=n.slice(r.index+r[0].length);t.className=n.slice(0,r.index)+(i?r[1]+i:"")}};function L(t){for(var e=t.childNodes.length;e>0;--e)t.removeChild(t.firstChild);return t}function M(t,e){return L(t).appendChild(e)}function A(t,e,n,r){var i=document.createElement(t);if(n&&(i.className=n),r&&(i.style.cssText=r),"string"==typeof e)i.appendChild(document.createTextNode(e));else if(e)for(var o=0;o=e)return s+(e-o);s+=a-o,s+=n-s%n,o=a+1}}v?j=function(t){t.selectionStart=0,t.selectionEnd=t.value.length}:s&&(j=function(t){try{t.select()}catch(t){}});var H=function(){this.id=null};function R(t,e){for(var n=0;n=e)return r+Math.min(s,e-i);if(i+=o-r,r=o+1,(i+=n-i%n)>=e)return r}}var X=[""];function G(t){for(;X.length<=t;)X.push(Y(X)+" ");return X[t]}function Y(t){return t[t.length-1]}function K(t,e){for(var n=[],r=0;r"€"&&(t.toUpperCase()!=t.toLowerCase()||J.test(t))}function et(t,e){return e?!!(e.source.indexOf("\\w")>-1&&tt(t))||e.test(t):tt(t)}function nt(t){for(var e in t)if(t.hasOwnProperty(e)&&t[e])return!1;return!0}var rt=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function it(t){return t.charCodeAt(0)>=768&&rt.test(t)}function ot(t,e,n){for(;(n<0?e>0:e=t.size)throw new Error("There is no line "+(e+t.first)+" in the document.");for(var n=t;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(e=t.first&&en?vt(n,at(t,n).text.length):function(t,e){var n=t.ch;return null==n||n>e?vt(t.line,e):n<0?vt(t.line,0):t}(e,at(t,e.line).text.length)}function Ct(t,e){for(var n=[],r=0;r=e:o.to>e);(r||(r=[])).push(new Tt(s,o.from,a?null:o.to))}}return r}(n,i,s),l=function(t,e,n){var r;if(t)for(var i=0;i=e:o.to>e)||o.from==e&&"bookmark"==s.type&&(!n||o.marker.insertLeft)){var a=null==o.from||(s.inclusiveLeft?o.from<=e:o.from0&&a)for(var x=0;x=0&&h<=0||u<=0&&h>=0)&&(u<=0&&(l.marker.inclusiveRight&&i.inclusiveLeft?gt(c.to,n)>=0:gt(c.to,n)>0)||u>=0&&(l.marker.inclusiveRight&&i.inclusiveLeft?gt(c.from,r)<=0:gt(c.from,r)<0)))return!0}}}function Rt(t){for(var e;e=Ft(t);)t=e.find(-1,!0).line;return t}function Wt(t,e){var n=at(t,e),r=Rt(n);return n==r?e:ht(r)}function zt(t,e){if(e>t.lastLine())return e;var n,r=at(t,e);if(!$t(t,r))return e;for(;n=It(r);)r=n.find(1,!0).line;return ht(r)+1}function $t(t,e){var n=St&&e.markedSpans;if(n)for(var r=void 0,i=0;ie.maxLineLength&&(e.maxLineLength=n,e.maxLine=t)})}var Gt=null;function Yt(t,e,n){var r;Gt=null;for(var i=0;ie)return i;o.to==e&&(o.from!=o.to&&"before"==n?r=i:Gt=i),o.from==e&&(o.from!=o.to&&"before"!=n?r=i:Gt=i)}return null!=r?r:Gt}var Kt=function(){var t="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",e="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";var n=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,r=/[stwN]/,i=/[LRr]/,o=/[Lb1n]/,s=/[1n]/;function a(t,e,n){this.level=t,this.from=e,this.to=n}return function(l,c){var u="ltr"==c?"L":"R";if(0==l.length||"ltr"==c&&!n.test(l))return!1;for(var h,f=l.length,d=[],p=0;pt.text.length?null:r}function Jt(t,e,n){var r=Qt(t,e.ch,n);return null==r?null:new vt(e.line,r,n<0?"after":"before")}function te(t,e,n,r,i){if(t){var o=Zt(n,e.doc.direction);if(o){var s,a=i<0?Y(o):o[0],l=i<0==(1==a.level)?"after":"before";if(a.level>0){var c=On(e,n);s=i<0?n.text.length-1:0;var u=Dn(e,c,s).top;s=st(function(t){return Dn(e,c,t).top==u},i<0==(1==a.level)?a.from:a.to-1,s),"before"==l&&(s=Qt(n,s,1))}else s=i<0?a.to:a.from;return new vt(r,s,l)}}return new vt(r,i<0?n.text.length:0,i<0?"before":"after")}function ee(t,e,n,r){var i=Zt(e,t.doc.direction);if(!i)return Jt(e,n,r);n.ch>=e.text.length?(n.ch=e.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var o=Yt(i,n.ch,n.sticky),s=i[o];if("ltr"==t.doc.direction&&s.level%2==0&&(r>0?s.to>n.ch:s.from=s.from&&f>=u.begin)){var d=h?"before":"after";return new vt(n.line,f,d)}}var p=function(t,e,r){for(var o=function(t,e){return e?new vt(n.line,l(t,1),"before"):new vt(n.line,t,"after")};t>=0&&t0==(1!=s.level),c=a?r.begin:l(r.end,-1);if(s.from<=c&&c0?u.end:l(u.begin,-1);return null==g||r>0&&g==e.text.length||!(v=p(r>0?0:i.length-1,r,c(g)))?null:v}var ne=[],re=function(t,e,n){if(t.addEventListener)t.addEventListener(e,n,!1);else if(t.attachEvent)t.attachEvent("on"+e,n);else{var r=t._handlers||(t._handlers={});r[e]=(r[e]||ne).concat(n)}};function ie(t,e){return t._handlers&&t._handlers[e]||ne}function oe(t,e,n){if(t.removeEventListener)t.removeEventListener(e,n,!1);else if(t.detachEvent)t.detachEvent("on"+e,n);else{var r=t._handlers,i=r&&r[e];if(i){var o=R(i,n);o>-1&&(r[e]=i.slice(0,o).concat(i.slice(o+1)))}}}function se(t,e){var n=ie(t,e);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i0}function ue(t){t.prototype.on=function(t,e){re(this,t,e)},t.prototype.off=function(t,e){oe(this,t,e)}}function he(t){t.preventDefault?t.preventDefault():t.returnValue=!1}function fe(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0}function de(t){return null!=t.defaultPrevented?t.defaultPrevented:0==t.returnValue}function pe(t){he(t),fe(t)}function ve(t){return t.target||t.srcElement}function ge(t){var e=t.which;return null==e&&(1&t.button?e=1:2&t.button?e=3:4&t.button&&(e=2)),y&&t.ctrlKey&&1==e&&(e=3),e}var me,ye,xe=function(){if(s&&a<9)return!1;var t=A("div");return"draggable"in t||"dragDrop"in t}();function be(t){if(null==me){var e=A("span","​");M(t,A("span",[e,document.createTextNode("x")])),0!=t.firstChild.offsetHeight&&(me=e.offsetWidth<=1&&e.offsetHeight>2&&!(s&&a<8))}var n=me?A("span","​"):A("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return n.setAttribute("cm-text",""),n}function we(t){if(null!=ye)return ye;var e=M(t,document.createTextNode("AخA")),n=S(e,0,1).getBoundingClientRect(),r=S(e,1,2).getBoundingClientRect();return L(t),!(!n||n.left==n.right)&&(ye=r.right-n.right<3)}var ke,Ce=3!="\n\nb".split(/\n/).length?function(t){for(var e=0,n=[],r=t.length;e<=r;){var i=t.indexOf("\n",e);-1==i&&(i=t.length);var o=t.slice(e,"\r"==t.charAt(i-1)?i-1:i),s=o.indexOf("\r");-1!=s?(n.push(o.slice(0,s)),e+=s+1):(n.push(o),e=i+1)}return n}:function(t){return t.split(/\r\n?|\n/)},_e=window.getSelection?function(t){try{return t.selectionStart!=t.selectionEnd}catch(t){return!1}}:function(t){var e;try{e=t.ownerDocument.selection.createRange()}catch(t){}return!(!e||e.parentElement()!=t)&&0!=e.compareEndPoints("StartToEnd",e)},Se="oncopy"in(ke=A("div"))||(ke.setAttribute("oncopy","return;"),"function"==typeof ke.oncopy),Te=null;var Le={},Me={};function Ae(t){if("string"==typeof t&&Me.hasOwnProperty(t))t=Me[t];else if(t&&"string"==typeof t.name&&Me.hasOwnProperty(t.name)){var e=Me[t.name];"string"==typeof e&&(e={name:e}),(t=Q(e,t)).name=e.name}else{if("string"==typeof t&&/^[\w\-]+\/[\w\-]+\+xml$/.test(t))return Ae("application/xml");if("string"==typeof t&&/^[\w\-]+\/[\w\-]+\+json$/.test(t))return Ae("application/json")}return"string"==typeof t?{name:t}:t||{name:"null"}}function Ee(t,e){e=Ae(e);var n=Le[e.name];if(!n)return Ee(t,"text/plain");var r=n(t,e);if(Ne.hasOwnProperty(e.name)){var i=Ne[e.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=e.name,e.helperType&&(r.helperType=e.helperType),e.modeProps)for(var s in e.modeProps)r[s]=e.modeProps[s];return r}var Ne={};function Oe(t,e){F(e,Ne.hasOwnProperty(t)?Ne[t]:Ne[t]={})}function De(t,e){if(!0===e)return e;if(t.copyState)return t.copyState(e);var n={};for(var r in e){var i=e[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function Be(t,e){for(var n;t.innerMode&&(n=t.innerMode(e))&&n.mode!=t;)e=n.state,t=n.mode;return n||{mode:t,state:e}}function je(t,e,n){return!t.startState||t.startState(e,n)}var Pe=function(t,e){this.pos=this.start=0,this.string=t,this.tabSize=e||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0};function Fe(t,e,n,r){var i=[t.state.modeGen],o={};Ve(t,e.text,t.doc.mode,n,function(t,e){return i.push(t,e)},o,r);for(var s=function(n){var r=t.state.overlays[n],s=1,a=0;Ve(t,e.text,r.mode,!0,function(t,e){for(var n=s;at&&i.splice(s,1,t,i[s+1],o),s+=2,a=Math.min(t,o)}if(e)if(r.opaque)i.splice(n,s-n,t,"overlay "+e),s=n+2;else for(;nt.options.maxHighlightLength?De(t.doc.mode,r):r);e.stateAfter=r,e.styles=i.styles,i.classes?e.styleClasses=i.classes:e.styleClasses&&(e.styleClasses=null),n===t.doc.frontier&&t.doc.frontier++}return e.styles}function He(t,e,n){var r=t.doc,i=t.display;if(!r.mode.startState)return!0;var o=function(t,e,n){for(var r,i,o=t.doc,s=n?-1:e-(t.doc.mode.innerMode?1e3:100),a=e;a>s;--a){if(a<=o.first)return o.first;var l=at(o,a-1);if(l.stateAfter&&(!n||a<=o.frontier))return a;var c=I(l.text,null,t.options.tabSize);(null==i||r>c)&&(i=a-1,r=c)}return i}(t,e,n),s=o>r.first&&at(r,o-1).stateAfter;return s=s?De(r.mode,s):je(r.mode),r.iter(o,e,function(n){Re(t,n.text,s);var a=o==e-1||o%5==0||o>=i.viewFrom&&oe.start)return o}throw new Error("Mode "+t.name+" failed to advance stream.")}function $e(t,e,n,r){var i,o=function(t){return{start:h.start,end:h.pos,string:h.current(),type:i||null,state:t?De(s.mode,u):u}},s=t.doc,a=s.mode;e=kt(s,e);var l,c=at(s,e.line),u=He(t,e.line,n),h=new Pe(c.text,t.options.tabSize);for(r&&(l=[]);(r||h.post.options.maxHighlightLength?(a=!1,s&&Re(t,e,r,h.pos),h.pos=e.length,l=null):l=qe(ze(n,h,r,f),o),f){var d=f[0].name;d&&(l="m-"+(l?d+" "+l:d))}if(!a||u!=l){for(;c=this.string.length},Pe.prototype.sol=function(){return this.pos==this.lineStart},Pe.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},Pe.prototype.next=function(){if(this.pose},Pe.prototype.eatSpace=function(){for(var t=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>t},Pe.prototype.skipToEnd=function(){this.pos=this.string.length},Pe.prototype.skipTo=function(t){var e=this.string.indexOf(t,this.pos);if(e>-1)return this.pos=e,!0},Pe.prototype.backUp=function(t){this.pos-=t},Pe.prototype.column=function(){return this.lastColumnPos0?null:(r&&!1!==e&&(this.pos+=r[0].length),r)}var i=function(t){return n?t.toLowerCase():t};if(i(this.string.substr(this.pos,t.length))==i(t))return!1!==e&&(this.pos+=t.length),!0},Pe.prototype.current=function(){return this.string.slice(this.start,this.pos)},Pe.prototype.hideFirstChars=function(t,e){this.lineStart+=t;try{return e()}finally{this.lineStart-=t}};var Ue=function(t,e,n){this.text=t,Ot(this,e),this.height=n?n(this):1};function Xe(t){t.parent=null,Nt(t)}Ue.prototype.lineNo=function(){return ht(this)},ue(Ue);var Ge={},Ye={};function Ke(t,e){if(!t||/^\s*$/.test(t))return null;var n=e.addModeClass?Ye:Ge;return n[t]||(n[t]=t.replace(/\S+/g,"cm-$&"))}function Ze(t,e){var n=E("span",null,null,l?"padding-right: .1px":null),r={pre:E("pre",[n],"CodeMirror-line"),content:n,col:0,pos:0,cm:t,trailingSpace:!1,splitSpaces:(s||l)&&t.getOption("lineWrapping")};e.measure={};for(var i=0;i<=(e.rest?e.rest.length:0);i++){var o=i?e.rest[i-1]:e.line,a=void 0;r.pos=0,r.addToken=Je,we(t.display.measure)&&(a=Zt(o,t.doc.direction))&&(r.addToken=tn(r.addToken,a)),r.map=[],nn(o,r,Ie(t,o,e!=t.display.externalMeasured&&ht(o))),o.styleClasses&&(o.styleClasses.bgClass&&(r.bgClass=B(o.styleClasses.bgClass,r.bgClass||"")),o.styleClasses.textClass&&(r.textClass=B(o.styleClasses.textClass,r.textClass||""))),0==r.map.length&&r.map.push(0,0,r.content.appendChild(be(t.display.measure))),0==i?(e.measure.map=r.map,e.measure.cache={}):((e.measure.maps||(e.measure.maps=[])).push(r.map),(e.measure.caches||(e.measure.caches=[])).push({}))}if(l){var c=r.content.lastChild;(/\bcm-tab\b/.test(c.className)||c.querySelector&&c.querySelector(".cm-tab"))&&(r.content.className="cm-tab-wrap-hack")}return se(t,"renderLine",t,e.line,r.pre),r.pre.className&&(r.textClass=B(r.pre.className,r.textClass||"")),r}function Qe(t){var e=A("span","•","cm-invalidchar");return e.title="\\u"+t.charCodeAt(0).toString(16),e.setAttribute("aria-label",e.title),e}function Je(t,e,n,r,i,o,l){if(e){var c,u=t.splitSpaces?function(t,e){if(t.length>1&&!/ /.test(t))return t;for(var n=e,r="",i=0;ic&&h.from<=c);f++);if(h.to>=u)return t(n,r,i,o,s,a,l);t(n,r.slice(0,h.to-c),i,o,null,a,l),o=null,r=r.slice(h.to-c),c=h.to}}}function en(t,e,n,r){var i=!r&&n.widgetNode;i&&t.map.push(t.pos,t.pos+e,i),!r&&t.cm.display.input.needsContentAttribute&&(i||(i=t.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(t.cm.display.input.setUneditable(i),t.content.appendChild(i)),t.pos+=e,t.trailingSpace=!1}function nn(t,e,n){var r=t.markedSpans,i=t.text,o=0;if(r)for(var s,a,l,c,u,h,f,d=i.length,p=0,v=1,g="",m=0;;){if(m==p){l=c=u=h=a="",f=null,m=1/0;for(var y=[],x=void 0,b=0;bp||k.collapsed&&w.to==p&&w.from==p)?(null!=w.to&&w.to!=p&&m>w.to&&(m=w.to,c=""),k.className&&(l+=" "+k.className),k.css&&(a=(a?a+";":"")+k.css),k.startStyle&&w.from==p&&(u+=" "+k.startStyle),k.endStyle&&w.to==m&&(x||(x=[])).push(k.endStyle,w.to),k.title&&!h&&(h=k.title),k.collapsed&&(!f||jt(f.marker,k)<0)&&(f=w)):w.from>p&&m>w.from&&(m=w.from)}if(x)for(var C=0;C=d)break;for(var S=Math.min(d,m);;){if(g){var T=p+g.length;if(!f){var L=T>S?g.slice(0,S-p):g;e.addToken(e,L,s?s+l:l,u,p+L.length==m?c:"",h,a)}if(T>=S){g=g.slice(S-p),p=S;break}p=T,u=""}g=i.slice(o,o=n[v++]),s=Ke(n[v++],e.cm.options)}}else for(var M=1;Mn)return{map:t.measure.maps[i],cache:t.measure.caches[i],before:!0}}function En(t,e,n,r){return Dn(t,On(t,e),n,r)}function Nn(t,e){if(e>=t.display.viewFrom&&e=n.lineN&&e2&&o.push((l.bottom+c.top)/2-n.top)}}o.push(n.bottom-n.top)}}(t,e.view,e.rect),e.hasHeights=!0),(o=function(t,e,n,r){var i,o=Pn(e.map,n,r),l=o.node,c=o.start,u=o.end,h=o.collapse;if(3==l.nodeType){for(var f=0;f<4;f++){for(;c&&it(e.line.text.charAt(o.coverStart+c));)--c;for(;o.coverStart+u1}(t))return e;var n=screen.logicalXDPI/screen.deviceXDPI,r=screen.logicalYDPI/screen.deviceYDPI;return{left:e.left*n,right:e.right*n,top:e.top*r,bottom:e.bottom*r}}(t.display.measure,i))}else{var d;c>0&&(h=r="right"),i=t.options.lineWrapping&&(d=l.getClientRects()).length>1?d["right"==r?d.length-1:0]:l.getBoundingClientRect()}if(s&&a<9&&!c&&(!i||!i.left&&!i.right)){var p=l.parentNode.getClientRects()[0];i=p?{left:p.left,right:p.left+tr(t.display),top:p.top,bottom:p.bottom}:jn}for(var v=i.top-e.rect.top,g=i.bottom-e.rect.top,m=(v+g)/2,y=e.view.measure.heights,x=0;xe)&&(i=(o=l-a)-1,e>=l&&(s="right")),null!=i){if(r=t[c+2],a==l&&n==(r.insertLeft?"left":"right")&&(s=n),"left"==n&&0==i)for(;c&&t[c-2]==t[c-3]&&t[c-1].insertLeft;)r=t[2+(c-=3)],s="left";if("right"==n&&i==l-a)for(;c=0&&(n=t[i]).left==n.right;i--);return n}function In(t){if(t.measure&&(t.measure.cache={},t.measure.heights=null,t.rest))for(var e=0;e=r.text.length?(l=r.text.length,c="before"):l<=0&&(l=0,c="after"),!a)return s("before"==c?l-1:l,"before"==c);function u(t,e,n){return s(n?t-1:t,a[e].level%2!=0!=n)}var h=Yt(a,l,c),f=Gt,d=u(l,h,"before"==c);return null!=f&&(d.other=u(l,f,"before"!=c)),d}function Xn(t,e){var n=0;e=kt(t.doc,e),t.options.lineWrapping||(n=tr(t.display)*e.ch);var r=at(t.doc,e.line),i=Vt(r)+Cn(t.display);return{left:n,right:n,top:i,bottom:i+r.height}}function Gn(t,e,n,r,i){var o=vt(t,e,n);return o.xRel=i,r&&(o.outside=!0),o}function Yn(t,e,n){var r=t.doc;if((n+=t.display.viewOffset)<0)return Gn(r.first,0,null,!0,-1);var i=ft(r,n),o=r.first+r.size-1;if(i>o)return Gn(r.first+r.size-1,at(r,o).text.length,null,!0,1);e<0&&(e=0);for(var s=at(r,i);;){var a=Qn(t,s,i,e,n),l=It(s),c=l&&l.find(0,!0);if(!l||!(a.ch>c.from.ch||a.ch==c.from.ch&&a.xRel>0))return a;i=ht(s=c.to.line)}}function Kn(t,e,n,r){var i=function(r){return $n(t,e,Dn(t,n,r),"line")},o=e.text.length,s=st(function(t){return i(t-1).bottom<=r},o,0);return{begin:s,end:o=st(function(t){return i(t).top>r},s,o)}}function Zn(t,e,n,r){return Kn(t,e,n,$n(t,e,Dn(t,n,r),"line").top)}function Qn(t,e,n,r,i){i-=Vt(e);var o,s=0,a=e.text.length,l=On(t,e);if(Zt(e,t.doc.direction)){var c;if(t.options.lineWrapping)s=(c=Kn(t,e,l,i)).begin,a=c.end;o=new vt(n,s);var u,h,f=Un(t,o,"line",e,l).left,d=fMath.abs(u)){if(p<0==u<0)throw new Error("Broke out of infinite loop in coordsCharInner");o=h}}else{var v=st(function(n){var o=$n(t,e,Dn(t,l,n),"line");return o.top>i?(a=Math.min(n,a),!0):!(o.bottom<=i)&&(o.left>r||!(o.rightg.right?1:0,o}function Jn(t){if(null!=t.cachedTextHeight)return t.cachedTextHeight;if(null==Bn){Bn=A("pre");for(var e=0;e<49;++e)Bn.appendChild(document.createTextNode("x")),Bn.appendChild(A("br"));Bn.appendChild(document.createTextNode("x"))}M(t.measure,Bn);var n=Bn.offsetHeight/50;return n>3&&(t.cachedTextHeight=n),L(t.measure),n||1}function tr(t){if(null!=t.cachedCharWidth)return t.cachedCharWidth;var e=A("span","xxxxxxxxxx"),n=A("pre",[e]);M(t.measure,n);var r=e.getBoundingClientRect(),i=(r.right-r.left)/10;return i>2&&(t.cachedCharWidth=i),i||10}function er(t){for(var e=t.display,n={},r={},i=e.gutters.clientLeft,o=e.gutters.firstChild,s=0;o;o=o.nextSibling,++s)n[t.options.gutters[s]]=o.offsetLeft+o.clientLeft+i,r[t.options.gutters[s]]=o.clientWidth;return{fixedPos:nr(e),gutterTotalWidth:e.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:e.wrapper.clientWidth}}function nr(t){return t.scroller.getBoundingClientRect().left-t.sizer.getBoundingClientRect().left}function rr(t){var e=Jn(t.display),n=t.options.lineWrapping,r=n&&Math.max(5,t.display.scroller.clientWidth/tr(t.display)-3);return function(i){if($t(t.doc,i))return 0;var o=0;if(i.widgets)for(var s=0;s=t.display.viewTo)return null;if((e-=t.display.viewFrom)<0)return null;for(var n=t.display.view,r=0;r=t.display.viewTo||a.to().linee||e==n&&s.to==e)&&(r(Math.max(s.from,e),Math.min(s.to,n),1==s.level?"rtl":"ltr"),i=!0)}i||r(e,n,"ltr")}(Zt(u,i.direction),n||0,null==r?h:r,function(t,e,i){var u,d,p,v=f(t,"left");if(t==e)u=v,d=p=v.left;else{if(u=f(e-1,"right"),"rtl"==i){var g=v;v=u,u=g}d=v.left,p=u.right}null==n&&0==t&&(d=a),u.top-v.top>3&&(c(d,v.top,null,v.bottom),d=a,v.bottoms.bottom||u.bottom==s.bottom&&u.right>s.right)&&(s=u),d0?e.blinker=setInterval(function(){return e.cursorDiv.style.visibility=(n=!n)?"":"hidden"},t.options.cursorBlinkRate):t.options.cursorBlinkRate<0&&(e.cursorDiv.style.visibility="hidden")}}function fr(t){t.state.focused||(t.display.input.focus(),dr(t))}function dr(t,e){t.state.delayingBlurEvent&&(t.state.delayingBlurEvent=!1),"nocursor"!=t.options.readOnly&&(t.state.focused||(se(t,"focus",t,e),t.state.focused=!0,D(t.display.wrapper,"CodeMirror-focused"),t.curOp||t.display.selForContextMenu==t.doc.sel||(t.display.input.reset(),l&&setTimeout(function(){return t.display.input.reset(!0)},20)),t.display.input.receivedFocus()),hr(t))}function pr(t,e){t.state.delayingBlurEvent||(t.state.focused&&(se(t,"blur",t,e),t.state.focused=!1,T(t.display.wrapper,"CodeMirror-focused")),clearInterval(t.display.blinker),setTimeout(function(){t.state.focused||(t.display.shift=!1)},150))}function vr(t){var e=t.display,n=e.view;if(e.alignWidgets||e.gutters.firstChild&&t.options.fixedGutter){for(var r=nr(e)-e.scroller.scrollLeft+t.doc.scrollLeft,i=e.gutters.offsetWidth,o=r+"px",s=0;s.001||u<-.001)&&(ut(i.line,o),yr(i.line),i.rest))for(var h=0;h=s&&(o=ft(e,Vt(at(e,l))-t.wrapper.clientHeight),s=l)}return{from:o,to:Math.max(s,o+1)}}function br(t,e){Math.abs(t.doc.scrollTop-e)<2||(t.doc.scrollTop=e,n||oi(t,{top:e}),t.display.scroller.scrollTop!=e&&(t.display.scroller.scrollTop=e),t.display.scrollbars.setScrollTop(e),n&&oi(t),ti(t,100))}function wr(t,e,n){(n?e==t.doc.scrollLeft:Math.abs(t.doc.scrollLeft-e)<2)||(e=Math.min(e,t.display.scroller.scrollWidth-t.display.scroller.clientWidth),t.doc.scrollLeft=e,vr(t),t.display.scroller.scrollLeft!=e&&(t.display.scroller.scrollLeft=e),t.display.scrollbars.setScrollLeft(e))}var kr=0,Cr=null;function _r(t){var e=t.wheelDeltaX,n=t.wheelDeltaY;return null==e&&t.detail&&t.axis==t.HORIZONTAL_AXIS&&(e=t.detail),null==n&&t.detail&&t.axis==t.VERTICAL_AXIS?n=t.detail:null==n&&(n=t.wheelDelta),{x:e,y:n}}function Sr(t){var e=_r(t);return e.x*=Cr,e.y*=Cr,e}function Tr(t,e){var r=_r(e),i=r.x,o=r.y,s=t.display,a=s.scroller,c=a.scrollWidth>a.clientWidth,u=a.scrollHeight>a.clientHeight;if(i&&c||o&&u){if(o&&y&&l)t:for(var f=e.target,d=s.view;f!=a;f=f.parentNode)for(var p=0;pt.clientWidth+1,n=t.scrollHeight>t.clientHeight+1,r=t.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=e?r+"px":"0";var i=t.viewHeight-(e?r:0);this.vert.firstChild.style.height=Math.max(0,t.scrollHeight-t.clientHeight+i)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(e){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=t.barLeft+"px";var o=t.viewWidth-t.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,t.scrollWidth-t.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&t.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:e?r:0}},Mr.prototype.setScrollLeft=function(t){this.horiz.scrollLeft!=t&&(this.horiz.scrollLeft=t),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz)},Mr.prototype.setScrollTop=function(t){this.vert.scrollTop!=t&&(this.vert.scrollTop=t),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert)},Mr.prototype.zeroWidthHack=function(){var t=y&&!d?"12px":"18px";this.horiz.style.height=this.vert.style.width=t,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new H,this.disableVert=new H},Mr.prototype.enableZeroWidthBar=function(t,e){t.style.pointerEvents="auto",e.set(1e3,function n(){var r=t.getBoundingClientRect();document.elementFromPoint(r.left+1,r.bottom-1)!=t?t.style.pointerEvents="none":e.set(1e3,n)})},Mr.prototype.clear=function(){var t=this.horiz.parentNode;t.removeChild(this.horiz),t.removeChild(this.vert)};var Ar=function(){};function Er(t,e){e||(e=Lr(t));var n=t.display.barWidth,r=t.display.barHeight;Nr(t,e);for(var i=0;i<4&&n!=t.display.barWidth||r!=t.display.barHeight;i++)n!=t.display.barWidth&&t.options.lineWrapping&&mr(t),Nr(t,Lr(t)),n=t.display.barWidth,r=t.display.barHeight}function Nr(t,e){var n=t.display,r=n.scrollbars.update(e);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&t.options.coverGutterNextToScrollbar&&t.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=e.gutterWidth+"px"):n.gutterFiller.style.display=""}Ar.prototype.update=function(){return{bottom:0,right:0}},Ar.prototype.setScrollLeft=function(){},Ar.prototype.setScrollTop=function(){},Ar.prototype.clear=function(){};var Or={native:Mr,null:Ar};function Dr(t){t.display.scrollbars&&(t.display.scrollbars.clear(),t.display.scrollbars.addClass&&T(t.display.wrapper,t.display.scrollbars.addClass)),t.display.scrollbars=new Or[t.options.scrollbarStyle](function(e){t.display.wrapper.insertBefore(e,t.display.scrollbarFiller),re(e,"mousedown",function(){t.state.focused&&setTimeout(function(){return t.display.input.focus()},0)}),e.setAttribute("cm-not-content","true")},function(e,n){"horizontal"==n?wr(t,e):br(t,e)},t),t.display.scrollbars.addClass&&D(t.display.wrapper,t.display.scrollbars.addClass)}function Br(t,e){var n=t.display,r=Jn(t.display);e.top<0&&(e.top=0);var i=t.curOp&&null!=t.curOp.scrollTop?t.curOp.scrollTop:n.scroller.scrollTop,o=Mn(t),s={};e.bottom-e.top>o&&(e.bottom=e.top+o);var a=t.doc.height+_n(n),l=e.topa-r;if(e.topi+o){var u=Math.min(e.top,(c?a:e.bottom)-o);u!=i&&(s.scrollTop=u)}var h=t.curOp&&null!=t.curOp.scrollLeft?t.curOp.scrollLeft:n.scroller.scrollLeft,f=Ln(t)-(t.options.fixedGutter?n.gutters.offsetWidth:0),d=e.right-e.left>f;return d&&(e.right=e.left+f),e.left<10?s.scrollLeft=0:e.leftf+h-3&&(s.scrollLeft=e.right+(d?0:10)-f),s}function jr(t,e,n){null==e&&null==n||Fr(t),null!=e&&(t.curOp.scrollLeft=(null==t.curOp.scrollLeft?t.doc.scrollLeft:t.curOp.scrollLeft)+e),null!=n&&(t.curOp.scrollTop=(null==t.curOp.scrollTop?t.doc.scrollTop:t.curOp.scrollTop)+n)}function Pr(t){Fr(t);var e=t.getCursor(),n=e,r=e;t.options.lineWrapping||(n=e.ch?vt(e.line,e.ch-1):e,r=vt(e.line,e.ch+1)),t.curOp.scrollToPos={from:n,to:r,margin:t.options.cursorScrollMargin}}function Fr(t){var e=t.curOp.scrollToPos;if(e){t.curOp.scrollToPos=null;var n=Xn(t,e.from),r=Xn(t,e.to),i=Br(t,{left:Math.min(n.left,r.left),top:Math.min(n.top,r.top)-e.margin,right:Math.max(n.right,r.right),bottom:Math.max(n.bottom,r.bottom)+e.margin});t.scrollTo(i.scrollLeft,i.scrollTop)}}var Ir=0;function Hr(t){var e;t.curOp={cm:t,viewChanged:!1,startHeight:t.doc.height,forceUpdate:!1,updateInput:null,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Ir},e=t.curOp,sn?sn.ops.push(e):e.ownsGroup=sn={ops:[e],delayedCallbacks:[]}}function Rr(t){!function(t,e){var n=t.ownsGroup;if(n)try{!function(t){var e=t.delayedCallbacks,n=0;do{for(;n=n.viewTo)||n.maxLineChanged&&e.options.lineWrapping,t.update=t.mustUpdate&&new ni(e,t.mustUpdate&&{top:t.scrollTop,ensure:t.scrollToPos},t.forceUpdate)}function zr(t){var e=t.cm,n=e.display;t.updatedDisplay&&mr(e),t.barMeasure=Lr(e),n.maxLineChanged&&!e.options.lineWrapping&&(t.adjustWidthTo=En(e,n.maxLine,n.maxLine.text.length).left+3,e.display.sizerWidth=t.adjustWidthTo,t.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+t.adjustWidthTo+Tn(e)+e.display.barWidth),t.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+t.adjustWidthTo-Ln(e))),(t.updatedDisplay||t.selectionChanged)&&(t.preparedSelection=n.input.prepareSelection(t.focus))}function $r(t){var e=t.cm;null!=t.adjustWidthTo&&(e.display.sizer.style.minWidth=t.adjustWidthTo+"px",t.maxScrollLeft(window.innerHeight||document.documentElement.clientHeight)&&(i=!1),null!=i&&!p){var o=A("div","​",null,"position: absolute;\n top: "+(e.top-n.viewOffset-Cn(t.display))+"px;\n height: "+(e.bottom-e.top+Tn(t)+n.barHeight)+"px;\n left: "+e.left+"px; width: "+Math.max(2,e.right-e.left)+"px;");t.display.lineSpace.appendChild(o),o.scrollIntoView(i),t.display.lineSpace.removeChild(o)}}}(e,function(t,e,n,r){var i;null==r&&(r=0);for(var o=0;o<5;o++){var s=!1,a=Un(t,e),l=n&&n!=e?Un(t,n):a,c=Br(t,i={left:Math.min(a.left,l.left),top:Math.min(a.top,l.top)-r,right:Math.max(a.left,l.left),bottom:Math.max(a.bottom,l.bottom)+r}),u=t.doc.scrollTop,h=t.doc.scrollLeft;if(null!=c.scrollTop&&(br(t,c.scrollTop),Math.abs(t.doc.scrollTop-u)>1&&(s=!0)),null!=c.scrollLeft&&(wr(t,c.scrollLeft),Math.abs(t.doc.scrollLeft-h)>1&&(s=!0)),!s)break}return i}(e,kt(r,t.scrollToPos.from),kt(r,t.scrollToPos.to),t.scrollToPos.margin));var i=t.maybeHiddenMarkers,o=t.maybeUnhiddenMarkers;if(i)for(var s=0;se)&&(i.updateLineNumbers=e),t.curOp.viewChanged=!0,e>=i.viewTo)St&&Wt(t.doc,e)i.viewFrom?Zr(t):(i.viewFrom+=r,i.viewTo+=r);else if(e<=i.viewFrom&&n>=i.viewTo)Zr(t);else if(e<=i.viewFrom){var o=Qr(t,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):Zr(t)}else if(n>=i.viewTo){var s=Qr(t,e,e,-1);s?(i.view=i.view.slice(0,s.index),i.viewTo=s.lineN):Zr(t)}else{var a=Qr(t,e,e,-1),l=Qr(t,n,n+r,1);a&&l?(i.view=i.view.slice(0,a.index).concat(on(t,a.lineN,l.lineN)).concat(i.view.slice(l.index)),i.viewTo+=r):Zr(t)}var c=i.externalMeasured;c&&(n=i.lineN&&e=r.viewTo)){var o=r.view[sr(t,e)];if(null!=o.node){var s=o.changes||(o.changes=[]);-1==R(s,n)&&s.push(n)}}}function Zr(t){t.display.viewFrom=t.display.viewTo=t.doc.first,t.display.view=[],t.display.viewOffset=0}function Qr(t,e,n,r){var i,o=sr(t,e),s=t.display.view;if(!St||n==t.doc.first+t.doc.size)return{index:o,lineN:n};for(var a=t.display.viewFrom,l=0;l0){if(o==s.length-1)return null;i=a+s[o].size-e,o++}else i=a-e;e+=i,n+=i}for(;Wt(t.doc,n)!=n;){if(o==(r<0?0:s.length-1))return null;n+=r*s[o-(r<0?1:0)].size,o+=r}return{index:o,lineN:n}}function Jr(t){for(var e=t.display.view,n=0,r=0;r=t.display.viewTo)){var n=+new Date+t.options.workTime,r=De(e.mode,He(t,e.frontier)),i=[];e.iter(e.frontier,Math.min(e.first+e.size,t.display.viewTo+500),function(o){if(e.frontier>=t.display.viewFrom){var s=o.styles,a=o.text.length>t.options.maxHighlightLength,l=Fe(t,o,a?De(e.mode,r):r,!0);o.styles=l.styles;var c=o.styleClasses,u=l.classes;u?o.styleClasses=u:c&&(o.styleClasses=null);for(var h=!s||s.length!=o.styles.length||c!=u&&(!c||!u||c.bgClass!=u.bgClass||c.textClass!=u.textClass),f=0;!h&&fn)return ti(t,t.options.workDelay),!0}),i.length&&Vr(t,function(){for(var e=0;e=n.viewFrom&&e.visible.to<=n.viewTo&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo)&&n.renderedView==n.view&&0==Jr(t))return!1;gr(t)&&(Zr(t),e.dims=er(t));var i=r.first+r.size,o=Math.max(e.visible.from-t.options.viewportMargin,r.first),s=Math.min(i,e.visible.to+t.options.viewportMargin);n.viewFroms&&n.viewTo-s<20&&(s=Math.min(i,n.viewTo)),St&&(o=Wt(t.doc,o),s=zt(t.doc,s));var a=o!=n.viewFrom||s!=n.viewTo||n.lastWrapHeight!=e.wrapperHeight||n.lastWrapWidth!=e.wrapperWidth;!function(t,e,n){var r=t.display;0==r.view.length||e>=r.viewTo||n<=r.viewFrom?(r.view=on(t,e,n),r.viewFrom=e):(r.viewFrom>e?r.view=on(t,e,r.viewFrom).concat(r.view):r.viewFromn&&(r.view=r.view.slice(0,sr(t,n)))),r.viewTo=n}(t,o,s),n.viewOffset=Vt(at(t.doc,n.viewFrom)),t.display.mover.style.top=n.viewOffset+"px";var c=Jr(t);if(!a&&0==c&&!e.force&&n.renderedView==n.view&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo))return!1;var u=O();return c>4&&(n.lineDiv.style.display="none"),function(t,e,n){var r=t.display,i=t.options.lineNumbers,o=r.lineDiv,s=o.firstChild;function a(e){var n=e.nextSibling;return l&&y&&t.display.currentWheelTarget==e?e.style.display="none":e.parentNode.removeChild(e),n}for(var c=r.view,u=r.viewFrom,h=0;h-1&&(d=!1),un(t,f,u,n)),d&&(L(f.lineNumber),f.lineNumber.appendChild(document.createTextNode(pt(t.options,u)))),s=f.node.nextSibling}else{var p=mn(t,f,u,n);o.insertBefore(p,s)}u+=f.size}for(;s;)s=a(s)}(t,n.updateLineNumbers,e.dims),c>4&&(n.lineDiv.style.display=""),n.renderedView=n.view,u&&O()!=u&&u.offsetHeight&&u.focus(),L(n.cursorDiv),L(n.selectionDiv),n.gutters.style.height=n.sizer.style.minHeight=0,a&&(n.lastWrapHeight=e.wrapperHeight,n.lastWrapWidth=e.wrapperWidth,ti(t,400)),n.updateLineNumbers=null,!0}function ii(t,e){for(var n=e.viewport,r=!0;(r&&t.options.lineWrapping&&e.oldDisplayWidth!=Ln(t)||(n&&null!=n.top&&(n={top:Math.min(t.doc.height+_n(t.display)-Mn(t),n.top)}),e.visible=xr(t.display,t.doc,n),!(e.visible.from>=t.display.viewFrom&&e.visible.to<=t.display.viewTo)))&&ri(t,e);r=!1){mr(t);var i=Lr(t);ar(t),Er(t,i),ai(t,i)}e.signal(t,"update",t),t.display.viewFrom==t.display.reportedViewFrom&&t.display.viewTo==t.display.reportedViewTo||(e.signal(t,"viewportChange",t,t.display.viewFrom,t.display.viewTo),t.display.reportedViewFrom=t.display.viewFrom,t.display.reportedViewTo=t.display.viewTo)}function oi(t,e){var n=new ni(t,e);if(ri(t,n)){mr(t),ii(t,n);var r=Lr(t);ar(t),Er(t,r),ai(t,r),n.finish()}}function si(t){var e=t.display.gutters.offsetWidth;t.display.sizer.style.marginLeft=e+"px"}function ai(t,e){t.display.sizer.style.minHeight=e.docHeight+"px",t.display.heightForcer.style.top=e.docHeight+"px",t.display.gutters.style.height=e.docHeight+t.display.barHeight+Tn(t)+"px"}function li(t){var e=t.display.gutters,n=t.options.gutters;L(e);for(var r=0;r-1&&!t.lineNumbers&&(t.gutters=t.gutters.slice(0),t.gutters.splice(e,1))}ni.prototype.signal=function(t,e){ce(t,e)&&this.events.push(arguments)},ni.prototype.finish=function(){for(var t=0;t=0&>(t,r.to())<=0)return n}return-1};var hi=function(t,e){this.anchor=t,this.head=e};function fi(t,e){var n=t[e];t.sort(function(t,e){return gt(t.from(),e.from())}),e=R(t,n);for(var r=1;r=0){var s=bt(o.from(),i.from()),a=xt(o.to(),i.to()),l=o.empty()?i.from()==i.head:o.from()==o.head;r<=e&&--e,t.splice(--r,2,new hi(l?a:s,l?s:a))}}return new ui(t,e)}function di(t,e){return new ui([new hi(t,e||t)],0)}function pi(t){return t.text?vt(t.from.line+t.text.length-1,Y(t.text).length+(1==t.text.length?t.from.ch:0)):t.to}function vi(t,e){if(gt(t,e.from)<0)return t;if(gt(t,e.to)<=0)return pi(e);var n=t.line+e.text.length-(e.to.line-e.from.line)-1,r=t.ch;return t.line==e.to.line&&(r+=pi(e).ch-e.to.ch),vt(n,r)}function gi(t,e){for(var n=[],r=0;r1&&t.remove(a.line+1,p-1),t.insert(a.line+1,m)}ln(t,"change",t,e)}function ki(t,e,n){!function t(r,i,o){if(r.linked)for(var s=0;sa-t.cm.options.historyEventDelay||"*"==e.origin.charAt(0)))&&(o=function(t,e){return e?(Li(t.done),Y(t.done)):t.done.length&&!Y(t.done).ranges?Y(t.done):t.done.length>1&&!t.done[t.done.length-2].ranges?(t.done.pop(),Y(t.done)):void 0}(i,i.lastOp==r)))s=Y(o.changes),0==gt(e.from,e.to)&&0==gt(e.from,s.to)?s.to=pi(e):o.changes.push(Ti(t,e));else{var l=Y(i.done);for(l&&l.ranges||Ei(t.sel,i.done),o={changes:[Ti(t,e)],generation:i.generation},i.done.push(o);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=a,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=e.origin,s||se(t,"historyAdded")}function Ai(t,e,n,r){var i=t.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||function(t,e,n,r){var i=e.charAt(0);return"*"==i||"+"==i&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-t.history.lastSelTime<=(t.cm?t.cm.options.historyEventDelay:500)}(t,o,Y(i.done),e))?i.done[i.done.length-1]=e:Ei(e,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&!1!==r.clearRedo&&Li(i.undone)}function Ei(t,e){var n=Y(e);n&&n.ranges&&n.equals(t)||e.push(t)}function Ni(t,e,n,r){var i=e["spans_"+t.id],o=0;t.iter(Math.max(t.first,n),Math.min(t.first+t.size,r),function(n){n.markedSpans&&((i||(i=e["spans_"+t.id]={}))[o]=n.markedSpans),++o})}function Oi(t){if(!t)return null;for(var e,n=0;n-1&&(Y(a)[h]=c[h],delete c[h])}}}return r}function ji(t,e,n,r){if(t.cm&&t.cm.display.shift||t.extend){var i=e.anchor;if(r){var o=gt(n,i)<0;o!=gt(r,i)<0?(i=n,n=r):o!=gt(n,r)<0&&(n=r)}return new hi(i,n)}return new hi(r||n,n)}function Pi(t,e,n,r){Wi(t,new ui([ji(t,t.sel.primary(),e,n)],0),r)}function Fi(t,e,n){for(var r=[],i=0;i=e.ch:a.to>e.ch))){if(i&&(se(l,"beforeCursorEnter"),l.explicitlyCleared)){if(o.markedSpans){--s;continue}break}if(!l.atomic)continue;if(n){var c=l.find(r<0?1:-1),u=void 0;if((r<0?l.inclusiveRight:l.inclusiveLeft)&&(c=Gi(t,c,-r,c&&c.line==e.line?o:null)),c&&c.line==e.line&&(u=gt(c,n))&&(r<0?u<0:u>0))return Ui(t,c,e,r,i)}var h=l.find(r<0?-1:1);return(r<0?l.inclusiveLeft:l.inclusiveRight)&&(h=Gi(t,h,r,h.line==e.line?o:null)),h?Ui(t,h,e,r,i):null}}return e}function Xi(t,e,n,r,i){var o=r||1,s=Ui(t,e,n,o,i)||!i&&Ui(t,e,n,o,!0)||Ui(t,e,n,-o,i)||!i&&Ui(t,e,n,-o,!0);return s||(t.cantEdit=!0,vt(t.first,0))}function Gi(t,e,n,r){return n<0&&0==e.ch?e.line>t.first?kt(t,vt(e.line-1)):null:n>0&&e.ch==(r||at(t,e.line)).text.length?e.line0)){var u=[l,1],h=gt(c.from,a.from),f=gt(c.to,a.to);(h<0||!s.inclusiveLeft&&!h)&&u.push({from:c.from,to:a.from}),(f>0||!s.inclusiveRight&&!f)&&u.push({from:a.to,to:c.to}),i.splice.apply(i,u),l+=u.length-3}}return i}(t,e.from,e.to);if(r)for(var i=r.length-1;i>=0;--i)Qi(t,{from:r[i].from,to:r[i].to,text:i?[""]:e.text});else Qi(t,e)}}function Qi(t,e){if(1!=e.text.length||""!=e.text[0]||0!=gt(e.from,e.to)){var n=gi(t,e);Mi(t,e,n,t.cm?t.cm.curOp.id:NaN),eo(t,e,n,At(t,e));var r=[];ki(t,function(t,n){n||-1!=R(r,t.history)||(oo(t.history,e),r.push(t.history)),eo(t,e,null,At(t,e))})}}function Ji(t,e,n){if(!t.cm||!t.cm.state.suppressEdits||n){for(var r,i=t.history,o=t.sel,s="undo"==e?i.done:i.undone,a="undo"==e?i.undone:i.done,l=0;l=0;--f){var d=h(f);if(d)return d.v}}}}function to(t,e){if(0!=e&&(t.first+=e,t.sel=new ui(K(t.sel.ranges,function(t){return new hi(vt(t.anchor.line+e,t.anchor.ch),vt(t.head.line+e,t.head.ch))}),t.sel.primIndex),t.cm)){Yr(t.cm,t.first,t.first-e,e);for(var n=t.cm.display,r=n.viewFrom;rt.lastLine())){if(e.from.lineo&&(e={from:e.from,to:vt(o,at(t,o).text.length),text:[e.text[0]],origin:e.origin}),e.removed=lt(t,e.from,e.to),n||(n=gi(t,e)),t.cm?function(t,e,n){var r=t.doc,i=t.display,o=e.from,s=e.to,a=!1,l=o.line;t.options.lineWrapping||(l=ht(Rt(at(r,o.line))),r.iter(l,s.line+1,function(t){if(t==i.maxLine)return a=!0,!0}));r.sel.contains(e.from,e.to)>-1&&le(t);wi(r,e,n,rr(t)),t.options.lineWrapping||(r.iter(l,o.line+e.text.length,function(t){var e=Ut(t);e>i.maxLineLength&&(i.maxLine=t,i.maxLineLength=e,i.maxLineChanged=!0,a=!1)}),a&&(t.curOp.updateMaxLine=!0));r.frontier=Math.min(r.frontier,o.line),ti(t,400);var c=e.text.length-(s.line-o.line)-1;e.full?Yr(t):o.line!=s.line||1!=e.text.length||bi(t.doc,e)?Yr(t,o.line,s.line+1,c):Kr(t,o.line,"text");var u=ce(t,"changes"),h=ce(t,"change");if(h||u){var f={from:o,to:s,text:e.text,removed:e.removed,origin:e.origin};h&&ln(t,"change",t,f),u&&(t.curOp.changeObjs||(t.curOp.changeObjs=[])).push(f)}t.display.selForContextMenu=null}(t.cm,e,r):wi(t,e,r),zi(t,n,$)}}function no(t,e,n,r,i){if(r||(r=n),gt(r,n)<0){var o=r;r=n,n=o}"string"==typeof e&&(e=t.splitLines(e)),Zi(t,{from:n,to:r,text:e,origin:i})}function ro(t,e,n,r){n1||!(this.children[0]instanceof ao))){var a=[];this.collapse(a),this.children=[new ao(a)],this.children[0].parent=this}},lo.prototype.collapse=function(t){for(var e=0;e50){for(var s=i.lines.length%25+25,a=s;a10);t.parent.maybeSpill()}},lo.prototype.iterN=function(t,e,n){for(var r=0;r0||0==s&&!1!==o.clearWhenEmpty)return o;if(o.replacedWith&&(o.collapsed=!0,o.widgetNode=E("span",[o.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||o.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(o.widgetNode.insertLeft=!0)),o.collapsed){if(Ht(t,e.line,e,n,o)||e.line!=n.line&&Ht(t,n.line,e,n,o))throw new Error("Inserting collapsed marker partially overlapping an existing one");St=!0}o.addToHistory&&Mi(t,{from:e,to:n,origin:"markText"},t.sel,NaN);var a,l=e.line,c=t.cm;if(t.iter(l,n.line+1,function(t){c&&o.collapsed&&!c.options.lineWrapping&&Rt(t)==c.display.maxLine&&(a=!0),o.collapsed&&l!=e.line&&ut(t,0),function(t,e){t.markedSpans=t.markedSpans?t.markedSpans.concat([e]):[e],e.marker.attachLine(t)}(t,new Tt(o,l==e.line?e.ch:null,l==n.line?n.ch:null)),++l}),o.collapsed&&t.iter(e.line,n.line+1,function(e){$t(t,e)&&ut(e,0)}),o.clearOnEnter&&re(o,"beforeCursorEnter",function(){return o.clear()}),o.readOnly&&(_t=!0,(t.history.done.length||t.history.undone.length)&&t.clearHistory()),o.collapsed&&(o.id=++ho,o.atomic=!0),c){if(a&&(c.curOp.updateMaxLine=!0),o.collapsed)Yr(c,e.line,n.line+1);else if(o.className||o.title||o.startStyle||o.endStyle||o.css)for(var u=e.line;u<=n.line;u++)Kr(c,u,"text");o.atomic&&qi(c.doc),ln(c,"markerAdded",c,o)}return o}fo.prototype.clear=function(){if(!this.explicitlyCleared){var t=this.doc.cm,e=t&&!t.curOp;if(e&&Hr(t),ce(this,"clear")){var n=this.find();n&&ln(this,"clear",n.from,n.to)}for(var r=null,i=null,o=0;ot.display.maxLineLength&&(t.display.maxLine=c,t.display.maxLineLength=u,t.display.maxLineChanged=!0)}null!=r&&t&&this.collapsed&&Yr(t,r,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,t&&qi(t.doc)),t&&ln(t,"markerCleared",t,this,r,i),e&&Rr(t),this.parent&&this.parent.clear()}},fo.prototype.find=function(t,e){var n,r;null==t&&"bookmark"==this.type&&(t=1);for(var i=0;i=0;l--)Zi(this,r[l]);a?Ri(this,a):this.cm&&Pr(this.cm)}),undo:Gr(function(){Ji(this,"undo")}),redo:Gr(function(){Ji(this,"redo")}),undoSelection:Gr(function(){Ji(this,"undo",!0)}),redoSelection:Gr(function(){Ji(this,"redo",!0)}),setExtending:function(t){this.extend=t},getExtending:function(){return this.extend},historySize:function(){for(var t=this.history,e=0,n=0,r=0;r=t.ch)&&e.push(i.marker.parent||i.marker)}return e},findMarks:function(t,e,n){t=kt(this,t),e=kt(this,e);var r=[],i=t.line;return this.iter(t.line,e.line+1,function(o){var s=o.markedSpans;if(s)for(var a=0;a=l.to||null==l.from&&i!=t.line||null!=l.from&&i==e.line&&l.from>=e.ch||n&&!n(l.marker)||r.push(l.marker.parent||l.marker)}++i}),r},getAllMarks:function(){var t=[];return this.iter(function(e){var n=e.markedSpans;if(n)for(var r=0;rt)return e=t,!0;t-=o,++n}),kt(this,vt(n,e))},indexFromPos:function(t){var e=(t=kt(this,t)).ch;if(t.linee&&(e=t.from),null!=t.to&&t.to-1)return e.state.draggingText(t),void setTimeout(function(){return e.display.input.focus()},20);try{var u=t.dataTransfer.getData("Text");if(u){var h;if(e.state.draggingText&&!e.state.draggingText.copy&&(h=e.listSelections()),zi(e.doc,di(n,n)),h)for(var f=0;f=0;e--)no(t.doc,"",r[e].from,r[e].to,"+delete");Pr(t)})}No.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},No.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},No.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Alt-F":"goWordRight","Alt-B":"goWordLeft","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-D":"delWordAfter","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},No.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},No.default=y?No.macDefault:No.pcDefault;var Ho={selectAll:Yi,singleSelection:function(t){return t.setSelection(t.getCursor("anchor"),t.getCursor("head"),$)},killLine:function(t){return Io(t,function(e){if(e.empty()){var n=at(t.doc,e.head.line).text.length;return e.head.ch==n&&e.head.line0)i=new vt(i.line,i.ch+1),t.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),vt(i.line,i.ch-2),i,"+transpose");else if(i.line>t.doc.first){var s=at(t.doc,i.line-1).text;s&&(i=new vt(i.line,1),t.replaceRange(o.charAt(0)+t.doc.lineSeparator()+s.charAt(s.length-1),vt(i.line-1,s.length-1),i,"+transpose"))}n.push(new hi(i,i))}t.setSelections(n)})},newlineAndIndent:function(t){return Vr(t,function(){for(var e=t.listSelections(),n=e.length-1;n>=0;n--)t.replaceRange(t.doc.lineSeparator(),e[n].anchor,e[n].head,"+input");e=t.listSelections();for(var r=0;ri-400&&0==gt(Xo.pos,n)?r="triple":Uo&&Uo.time>i-400&&0==gt(Uo.pos,n)?(r="double",Xo={time:i,pos:n}):(r="single",Uo={time:i,pos:n});var o,c=t.doc.sel,u=y?e.metaKey:e.ctrlKey;t.options.dragDrop&&xe&&!t.isReadOnly()&&"single"==r&&(o=c.contains(n))>-1&&(gt((o=c.ranges[o]).from(),n)<0||n.xRel>0)&&(gt(o.to(),n)>0||n.xRel<0)?function(t,e,n,r){var i=t.display,o=+new Date,c=Ur(t,function(u){l&&(i.scroller.draggable=!1),t.state.draggingText=!1,oe(document,"mouseup",c),oe(i.scroller,"drop",c),Math.abs(e.clientX-u.clientX)+Math.abs(e.clientY-u.clientY)<10&&(he(u),!r&&+new Date-200-1?u[l]:new hi(n,n)):(a=s.sel.primary(),l=s.sel.primIndex);if(x?e.shiftKey&&e.metaKey:e.altKey)r="rect",i||(a=new hi(n,n)),n=or(t,e,!0,!0),l=-1;else if("double"==r){var h=t.findWordAt(n);a=t.display.shift||s.extend?ji(s,a,h.anchor,h.head):h}else if("triple"==r){var f=new hi(vt(n.line,0),kt(s,vt(n.line+1,0)));a=t.display.shift||s.extend?ji(s,a,f.anchor,f.head):f}else a=ji(s,a,n);i?-1==l?(l=u.length,Wi(s,fi(u.concat([a]),l),{scroll:!1,origin:"*mouse"})):u.length>1&&u[l].empty()&&"single"==r&&!e.shiftKey?(Wi(s,fi(u.slice(0,l).concat(u.slice(l+1)),0),{scroll:!1,origin:"*mouse"}),c=s.sel):Ii(s,l,a,q):(l=0,Wi(s,new ui([a],0),q),c=s.sel);var d=n;var p=o.wrapper.getBoundingClientRect(),v=0;function g(e){var i=++v,u=or(t,e,!0,"rect"==r);if(u)if(0!=gt(u,d)){t.curOp.focus=O(),function(e){if(0==gt(d,e))return;if(d=e,"rect"==r){for(var i=[],o=t.options.tabSize,u=I(at(s,n.line).text,n.ch,o),h=I(at(s,e.line).text,e.ch,o),f=Math.min(u,h),p=Math.max(u,h),v=Math.min(n.line,e.line),g=Math.min(t.lastLine(),Math.max(n.line,e.line));v<=g;v++){var m=at(s,v).text,y=U(m,f,o);f==p?i.push(new hi(vt(v,y),vt(v,y))):m.length>y&&i.push(new hi(vt(v,y),vt(v,U(m,p,o))))}i.length||i.push(new hi(n,n)),Wi(s,fi(c.ranges.slice(0,l).concat(i),l),{origin:"*mouse",scroll:!1}),t.scrollIntoView(e)}else{var x,b=a,w=b.anchor,k=e;if("single"!=r)gt((x="double"==r?t.findWordAt(e):new hi(vt(e.line,0),kt(s,vt(e.line+1,0)))).anchor,w)>0?(k=x.head,w=bt(b.from(),x.anchor)):(k=x.anchor,w=xt(b.to(),x.head));var C=c.ranges.slice(0);C[l]=new hi(kt(s,w),k),Wi(s,fi(C,l),q)}}(u);var h=xr(o,s);(u.line>=h.to||u.linep.bottom?20:0;f&&setTimeout(Ur(t,function(){v==i&&(o.scroller.scrollTop+=f,g(e))}),50)}}function m(e){t.state.selectingText=!1,v=1/0,he(e),o.input.focus(),oe(document,"mousemove",y),oe(document,"mouseup",b),s.history.lastSelOrigin=null}var y=Ur(t,function(t){ge(t)?g(t):m(t)}),b=Ur(t,m);t.state.selectingText=b,re(document,"mousemove",y),re(document,"mouseup",b)}(t,e,n,r,u)}(e,t,r):ve(t)==n.scroller&&he(t);break;case 2:l&&(e.state.lastMiddleDown=+new Date),r&&Pi(e.doc,r),setTimeout(function(){return n.input.focus()},20),he(t);break;case 3:C?es(e,t):function(t){t.state.delayingBlurEvent=!0,setTimeout(function(){t.state.delayingBlurEvent&&(t.state.delayingBlurEvent=!1,pr(t))},100)}(e)}}}function Jo(t,e,n,r){var i,o;try{i=e.clientX,o=e.clientY}catch(e){return!1}if(i>=Math.floor(t.display.gutters.getBoundingClientRect().right))return!1;r&&he(e);var s=t.display,a=s.lineDiv.getBoundingClientRect();if(o>a.bottom||!ce(t,n))return de(e);o-=a.top-s.viewOffset;for(var l=0;l=i)return se(t,n,t,ft(t.doc,o),t.options.gutters[l],e),de(e)}}function ts(t,e){return Jo(t,e,"gutterClick",!0)}function es(t,e){kn(t.display,e)||function(t,e){if(!ce(t,"gutterContextMenu"))return!1;return Jo(t,e,"gutterContextMenu",!1)}(t,e)||ae(t,e,"contextmenu")||t.display.input.onContextMenu(e)}function ns(t){t.display.wrapper.className=t.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+t.options.theme.replace(/(^|\s)\s*/g," cm-s-"),Rn(t)}var rs={toString:function(){return"CodeMirror.Init"}},is={},os={};function ss(t){li(t),Yr(t),vr(t)}function as(t,e,n){if(!e!=!(n&&n!=rs)){var r=t.display.dragFunctions,i=e?re:oe;i(t.display.scroller,"dragstart",r.start),i(t.display.scroller,"dragenter",r.enter),i(t.display.scroller,"dragover",r.over),i(t.display.scroller,"dragleave",r.leave),i(t.display.scroller,"drop",r.drop)}}function ls(t){t.options.lineWrapping?(D(t.display.wrapper,"CodeMirror-wrap"),t.display.sizer.style.minWidth="",t.display.sizerWidth=null):(T(t.display.wrapper,"CodeMirror-wrap"),Xt(t)),ir(t),Yr(t),Rn(t),setTimeout(function(){return Er(t)},100)}function cs(t,e){var r=this;if(!(this instanceof cs))return new cs(t,e);this.options=e=e?F(e):{},F(is,e,!1),ci(e);var i=e.value;"string"==typeof i&&(i=new xo(i,e.mode,null,e.lineSeparator,e.direction)),this.doc=i;var o=new cs.inputStyles[e.inputStyle](this),c=this.display=new function(t,e,r){var i=this;this.input=r,i.scrollbarFiller=A("div",null,"CodeMirror-scrollbar-filler"),i.scrollbarFiller.setAttribute("cm-not-content","true"),i.gutterFiller=A("div",null,"CodeMirror-gutter-filler"),i.gutterFiller.setAttribute("cm-not-content","true"),i.lineDiv=E("div",null,"CodeMirror-code"),i.selectionDiv=A("div",null,null,"position: relative; z-index: 1"),i.cursorDiv=A("div",null,"CodeMirror-cursors"),i.measure=A("div",null,"CodeMirror-measure"),i.lineMeasure=A("div",null,"CodeMirror-measure"),i.lineSpace=E("div",[i.measure,i.lineMeasure,i.selectionDiv,i.cursorDiv,i.lineDiv],null,"position: relative; outline: none");var o=E("div",[i.lineSpace],"CodeMirror-lines");i.mover=A("div",[o],null,"position: relative"),i.sizer=A("div",[i.mover],"CodeMirror-sizer"),i.sizerWidth=null,i.heightForcer=A("div",null,null,"position: absolute; height: "+W+"px; width: 1px;"),i.gutters=A("div",null,"CodeMirror-gutters"),i.lineGutter=null,i.scroller=A("div",[i.sizer,i.heightForcer,i.gutters],"CodeMirror-scroll"),i.scroller.setAttribute("tabIndex","-1"),i.wrapper=A("div",[i.scrollbarFiller,i.gutterFiller,i.scroller],"CodeMirror"),s&&a<8&&(i.gutters.style.zIndex=-1,i.scroller.style.paddingRight=0),l||n&&m||(i.scroller.draggable=!0),t&&(t.appendChild?t.appendChild(i.wrapper):t(i.wrapper)),i.viewFrom=i.viewTo=e.first,i.reportedViewFrom=i.reportedViewTo=e.first,i.view=[],i.renderedView=null,i.externalMeasured=null,i.viewOffset=0,i.lastWrapHeight=i.lastWrapWidth=0,i.updateLineNumbers=null,i.nativeBarWidth=i.barHeight=i.barWidth=0,i.scrollbarsClipped=!1,i.lineNumWidth=i.lineNumInnerWidth=i.lineNumChars=null,i.alignWidgets=!1,i.cachedCharWidth=i.cachedTextHeight=i.cachedPaddingH=null,i.maxLine=null,i.maxLineLength=0,i.maxLineChanged=!1,i.wheelDX=i.wheelDY=i.wheelStartX=i.wheelStartY=null,i.shift=!1,i.selForContextMenu=null,i.activeTouch=null,r.init(i)}(t,i,o);for(var u in c.wrapper.CodeMirror=this,li(this),ns(this),e.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),Dr(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,selectingText:!1,draggingText:!1,highlight:new H,keySeq:null,specialChars:null},e.autofocus&&!m&&c.input.focus(),s&&a<11&&setTimeout(function(){return r.display.input.reset(!0)},20),function(t){var e=t.display;re(e.scroller,"mousedown",Ur(t,Qo)),re(e.scroller,"dblclick",s&&a<11?Ur(t,function(e){if(!ae(t,e)){var n=or(t,e);if(n&&!ts(t,e)&&!kn(t.display,e)){he(e);var r=t.findWordAt(n);Pi(t.doc,r.anchor,r.head)}}}):function(e){return ae(t,e)||he(e)});C||re(e.scroller,"contextmenu",function(e){return es(t,e)});var n,r={end:0};function i(){e.activeTouch&&(n=setTimeout(function(){return e.activeTouch=null},1e3),(r=e.activeTouch).end=+new Date)}function o(t,e){if(null==e.left)return!0;var n=e.left-t.left,r=e.top-t.top;return n*n+r*r>400}re(e.scroller,"touchstart",function(i){if(!ae(t,i)&&!function(t){if(1!=t.touches.length)return!1;var e=t.touches[0];return e.radiusX<=1&&e.radiusY<=1}(i)){e.input.ensurePolled(),clearTimeout(n);var o=+new Date;e.activeTouch={start:o,moved:!1,prev:o-r.end<=300?r:null},1==i.touches.length&&(e.activeTouch.left=i.touches[0].pageX,e.activeTouch.top=i.touches[0].pageY)}}),re(e.scroller,"touchmove",function(){e.activeTouch&&(e.activeTouch.moved=!0)}),re(e.scroller,"touchend",function(n){var r=e.activeTouch;if(r&&!kn(e,n)&&null!=r.left&&!r.moved&&new Date-r.start<300){var s,a=t.coordsChar(e.activeTouch,"page");s=!r.prev||o(r,r.prev)?new hi(a,a):!r.prev.prev||o(r,r.prev.prev)?t.findWordAt(a):new hi(vt(a.line,0),kt(t.doc,vt(a.line+1,0))),t.setSelection(s.anchor,s.head),t.focus(),he(n)}i()}),re(e.scroller,"touchcancel",i),re(e.scroller,"scroll",function(){e.scroller.clientHeight&&(br(t,e.scroller.scrollTop),wr(t,e.scroller.scrollLeft,!0),se(t,"scroll",t))}),re(e.scroller,"mousewheel",function(e){return Tr(t,e)}),re(e.scroller,"DOMMouseScroll",function(e){return Tr(t,e)}),re(e.wrapper,"scroll",function(){return e.wrapper.scrollTop=e.wrapper.scrollLeft=0}),e.dragFunctions={enter:function(e){ae(t,e)||pe(e)},over:function(e){ae(t,e)||(!function(t,e){var n=or(t,e);if(n){var r=document.createDocumentFragment();cr(t,n,r),t.display.dragCursor||(t.display.dragCursor=A("div",null,"CodeMirror-cursors CodeMirror-dragcursors"),t.display.lineSpace.insertBefore(t.display.dragCursor,t.display.cursorDiv)),M(t.display.dragCursor,r)}}(t,e),pe(e))},start:function(e){return function(t,e){if(s&&(!t.state.draggingText||+new Date-bo<100))pe(e);else if(!ae(t,e)&&!kn(t.display,e)&&(e.dataTransfer.setData("Text",t.getSelection()),e.dataTransfer.effectAllowed="copyMove",e.dataTransfer.setDragImage&&!f)){var n=A("img",null,null,"position: fixed; left: 0; top: 0;");n.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",h&&(n.width=n.height=1,t.display.wrapper.appendChild(n),n._top=n.offsetTop),e.dataTransfer.setDragImage(n,0,0),h&&n.parentNode.removeChild(n)}}(t,e)},drop:Ur(t,wo),leave:function(e){ae(t,e)||ko(t)}};var l=e.input.getField();re(l,"keyup",function(e){return Ko.call(t,e)}),re(l,"keydown",Ur(t,Yo)),re(l,"keypress",Ur(t,Zo)),re(l,"focus",function(e){return dr(t,e)}),re(l,"blur",function(e){return pr(t,e)})}(this),So(),Hr(this),this.curOp.forceUpdate=!0,Ci(this,i),e.autofocus&&!m||this.hasFocus()?setTimeout(P(dr,this),20):pr(this),os)os.hasOwnProperty(u)&&os[u](r,e[u],rs);gr(this),e.finishInit&&e.finishInit(this);for(var d=0;d150)){if(!r)return;n="prev"}}else c=0,n="not";"prev"==n?c=e>o.first?I(at(o,e-1).text,null,s):0:"add"==n?c=l+t.options.indentUnit:"subtract"==n?c=l-t.options.indentUnit:"number"==typeof n&&(c=l+n),c=Math.max(0,c);var h="",f=0;if(t.options.indentWithTabs)for(var d=Math.floor(c/s);d;--d)f+=s,h+="\t";if(f1)if(fs&&fs.text.join("\n")==e){if(r.ranges.length%fs.text.length==0){c=[];for(var u=0;u=0;h--){var f=r.ranges[h],d=f.from(),p=f.to();f.empty()&&(n&&n>0?d=vt(d.line,d.ch-n):t.state.overwrite&&!a?p=vt(p.line,Math.min(at(o,p.line).text.length,p.ch+Y(l).length)):fs&&fs.lineWise&&fs.text.join("\n")==e&&(d=p=vt(d.line,0))),s=t.curOp.updateInput;var v={from:d,to:p,text:c?c[h%c.length]:l,origin:i||(a?"paste":t.state.cutIncoming?"cut":"+input")};Zi(t.doc,v),ln(t,"inputRead",t,v)}e&&!a&&gs(t,e),Pr(t),t.curOp.updateInput=s,t.curOp.typing=!0,t.state.pasteIncoming=t.state.cutIncoming=!1}function vs(t,e){var n=t.clipboardData&&t.clipboardData.getData("Text");if(n)return t.preventDefault(),e.isReadOnly()||e.options.disableInput||Vr(e,function(){return ps(e,n,0,null,"paste")}),!0}function gs(t,e){if(t.options.electricChars&&t.options.smartIndent)for(var n=t.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=t.getModeAt(i.head),s=!1;if(o.electricChars){for(var a=0;a-1){s=hs(t,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(at(t.doc,i.head.line).text.slice(0,i.head.ch))&&(s=hs(t,i.head.line,"smart"));s&&ln(t,"electricInput",t,i.head.line)}}}function ms(t){for(var e=[],n=[],r=0;r=t.first+t.size||(e=new vt(s,e.ch,e.sticky),!(a=at(t,s))))return!1;e=te(i,t.cm,a,e.line,n)}else e=o;return!0}if("char"==r)l();else if("column"==r)l(!0);else if("word"==r||"group"==r)for(var c=null,u="group"==r,h=t.cm&&t.cm.getHelper(e,"wordChars"),f=!0;!(n<0)||l(!f);f=!1){var d=a.text.charAt(e.ch)||"\n",p=et(d,h)?"w":u&&"\n"==d?"n":!u||/\s/.test(d)?null:"p";if(!u||f||p||(p="s"),c&&c!=p){n<0&&(n=1,l(),e.sticky="after");break}if(p&&(c=p),n>0&&!l(!f))break}var v=Xi(t,e,o,s,!0);return mt(o,v)&&(v.hitSide=!0),v}function ws(t,e,n,r){var i,o,s=t.doc,a=e.left;if("page"==r){var l=Math.min(t.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),c=Math.max(l-.5*Jn(t.display),3);i=(n>0?e.bottom:e.top)+n*c}else"line"==r&&(i=n>0?e.bottom+3:e.top-3);for(;(o=Yn(t,a,i)).outside;){if(n<0?i<=0:i>=s.height){o.hitSide=!0;break}i+=5*n}return o}var ks=function(t){this.cm=t,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new H,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};function Cs(t,e){var n=Nn(t,e.line);if(!n||n.hidden)return null;var r=at(t.doc,e.line),i=An(n,r,e.line),o=Zt(r,t.doc.direction),s="left";o&&(s=Yt(o,e.ch)%2?"right":"left");var a=Pn(i.map,e.ch,s);return a.offset="right"==a.collapse?a.end:a.start,a}function _s(t,e){return e&&(t.bad=!0),t}function Ss(t,e,n){var r;if(e==t.display.lineDiv){if(!(r=t.display.lineDiv.childNodes[n]))return _s(t.clipPos(vt(t.display.viewTo-1)),!0);e=null,n=0}else for(r=e;;r=r.parentNode){if(!r||r==t.display.lineDiv)return null;if(r.parentNode&&r.parentNode==t.display.lineDiv)break}for(var i=0;ir.firstLine()&&(s=vt(s.line-1,at(r.doc,s.line-1).length)),a.ch==at(r.doc,a.line).text.length&&a.linei.viewTo-1)return!1;s.line==i.viewFrom||0==(t=sr(r,s.line))?(e=ht(i.view[0].line),n=i.view[0].node):(e=ht(i.view[t].line),n=i.view[t-1].node.nextSibling);var l,c,u=sr(r,a.line);if(u==i.view.length-1?(l=i.viewTo-1,c=i.lineDiv.lastChild):(l=ht(i.view[u+1].line)-1,c=i.view[u+1].node.previousSibling),!n)return!1;for(var h=r.doc.splitLines(function(t,e,n,r,i){var o="",s=!1,a=t.doc.lineSeparator();function l(){s&&(o+=a,s=!1)}function c(t){t&&(l(),o+=t)}function u(e){if(1==e.nodeType){var n=e.getAttribute("cm-text");if(null!=n)return void c(n||e.textContent.replace(/\u200b/g,""));var o,h=e.getAttribute("cm-marker");if(h){var f=t.findMarks(vt(r,0),vt(i+1,0),(v=+h,function(t){return t.id==v}));return void(f.length&&(o=f[0].find())&&c(lt(t.doc,o.from,o.to).join(a)))}if("false"==e.getAttribute("contenteditable"))return;var d=/^(pre|div|p)$/i.test(e.nodeName);d&&l();for(var p=0;p1&&f.length>1;)if(Y(h)==Y(f))h.pop(),f.pop(),l--;else{if(h[0]!=f[0])break;h.shift(),f.shift(),e++}for(var d=0,p=0,v=h[0],g=f[0],m=Math.min(v.length,g.length);ds.ch&&y.charCodeAt(y.length-p-1)==x.charCodeAt(x.length-p-1);)d--,p++;h[h.length-1]=y.slice(0,y.length-p).replace(/^\u200b+/,""),h[0]=h[0].slice(d).replace(/\u200b+$/,"");var w=vt(e,d),k=vt(l,f.length?Y(f).length-p:0);return h.length>1||h[0]||gt(w,k)?(no(r.doc,h,w,k,"+input"),!0):void 0},ks.prototype.ensurePolled=function(){this.forceCompositionEnd()},ks.prototype.reset=function(){this.forceCompositionEnd()},ks.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},ks.prototype.readFromDOMSoon=function(){var t=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout(function(){if(t.readDOMTimeout=null,t.composing){if(!t.composing.done)return;t.composing=null}t.updateFromDOM()},80))},ks.prototype.updateFromDOM=function(){var t=this;!this.cm.isReadOnly()&&this.pollContent()||Vr(this.cm,function(){return Yr(t.cm)})},ks.prototype.setUneditable=function(t){t.contentEditable="false"},ks.prototype.onKeyPress=function(t){0!=t.charCode&&(t.preventDefault(),this.cm.isReadOnly()||Ur(this.cm,ps)(this.cm,String.fromCharCode(null==t.charCode?t.keyCode:t.charCode),0))},ks.prototype.readOnlyChanged=function(t){this.div.contentEditable=String("nocursor"!=t)},ks.prototype.onContextMenu=function(){},ks.prototype.resetPosition=function(){},ks.prototype.needsContentAttribute=!0;var Ls=function(t){this.cm=t,this.prevInput="",this.pollingFast=!1,this.polling=new H,this.inaccurateSelection=!1,this.hasSelection=!1,this.composing=null};Ls.prototype.init=function(t){var e=this,n=this,r=this.cm,i=this.wrapper=xs(),o=this.textarea=i.firstChild;function l(t){if(!ae(r,t)){if(r.somethingSelected())ds({lineWise:!1,text:r.getSelections()}),n.inaccurateSelection&&(n.prevInput="",n.inaccurateSelection=!1,o.value=fs.text.join("\n"),j(o));else{if(!r.options.lineWiseCopyCut)return;var e=ms(r);ds({lineWise:!0,text:e.text}),"cut"==t.type?r.setSelections(e.ranges,null,$):(n.prevInput="",o.value=e.text.join("\n"),j(o))}"cut"==t.type&&(r.state.cutIncoming=!0)}}t.wrapper.insertBefore(i,t.wrapper.firstChild),v&&(o.style.width="0px"),re(o,"input",function(){s&&a>=9&&e.hasSelection&&(e.hasSelection=null),n.poll()}),re(o,"paste",function(t){ae(r,t)||vs(t,r)||(r.state.pasteIncoming=!0,n.fastPoll())}),re(o,"cut",l),re(o,"copy",l),re(t.scroller,"paste",function(e){kn(t,e)||ae(r,e)||(r.state.pasteIncoming=!0,n.focus())}),re(t.lineSpace,"selectstart",function(e){kn(t,e)||he(e)}),re(o,"compositionstart",function(){var t=r.getCursor("from");n.composing&&n.composing.range.clear(),n.composing={start:t,range:r.markText(t,r.getCursor("to"),{className:"CodeMirror-composing"})}}),re(o,"compositionend",function(){n.composing&&(n.poll(),n.composing.range.clear(),n.composing=null)})},Ls.prototype.prepareSelection=function(){var t=this.cm,e=t.display,n=t.doc,r=lr(t);if(t.options.moveInputWithCursor){var i=Un(t,n.sel.primary().head,"div"),o=e.wrapper.getBoundingClientRect(),s=e.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(e.wrapper.clientHeight-10,i.top+s.top-o.top)),r.teLeft=Math.max(0,Math.min(e.wrapper.clientWidth-10,i.left+s.left-o.left))}return r},Ls.prototype.showSelection=function(t){var e=this.cm.display;M(e.cursorDiv,t.cursors),M(e.selectionDiv,t.selection),null!=t.teTop&&(this.wrapper.style.top=t.teTop+"px",this.wrapper.style.left=t.teLeft+"px")},Ls.prototype.reset=function(t){if(!this.contextMenuPending){var e,n,r=this.cm,i=r.doc;if(r.somethingSelected()){this.prevInput="";var o=i.sel.primary(),l=(e=Se&&(o.to().line-o.from().line>100||(n=r.getSelection()).length>1e3))?"-":n||r.getSelection();this.textarea.value=l,r.state.focused&&j(this.textarea),s&&a>=9&&(this.hasSelection=l)}else t||(this.prevInput=this.textarea.value="",s&&a>=9&&(this.hasSelection=null));this.inaccurateSelection=e}},Ls.prototype.getField=function(){return this.textarea},Ls.prototype.supportsTouch=function(){return!1},Ls.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!m||O()!=this.textarea))try{this.textarea.focus()}catch(t){}},Ls.prototype.blur=function(){this.textarea.blur()},Ls.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},Ls.prototype.receivedFocus=function(){this.slowPoll()},Ls.prototype.slowPoll=function(){var t=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){t.poll(),t.cm.state.focused&&t.slowPoll()})},Ls.prototype.fastPoll=function(){var t=!1,e=this;e.pollingFast=!0,e.polling.set(20,function n(){e.poll()||t?(e.pollingFast=!1,e.slowPoll()):(t=!0,e.polling.set(60,n))})},Ls.prototype.poll=function(){var t=this,e=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||!e.state.focused||_e(n)&&!r&&!this.composing||e.isReadOnly()||e.options.disableInput||e.state.keySeq)return!1;var i=n.value;if(i==r&&!e.somethingSelected())return!1;if(s&&a>=9&&this.hasSelection===i||y&&/[\uf700-\uf7ff]/.test(i))return e.display.input.reset(),!1;if(e.doc.sel==e.display.selForContextMenu){var o=i.charCodeAt(0);if(8203!=o||r||(r="​"),8666==o)return this.reset(),this.cm.execCommand("undo")}for(var l=0,c=Math.min(r.length,i.length);l1e3||i.indexOf("\n")>-1?n.value=t.prevInput="":t.prevInput=i,t.composing&&(t.composing.range.clear(),t.composing.range=e.markText(t.composing.start,e.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},Ls.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},Ls.prototype.onKeyPress=function(){s&&a>=9&&(this.hasSelection=null),this.fastPoll()},Ls.prototype.onContextMenu=function(t){var e=this,n=e.cm,r=n.display,i=e.textarea,o=or(n,t),c=r.scroller.scrollTop;if(o&&!h){n.options.resetSelectionOnContextMenu&&-1==n.doc.sel.contains(o)&&Ur(n,Wi)(n.doc,di(o),$);var u=i.style.cssText,f=e.wrapper.style.cssText;e.wrapper.style.cssText="position: absolute";var d,p=e.wrapper.getBoundingClientRect();if(i.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(t.clientY-p.top-5)+"px; left: "+(t.clientX-p.left-5)+"px;\n z-index: 1000; background: "+(s?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",l&&(d=window.scrollY),r.input.focus(),l&&window.scrollTo(null,d),r.input.reset(),n.somethingSelected()||(i.value=e.prevInput=" "),e.contextMenuPending=!0,r.selForContextMenu=n.doc.sel,clearTimeout(r.detectingSelectAll),s&&a>=9&&g(),C){pe(t);var v=function(){oe(window,"mouseup",v),setTimeout(m,20)};re(window,"mouseup",v)}else setTimeout(m,50)}function g(){if(null!=i.selectionStart){var t=n.somethingSelected(),o="​"+(t?i.value:"");i.value="⇚",i.value=o,e.prevInput=t?"":"​",i.selectionStart=1,i.selectionEnd=o.length,r.selForContextMenu=n.doc.sel}}function m(){if(e.contextMenuPending=!1,e.wrapper.style.cssText=f,i.style.cssText=u,s&&a<9&&r.scrollbars.setScrollTop(r.scroller.scrollTop=c),null!=i.selectionStart){(!s||s&&a<9)&&g();var t=0,o=function(){r.selForContextMenu==n.doc.sel&&0==i.selectionStart&&i.selectionEnd>0&&"​"==e.prevInput?Ur(n,Yi)(n):t++<10?r.detectingSelectAll=setTimeout(o,500):(r.selForContextMenu=null,r.input.reset())};r.detectingSelectAll=setTimeout(o,200)}}},Ls.prototype.readOnlyChanged=function(t){t||this.reset()},Ls.prototype.setUneditable=function(){},Ls.prototype.needsContentAttribute=!1,function(t){var e=t.optionHandlers;function n(n,r,i,o){t.defaults[n]=r,i&&(e[n]=o?function(t,e,n){n!=rs&&i(t,e,n)}:i)}t.defineOption=n,t.Init=rs,n("value","",function(t,e){return t.setValue(e)},!0),n("mode",null,function(t,e){t.doc.modeOption=e,yi(t)},!0),n("indentUnit",2,yi,!0),n("indentWithTabs",!1),n("smartIndent",!0),n("tabSize",4,function(t){xi(t),Rn(t),Yr(t)},!0),n("lineSeparator",null,function(t,e){if(t.doc.lineSep=e,e){var n=[],r=t.doc.first;t.doc.iter(function(t){for(var i=0;;){var o=t.text.indexOf(e,i);if(-1==o)break;i=o+e.length,n.push(vt(r,o))}r++});for(var i=n.length-1;i>=0;i--)no(t.doc,e,n[i],vt(n[i].line,n[i].ch+e.length))}}),n("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g,function(t,e,n){t.state.specialChars=new RegExp(e.source+(e.test("\t")?"":"|\t"),"g"),n!=rs&&t.refresh()}),n("specialCharPlaceholder",Qe,function(t){return t.refresh()},!0),n("electricChars",!0),n("inputStyle",m?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),n("spellcheck",!1,function(t,e){return t.getInputField().spellcheck=e},!0),n("rtlMoveVisually",!b),n("wholeLineUpdateBefore",!0),n("theme","default",function(t){ns(t),ss(t)},!0),n("keyMap","default",function(t,e,n){var r=Fo(e),i=n!=rs&&Fo(n);i&&i.detach&&i.detach(t,r),r.attach&&r.attach(t,i||null)}),n("extraKeys",null),n("lineWrapping",!1,ls,!0),n("gutters",[],function(t){ci(t.options),ss(t)},!0),n("fixedGutter",!0,function(t,e){t.display.gutters.style.left=e?nr(t.display)+"px":"0",t.refresh()},!0),n("coverGutterNextToScrollbar",!1,function(t){return Er(t)},!0),n("scrollbarStyle","native",function(t){Dr(t),Er(t),t.display.scrollbars.setScrollTop(t.doc.scrollTop),t.display.scrollbars.setScrollLeft(t.doc.scrollLeft)},!0),n("lineNumbers",!1,function(t){ci(t.options),ss(t)},!0),n("firstLineNumber",1,ss,!0),n("lineNumberFormatter",function(t){return t},ss,!0),n("showCursorWhenSelecting",!1,ar,!0),n("resetSelectionOnContextMenu",!0),n("lineWiseCopyCut",!0),n("readOnly",!1,function(t,e){"nocursor"==e?(pr(t),t.display.input.blur(),t.display.disabled=!0):t.display.disabled=!1,t.display.input.readOnlyChanged(e)}),n("disableInput",!1,function(t,e){e||t.display.input.reset()},!0),n("dragDrop",!0,as),n("allowDropFileTypes",null),n("cursorBlinkRate",530),n("cursorScrollMargin",0),n("cursorHeight",1,ar,!0),n("singleCursorHeightPerLine",!0,ar,!0),n("workTime",100),n("workDelay",100),n("flattenSpans",!0,xi,!0),n("addModeClass",!1,xi,!0),n("pollInterval",100),n("undoDepth",200,function(t,e){return t.doc.history.undoDepth=e}),n("historyEventDelay",1250),n("viewportMargin",10,function(t){return t.refresh()},!0),n("maxHighlightLength",1e4,xi,!0),n("moveInputWithCursor",!0,function(t,e){e||t.display.input.resetPosition()}),n("tabindex",null,function(t,e){return t.display.input.getField().tabIndex=e||""}),n("autofocus",null),n("direction","ltr",function(t,e){return t.doc.setDirection(e)},!0)}(cs),function(t){var e=t.optionHandlers,n=t.helpers={};t.prototype={constructor:t,focus:function(){window.focus(),this.display.input.focus()},setOption:function(t,n){var r=this.options,i=r[t];r[t]==n&&"mode"!=t||(r[t]=n,e.hasOwnProperty(t)&&Ur(this,e[t])(this,n,i),se(this,"optionChange",this,t))},getOption:function(t){return this.options[t]},getDoc:function(){return this.doc},addKeyMap:function(t,e){this.state.keyMaps[e?"push":"unshift"](Fo(t))},removeKeyMap:function(t){for(var e=this.state.keyMaps,n=0;nn&&(hs(this,i.head.line,t,!0),n=i.head.line,r==this.doc.sel.primIndex&&Pr(this));else{var o=i.from(),s=i.to(),a=Math.max(n,o.line);n=Math.min(this.lastLine(),s.line-(s.ch?0:1))+1;for(var l=a;l0&&Ii(this.doc,r,new hi(o,c[r].to()),$)}}}),getTokenAt:function(t,e){return $e(this,t,e)},getLineTokens:function(t,e){return $e(this,vt(t),e,!0)},getTokenTypeAt:function(t){t=kt(this.doc,t);var e,n=Ie(this,at(this.doc,t.line)),r=0,i=(n.length-1)/2,o=t.ch;if(0==o)e=n[2];else for(;;){var s=r+i>>1;if((s?n[2*s-1]:0)>=o)i=s;else{if(!(n[2*s+1]o&&(t=o,i=!0),r=at(this.doc,t)}else r=t;return $n(this,r,{top:0,left:0},e||"page",n||i).top+(i?this.doc.height-Vt(r):0)},defaultTextHeight:function(){return Jn(this.display)},defaultCharWidth:function(){return tr(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(t,e,n,r,i){var o,s,a,l=this.display,c=(t=Un(this,kt(this.doc,t))).bottom,u=t.left;if(e.style.position="absolute",e.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(e),l.sizer.appendChild(e),"over"==r)c=t.top;else if("above"==r||"near"==r){var h=Math.max(l.wrapper.clientHeight,this.doc.height),f=Math.max(l.sizer.clientWidth,l.lineSpace.clientWidth);("above"==r||t.bottom+e.offsetHeight>h)&&t.top>e.offsetHeight?c=t.top-e.offsetHeight:t.bottom+e.offsetHeight<=h&&(c=t.bottom),u+e.offsetWidth>f&&(u=f-e.offsetWidth)}e.style.top=c+"px",e.style.left=e.style.right="","right"==i?(u=l.sizer.clientWidth-e.offsetWidth,e.style.right="0px"):("left"==i?u=0:"middle"==i&&(u=(l.sizer.clientWidth-e.offsetWidth)/2),e.style.left=u+"px"),n&&(o=this,s={left:u,top:c,right:u+e.offsetWidth,bottom:c+e.offsetHeight},null!=(a=Br(o,s)).scrollTop&&br(o,a.scrollTop),null!=a.scrollLeft&&wr(o,a.scrollLeft))},triggerOnKeyDown:Xr(Yo),triggerOnKeyPress:Xr(Zo),triggerOnKeyUp:Ko,execCommand:function(t){if(Ho.hasOwnProperty(t))return Ho[t].call(null,this)},triggerElectric:Xr(function(t){gs(this,t)}),findPosH:function(t,e,n,r){var i=1;e<0&&(i=-1,e=-e);for(var o=kt(this.doc,t),s=0;s0&&s(e.charAt(n-1));)--n;for(;r.5)&&ir(this),se(this,"refresh",this)}),swapDoc:Xr(function(t){var e=this.doc;return e.cm=null,Ci(this,t),Rn(this),this.display.input.reset(),this.scrollTo(t.scrollLeft,t.scrollTop),this.curOp.forceScroll=!0,ln(this,"swapDoc",this,e),e}),getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},ue(t),t.registerHelper=function(e,r,i){n.hasOwnProperty(e)||(n[e]=t[e]={_global:[]}),n[e][r]=i},t.registerGlobalHelper=function(e,r,i,o){t.registerHelper(e,r,o),n[e]._global.push({pred:i,val:o})}}(cs);var Ms="iter insert remove copy getEditor constructor".split(" ");for(var As in xo.prototype)xo.prototype.hasOwnProperty(As)&&R(Ms,As)<0&&(cs.prototype[As]=function(t){return function(){return t.apply(this.doc,arguments)}}(xo.prototype[As]));return ue(xo),cs.inputStyles={textarea:Ls,contenteditable:ks},cs.defineMode=function(t){cs.defaults.mode||"null"==t||(cs.defaults.mode=t),function(t,e){arguments.length>2&&(e.dependencies=Array.prototype.slice.call(arguments,2)),Le[t]=e}.apply(this,arguments)},cs.defineMIME=function(t,e){Me[t]=e},cs.defineMode("null",function(){return{token:function(t){return t.skipToEnd()}}}),cs.defineMIME("text/plain","null"),cs.defineExtension=function(t,e){cs.prototype[t]=e},cs.defineDocExtension=function(t,e){xo.prototype[t]=e},cs.fromTextArea=function(t,e){if((e=e?F(e):{}).value=t.value,!e.tabindex&&t.tabIndex&&(e.tabindex=t.tabIndex),!e.placeholder&&t.placeholder&&(e.placeholder=t.placeholder),null==e.autofocus){var n=O();e.autofocus=n==t||null!=t.getAttribute("autofocus")&&n==document.body}function r(){t.value=a.getValue()}var i;if(t.form&&(re(t.form,"submit",r),!e.leaveSubmitMethodAlone)){var o=t.form;i=o.submit;try{var s=o.submit=function(){r(),o.submit=i,o.submit(),o.submit=s}}catch(t){}}e.finishInit=function(e){e.save=r,e.getTextArea=function(){return t},e.toTextArea=function(){e.toTextArea=isNaN,r(),t.parentNode.removeChild(e.getWrapperElement()),t.style.display="",t.form&&(oe(t.form,"submit",r),"function"==typeof t.form.submit&&(t.form.submit=i))}},t.style.display="none";var a=cs(function(e){return t.parentNode.insertBefore(e,t.nextSibling)},e);return a},function(t){t.off=oe,t.on=re,t.wheelEventPixels=Sr,t.Doc=xo,t.splitLines=Ce,t.countColumn=I,t.findColumn=U,t.isWordChar=tt,t.Pass=z,t.signal=se,t.Line=Ue,t.changeEnd=pi,t.scrollbarModel=Or,t.Pos=vt,t.cmpPos=gt,t.modes=Le,t.mimeModes=Me,t.resolveMode=Ae,t.getMode=Ee,t.modeExtensions=Ne,t.extendMode=Oe,t.copyState=De,t.startState=je,t.innerMode=Be,t.commands=Ho,t.keyMap=No,t.keyName=Po,t.isModifierKey=jo,t.lookupKey=Bo,t.normalizeKeyMap=Do,t.StringStream=Pe,t.SharedTextMarker=vo,t.TextMarker=fo,t.LineWidget=co,t.e_preventDefault=he,t.e_stopPropagation=fe,t.e_stop=pe,t.addClass=D,t.contains=N,t.rmClass=T,t.keyNames=Lo}(cs),cs.version="5.25.0",cs}),function(t){"object"==typeof exports&&"object"==typeof module?t(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],t):t(CodeMirror)}(function(t){"use strict";var e="CodeMirror-activeline",n="CodeMirror-activeline-background",r="CodeMirror-activeline-gutter";function i(t){for(var i=0;i!?|~^]/,d=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function p(t,e,n){return r=t,i=n,e}function v(t,e){var n,r=t.next();if('"'==r||"'"==r)return e.tokenize=(n=r,function(t,e){var r,i=!1;if(a&&"@"==t.peek()&&t.match(d))return e.tokenize=v,p("jsonld-keyword","meta");for(;null!=(r=t.next())&&(r!=n||i);)i=!i&&"\\"==r;return i||(e.tokenize=v),p("string","string")}),e.tokenize(t,e);if("."==r&&t.match(/^\d+(?:[eE][+\-]?\d+)?/))return p("number","number");if("."==r&&t.match(".."))return p("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(r))return p(r);if("="==r&&t.eat(">"))return p("=>","operator");if("0"==r&&t.eat(/x/i))return t.eatWhile(/[\da-f]/i),p("number","number");if(/\d/.test(r))return t.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),p("number","number");if("/"==r)return t.eat("*")?(e.tokenize=g,g(t,e)):t.eat("/")?(t.skipToEnd(),p("comment","comment")):"operator"==e.lastType||"keyword c"==e.lastType||"sof"==e.lastType||/^[\[{}\(,;:]$/.test(e.lastType)?(function(t){for(var e,n=!1,r=!1;null!=(e=t.next());){if(!n){if("/"==e&&!r)return;"["==e?r=!0:r&&"]"==e&&(r=!1)}n=!n&&"\\"==e}}(t),t.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/),p("regexp","string-2")):(t.eatWhile(f),p("operator","operator",t.current()));if("`"==r)return e.tokenize=m,m(t,e);if("#"==r)return t.skipToEnd(),p("error","error");if(f.test(r))return t.eatWhile(f),p("operator","operator",t.current());if(u.test(r)){t.eatWhile(u);var i=t.current(),o=h.propertyIsEnumerable(i)&&h[i];return o&&"."!=e.lastType?p(o.type,o.style,i):p("variable","variable",i)}}function g(t,e){for(var n,r=!1;n=t.next();){if("/"==n&&r){e.tokenize=v;break}r="*"==n}return p("comment","comment")}function m(t,e){for(var n,r=!1;null!=(n=t.next());){if(!r&&("`"==n||"$"==n&&t.eat("{"))){e.tokenize=v;break}r=!r&&"\\"==n}return p("quasi","string-2",t.current())}var y="([{}])";function x(t,e){e.fatArrowAt&&(e.fatArrowAt=null);var n=t.string.indexOf("=>",t.start);if(!(n<0)){for(var r=0,i=!1,o=n-1;o>=0;--o){var s=t.string.charAt(o),a=y.indexOf(s);if(a>=0&&a<3){if(!r){++o;break}if(0==--r)break}else if(a>=3&&a<6)++r;else if(u.test(s))i=!0;else{if(/["'\/]/.test(s))return;if(i&&!r){++o;break}}}i&&!r&&(e.fatArrowAt=o)}}var b={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,"jsonld-keyword":!0};function w(t,e,n,r,i,o){this.indented=t,this.column=e,this.type=n,this.prev=i,this.info=o,null!=r&&(this.align=r)}function k(t,e){for(var n=t.localVars;n;n=n.next)if(n.name==e)return!0;for(var r=t.context;r;r=r.prev)for(n=r.vars;n;n=n.next)if(n.name==e)return!0}var C={state:null,column:null,marked:null,cc:null};function _(){for(var t=arguments.length-1;t>=0;t--)C.cc.push(arguments[t])}function S(){return _.apply(null,arguments),!0}function T(t){function e(e){for(var n=e;n;n=n.next)if(n.name==t)return!0;return!1}var r=C.state;if(r.context){if(C.marked="def",e(r.localVars))return;r.localVars={name:t,next:r.localVars}}else{if(e(r.globalVars))return;n.globalVars&&(r.globalVars={name:t,next:r.globalVars})}}var L={name:"this",next:{name:"arguments"}};function M(){C.state.context={prev:C.state.context,vars:C.state.localVars},C.state.localVars=L}function A(){C.state.localVars=C.state.context.vars,C.state.context=C.state.context.prev}function E(t,e){var n=function(){var n=C.state,r=n.indented;if("stat"==n.lexical.type)r=n.lexical.indented;else for(var i=n.lexical;i&&")"==i.type&&i.align;i=i.prev)r=i.indented;n.lexical=new w(r,C.stream.column(),t,null,n.lexical,e)};return n.lex=!0,n}function N(){var t=C.state;t.lexical.prev&&(")"==t.lexical.type&&(t.indented=t.lexical.indented),t.lexical=t.lexical.prev)}function O(t){return function e(n){return n==t?S():";"==t?_():S(e)}}function D(t,e){return"var"==t?S(E("vardef",e.length),et,O(";"),N):"keyword a"==t?S(E("form"),B,D,N):"keyword b"==t?S(E("form"),D,N):"{"==t?S(E("}"),Q,N):";"==t?S():"if"==t?("else"==C.state.lexical.info&&C.state.cc[C.state.cc.length-1]==N&&C.state.cc.pop()(),S(E("form"),B,D,N,st)):"function"==t?S(ft):"for"==t?S(E("form"),at,D,N):"variable"==t?S(E("stat"),V):"switch"==t?S(E("form"),B,E("}","switch"),O("{"),Q,N,N):"case"==t?S(B,O(":")):"default"==t?S(O(":")):"catch"==t?S(E("form"),M,O("("),dt,O(")"),D,N,A):"module"==t?S(E("form"),M,yt,A,N):"class"==t?S(E("form"),pt,N):"export"==t?S(E("form"),xt,N):"import"==t?S(E("form"),bt,N):_(E("stat"),B,O(";"),N)}function B(t){return P(t,!1)}function j(t){return P(t,!0)}function P(t,e){if(C.state.fatArrowAt==C.stream.start){var n=e?q:$;if("("==t)return S(M,E(")"),K(nt,")"),N,O("=>"),n,A);if("variable"==t)return _(M,nt,O("=>"),n,A)}var r=e?R:H;return b.hasOwnProperty(t)?S(r):"function"==t?S(ft,r):"keyword c"==t?S(e?I:F):"("==t?S(E(")"),F,St,O(")"),N,r):"operator"==t||"spread"==t?S(e?j:B):"["==t?S(E("]"),Ct,N,r):"{"==t?Z(X,"}",null,r):"quasi"==t?_(W,r):S()}function F(t){return t.match(/[;\}\)\],]/)?_():_(B)}function I(t){return t.match(/[;\}\)\],]/)?_():_(j)}function H(t,e){return","==t?S(B):R(t,e,!1)}function R(t,e,n){var r=0==n?H:R,i=0==n?B:j;return"=>"==t?S(M,n?q:$,A):"operator"==t?/\+\+|--/.test(e)?S(r):"?"==e?S(B,O(":"),i):S(i):"quasi"==t?_(W,r):";"!=t?"("==t?Z(j,")","call",r):"."==t?S(U,r):"["==t?S(E("]"),F,O("]"),N,r):void 0:void 0}function W(t,e){return"quasi"!=t?_():"${"!=e.slice(e.length-2)?S(W):S(B,z)}function z(t){if("}"==t)return C.marked="string-2",C.state.tokenize=m,S(W)}function $(t){return x(C.stream,C.state),_("{"==t?D:B)}function q(t){return x(C.stream,C.state),_("{"==t?D:j)}function V(t){return":"==t?S(N,D):_(H,O(";"),N)}function U(t){if("variable"==t)return C.marked="property",S()}function X(t,e){return"variable"==t||"keyword"==C.style?(C.marked="property",S("get"==e||"set"==e?G:Y)):"number"==t||"string"==t?(C.marked=a?"property":C.style+" property",S(Y)):"jsonld-keyword"==t?S(Y):"["==t?S(B,O("]"),Y):void 0}function G(t){return"variable"!=t?_(Y):(C.marked="property",S(ft))}function Y(t){return":"==t?S(j):"("==t?_(ft):void 0}function K(t,e){function n(r){if(","==r){var i=C.state.lexical;return"call"==i.info&&(i.pos=(i.pos||0)+1),S(t,n)}return r==e?S():S(O(e))}return function(r){return r==e?S():_(t,n)}}function Z(t,e,n){for(var r=3;r=0;--l){var c=e.cc[l];if(c==N)a=a.prev;else if(c!=st)break}"stat"==a.type&&"}"==i&&(a=a.prev),s&&")"==a.type&&"stat"==a.prev.type&&(a=a.prev);var u=a.type,h=i==u;return"vardef"==u?a.indented+("operator"==e.lastType||","==e.lastType?a.info+1:0):"form"==u&&"{"==i?a.indented:"form"==u?a.indented+o:"stat"==u?a.indented+(function(t,e){return"operator"==t.lastType||","==t.lastType||f.test(e.charAt(0))||/[,.]/.test(e.charAt(0))}(e,r)?s||o:0):"switch"!=a.info||h||0==n.doubleIndentSwitch?a.align?a.column+(h?0:1):a.indented+(h?0:o):a.indented+(/^(?:case|default)\b/.test(r)?o:2*o)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:l?null:"/*",blockCommentEnd:l?null:"*/",lineComment:l?null:"//",fold:"brace",helperType:l?"json":"javascript",jsonldMode:a,jsonMode:l}}),t.registerHelper("wordChars","javascript",/[\w$]/),t.defineMIME("text/javascript","javascript"),t.defineMIME("text/ecmascript","javascript"),t.defineMIME("application/javascript","javascript"),t.defineMIME("application/x-javascript","javascript"),t.defineMIME("application/ecmascript","javascript"),t.defineMIME("application/json",{name:"javascript",json:!0}),t.defineMIME("application/x-json",{name:"javascript",json:!0}),t.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),t.defineMIME("text/typescript",{name:"javascript",typescript:!0}),t.defineMIME("application/typescript",{name:"javascript",typescript:!0})}),function(){function t(){this.Diff_Timeout=1,this.Diff_EditCost=4,this.Match_Threshold=.5,this.Match_Distance=1e3,this.Patch_DeleteThreshold=.5,this.Patch_Margin=4,this.Match_MaxBits=32}t.prototype.diff_main=function(t,e,n,r){if(void 0===r&&(r=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1e3*this.Diff_Timeout),null==t||null==e)throw Error("Null input. (diff_main)");if(t==e)return t?[[0,t]]:[];void 0===n&&(n=!0);var i=n,o=this.diff_commonPrefix(t,e);n=t.substring(0,o),t=t.substring(o),e=e.substring(o);o=this.diff_commonSuffix(t,e);var s=t.substring(t.length-o);return t=t.substring(0,t.length-o),e=e.substring(0,e.length-o),t=this.diff_compute_(t,e,i,r),n&&t.unshift([0,n]),s&&t.push([0,s]),this.diff_cleanupMerge(t),t},t.prototype.diff_compute_=function(t,e,n,r){if(!t)return[[1,e]];if(!e)return[[-1,t]];var i=t.length>e.length?t:e,o=t.length>e.length?e:t,s=i.indexOf(o);return-1!=s?(n=[[1,i.substring(0,s)],[0,o],[1,i.substring(s+o.length)]],t.length>e.length&&(n[0][0]=n[2][0]=-1),n):1==o.length?[[-1,t],[1,e]]:(i=this.diff_halfMatch_(t,e))?(o=i[0],t=i[1],s=i[2],e=i[3],i=i[4],o=this.diff_main(o,s,n,r),n=this.diff_main(t,e,n,r),o.concat([[0,i]],n)):n&&100n);g++){for(var m=-g+f;m<=g-d;m+=2){for(var y,x=s+m,b=(y=m==-g||m!=g&&l[x-1]r)d+=2;else if(b>i)f+=2;else if(h&&(0<=(x=s+u-m)&&x=w)return this.diff_bisectSplit_(t,e,y,b,n)}}for(m=-g+p;m<=g-v;m+=2){for(x=s+m,y=(w=m==-g||m!=g&&c[x-1]r)v+=2;else if(y>i)p+=2;else if(!h&&(0<=(x=s+u-m)&&x=(w=r-w))))return this.diff_bisectSplit_(t,e,y,b,n)}}return[[-1,t],[1,e]]},t.prototype.diff_bisectSplit_=function(t,e,n,r,i){var o=t.substring(0,n),s=e.substring(0,r);return t=t.substring(n),e=e.substring(r),o=this.diff_main(o,s,!1,i),i=this.diff_main(t,e,!1,i),o.concat(i)},t.prototype.diff_linesToChars_=function(t,e){function n(t){for(var e="",n=0,o=-1,s=r.length;or?t=t.substring(n-r):n=t.length?[r,i,o,s,u]:null}if(0>=this.Diff_Timeout)return null;var r=t.length>e.length?t:e,i=t.length>e.length?e:t;if(4>r.length||2*i.lengthr[4].length?l:r:l,t.length>e.length?(l=o[0],r=o[1],i=o[2],s=o[3]):(i=o[0],s=o[1],l=o[2],r=o[3]),[l,r,i,s,o=o[4]]):null},t.prototype.diff_cleanupSemantic=function(t){for(var e=!1,n=[],r=0,i=null,o=0,s=0,a=0,l=0,c=0;o=(i=this.diff_commonOverlap_(n,e))?(r>=e.length/2||r>=n.length/2)&&(t.splice(o,0,[0,n.substring(0,r)]),t[o-1][1]=e.substring(0,e.length-r),t[o+1][1]=n.substring(r),o++):(i>=e.length/2||i>=n.length/2)&&(t.splice(o,0,[0,e.substring(0,i)]),t[o-1][0]=1,t[o-1][1]=n.substring(0,n.length-i),t[o+1][0]=-1,t[o+1][1]=e.substring(i),o++),o++),o++},t.prototype.diff_cleanupSemanticLossless=function(e){function n(e,n){if(!e||!n)return 6;var r=e.charAt(e.length-1),i=n.charAt(0),o=r.match(t.nonAlphaNumericRegex_),s=i.match(t.nonAlphaNumericRegex_),a=o&&r.match(t.whitespaceRegex_),l=s&&i.match(t.whitespaceRegex_),c=(r=a&&r.match(t.linebreakRegex_),i=l&&i.match(t.linebreakRegex_),r&&e.match(t.blanklineEndRegex_)),u=i&&n.match(t.blanklineStartRegex_);return c||u?5:r||i?4:o&&!a&&l?3:a||l?2:o||s?1:0}for(var r=1;r=u&&(u=h,l=i,a=o,c=s)}e[r-1][1]!=l&&(l?e[r-1][1]=l:(e.splice(r-1,1),r--),e[r][1]=a,c?e[r+1][1]=c:(e.splice(r+1,1),r--))}r++}},t.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/,t.whitespaceRegex_=/\s/,t.linebreakRegex_=/[\r\n]/,t.blanklineEndRegex_=/\n\r?\n$/,t.blanklineStartRegex_=/^\r?\n\r?\n/,t.prototype.diff_cleanupEfficiency=function(t){for(var e=!1,n=[],r=0,i=null,o=0,s=!1,a=!1,l=!1,c=!1;oe));n++)o=r,s=i;return t.length!=n&&-1===t[n][0]?s:s+(e-o)},t.prototype.diff_prettyHtml=function(t){for(var e=[],n=/&/g,r=//g,o=/\n/g,s=0;s");switch(a){case 1:e[s]=''+l+"";break;case-1:e[s]=''+l+"";break;case 0:e[s]=""+l+""}}return e.join("")},t.prototype.diff_text1=function(t){for(var e=[],n=0;nthis.Match_MaxBits)throw Error("Pattern too long for this browser.");var i=this.match_alphabet_(e),o=this,s=this.Match_Threshold;-1!=(h=t.indexOf(e,n))&&(s=Math.min(r(0,h),s),-1!=(h=t.lastIndexOf(e,n+e.length))&&(s=Math.min(r(0,h),s)));for(var a,l,c,u=1<=a;p--){var v=i[t.charAt(p-1)];if(l[p]=0===d?(l[p+1]<<1|1)&v:(l[p+1]<<1|1)&v|(c[p+1]|c[p])<<1|1|c[p+1],l[p]&u&&(v=r(d,p-1))<=s){if(s=v,!((h=p-1)>n))break;a=Math.max(1,2*n-h)}}if(r(d+1,n)>s)break;c=l}return h},t.prototype.match_alphabet_=function(t){for(var e={},n=0;n=2*this.Patch_Margin&&o&&(this.patch_addContext_(e,l),r.push(e),e=new t.patch_obj,o=0,l=i,s=a)}1!==u&&(s+=h.length),-1!==u&&(a+=h.length)}return o&&(this.patch_addContext_(e,l),r.push(e)),r},t.prototype.patch_deepCopy=function(e){for(var n=[],r=0;rthis.Match_MaxBits?-1!=(s=this.match_main(e,u.substring(0,this.Match_MaxBits),a))&&(-1==(l=this.match_main(e,u.substring(u.length-this.Match_MaxBits),a+u.length-this.Match_MaxBits))||s>=l)&&(s=-1):s=this.match_main(e,u,a),-1==s)i[o]=!1,r-=t[o].length2-t[o].length1;else if(i[o]=!0,r=s-a,u==(a=-1==l?e.substring(s,s+u.length):e.substring(s,l+this.Match_MaxBits)))e=e.substring(0,s)+this.diff_text2(t[o].diffs)+e.substring(s+u.length);else if(a=this.diff_main(u,a,!1),u.length>this.Match_MaxBits&&this.diff_levenshtein(a)/u.length>this.Patch_DeleteThreshold)i[o]=!1;else{this.diff_cleanupSemanticLossless(a);var c,u=0;for(l=0;li[0][1].length){var o=e-i[0][1].length;i[0][1]=n.substring(i[0][1].length)+i[0][1],r.start1-=o,r.start2-=o,r.length1+=o,r.length2+=o}return 0==(i=(r=t[t.length-1]).diffs).length||0!=i[i.length-1][0]?(i.push([0,n]),r.length1+=e,r.length2+=e):e>i[i.length-1][1].length&&(o=e-i[i.length-1][1].length,i[i.length-1][1]+=n.substring(0,o),r.length1+=o,r.length2+=o),n},t.prototype.patch_splitMax=function(e){for(var n=this.Match_MaxBits,r=0;r2*n?(l.length1+=u.length,o+=u.length,c=!1,l.diffs.push([a,u]),i.diffs.shift()):(u=u.substring(0,n-l.length1-this.Patch_Margin),l.length1+=u.length,o+=u.length,0===a?(l.length2+=u.length,s+=u.length):c=!1,l.diffs.push([a,u]),u==i.diffs[0][1]?i.diffs.shift():i.diffs[0][1]=i.diffs[0][1].substring(u.length))}a=(a=this.diff_text2(l.diffs)).substring(a.length-this.Patch_Margin),""!==(u=this.diff_text1(i.diffs).substring(0,this.Patch_Margin))&&(l.length1+=u.length,l.length2+=u.length,0!==l.diffs.length&&0===l.diffs[l.diffs.length-1][0]?l.diffs[l.diffs.length-1][1]+=u:l.diffs.push([0,u])),c||e.splice(++r,0,l)}}},t.prototype.patch_toText=function(t){for(var e=[],n=0;ni)return!1;var o=n.getScrollInfo();if("align"==t.mv.options.connect)g=o.top;else{var s,a,l=.5*o.clientHeight,c=o.top+l,u=n.lineAtHeight(c,"local"),h=function(t,e,n){for(var r,i,o,s,a=0;ae?(i=l.editFrom,s=l.origFrom):u>e&&(i=l.editTo,s=l.origTo)),u<=e?(r=l.editTo,o=l.origTo):c<=e&&(r=l.editFrom,o=l.origFrom)}return{edit:{before:r,after:i},orig:{before:o,after:s}}}(t.chunks,u,e),f=p(n,e?h.edit:h.orig),d=p(r,e?h.orig:h.edit),v=(c-f.top)/(f.bot-f.top),g=d.top-l+v*(d.bot-d.top);if(g>o.top&&(a=o.top/l)<1)g=g*a+o.top*(1-a);else if((s=o.height-o.clientHeight-o.top)s&&(a=s/l)<1&&(g=g*a+(m.height-m.clientHeight-s)*(1-a))}}return r.scrollTo(o.left,g),r.state.scrollSetAt=i,r.state.scrollSetBy=t,!0}function p(t,e){var n=e.after;return null==n&&(n=t.lastLine()+1),{top:t.heightAtLine(e.before||0,"local"),bot:t.heightAtLine(n,"local")}}function v(t,e,n){t.lockScroll=e,e&&0!=n&&d(t,DIFF_INSERT)&&w(t)}function g(t,e,n){for(var r=n.classLocation,i=0;i20||n.from-o.to>20?(m(t,n.marked,i),b(t,e,r,n.marked,o.from,o.to,i),n.from=o.from,n.to=o.to):(o.fromn.to&&(b(t,e,r,n.marked,n.to,o.to,i),n.to=o.to))})}function x(t,e,n,r,i,o){for(var s=n.classLocation,a=t.getLineHandle(e),l=0;lb&&(p&&(f(d,b),p=!1),d=w)}else if(p=!0,m==n){var k=U(l,y,!0),C=Q(c,l),_=Z(u,k);J(C,_)||r.push(t.markText(C,_,{className:h})),l=k}}p&&f(d,l.line+1)}function w(t){if(t.showDifferences){if(t.svg){$(t.svg);var e=t.gap.offsetWidth;q(t.svg,"width",e,"height",t.gap.offsetHeight)}t.copyButtons&&$(t.copyButtons);for(var n=t.edit.getViewport(),r=t.orig.getViewport(),i=t.mv.wrap.getBoundingClientRect().top,o=i-t.edit.getScrollerElement().getBoundingClientRect().top+t.edit.getScrollInfo().top,s=i-t.orig.getScrollerElement().getBoundingClientRect().top+t.orig.getScrollInfo().top,a=0;a=n.from&&l.origFrom<=r.to&&l.origTo>=r.from&&M(t,l,s,o,e)}}}function k(t,e){for(var n=0,r=0,i=0;it&&o.editFrom<=t)return null;if(o.editFrom>t)break;n=o.editTo,r=o.origTo}return r+(t-n)}function C(t,e,n){for(var r=t.state.trackAlignable,i=t.firstLine(),o=0,s=[],a=0;;a++){for(var l=e[a],c=l?n?l.origFrom:l.editFrom:1e9;oh){o++,i--;continue t}if(f.editTo>u){if(f.editFrom<=u)continue t;break}a+=f.origTo-f.origFrom-(f.editTo-f.editFrom),s++}if(u==h-a)l[r]=h,o++;else if(u1&&n.push(L(t[o],e[o],a))}}function L(t,e,n){var r=!0;e>t.lastLine()&&(e--,r=!1);var i=document.createElement("div");return i.className="CodeMirror-merge-spacer",i.style.height=n+"px",i.style.minWidth="1px",t.addLineWidget(e,i,{height:n,above:r,mergeSpacer:!0,handleMouseEvents:!0})}function M(t,e,n,r,i){var s="left"==t.type,a=t.orig.heightAtLine(e.origFrom,"local",!0)-n;if(t.svg){var l=a,c=t.edit.heightAtLine(e.editFrom,"local",!0)-r;if(s){var u=l;l=c,c=u}var h=t.orig.heightAtLine(e.origTo,"local",!0)-n,f=t.edit.heightAtLine(e.editTo,"local",!0)-r;if(s){u=h;h=f,f=u}var d=" C "+i/2+" "+c+" "+i/2+" "+l+" "+(i+2)+" "+l,p=" C "+i/2+" "+h+" "+i/2+" "+f+" -1 "+f;q(t.svg.appendChild(document.createElementNS(o,"path")),"d","M -1 "+c+d+" L "+(i+2)+" "+h+p+" z","class",t.classes.connect)}if(t.copyButtons){var v=t.copyButtons.appendChild(z("div","left"==t.type?"⇝":"⇜","CodeMirror-merge-copy")),g=t.mv.options.allowEditingOriginals;if(v.title=g?"Push to left":"Revert chunk",v.chunk=e,v.style.top=(e.origTo>e.origFrom?a:t.edit.heightAtLine(e.editFrom,"local")-r)+"px",g){var m=t.edit.heightAtLine(e.editFrom,"local")-r,y=t.copyButtons.appendChild(z("div","right"==t.type?"⇝":"⇜","CodeMirror-merge-copy-reverse"));y.title="Push to right",y.chunk={editFrom:e.origFrom,editTo:e.origTo,origFrom:e.editFrom,origTo:e.editTo},y.style.top=m+"px","right"==t.type?y.style.left="2px":y.style.right="2px"}}}function A(t,e,n,r){if(!t.diffOutOfDate){var o=r.origTo>n.lastLine()?i(r.origFrom-1):i(r.origFrom,0),s=i(r.origTo,0),a=r.editTo>e.lastLine()?i(r.editFrom-1):i(r.editFrom,0),l=i(r.editTo,0),c=t.mv.options.revertChunk;c?c(t.mv,n,o,s,e,a,l):e.replaceRange(n.getRange(o,s),a,l)}}var E=t.MergeView=function(e,n){if(!(this instanceof E))return new E(e,n);this.options=n;var r=n.origLeft,i=null==n.origRight?n.orig:n.origRight,o=null!=r,s=null!=i,a=1+(o?1:0)+(s?1:0),l=[],c=this.left=null,h=this.right=null,f=this;if(o){c=this.left=new u(this,"left");var d=W("div",null,"CodeMirror-merge-pane CodeMirror-merge-left");l.push(d),l.push(N(c))}var p=W("div",null,"CodeMirror-merge-pane CodeMirror-merge-editor");if(l.push(p),s){h=this.right=new u(this,"right"),l.push(N(h));var v=W("div",null,"CodeMirror-merge-pane CodeMirror-merge-right");l.push(v)}(s?v:p).className+=" CodeMirror-merge-pane-rightmost",l.push(W("div",null,null,"height: 0; clear: both;"));var g=this.wrap=e.appendChild(W("div",l,"CodeMirror-merge CodeMirror-merge-"+a+"pane"));this.edit=t(p,V(n)),c&&c.init(d,r,n),h&&h.init(v,i,n),n.collapseIdentical&&this.editor().operation(function(){!function(t,e){"number"!=typeof e&&(e=2);for(var n=[],r=t.editor(),i=r.firstLine(),o=i,s=r.lastLine();o<=s;o++)n.push(!0);t.left&&R(t.left,e,i,n);t.right&&R(t.right,e,i,n);for(var a=0;ae){var u=[{line:l,cm:r}];t.left&&u.push({line:k(l,t.left.chunks),cm:t.left.orig}),t.right&&u.push({line:k(l,t.right.chunks),cm:t.right.orig});var h=H(c,u);t.options.onCollapse&&t.options.onCollapse(t,l,c,h)}}}(f,n.collapseIdentical)}),"align"==n.connect&&(this.aligners=[],S(this.left||this.right,!0)),c&&c.registerEvents(h),h&&h.registerEvents(c);var m=function(){c&&w(c),h&&w(h)};t.on(window,"resize",m);var y=setInterval(function(){for(var e=g.parentNode;e&&e!=document.body;e=e.parentNode);e||(clearInterval(y),t.off(window,"resize",m))},5e3)};function N(e){var n=e.lockButton=W("div",null,"CodeMirror-merge-scrolllock");n.title="Toggle locked scrolling";var r=W("div",[n],"CodeMirror-merge-scrolllock-wrap");t.on(n,"click",function(){v(e,!e.lockScroll)});var i=[r];if(!1!==e.mv.options.revertButtons&&(e.copyButtons=W("div",null,"CodeMirror-merge-copybuttons-"+e.type),t.on(e.copyButtons,"click",function(t){var n=t.target||t.srcElement;n.chunk&&("CodeMirror-merge-copy-reverse"!=n.className?A(e,e.edit,e.orig,n.chunk):A(e,e.orig,e.edit,n.chunk))}),i.unshift(e.copyButtons)),"align"!=e.mv.options.connect){var s=document.createElementNS&&document.createElementNS(o,"svg");s&&!s.createSVGRect&&(s=null),e.svg=s,s&&i.push(s)}return e.gap=W("div",i,"CodeMirror-merge-gap")}function O(t){return"string"==typeof t?t:t.getValue()}E.prototype={constructor:E,editor:function(){return this.edit},rightOriginal:function(){return this.right&&this.right.orig},leftOriginal:function(){return this.left&&this.left.orig},setShowDifferences:function(t){this.right&&this.right.setShowDifferences(t),this.left&&this.left.setShowDifferences(t)},rightChunks:function(){if(this.right)return h(this.right),this.right.chunks},leftChunks:function(){if(this.left)return h(this.left),this.left.chunks}};var D=new diff_match_patch;function B(t,e,n){for(var r=D.diff_main(t,e),i=0;ih&&(a&&e.push({origFrom:r,origTo:f,editFrom:n,editTo:h}),n=p,r=v)}else U(c==DIFF_INSERT?o:s,l[1])}return(n<=o.line||r<=s.line)&&e.push({origFrom:r,origTo:s.line+1,editFrom:n,editTo:o.line+1}),e}function P(t,e){if(e==t.length-1)return!0;var n=t[e+1][1];return!(1==n.length&&e1||e==t.length-3)&&10==n.charCodeAt(0))}function F(t,e){if(0==e)return!0;var n=t[e-1][1];return 10==n.charCodeAt(n.length-1)&&(1==e||10==(n=t[e-2][1]).charCodeAt(n.length-1))}function I(e,n,r){e.addLineClass(n,"wrap","CodeMirror-merge-collapsed-line");var o=document.createElement("span");o.className="CodeMirror-merge-collapsed-widget",o.title="Identical text collapsed. Click to expand.";var s=e.markText(i(n,0),i(r-1),{inclusiveLeft:!0,inclusiveRight:!0,replacedWith:o,clearOnEnter:!0});function a(){s.clear(),e.removeLineClass(n,"wrap","CodeMirror-merge-collapsed-line")}return t.on(o,"click",a),{mark:s,clear:a}}function H(t,e){var n=[];function r(){for(var t=0;t=0&&a0;--e)t.removeChild(t.firstChild)}function q(t){for(var e=1;e0?t:e}function J(t,e){return t.line==e.line&&t.ch==e.ch}function tt(t,e,n){for(var r=t.length-1;r>=0;r--){var i=t[r],o=(n?i.origTo:i.editTo)-1;if(oe)return o}}function nt(e,n){var r=null,i=e.state.diffViews,o=e.getCursor().line;if(i)for(var s=0;sr:c0)break}this.signal(),this.alignable.splice(n,0,t,e)},find:function(t){for(var e=0;e-1){var c=this.alignable[o+1];c==G?this.alignable.splice(o,2):this.alignable[o+1]=c&~G}s>-1&&n&&this.set(t+n,G)}},t.commands.goNextDiff=function(t){return nt(t,1)},t.commands.goPrevDiff=function(t){return nt(t,-1)}});var dv,EXPAND=0,SHRINK=1,repositoryTabHeight=40;function open_answer(t,e,n){$.ajax({url:"/myshixuns/"+e+"/stages/"+t+"/answer",data:{choose:n},dataType:"script"})}function choice_answer(t,e){if("2"==t)$(e).toggleClass("card-check"),$(e).toggleClass("color_white");else if("1"==t){var n=$(".color_white");n.removeClass("card-check"),n.removeClass("color_white"),$(e).addClass("card-check"),$(e).toggleClass("color_white")}}function check_tab(t,e,n){$("."+t).removeClass(e),$(n).addClass(e);var r=$(n).index()+1;$("#"+t+"_"+r).siblings().addClass("undis"),$("#"+t+"_"+r).removeClass("undis")}function toggle_test_case_choose(t,e){var n=$("#test_case_"+e).parent().prev(".-task-ces-top").children("i:first-child");n.hasClass("fa-caret-down")?(n.addClass("fa-caret-right"),n.removeClass("fa-caret-down")):n.hasClass("fa-caret-right")&&(n.addClass("fa-caret-down"),n.removeClass("fa-caret-right")),$("#test_case_"+e).toggle()}function toggle_test_case(t,e,n,r,i){var o=new Base64;e=o.decode(e),n=(n=o.decode(n)).replace(/\\r\\n/g,"\r\n").replace(/\\r/g,"\r").replace(/\\n/g,"\n").replace(/\\t/g,"\t").replace(/<\/\/script>/g,"<\/script>"),e=e.replace(/\\r\\n/g,"\r\n").replace(/\\r/g,"\r").replace(/\\n/g,"\n").replace(/\\t/g,"\t");var s=$("#test_case_"+r).parent().prev(".-task-ces-top").children("i:first-child");if(s.hasClass("fa-caret-down"))s.addClass("fa-caret-right"),s.removeClass("fa-caret-down"),$("#result_different_show_"+r).siblings(".-task-ces-info").attr("style","display:none"),$("#result_different_show_"+r).hide(),$("#test_case_"+r).hide();else if(s.hasClass("fa-caret-right")&&(s.addClass("fa-caret-down"),s.removeClass("fa-caret-right"),$("#result_different_show_"+r).show(),$("#test_case_"+r).show(),$("#result_different_show_"+r).siblings(".-task-ces-info").attr("style","display:block"),1==t||i)){r="result_different_show_"+r;var a=e,l="null"==n?"":n;CodeMirror.k_init(r,l,a);""==l&&($(".CodeMirror-merge-r-chunk").css("background","none"),$(".CodeMirror-merge-r-inserted").css("background-image","none"));var c=0;c=$("#"+r).find(".CodeMirror-merge-pane").eq(0).height()>$("#"+r).find(".CodeMirror-merge-pane").eq(1).height()?parseInt($("#"+r).find(".CodeMirror-merge-pane").eq(0).height()):parseInt($("#"+r).find(".CodeMirror-merge-pane").eq(1).height()),$("#"+r).find(".CodeMirror").height(c),$(".CodeMirror-merge-gap").css("height",c),$(".CodeMirror-merge-gap").find("svg").css("height",c)}}function CodeMirror_fromTextArea(t){return CodeMirror.fromTextArea(document.getElementById(t),{lineNumbers:!0,theme:"railscasts",indentUnit:4,matchBrackets:!0,autoRefresh:!0,smartIndent:!0,extraKeys:{"Ctrl-Q":"autocomplete"},autofocus:!0,styleActiveLine:!0,lint:!0,gutters:["CodeMirror-linenumbers","breakpoints"]})}$(function(){function t(t){var e=document.getElementById("game_webssh");null!=e&&null!=e&&""!=e&&e.contentWindow.postMessage({tp:"resize",rows:t,cols:0},"https://webssh.educoder.net")}window.top.__updateWebsshRows=t;var e,n,r,i,o=$(document),s=$(".b-label"),a=$(".h-center"),l=!1,u=!1,h=0;s.live("mousedown",function(){return $("#game_webssh").css("pointer-events","none"),l=!0,leftOffset=$(".labelN").offset().left,r=$(".labelN").width(),!1}),a.live("mousedown",function(){return $("#game_webssh").css("pointer-events","none"),u=!0,topOffset=$(".centerH").offset().top,i=$(".centerH").height(),!1}),setTimeout(function(){$(".CodeMirror.cm-s-railscasts").css("height",$("#games_repository_contents").height()-repositoryTabHeight)},800),$(window).on("resize",function(){$(".CodeMirror.cm-s-railscasts").css("height",$("#games_repository_contents").height()-repositoryTabHeight)});var f=!(null==window.mozInnerScreenX)?19:18;o.live("mousemove",function(o){if($(".-brother").show(),l&&(clickX=o.pageX,clickX>leftOffset+0&&clickXtopOffset+100){a.css("top",clickY-7-topOffset+"px"),$("#games_repository_contents").height(clickY-topOffset+"px"),$(".CodeMirror.cm-s-railscasts").css("height",clickY-topOffset-repositoryTabHeight- $('#games_repository_contents .codePath').height() - 12),n=clickY-topOffset,$("#games_valuation_contents").height(i-n+"px");var c=$("#games_repository_contents").height()-$("#top_repository").height()-50,d=$("#games_repository_contents").height()-50;$("#games_repository_contents").width();$(".game_webssh").css("min-height",d),$(".game_webssh").css("max-height",d);var p=Math.floor(d/f);$("#file_entry_content").find(".CodeMirror-scroll").css("min-height",c),$("#file_entry_content").find(".CodeMirror-scroll").css("max-height",c)}else a.css("top","0px");h!=p?(t(p),h=p):h=p}}),o.live("mouseup",function(t){$("#game_webssh").css("pointer-events","inherit"),u=!1,l=!1,t.cancelBubble=!0,$(".-brother").hide()}),window.__tpiOnResize=function(){var t=$("#games_repository_contents").height()-50;if($(".game_webssh").css("min-height",t),$(".game_webssh").css("max-height",t),document.getElementById("game_webssh")){var e=!(null==window.mozInnerScreenX)?19:18,n=(t=$("#games_repository_contents").height()-50,Math.floor(t/e));window.top.__updateWebsshRows&&window.top.__updateWebsshRows(n)}},window.onresize=function(){__tpiOnResize()},$("#all_task_show").on("click",function(t){c=0,$("#all_task_tab").removeClass("leftnav-active"),$("#all_task_show").css("background","rgba(0,0,0,0)"),$("#all_task_index").css("left",0).stop().animate({left:"-505px"},400,function(){$("#all_task_show").hide(),fadein=0})}),$("#all_task_index").on("click",function(t){t.stopPropagation()}),$("#next_step").live("click",function(){nNext=$("#next_step_area"),html="下一关",nNext.html(html)}),$("#prev_step").live("click",function(){nNext=$("#prev_step_area"),html="上一关",nNext.html(html)})});var control=0,control_1=0;function repository_extend_and_zoom(){var t=$("#games_repository_contents"),e=$("#games_valuation_contents"),n=$("#extend_and_zoom").children("i"),r=$("#file_entry_content").find(".CodeMirror-scroll"),i=$(".h-center");0==control?(t.addClass("-flex-basic100"),e.addClass("-flex-basic0"),n.addClass("fa-compress"),n.removeClass("fa-expand"),$("#extend_and_zoom").attr("data-tip-left","收起"),i.hide(),control=1):1==control&&(t.removeClass("-flex-basic100"),e.removeClass("-flex-basic0"),n.removeClass("fa-compress"),n.addClass("fa-expand"),$("#extend_and_zoom").attr("data-tip-left","展开"),i.show(),control=0),window.editor_CodeMirror&&editor_CodeMirror.setSize("auto","auto"),$(".CodeMirror.cm-s-railscasts").css("height",$("#games_repository_contents").height()-repositoryTabHeight);var o=t.height()-$("#top_repository").height()-50;r.css("min-height",o)}function valuation_extend_and_zoom(){var t=$("#games_repository_contents"),e=$("#games_valuation_contents"),n=$("#valuation_extend_and_zoom").children("i"),r=$(".h-center");0==control_1?(t.addClass("-flex-basic0"),e.addClass("-flex-basic100"),n.removeClass("fa-expand"),n.addClass("fa-compress"),$("#valuation_extend_and_zoom").attr("data-tip-left","收起"),r.hide(),control_1=1):1==control_1&&(t.removeClass("-flex-basic0"),e.removeClass("-flex-basic100"),n.addClass("fa-expand"),n.removeClass("fa-compress"),$("#valuation_extend_and_zoom").attr("data-tip-left","展开"),r.show(),control_1=0)}var h=!0;function game_praise(t,e){treadStatus||$.ajax({url:"/praise_tread/praise_plus?obj_id="+t+"&obj_type="+e,data:{horizontal:h,game_praise:!0},success:function(t){h=!h;var e=$("#game_praise_count");t.praise?(praiseStatus=!0,e.html(t.praise_tread_count),$("#game_praise_tread").children("i").addClass("color-orange03"),$("#game_praise_tread").attr("data-tip-top","取消点赞")):(praiseStatus=!1,e.html(t.praise_tread_count),$("#game_praise_tread").children("i").removeClass("color-orange03"),$("#game_praise_tread").attr("data-tip-top","点赞"))}})}var editor2,d=!0;function game_tread(t){praiseStatus||$.ajax({url:"/praise_tread/praise_plus?obj_id="+t+"&obj_type=ChallengeTread",data:{horizontal:d,game_praise:!0},success:function(t){d=!d;var e=$("#game_tread_count");t.praise?(treadStatus=!0,e.html(t.praise_tread_count),$("#game_tread").children("i").addClass("color-orange"),$("#game_tread").attr("data-tip-top","取消踩")):(treadStatus=!1,e.html(t.praise_tread_count),$("#game_tread").children("i").removeClass("color-orange"),$("#game_tread").attr("data-tip-top","踩"))}})}function setupAjaxIndicatorBase(){$("#ajax-indicator-base").bind("ajaxSend",function(t,e,n){n&&n.url&&(n.url.match(/account\/heartbeat$/)||n.url.match(/file_update/)||n.url.match(/game_build/)||n.url.match(/game_status/)||n.url.match(/refresh_game_list/)||n.url.match(/next_step/)||n.url.match(/prev_step/)||n.url.match(/open_webssh/)||n.url.match(/repository/)||n.url.match(/get_waiting_time/))||0===$(".ajax-loading").length&&"application/octet-stream"!=n.contentType&&$("#ajax-indicator-base").css("display","flex").html("").show()}),$("#ajax-indicator-base").bind("ajaxStop",function(){$("#ajax-indicator-base").html("").hide(),MathJax&&MathJax.Hub&&MathJax.Hub.Queue(["Typeset",MathJax.Hub]);try{prettyPrint()}catch(t){}})}function match_specific_symbol(t){return t=t.replace(/ /g,'').replace(/\r\n$/,'').replace(/\n$/,'').replace(/\r$/,'').replace(/\r\n/g,"
                                      ").replace(/\n/g,"
                                      ").replace(/\r/g,"
                                      ").replace(/\t/g,'')}function code_evaluation(t,e,n,r,i,o,s,a,l,c,u,h,f,d){var p,v,g,m,y,x,b;if(p='
                                      ','
                                      ',-1!=h.indexOf("Html")&&(p='
                                      '),"0"!=e){var w="";""!=d&&null!=d&&null!=d&&(w=' 本次评测耗时:'+d+"秒"),v=r==n?w+'

                                      '+n+"/"+n+" 全部通过

                                      ":w+'

                                      '+r+"/"+n+""+u+"

                                      "}for(var k="",C=0;C':1==t[C].result?'':"",0==t[C].is_public?m=f&&"false"!=f?''+m:0==t[C].result||1==t[C].result?''+m:'':0!=t[C].result&&1!=t[C].result&&(m=void 0),b=null==t[C].input||""==t[C].input?"":'
                                      测试输入:

                                      '+(null==t[C].input||""==t[C].input?"空":t[C].input.replace(/\r\n/g,"
                                      "))+"

                                      ",1==t[C].is_public||"true"==f||f&&"false"!=f?y='
                                      ':0==t[C].is_public&&(y='
                                      • 此为隐藏测试项,解锁

                                      '),g='
                                      '+y+"
                                      ";var _=new Base64,S=null==t[C].actual_output?"":_.encode(t[C].actual_output),T=null==t[C].output?"":_.encode(t[C].output);k+='
                                      测试集 '+(C+1)+""+(null==m?"":m)+"
                                      "+g}"0"!=e&&(x=r==n?'

                                      '+n+"/"+n+" 全部通过

                                      ":'

                                      '+r+"/"+n+" "+u+"

                                      ");var L=p+('
                                      '+(null==v?"":v)+k+"
                                      ")+('
                                      '+(null==x?"":x)+'
                                      • 公开测试:'+a+"/"+o+'
                                      • 隐藏测试:'+s+"/"+i+'
                                      • 经验值:+ '+l+'
                                      • 金币:'+(c>=0?"+ "+c:c)+"
                                      ");$("#game_test_set_results").html(L)}function elocalStorage(t,e,n){if(window.sessionStorage){if(editor2=t,null!==window.sessionStorage.getItem("content"+e)){var r='您上次有已保存的数据,是否恢复 ? / 不恢复";$("#e_tips_"+n).html(r)}setInterval(function(){var r=(d=new Date).getHours(),i=d.getMinutes(),o=d.getSeconds();if(r=r<10?"0"+r:r,i=i<10?"0"+i:i,o=o<10?"0"+o:o,t.sync(),!t.isEmpty()){add_data("content",e,t.html());var s="#e_tips_"+n;$("#e_tip_"+n).html(" 数据已于 "+r+":"+i+":"+o+" 保存 "),$(s).html("")}},1e4)}else $(".ke-edit").after("您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!")}function add_data(t,e,n){window.sessionStorage.setItem(t+e,n)}function pop_box_new(t,e,n){$("#popupAll").length>0&&$("#popupAll").remove(),w=($(window).width()-e)/2,h=($(window).height()-n)/2;function r(t){this.div=document.getElementById(t),this.div&&(this.div.style.cursor="move",this.div.style.position="fixed"),this.disX=0,this.disY=0;var e=this;this.div.onmousedown=function(t){e.getDistance(t),document.onmousemove=function(t){e.setPosition(t)},e.div.onmouseup=function(){e.clearEvent()}}}$(document.body).append('
                                      '),$("#popupWrap").html(t),$("#popupWrap").css({top:h+"px",left:w+"px",padding:"0",border:"none",position:"fixed","z-index":"99999","background-color":"#fff","border-radius":"10px"}),$("#popupWrap").parent().parent().show(),$("#popupWrap").find("a[class*='pop_close']").click(function(){$("#popupAll").hide()}),r.prototype.getDistance=function(t){var e=t||event;this.disX=e.clientX-this.div.offsetLeft,this.disY=e.clientY-this.div.offsetTop},r.prototype.setPosition=function(t){var e=t||event,n=e.clientX-this.disX,r=e.clientY-this.disY;n<=0?n=0:n>=document.documentElement.clientWidth-this.div.offsetWidth&&(n=document.documentElement.clientWidth-this.div.offsetWidth),r<=0?r=0:r>=document.documentElement.clientHeight-this.div.offsetHeight&&(r=document.documentElement.clientHeight-this.div.offsetHeight),this.div.style.left=n+"px",this.div.style.top=r+"px"},r.prototype.clearEvent=function(){this.div.onmouseup=null,document.onmousemove=null},new r("popupWrap"),$("#popupWrap input, #popupWrap textarea, #popupWrap ul, #popupWrap a").mousedown(function(t){t.stopPropagation(),new r("popupWrap")})}function sure_box_redirect_btn(t,e,n){pop_box_new('

                                      提示

                                      '+e+'

                                      ",480,160)}function sure_box_redirect_btn2(t,e,n){pop_box_new('

                                      提示

                                      '+e+'

                                      ",578,205)}function op_confirm_box_loading(t,e){pop_box_new('

                                      提示

                                      '+e+'

                                      ',578,205)}function delete_confirm_box_2(t,e){pop_box_new('

                                      提示

                                      '+e+'

                                      ',480,160)}function notice_box(t){pop_box_new('

                                      提示

                                      '+t+'

                                      ',480,160)}function hideModal(t){$("#popupAll").length>0?$("#popupAll").remove():(t?$(t).parents(".ui-dialog-content"):$("#ajax-modal")).dialog("close")}function is_cdn_link(t){return-1!=t.indexOf("http")||-1!=t.indexOf("com")||-1!=t.indexOf("net")||-1!=t.indexOf("org")||-1!=t.indexOf("cdn")}function tpi_html_show(){for(var t=editor_CodeMirror.getValue(),e=$("#html_form"),n=t,r=[],i=[],o=/(?:[\n\r\s]*?)(?:<\/link>)*/im,s=/(?:[\n\r\s]*?)(?:<\/script>)*/im,a=o.exec(n),l=s.exec(n);null!=a;)is_cdn_link(a[1])?n=n.replace(a[0],a[0].replace(/link/,"edulink")):(n=n.replace(o,"EDUCODERCSS"),r.push(a[1])),a=o.exec(n);for(;null!=l;)is_cdn_link(l[1])?n=n.replace(l[0],l[0].replace(/script/g,"w3scrw3ipttag")):(n=n.replace(s,"EDUCODERJS"),i.push(l[1])),l=s.exec(n);n=n.replace(/=/gi,"w3equalsign").replace(/script/gi,"w3scrw3ipttag"),$("#data_param").val(n),$("#data_css_param").val(r),$("#data_js_param").val(i),e.attr("action","/iframes/html_content?gpid="+__myshixun.gpid),e.submit()}$(document).ready(setupAjaxIndicatorBase); + +/*CodeMirror addon hint -----------------------------------------------Start*/ +/* showHint */ +!function(t){"object"==typeof exports&&"object"==typeof module?t(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],t):t(CodeMirror)}(function(t){"use strict";var i="CodeMirror-hint",e="CodeMirror-hint-active";function n(t,i){this.cm=t,this.options=i,this.widget=null,this.debounce=0,this.tick=0,this.startPos=this.cm.getCursor("start"),this.startLen=this.cm.getLine(this.startPos.line).length-this.cm.getSelection().length;var e=this;t.on("cursorActivity",this.activityFunc=function(){e.cursorActivity()})}t.showHint=function(t,i,e){if(!i)return t.showHint(e);e&&e.async&&(i.async=!0);var n={hint:i};if(e)for(var o in e)n[o]=e[o];return t.showHint(n)},t.defineExtension("showHint",function(i){i=function(t,i,e){var n=t.options.hintOptions,o={};for(var s in a)o[s]=a[s];if(n)for(var s in n)void 0!==n[s]&&(o[s]=n[s]);if(e)for(var s in e)void 0!==e[s]&&(o[s]=e[s]);o.hint.resolve&&(o.hint=o.hint.resolve(t,i));return o}(this,this.getCursor("start"),i);var e=this.listSelections();if(!(e.length>1)){if(this.somethingSelected()){if(!i.hint.supportsSelection)return;for(var o=0;ol.clientHeight+1,x=h.getScrollInfo();if(C>0){var A=k.bottom-k.top;if(m.top-(m.bottom-k.top)-A>0)l.style.top=(v=m.top-A)+"px",y=!1;else if(A>H){l.style.height=H-5+"px",l.style.top=(v=m.bottom-k.top)+"px";var S=h.getCursor();o.from.ch!=S.ch&&(m=h.cursorCoords(S),l.style.left=(g=m.left)+"px",k=l.getBoundingClientRect())}}var T,M=k.right-w;if(M>0&&(k.right-k.left>w&&(l.style.width=w-5+"px",M-=k.right-k.left-w),l.style.left=(g=m.left-M)+"px"),b)for(var E=l.firstChild;E;E=E.nextSibling)E.style.paddingRight=h.display.nativeBarWidth+"px";(h.addKeyMap(this.keyMap=function(t,i){var e={Up:function(){i.moveFocus(-1)},Down:function(){i.moveFocus(1)},PageUp:function(){i.moveFocus(1-i.menuSize(),!0)},PageDown:function(){i.moveFocus(i.menuSize()-1,!0)},Home:function(){i.setFocus(0)},End:function(){i.setFocus(i.length-1)},Enter:i.pick,Tab:i.pick,Esc:i.close},n=t.options.customKeys,o=n?{}:e;function s(t,n){var s;s="string"!=typeof n?function(t){return n(t,i)}:e.hasOwnProperty(n)?e[n]:n,o[t]=s}if(n)for(var c in n)n.hasOwnProperty(c)&&s(c,n[c]);var r=t.options.extraKeys;if(r)for(var c in r)r.hasOwnProperty(c)&&s(c,r[c]);return o}(n,{moveFocus:function(t,i){s.changeActive(s.selectedHint+t,i)},setFocus:function(t){s.changeActive(t)},menuSize:function(){return s.screenAmount()},length:a.length,close:function(){n.close()},pick:function(){s.pick()},data:o})),n.options.closeOnUnfocus)&&(h.on("blur",this.onBlur=function(){T=setTimeout(function(){n.close()},100)}),h.on("focus",this.onFocus=function(){clearTimeout(T)}));return h.on("scroll",this.onScroll=function(){var t=h.getScrollInfo(),i=h.getWrapperElement().getBoundingClientRect(),e=v+x.top-t.top,o=e-(window.pageYOffset||(document.documentElement||document.body).scrollTop);if(y||(o+=l.offsetHeight),o<=i.top||o>=i.bottom)return n.close();l.style.top=e+"px",l.style.left=g+x.left-t.left+"px"}),t.on(l,"dblclick",function(t){var i=r(l,t.target||t.srcElement);i&&null!=i.hintId&&(s.changeActive(i.hintId),s.pick())}),t.on(l,"click",function(t){var i=r(l,t.target||t.srcElement);i&&null!=i.hintId&&(s.changeActive(i.hintId),n.options.completeOnSingleClick&&s.pick())}),t.on(l,"mousedown",function(){setTimeout(function(){h.focus()},20)}),t.signal(o,"select",a[0],l.firstChild),!0}function l(t,i,e,n){if(t.async)t(i,n,e);else{var o=t(i,e);o&&o.then?o.then(n):n(o)}}n.prototype={close:function(){this.active()&&(this.cm.state.completionActive=null,this.tick=null,this.cm.off("cursorActivity",this.activityFunc),this.widget&&this.data&&t.signal(this.data,"close"),this.widget&&this.widget.close(),t.signal(this.cm,"endCompletion",this.cm))},active:function(){return this.cm.state.completionActive==this},pick:function(i,e){var n=i.list[e];n.hint?n.hint(this.cm,i,n):this.cm.replaceRange(c(n),n.from||i.from,n.to||i.to,"complete"),t.signal(i,"pick",n),this.close()},cursorActivity:function(){this.debounce&&(s(this.debounce),this.debounce=0);var t=this.cm.getCursor(),i=this.cm.getLine(t.line);if(t.line!=this.startPos.line||i.length-t.ch!=this.startLen-this.startPos.ch||t.ch0&&n.to.ch-n.from.ch!=o.to.ch-o.from.ch)))&&(this.data=i,i&&i.list.length))if(s&&1==i.list.length)this.pick(i,0);else{if(1==i.list.length&&i.to.ch-i.from.ch===i.list[0].length)return;this.widget=new h(this,i),t.signal(i,"shown")}}},h.prototype={close:function(){if(this.completion.widget==this){this.completion.widget=null,this.hints.parentNode.removeChild(this.hints),this.completion.cm.removeKeyMap(this.keyMap);var t=this.completion.cm;this.completion.options.closeOnUnfocus&&(t.off("blur",this.onBlur),t.off("focus",this.onFocus)),t.off("scroll",this.onScroll)}},disable:function(){this.completion.cm.removeKeyMap(this.keyMap);var t=this;this.keyMap={Enter:function(){t.picked=!0}},this.completion.cm.addKeyMap(this.keyMap)},pick:function(){this.completion.pick(this.data,this.selectedHint)},changeActive:function(i,n){if(i>=this.data.list.length?i=n?this.data.list.length-1:0:i<0&&(i=n?0:this.data.list.length-1),this.selectedHint!=i){var o=this.hints.childNodes[this.selectedHint];o.className=o.className.replace(" "+e,""),(o=this.hints.childNodes[this.selectedHint=i]).className+=" "+e,o.offsetTopthis.hints.scrollTop+this.hints.clientHeight&&(this.hints.scrollTop=o.offsetTop+o.offsetHeight-this.hints.clientHeight+3),t.signal(this.data,"select",this.data.list[this.selectedHint],o)}},screenAmount:function(){return Math.floor(this.hints.clientHeight/this.hints.firstChild.offsetHeight)||1}},t.registerHelper("hint","auto",{resolve:function(i,e){var n,o=i.getHelpers(e,"hint");if(o.length){var s=function(t,i,e){var n=function(t,i){if(!t.somethingSelected())return i;for(var e=[],n=0;n0?i(t):o(s+1)})}(0)};return s.async=!0,s.supportsSelection=!0,s}if(n=i.getHelper(i.getCursor(),"hintWords")){t.signal(i,"hinting",n);var c=i.state.myhints,r=n.slice(0);return c&&c.forEach(function(t){-1===n.indexOf(t)&&r.push(t)}),function(i){return t.hint.fromList(i,{words:r})}}return t.hint.anyword?function(i,e){return t.hint.anyword(i,e)}:function(){}}}),t.registerHelper("hint","fromList",function(i,e){var n=i.getCursor(),o=i.getTokenAt(n),s=t.Pos(n.line,o.end);if(o.string&&/\w/.test(o.string[o.string.length-1]))var c=o.string,r=t.Pos(n.line,o.start);else c="",r=s;var h=[];if(fuzzysort&&fuzzysort.go){var l=fuzzysort.go(c,e.words);l&&l.forEach(function(t){h.push(t.target)})}else for(var a=0;a,]/,closeOnUnfocus:!0,completeOnSingleClick:!0,container:null,customKeys:null,extraKeys:null};t.defineOption("hintOptions",null)}); + +/* anyword-hint */ +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";var r=/[A-z]+/;e.registerHelper("hint","anyword",function(t,o){for(var i=o&&o.word||r,n=o&&o.range||500,f=t.getCursor(),s=t.getLine(f.line),a=f.ch,c=a;c&&i.test(s.charAt(c-1));)--c;for(var l=c!=a&&s.slice(c,a),d=o&&o.list||[],u={},p=new RegExp(i.source,"g"),g=-1;g<=1;g+=2)for(var h=f.line,m=Math.min(Math.max(h+g*n,t.firstLine()),t.lastLine())+g;h!=m;h+=g)for(var y,b=t.getLine(h);y=p.exec(b);)h==f.line&&y[0]===l||l&&0!=y[0].lastIndexOf(l,0)||Object.prototype.hasOwnProperty.call(u,y[0])||(u[y[0]]=!0,d.push(y[0]));return{list:d,from:e.Pos(f.line,c),to:e.Pos(f.line,a)}})}); + +/* fuzzysort */ +!function(e,r){"function"==typeof define&&define.amd?define([],r):"object"==typeof module&&module.exports?module.exports=r():e.fuzzysort=r()}(this,function(){var e="undefined"!=typeof require&&"undefined"==typeof window,r=new Map,n=new Map,o=[];o.total=0;var t=[],i=[];function a(){r.clear(),n.clear(),t=[],i=[]}function l(e){for(var r=-9007199254740991,n=e.length-1;n>=0;--n){var o=e[n];if(null!==o){var t=o.score;t>r&&(r=t)}}return-9007199254740991===r?null:r}function f(e,r){var n=e[r];if(void 0!==n)return n;var o=r;Array.isArray(r)||(o=r.split("."));for(var t=o.length,i=-1;e&&++i>1]=e[n],t=1+(n<<1)}for(var a=n-1>>1;n>0&&o.score>1)e[n]=e[a];e[n]=o}return n.add=function(n){var o=r;e[r++]=n;for(var t=o-1>>1;o>0&&n.score>1)e[o]=e[t];e[o]=n},n.poll=function(){if(0!==r){var n=e[0];return e[0]=e[--r],o(),n}},n.peek=function(n){if(0!==r)return e[0]},n.replaceTop=function(r){e[0]=r,o()},n},p=s();return function d(c){var g={single:function(e,r,n){return e?(u(e)||(e=g.getPreparedSearch(e)),r?(u(r)||(r=g.getPrepared(r)),((n&&void 0!==n.allowTypo?n.allowTypo:!c||void 0===c.allowTypo||c.allowTypo)?g.algorithm:g.algorithmNoTypo)(e,r,e[0])):null):null},go:function(e,r,n){if(!e)return o;var t=(e=g.prepareSearch(e))[0],i=n&&n.threshold||c&&c.threshold||-9007199254740991,a=n&&n.limit||c&&c.limit||9007199254740991,s=(n&&void 0!==n.allowTypo?n.allowTypo:!c||void 0===c.allowTypo||c.allowTypo)?g.algorithm:g.algorithmNoTypo,d=0,v=0,h=r.length;if(n&&n.keys)for(var w=n.scoreFn||l,x=n.keys,y=x.length,m=h-1;m>=0;--m){for(var T=r[m],k=new Array(y),b=y-1;b>=0;--b)(_=f(T,B=x[b]))?(u(_)||(_=g.getPrepared(_)),k[b]=s(e,_,t)):k[b]=null;k.obj=T;var I=w(k);null!==I&&(Ip.peek().score&&p.replaceTop(k))))}else if(n&&n.key){var B=n.key;for(m=h-1;m>=0;--m)(_=f(T=r[m],B))&&(u(_)||(_=g.getPrepared(_)),null!==(C=s(e,_,t))&&(C.scorep.peek().score&&p.replaceTop(C)))))}else for(m=h-1;m>=0;--m){var _,C;(_=r[m])&&(u(_)||(_=g.getPrepared(_)),null!==(C=s(e,_,t))&&(C.scorep.peek().score&&p.replaceTop(C)))))}if(0===d)return o;var A=new Array(d);for(m=d-1;m>=0;--m)A[m]=p.poll();return A.total=d+v,A},goAsync:function(r,n,t){var i=!1,a=new Promise(function(a,p){if(!r)return a(o);var d=(r=g.prepareSearch(r))[0],v=s(),h=n.length-1,w=t&&t.threshold||c&&c.threshold||-9007199254740991,x=t&&t.limit||c&&c.limit||9007199254740991,y=(t&&void 0!==t.allowTypo?t.allowTypo:!c||void 0===c.allowTypo||c.allowTypo)?g.algorithm:g.algorithmNoTypo,m=0,T=0;function k(){if(i)return p("canceled");var s=Date.now();if(t&&t.keys)for(var c=t.scoreFn||l,b=t.keys,I=b.length;h>=0;--h){for(var B=n[h],_=new Array(I),C=I-1;C>=0;--C)(P=f(B,L=b[C]))?(u(P)||(P=g.getPrepared(P)),_[C]=y(r,P,d)):_[C]=null;_.obj=B;var A=c(_);if(null!==A&&!(Av.peek().score&&v.replaceTop(_)),h%1e3==0&&Date.now()-s>=10))return void(e?setImmediate(k):setTimeout(k))}else if(t&&t.key){for(var L=t.key;h>=0;--h)if((P=f(B=n[h],L))&&(u(P)||(P=g.getPrepared(P)),null!==(j=y(r,P,d))&&!(j.scorev.peek().score&&v.replaceTop(j)),h%1e3==0&&Date.now()-s>=10)))return void(e?setImmediate(k):setTimeout(k))}else for(;h>=0;--h){var P,j;if((P=n[h])&&(u(P)||(P=g.getPrepared(P)),null!==(j=y(r,P,d))&&!(j.scorev.peek().score&&v.replaceTop(j)),h%1e3==0&&Date.now()-s>=10)))return void(e?setImmediate(k):setTimeout(k))}if(0===m)return a(o);for(var N=new Array(m),S=m-1;S>=0;--S)N[S]=v.poll();N.total=m+T,a(N)}e?setImmediate(k):k()});return a.cancel=function(){i=!0},a},highlight:function(e,r,n){if(null===e)return null;void 0===r&&(r=""),void 0===n&&(n="");for(var o="",t=0,i=!1,a=e.target,l=a.length,f=e.indexes,u=0;u999)return g.prepare(e);var n=r.get(e);return void 0!==n?n:(n=g.prepare(e),r.set(e,n),n)},getPreparedSearch:function(e){if(e.length>999)return g.prepareSearch(e);var r=n.get(e);return void 0!==r?r:(r=g.prepareSearch(e),n.set(e,r),r)},algorithm:function(e,r,n){for(var o=r._targetLowerCodes,a=e.length,l=o.length,f=0,u=0,s=0,p=0;;){if(n===o[u]){if(t[p++]=u,++f===a)break;n=e[0===s?f:s===f?f+1:s===f-1?f-1:f]}if(++u>=l)for(;;){if(f<=1)return null;if(0===s){if(n===e[--f])continue;s=f}else{if(1===s)return null;if((n=e[1+(f=--s)])===e[f])continue}u=t[(p=f)-1]+1;break}}f=0;var d=0,c=!1,v=0,h=r._nextBeginningIndexes;null===h&&(h=r._nextBeginningIndexes=g.prepareNextBeginningIndexes(r.target));var w=u=0===t[0]?0:h[t[0]-1];if(u!==l)for(;;)if(u>=l){if(f<=0){if(++d>a-2)break;if(e[d]===e[d+1])continue;u=w;continue}--f,u=h[i[--v]]}else if(e[0===d?f:d===f?f+1:d===f-1?f-1:f]===o[u]){if(i[v++]=u,++f===a){c=!0;break}++u}else u=h[u];if(c)var x=i,y=v;else x=t,y=p;for(var m=0,T=-1,k=0;k=0;--k)r.indexes[k]=x[k];return r},algorithmNoTypo:function(e,r,n){for(var o=r._targetLowerCodes,a=e.length,l=o.length,f=0,u=0,s=0;;){if(n===o[u]){if(t[s++]=u,++f===a)break;n=e[f]}if(++u>=l)return null}f=0;var p=!1,d=0,c=r._nextBeginningIndexes;if(null===c&&(c=r._nextBeginningIndexes=g.prepareNextBeginningIndexes(r.target)),(u=0===t[0]?0:c[t[0]-1])!==l)for(;;)if(u>=l){if(f<=0)break;--f,u=c[i[--d]]}else if(e[f]===o[u]){if(i[d++]=u,++f===a){p=!0;break}++u}else u=c[u];if(p)var v=i,h=d;else v=t,h=s;for(var w=0,x=-1,y=0;y=0;--y)r.indexes[y]=v[y];return r},prepareLowerCodes:function(e){for(var r=e.length,n=[],o=e.toLowerCase(),t=0;t=65&&l<=90,u=f||l>=97&&l<=122||l>=48&&l<=57,s=f&&!t||!i||!u;t=f,i=u,s&&(n[o++]=a)}return n},prepareNextBeginningIndexes:function(e){for(var r=e.length,n=g.prepareBeginningIndexes(e),o=[],t=n[0],i=0,a=0;aa?o[a]=t:(t=n[++i],o[a]=void 0===t?r:t);return o},cleanup:a,new:d};return g}()}); +/*CodeMirror addon hint -----------------------------------------------End*/ + +//提示框:只有一个知道啦按钮,点击打开新窗口 +// +function sure_box_redirect(url, str){ + var htmlvalue = '

                                      提示

                                      '+ + '

                                      ' + str + '

                                      '+ + '知道啦
                                      '; + pop_box_new(htmlvalue, 480, 160); +} +// 长提示框:只有一个“知道啦”按钮,点击关闭弹框 +// +function yes_notice_box(str){ + var htmlvalue = '

                                      提示

                                      '+ + '

                                      ' + str + '

                                      '+ + '知道啦
                                      '; + pop_box_new(htmlvalue, 575, 200); +} + +// --------------------- --------------------- --------------------- --------------------- START +function notice_sure_box(str){ + var htmlvalue = '

                                      提示

                                      '+ + '

                                      ' + str + '

                                      '+ + '知道啦
                                      '; + pop_box_new(htmlvalue, 480, 160); +} +//点击删除时的确认弹框: 走destroy方法,remote为true +function delete_confirm_box_2_react(url, str, data){ + var htmlvalue = '
                                      提示
                                      '+ + '

                                      ' + str + '

                                      '; + pop_box_new(htmlvalue, 480, 160); + // encodeURIComponent(JSON.stringify(data)) + // "$(window.top).trigger(\'' + url +'\', \'' + url + '\')" +} +// https://github.com/facebook/react/issues/3249#issuecomment-177750141 +function _triggerEvent(eventName, data, target) { + var event = document.createEvent("HTMLEvents"); + event.initEvent(eventName, true, true); + var target = target || document; + // $('body>#root').data(eventName, data) + window[eventName] = data; + target.dispatchEvent(event); +} +// --------------------- --------------------- --------------------- --------------------- END + +// CodeMirror python +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e){return new RegExp("^(("+e.join(")|(")+"))\\b")}var n=t(["and","or","not","is"]),r=["as","assert","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","lambda","pass","raise","return","try","while","with","yield","in"],i=["abs","all","any","bin","bool","bytearray","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip","__import__","NotImplemented","Ellipsis","__debug__"];function o(e){return e.scopes[e.scopes.length-1]}e.registerHelper("hintWords","python",r.concat(i)),e.defineMode("python",function(a,s){for(var c="error",l=s.delimiters||s.singleDelimiters||/^[\(\)\[\]\{\}@,:`=;\.\\]/,u=[s.singleOperators,s.doubleOperators,s.doubleDelimiters,s.tripleDelimiters,s.operators||/^([-+*/%\/&|^]=?|[<>=]+|\/\/=?|\*\*=?|!=|[~!@])/],f=0;fr?_(t):i0&&z(e,t)&&(a+=" "+c),a}return v(e,t)}function v(e,t){if(e.eatSpace())return null;if(e.match(/^#.*/))return"comment";if(e.match(/^[0-9\.]/,!1)){var r=!1;if(e.match(/^[\d_]*\.\d+(e[\+\-]?\d+)?/i)&&(r=!0),e.match(/^[\d_]+\.\d*/)&&(r=!0),e.match(/^\.\d+/)&&(r=!0),r)return e.eat(/J/i),"number";var i=!1;if(e.match(/^0x[0-9a-f_]+/i)&&(i=!0),e.match(/^0b[01_]+/i)&&(i=!0),e.match(/^0o[0-7_]+/i)&&(i=!0),e.match(/^[1-9][\d_]*(e[\+\-]?[\d_]+)?/)&&(e.eat(/J/i),i=!0),e.match(/^0(?![\dx])/i)&&(i=!0),i)return e.eat(/L/i),"number"}if(e.match(y))return-1!==e.current().toLowerCase().indexOf("f")?(t.tokenize=function(e,t){for(;"rubf".indexOf(e.charAt(0).toLowerCase())>=0;)e=e.substr(1);var n=1==e.length,r="string";function i(t,n){return t.match(e)?(n.tokenize=o,r):t.match("{")?"punctuation":t.match("}")?(n.tokenize=o,"punctuation"):v(t,n)}function o(o,a){for(;!o.eol();)if(o.eatWhile(/[^'"\{\}\\]/),o.eat("\\")){if(o.next(),n&&o.eol())return r}else{if(o.match(e))return a.tokenize=t,r;if(o.match("{{"))return r;if(o.match("{",!1))return a.tokenize=i,o.current()?r:(o.next(),"punctuation");if(o.match("}}"))return r;if(o.match("}"))return c;o.eat(/['"]/)}if(n){if(s.singleLineStringErrors)return c;a.tokenize=t}return r}return o.isString=!0,o}(e.current(),t.tokenize),t.tokenize(e,t)):(t.tokenize=function(e){for(;"rubf".indexOf(e.charAt(0).toLowerCase())>=0;)e=e.substr(1);var t=1==e.length,n="string";function r(r,i){for(;!r.eol();)if(r.eatWhile(/[^'"\\]/),r.eat("\\")){if(r.next(),t&&r.eol())return n}else{if(r.match(e))return i.tokenize=x,n;r.eat(/['"]/)}if(t){if(s.singleLineStringErrors)return c;i.tokenize=x}return n}return r.isString=!0,r}(e.current()),t.tokenize(e,t));for(var o=0;o1&&o(t).offset>n;){if("py"!=o(t).type)return!0;t.scopes.pop()}return o(t).offset!=n}function w(e,t){e.sol()&&(t.beginningOfLine=!0);var n=t.tokenize(e,t),r=e.current();if(t.beginningOfLine&&"@"==r)return e.match(b,!1)?"meta":h?"operator":c;if(/\S/.test(r)&&(t.beginningOfLine=!1),"variable"!=n&&"builtin"!=n||"meta"!=t.lastToken||(n="meta"),"pass"!=r&&"return"!=r||(t.dedent+=1),"lambda"==r&&(t.lambda=!0),":"!=r||t.lambda||"py"!=o(t).type||_(t),1==r.length&&!/string|comment/.test(n)){var i="[({".indexOf(r);if(-1!=i&&function(e,t,n){var r=e.match(/^([\s\[\{\(]|#.*)*$/,!1)?null:e.column()+1;t.scopes.push({offset:t.indent+p,type:n,align:r})}(e,t,"])}".slice(i,i+1)),-1!=(i="])}".indexOf(r))){if(o(t).type!=r)return c;t.indent=t.scopes.pop().offset-p}}return t.dedent>0&&e.eol()&&"py"==o(t).type&&(t.scopes.length>1&&t.scopes.pop(),t.dedent-=1),n}return{startState:function(e){return{tokenize:x,scopes:[{offset:e||0,type:"py",align:null}],indent:e||0,lastToken:null,lambda:!1,dedent:0}},token:function(e,t){var n=t.errorToken;n&&(t.errorToken=!1);var r=w(e,t);return r&&"comment"!=r&&(t.lastToken="keyword"==r||"punctuation"==r?e.current():r),"punctuation"==r&&(r=null),e.eol()&&t.lambda&&(t.lambda=!1),n?r+" "+c:r},indent:function(t,n){if(t.tokenize!=x)return t.tokenize.isString?e.Pass:0;var r=o(t),i=r.type==n.charAt(0);return null!=r.align?r.align-(i?1:0):r.offset-(i?p:0)},electricInput:/^\s*[\}\]\)]$/,closeBrackets:{triples:"'\""},lineComment:"#",fold:"indent"}}),e.defineMIME("text/x-python","python");var a;e.defineMIME("text/x-cython",{name:"python",extra_keywords:(a="by cdef cimport cpdef ctypedef enum except extern gil include nogil property public readonly struct union DEF IF ELIF ELSE",a.split(" "))})}); +// CodeMirror c-like(java) +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e,t,n,r,o,a){this.indented=e,this.column=t,this.type=n,this.info=r,this.align=o,this.prev=a}function n(e,n,r,o){var a=e.indented;return e.context&&"statement"==e.context.type&&"statement"!=r&&(a=e.context.indented),e.context=new t(a,n,r,o,null,e.context)}function r(e){var t=e.context.type;return")"!=t&&"]"!=t&&"}"!=t||(e.indented=e.context.indented),e.context=e.context.prev}function o(e,t,n){return"variable"==t.prevToken||"type"==t.prevToken||(!!/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(e.string.slice(0,n))||(!(!t.typeAtEndOfLine||e.column()!=e.indentation())||void 0))}function a(e){for(;;){if(!e||"top"==e.type)return!0;if("}"==e.type&&"namespace"!=e.prev.info)return!1;e=e.prev}}function i(e){for(var t={},n=e.split(" "),r=0;r!?|\/]/,L=s.isIdentifierChar||/[\w\$_\xa1-\uffff]/;function D(e,t){var n,r=e.next();if(k[r]){var o=k[r](e,t);if(!1!==o)return o}if('"'==r||"'"==r)return t.tokenize=(n=r,function(e,t){for(var r,o=!1,a=!1;null!=(r=e.next());){if(r==n&&!o){a=!0;break}o=!o&&"\\"==r}return(a||!o&&!w)&&(t.tokenize=null),"string"}),t.tokenize(e,t);if(C.test(r))return c=r,null;if(T.test(r)){if(e.backUp(1),e.match(M))return"number";e.next()}if("/"==r){if(e.eat("*"))return t.tokenize=z,z(e,t);if(e.eat("/"))return e.skipToEnd(),"comment"}if(P.test(r)){for(;!e.match(/^\/[\/*]/,!1)&&e.eat(P););return"operator"}if(e.eatWhile(L),S)for(;e.match(S);)e.eatWhile(L);var a=e.current();return l(m,a)?(l(g,a)&&(c="newstatement"),l(x,a)&&(u=!0),"keyword"):l(h,a)?"type":l(y,a)?(l(g,a)&&(c="newstatement"),"builtin"):l(b,a)?"atom":"variable"}function z(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=null;break}r="*"==n}return"comment"}function I(e,t){s.typeFirstDefinitions&&e.eol()&&a(t.context)&&(t.typeAtEndOfLine=o(e,t,e.pos))}return{startState:function(e){return{tokenize:null,context:new t((e||0)-d,0,"top",null,!1),indented:0,startOfLine:!0,prevToken:null}},token:function(e,t){var i=t.context;if(e.sol()&&(null==i.align&&(i.align=!1),t.indented=e.indentation(),t.startOfLine=!0),e.eatSpace())return I(e,t),null;c=u=null;var l=(t.tokenize||D)(e,t);if("comment"==l||"meta"==l)return l;if(null==i.align&&(i.align=!0),";"==c||":"==c||","==c&&e.match(/^\s*(?:\/\/.*)?$/,!1))for(;"statement"==t.context.type;)r(t);else if("{"==c)n(t,e.column(),"}");else if("["==c)n(t,e.column(),"]");else if("("==c)n(t,e.column(),")");else if("}"==c){for(;"statement"==i.type;)i=r(t);for("}"==i.type&&(i=r(t));"statement"==i.type;)i=r(t)}else c==i.type?r(t):v&&(("}"==i.type||"top"==i.type)&&";"!=c||"statement"==i.type&&"newstatement"==c)&&n(t,e.column(),"statement",e.current());if("variable"==l&&("def"==t.prevToken||s.typeFirstDefinitions&&o(e,t,e.start)&&a(t.context)&&e.match(/^\s*\(/,!1))&&(l="def"),k.token){var d=k.token(e,t,l);void 0!==d&&(l=d)}return"def"==l&&!1===s.styleDefs&&(l="variable"),t.startOfLine=!1,t.prevToken=u?"def":l||c,I(e,t),l},indent:function(t,n){if(t.tokenize!=D&&null!=t.tokenize||t.typeAtEndOfLine)return e.Pass;var r=t.context,o=n&&n.charAt(0);if("statement"==r.type&&"}"==o&&(r=r.prev),s.dontIndentStatements)for(;"statement"==r.type&&s.dontIndentStatements.test(r.info);)r=r.prev;if(k.indent){var a=k.indent(t,r,n);if("number"==typeof a)return a}var i=o==r.type,l=r.prev&&"switch"==r.prev.info;if(s.allmanIndentation&&/[{(]/.test(o)){for(;"top"!=r.type&&"}"!=r.type;)r=r.prev;return r.indented}return"statement"==r.type?r.indented+("{"==o?0:f):!r.align||p&&")"==r.type?")"!=r.type||i?r.indented+(i?0:d)+(i||!l||/^(?:case|default)\b/.test(n)?0:d):r.indented+f:r.column+(i?0:1)},electricInput:_?/^\s*(?:case .*?:|default:|\{\}?|\})$/:/^\s*[{}]$/,blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:"//",fold:"brace"}});var s="auto if break case register continue return default do sizeof static else struct switch extern typedef union for goto while enum const volatile",c="int long char short double float unsigned signed void size_t ptrdiff_t";function u(e,t){if(!t.startOfLine)return!1;for(var n,r=null;n=e.peek();){if("\\"==n&&e.match(/^.$/)){r=u;break}if("/"==n&&e.match(/^\/[\/\*]/,!1))break;e.next()}return t.tokenize=r,"meta"}function d(e,t){return"type"==t.prevToken&&"type"}function f(e){return e.eatWhile(/[\w\.']/),"number"}function p(e,t){if(e.backUp(1),e.match(/(R|u8R|uR|UR|LR)/)){var n=e.match(/"([^\s\\()]{0,16})\(/);return!!n&&(t.cpp11RawStringDelim=n[1],t.tokenize=h,h(e,t))}return e.match(/(u8|u|U|L)/)?!!e.match(/["']/,!1)&&"string":(e.next(),!1)}function m(e,t){for(var n;null!=(n=e.next());)if('"'==n&&!e.eat('"')){t.tokenize=null;break}return"string"}function h(e,t){var n=t.cpp11RawStringDelim.replace(/[^\w\s]/g,"\\$&");return e.match(new RegExp(".*?\\)"+n+'"'))?t.tokenize=null:e.skipToEnd(),"string"}function y(t,n){"string"==typeof t&&(t=[t]);var r=[];function o(e){if(e)for(var t in e)e.hasOwnProperty(t)&&r.push(t)}o(n.keywords),o(n.types),o(n.builtin),o(n.atoms),r.length&&(n.helperType=t[0],e.registerHelper("hintWords",t[0],r));for(var a=0;a!?|\/#:@]/,hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){return!!e.match('""')&&(t.tokenize=g,t.tokenize(e,t))},"'":function(e){return e.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},"=":function(e,n){var r=n.context;return!("}"!=r.type||!r.align||!e.eat(">"))&&(n.context=new t(r.indented,r.column,r.type,r.info,null,r.prev),"operator")},"/":function(e,t){return!!e.eat("*")&&(t.tokenize=function e(t){return function(n,r){for(var o;o=n.next();){if("*"==o&&n.eat("/")){if(1==t){r.tokenize=null;break}return r.tokenize=e(t-1),r.tokenize(n,r)}if("/"==o&&n.eat("*"))return r.tokenize=e(t+1),r.tokenize(n,r)}return"comment"}}(1),t.tokenize(e,t))}},modeProps:{closeBrackets:{triples:'"'}}}),y("text/x-kotlin",{name:"clike",keywords:i("package as typealias class interface this super val operator var fun for is in This throw return annotation break continue object if else while do try when !in !is as? file import where by get set abstract enum open inner override private public internal protected catch finally out final vararg reified dynamic companion constructor init sealed field property receiver param sparam lateinit data inline noinline tailrec external annotation crossinline const operator infix suspend actual expect setparam"),types:i("Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable Compiler Double Exception Float Integer Long Math Number Object Package Pair Process Runtime Runnable SecurityManager Short StackTraceElement StrictMath String StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy LazyThreadSafetyMode LongArray Nothing ShortArray Unit"),intendSwitch:!1,indentStatements:!1,multiLineStrings:!0,number:/^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,blockKeywords:i("catch class do else finally for if where try while enum"),defKeywords:i("class val var object interface fun"),atoms:i("true false null this"),hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){var n;return t.tokenize=(n=e.match('""'),function(e,t){for(var r,o=!1,a=!1;!e.eol();){if(!n&&!o&&e.match('"')){a=!0;break}if(n&&e.match('"""')){a=!0;break}r=e.next(),!o&&"$"==r&&e.match("{")&&e.skipTo("}"),o=!o&&"\\"==r&&!n}return!a&&n||(t.tokenize=null),"string"}),t.tokenize(e,t)}},modeProps:{closeBrackets:{triples:'"'}}}),y(["x-shader/x-vertex","x-shader/x-fragment"],{name:"clike",keywords:i("sampler1D sampler2D sampler3D samplerCube sampler1DShadow sampler2DShadow const attribute uniform varying break continue discard return for while do if else struct in out inout"),types:i("float int bool void vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 mat2 mat3 mat4"),blockKeywords:i("for while do if else struct"),builtin:i("radians degrees sin cos tan asin acos atan pow exp log exp2 sqrt inversesqrt abs sign floor ceil fract mod min max clamp mix step smoothstep length distance dot cross normalize ftransform faceforward reflect refract matrixCompMult lessThan lessThanEqual greaterThan greaterThanEqual equal notEqual any all not texture1D texture1DProj texture1DLod texture1DProjLod texture2D texture2DProj texture2DLod texture2DProjLod texture3D texture3DProj texture3DLod texture3DProjLod textureCube textureCubeLod shadow1D shadow2D shadow1DProj shadow2DProj shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod dFdx dFdy fwidth noise1 noise2 noise3 noise4"),atoms:i("true false gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_FogCoord gl_PointCoord gl_Position gl_PointSize gl_ClipVertex gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_TexCoord gl_FogFragCoord gl_FragCoord gl_FrontFacing gl_FragData gl_FragDepth gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose gl_ProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixInverseTranspose gl_TextureMatrixInverseTranspose gl_NormalScale gl_DepthRange gl_ClipPlane gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel gl_FrontLightModelProduct gl_BackLightModelProduct gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ gl_FogParameters gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits gl_MaxDrawBuffers"),indentSwitch:!1,hooks:{"#":u},modeProps:{fold:["brace","include"]}}),y("text/x-nesc",{name:"clike",keywords:i(s+"as atomic async call command component components configuration event generic implementation includes interface module new norace nx_struct nx_union post provides signal task uses abstract extends"),types:i(c),blockKeywords:i("case do else for if switch while struct"),atoms:i("null true false"),hooks:{"#":u},modeProps:{fold:["brace","include"]}}),y("text/x-objectivec",{name:"clike",keywords:i(s+"inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),types:i(c),atoms:i("YES NO NULL NILL ON OFF true false"),hooks:{"@":function(e){return e.eatWhile(/[\w\$]/),"keyword"},"#":u,indent:function(e,t,n){if("statement"==t.type&&/^@\w/.test(n))return t.indented}},modeProps:{fold:"brace"}}),y("text/x-squirrel",{name:"clike",keywords:i("base break clone continue const default delete enum extends function in class foreach local resume return this throw typeof yield constructor instanceof static"),types:i(c),blockKeywords:i("case catch class else for foreach if switch try while"),defKeywords:i("function local class"),typeFirstDefinitions:!0,atoms:i("true false null"),hooks:{"#":u},modeProps:{fold:["brace","include"]}});var x=null;y("text/x-ceylon",{name:"clike",keywords:i("abstracts alias assembly assert assign break case catch class continue dynamic else exists extends finally for function given if import in interface is let module new nonempty object of out outer package return satisfies super switch then this throw try value void while"),types:function(e){var t=e.charAt(0);return t===t.toUpperCase()&&t!==t.toLowerCase()},blockKeywords:i("case catch class dynamic else finally for function if interface module new object switch try while"),defKeywords:i("class dynamic function interface module object package value"),builtin:i("abstract actual aliased annotation by default deprecated doc final formal late license native optional sealed see serializable shared suppressWarnings tagged throws variable"),isPunctuationChar:/[\[\]{}\(\),;\:\.`]/,isOperatorChar:/[+\-*&%=<>!?|^~:\/]/,numberStart:/[\d#$]/,number:/^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,multiLineStrings:!0,typeFirstDefinitions:!0,atoms:i("true false null larger smaller equal empty finished"),indentSwitch:!1,styleDefs:!1,hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){return t.tokenize=function e(t){return function(n,r){for(var o,a=!1,i=!1;!n.eol();){if(!a&&n.match('"')&&("single"==t||n.match('""'))){i=!0;break}if(!a&&n.match("``")){x=e(t),i=!0;break}o=n.next(),a="single"==t&&!a&&"\\"==o}return i&&(r.tokenize=null),"string"}}(e.match('""')?"triple":"single"),t.tokenize(e,t)},"`":function(e,t){return!(!x||!e.match("`"))&&(t.tokenize=x,x=null,t.tokenize(e,t))},"'":function(e){return e.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},token:function(e,t,n){if(("variable"==n||"type"==n)&&"."==t.prevToken)return"variable-2"}},modeProps:{fold:["brace","import"],closeBrackets:{triples:'"'}}})}); +// CodeMirror matchbrackets +!function(t){"object"==typeof exports&&"object"==typeof module?t(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],t):t(CodeMirror)}(function(t){var e=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),n=t.Pos,r={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"};function i(t,e,i){var c=t.getLineHandle(e.line),o=e.ch-1,l=i&&i.afterCursor;null==l&&(l=/(^| )cm-fat-cursor($| )/.test(t.getWrapperElement().className));var h=!l&&o>=0&&r[c.text.charAt(o)]||r[c.text.charAt(++o)];if(!h)return null;var s=">"==h.charAt(1)?1:-1;if(i&&i.strict&&s>0!=(o==e.ch))return null;var u=t.getTokenTypeAt(n(e.line,o+1)),f=a(t,n(e.line,o+(s>0?1:0)),s,u||null,i);return null==f?null:{from:n(e.line,o),to:f&&f.pos,match:f&&f.ch==h.charAt(0),forward:s>0}}function a(t,e,i,a,c){for(var o=c&&c.maxScanLineLength||1e4,l=c&&c.maxScanLines||1e3,h=[],s=c&&c.bracketRegex?c.bracketRegex:/[(){}[\]]/,u=i>0?Math.min(e.line+l,t.lastLine()+1):Math.max(t.firstLine()-1,e.line-l),f=e.line;f!=u;f+=i){var m=t.getLine(f);if(m){var g=i>0?0:m.length-1,d=i>0?m.length:-1;if(!(m.length>o))for(f==e.line&&(g=e.ch-(i<0?1:0));g!=d;g+=i){var k=m.charAt(g);if(s.test(k)&&(void 0===a||t.getTokenTypeAt(n(f,g+1))==a))if(">"==r[k].charAt(1)==i>0)h.push(k);else{if(!h.length)return{pos:n(f,g),ch:k};h.pop()}}}}return f-i!=(i>0?t.lastLine():t.firstLine())&&null}function c(t,r,a){for(var c=t.state.matchBrackets.maxHighlightLineLength||1e3,o=[],l=t.listSelections(),h=0;h
                                      ", + testIcon1 : "
                                      " + }, + //这个配置在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 + onload: function(){ + // this.previewing(); + $("#"+ 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", "多行公式"); + + callback && callback() + } + }, otherOptions)); + return editorName; +} + +// --------------------------------------------------------------------------------------------- +// md编辑器拖拽改变高度,TODO其他初始化参数,高度改变阈值... +// 写这里,供非react版本时copy一份用 +function initMDEditorDragResize(resizeBarSelector, mdEditor, options) { + if (!options) { + options = {} + } + if($('#'+ mdEditor.id).length === 0) { + console.error('未找到editor') + return; + } + var doc = $(document); + var editor__resize = $('#'+ mdEditor.id).parent().find(resizeBarSelector); + if (editor__resize.length === 0) { + console.error('未找到resizeBar') + return; + } + var dragging = false; + var topOffset, clickY, initDelta; + let initHeight = options.initHeight || 240; + + editor__resize.on('mousedown',function(){ + dragging = true; + topOffset = editor__resize.offset().top; + initDelta = $('#' + mdEditor.id).height() - initHeight; + }); + doc.live('mousemove', function(e){ + if(dragging){ + clickY = e.pageY; + + let delta = clickY - topOffset + initDelta; + if (delta > 300 ) { + delta = 300; + } + if (delta < 0) { + delta = 0; + } + + mdEditor.resize('', `${initHeight + delta}px`) + + // $('#memo_comment_editorMd').height(initHeight + delta) + } + return false + }); + + doc.live("mouseup", function(e) { + dragging = false; + }); +} \ No newline at end of file diff --git a/public/react/public/js/js_min_cm.js b/public/react/public/js/js_min_cm.js new file mode 100755 index 000000000..a417c5c60 --- /dev/null +++ b/public/react/public/js/js_min_cm.js @@ -0,0 +1,7 @@ +// 记录下cm相关的脚本 +// CodeMirror python +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e){return new RegExp("^(("+e.join(")|(")+"))\\b")}var n=t(["and","or","not","is"]),r=["as","assert","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","lambda","pass","raise","return","try","while","with","yield","in"],i=["abs","all","any","bin","bool","bytearray","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip","__import__","NotImplemented","Ellipsis","__debug__"];function o(e){return e.scopes[e.scopes.length-1]}e.registerHelper("hintWords","python",r.concat(i)),e.defineMode("python",function(a,s){for(var c="error",l=s.delimiters||s.singleDelimiters||/^[\(\)\[\]\{\}@,:`=;\.\\]/,u=[s.singleOperators,s.doubleOperators,s.doubleDelimiters,s.tripleDelimiters,s.operators||/^([-+*/%\/&|^]=?|[<>=]+|\/\/=?|\*\*=?|!=|[~!@])/],f=0;fr?_(t):i0&&z(e,t)&&(a+=" "+c),a}return v(e,t)}function v(e,t){if(e.eatSpace())return null;if(e.match(/^#.*/))return"comment";if(e.match(/^[0-9\.]/,!1)){var r=!1;if(e.match(/^[\d_]*\.\d+(e[\+\-]?\d+)?/i)&&(r=!0),e.match(/^[\d_]+\.\d*/)&&(r=!0),e.match(/^\.\d+/)&&(r=!0),r)return e.eat(/J/i),"number";var i=!1;if(e.match(/^0x[0-9a-f_]+/i)&&(i=!0),e.match(/^0b[01_]+/i)&&(i=!0),e.match(/^0o[0-7_]+/i)&&(i=!0),e.match(/^[1-9][\d_]*(e[\+\-]?[\d_]+)?/)&&(e.eat(/J/i),i=!0),e.match(/^0(?![\dx])/i)&&(i=!0),i)return e.eat(/L/i),"number"}if(e.match(y))return-1!==e.current().toLowerCase().indexOf("f")?(t.tokenize=function(e,t){for(;"rubf".indexOf(e.charAt(0).toLowerCase())>=0;)e=e.substr(1);var n=1==e.length,r="string";function i(t,n){return t.match(e)?(n.tokenize=o,r):t.match("{")?"punctuation":t.match("}")?(n.tokenize=o,"punctuation"):v(t,n)}function o(o,a){for(;!o.eol();)if(o.eatWhile(/[^'"\{\}\\]/),o.eat("\\")){if(o.next(),n&&o.eol())return r}else{if(o.match(e))return a.tokenize=t,r;if(o.match("{{"))return r;if(o.match("{",!1))return a.tokenize=i,o.current()?r:(o.next(),"punctuation");if(o.match("}}"))return r;if(o.match("}"))return c;o.eat(/['"]/)}if(n){if(s.singleLineStringErrors)return c;a.tokenize=t}return r}return o.isString=!0,o}(e.current(),t.tokenize),t.tokenize(e,t)):(t.tokenize=function(e){for(;"rubf".indexOf(e.charAt(0).toLowerCase())>=0;)e=e.substr(1);var t=1==e.length,n="string";function r(r,i){for(;!r.eol();)if(r.eatWhile(/[^'"\\]/),r.eat("\\")){if(r.next(),t&&r.eol())return n}else{if(r.match(e))return i.tokenize=x,n;r.eat(/['"]/)}if(t){if(s.singleLineStringErrors)return c;i.tokenize=x}return n}return r.isString=!0,r}(e.current()),t.tokenize(e,t));for(var o=0;o1&&o(t).offset>n;){if("py"!=o(t).type)return!0;t.scopes.pop()}return o(t).offset!=n}function w(e,t){e.sol()&&(t.beginningOfLine=!0);var n=t.tokenize(e,t),r=e.current();if(t.beginningOfLine&&"@"==r)return e.match(b,!1)?"meta":h?"operator":c;if(/\S/.test(r)&&(t.beginningOfLine=!1),"variable"!=n&&"builtin"!=n||"meta"!=t.lastToken||(n="meta"),"pass"!=r&&"return"!=r||(t.dedent+=1),"lambda"==r&&(t.lambda=!0),":"!=r||t.lambda||"py"!=o(t).type||_(t),1==r.length&&!/string|comment/.test(n)){var i="[({".indexOf(r);if(-1!=i&&function(e,t,n){var r=e.match(/^([\s\[\{\(]|#.*)*$/,!1)?null:e.column()+1;t.scopes.push({offset:t.indent+p,type:n,align:r})}(e,t,"])}".slice(i,i+1)),-1!=(i="])}".indexOf(r))){if(o(t).type!=r)return c;t.indent=t.scopes.pop().offset-p}}return t.dedent>0&&e.eol()&&"py"==o(t).type&&(t.scopes.length>1&&t.scopes.pop(),t.dedent-=1),n}return{startState:function(e){return{tokenize:x,scopes:[{offset:e||0,type:"py",align:null}],indent:e||0,lastToken:null,lambda:!1,dedent:0}},token:function(e,t){var n=t.errorToken;n&&(t.errorToken=!1);var r=w(e,t);return r&&"comment"!=r&&(t.lastToken="keyword"==r||"punctuation"==r?e.current():r),"punctuation"==r&&(r=null),e.eol()&&t.lambda&&(t.lambda=!1),n?r+" "+c:r},indent:function(t,n){if(t.tokenize!=x)return t.tokenize.isString?e.Pass:0;var r=o(t),i=r.type==n.charAt(0);return null!=r.align?r.align-(i?1:0):r.offset-(i?p:0)},electricInput:/^\s*[\}\]\)]$/,closeBrackets:{triples:"'\""},lineComment:"#",fold:"indent"}}),e.defineMIME("text/x-python","python");var a;e.defineMIME("text/x-cython",{name:"python",extra_keywords:(a="by cdef cimport cpdef ctypedef enum except extern gil include nogil property public readonly struct union DEF IF ELIF ELSE",a.split(" "))})}); +// CodeMirror c-like(java) +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(e){"use strict";function t(e,t,n,r,o,a){this.indented=e,this.column=t,this.type=n,this.info=r,this.align=o,this.prev=a}function n(e,n,r,o){var a=e.indented;return e.context&&"statement"==e.context.type&&"statement"!=r&&(a=e.context.indented),e.context=new t(a,n,r,o,null,e.context)}function r(e){var t=e.context.type;return")"!=t&&"]"!=t&&"}"!=t||(e.indented=e.context.indented),e.context=e.context.prev}function o(e,t,n){return"variable"==t.prevToken||"type"==t.prevToken||(!!/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(e.string.slice(0,n))||(!(!t.typeAtEndOfLine||e.column()!=e.indentation())||void 0))}function a(e){for(;;){if(!e||"top"==e.type)return!0;if("}"==e.type&&"namespace"!=e.prev.info)return!1;e=e.prev}}function i(e){for(var t={},n=e.split(" "),r=0;r!?|\/]/,L=s.isIdentifierChar||/[\w\$_\xa1-\uffff]/;function D(e,t){var n,r=e.next();if(k[r]){var o=k[r](e,t);if(!1!==o)return o}if('"'==r||"'"==r)return t.tokenize=(n=r,function(e,t){for(var r,o=!1,a=!1;null!=(r=e.next());){if(r==n&&!o){a=!0;break}o=!o&&"\\"==r}return(a||!o&&!w)&&(t.tokenize=null),"string"}),t.tokenize(e,t);if(C.test(r))return c=r,null;if(T.test(r)){if(e.backUp(1),e.match(M))return"number";e.next()}if("/"==r){if(e.eat("*"))return t.tokenize=z,z(e,t);if(e.eat("/"))return e.skipToEnd(),"comment"}if(P.test(r)){for(;!e.match(/^\/[\/*]/,!1)&&e.eat(P););return"operator"}if(e.eatWhile(L),S)for(;e.match(S);)e.eatWhile(L);var a=e.current();return l(m,a)?(l(g,a)&&(c="newstatement"),l(x,a)&&(u=!0),"keyword"):l(h,a)?"type":l(y,a)?(l(g,a)&&(c="newstatement"),"builtin"):l(b,a)?"atom":"variable"}function z(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=null;break}r="*"==n}return"comment"}function I(e,t){s.typeFirstDefinitions&&e.eol()&&a(t.context)&&(t.typeAtEndOfLine=o(e,t,e.pos))}return{startState:function(e){return{tokenize:null,context:new t((e||0)-d,0,"top",null,!1),indented:0,startOfLine:!0,prevToken:null}},token:function(e,t){var i=t.context;if(e.sol()&&(null==i.align&&(i.align=!1),t.indented=e.indentation(),t.startOfLine=!0),e.eatSpace())return I(e,t),null;c=u=null;var l=(t.tokenize||D)(e,t);if("comment"==l||"meta"==l)return l;if(null==i.align&&(i.align=!0),";"==c||":"==c||","==c&&e.match(/^\s*(?:\/\/.*)?$/,!1))for(;"statement"==t.context.type;)r(t);else if("{"==c)n(t,e.column(),"}");else if("["==c)n(t,e.column(),"]");else if("("==c)n(t,e.column(),")");else if("}"==c){for(;"statement"==i.type;)i=r(t);for("}"==i.type&&(i=r(t));"statement"==i.type;)i=r(t)}else c==i.type?r(t):v&&(("}"==i.type||"top"==i.type)&&";"!=c||"statement"==i.type&&"newstatement"==c)&&n(t,e.column(),"statement",e.current());if("variable"==l&&("def"==t.prevToken||s.typeFirstDefinitions&&o(e,t,e.start)&&a(t.context)&&e.match(/^\s*\(/,!1))&&(l="def"),k.token){var d=k.token(e,t,l);void 0!==d&&(l=d)}return"def"==l&&!1===s.styleDefs&&(l="variable"),t.startOfLine=!1,t.prevToken=u?"def":l||c,I(e,t),l},indent:function(t,n){if(t.tokenize!=D&&null!=t.tokenize||t.typeAtEndOfLine)return e.Pass;var r=t.context,o=n&&n.charAt(0);if("statement"==r.type&&"}"==o&&(r=r.prev),s.dontIndentStatements)for(;"statement"==r.type&&s.dontIndentStatements.test(r.info);)r=r.prev;if(k.indent){var a=k.indent(t,r,n);if("number"==typeof a)return a}var i=o==r.type,l=r.prev&&"switch"==r.prev.info;if(s.allmanIndentation&&/[{(]/.test(o)){for(;"top"!=r.type&&"}"!=r.type;)r=r.prev;return r.indented}return"statement"==r.type?r.indented+("{"==o?0:f):!r.align||p&&")"==r.type?")"!=r.type||i?r.indented+(i?0:d)+(i||!l||/^(?:case|default)\b/.test(n)?0:d):r.indented+f:r.column+(i?0:1)},electricInput:_?/^\s*(?:case .*?:|default:|\{\}?|\})$/:/^\s*[{}]$/,blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:"//",fold:"brace"}});var s="auto if break case register continue return default do sizeof static else struct switch extern typedef union for goto while enum const volatile",c="int long char short double float unsigned signed void size_t ptrdiff_t";function u(e,t){if(!t.startOfLine)return!1;for(var n,r=null;n=e.peek();){if("\\"==n&&e.match(/^.$/)){r=u;break}if("/"==n&&e.match(/^\/[\/\*]/,!1))break;e.next()}return t.tokenize=r,"meta"}function d(e,t){return"type"==t.prevToken&&"type"}function f(e){return e.eatWhile(/[\w\.']/),"number"}function p(e,t){if(e.backUp(1),e.match(/(R|u8R|uR|UR|LR)/)){var n=e.match(/"([^\s\\()]{0,16})\(/);return!!n&&(t.cpp11RawStringDelim=n[1],t.tokenize=h,h(e,t))}return e.match(/(u8|u|U|L)/)?!!e.match(/["']/,!1)&&"string":(e.next(),!1)}function m(e,t){for(var n;null!=(n=e.next());)if('"'==n&&!e.eat('"')){t.tokenize=null;break}return"string"}function h(e,t){var n=t.cpp11RawStringDelim.replace(/[^\w\s]/g,"\\$&");return e.match(new RegExp(".*?\\)"+n+'"'))?t.tokenize=null:e.skipToEnd(),"string"}function y(t,n){"string"==typeof t&&(t=[t]);var r=[];function o(e){if(e)for(var t in e)e.hasOwnProperty(t)&&r.push(t)}o(n.keywords),o(n.types),o(n.builtin),o(n.atoms),r.length&&(n.helperType=t[0],e.registerHelper("hintWords",t[0],r));for(var a=0;a!?|\/#:@]/,hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){return!!e.match('""')&&(t.tokenize=g,t.tokenize(e,t))},"'":function(e){return e.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},"=":function(e,n){var r=n.context;return!("}"!=r.type||!r.align||!e.eat(">"))&&(n.context=new t(r.indented,r.column,r.type,r.info,null,r.prev),"operator")},"/":function(e,t){return!!e.eat("*")&&(t.tokenize=function e(t){return function(n,r){for(var o;o=n.next();){if("*"==o&&n.eat("/")){if(1==t){r.tokenize=null;break}return r.tokenize=e(t-1),r.tokenize(n,r)}if("/"==o&&n.eat("*"))return r.tokenize=e(t+1),r.tokenize(n,r)}return"comment"}}(1),t.tokenize(e,t))}},modeProps:{closeBrackets:{triples:'"'}}}),y("text/x-kotlin",{name:"clike",keywords:i("package as typealias class interface this super val operator var fun for is in This throw return annotation break continue object if else while do try when !in !is as? file import where by get set abstract enum open inner override private public internal protected catch finally out final vararg reified dynamic companion constructor init sealed field property receiver param sparam lateinit data inline noinline tailrec external annotation crossinline const operator infix suspend actual expect setparam"),types:i("Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable Compiler Double Exception Float Integer Long Math Number Object Package Pair Process Runtime Runnable SecurityManager Short StackTraceElement StrictMath String StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy LazyThreadSafetyMode LongArray Nothing ShortArray Unit"),intendSwitch:!1,indentStatements:!1,multiLineStrings:!0,number:/^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,blockKeywords:i("catch class do else finally for if where try while enum"),defKeywords:i("class val var object interface fun"),atoms:i("true false null this"),hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){var n;return t.tokenize=(n=e.match('""'),function(e,t){for(var r,o=!1,a=!1;!e.eol();){if(!n&&!o&&e.match('"')){a=!0;break}if(n&&e.match('"""')){a=!0;break}r=e.next(),!o&&"$"==r&&e.match("{")&&e.skipTo("}"),o=!o&&"\\"==r&&!n}return!a&&n||(t.tokenize=null),"string"}),t.tokenize(e,t)}},modeProps:{closeBrackets:{triples:'"'}}}),y(["x-shader/x-vertex","x-shader/x-fragment"],{name:"clike",keywords:i("sampler1D sampler2D sampler3D samplerCube sampler1DShadow sampler2DShadow const attribute uniform varying break continue discard return for while do if else struct in out inout"),types:i("float int bool void vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 mat2 mat3 mat4"),blockKeywords:i("for while do if else struct"),builtin:i("radians degrees sin cos tan asin acos atan pow exp log exp2 sqrt inversesqrt abs sign floor ceil fract mod min max clamp mix step smoothstep length distance dot cross normalize ftransform faceforward reflect refract matrixCompMult lessThan lessThanEqual greaterThan greaterThanEqual equal notEqual any all not texture1D texture1DProj texture1DLod texture1DProjLod texture2D texture2DProj texture2DLod texture2DProjLod texture3D texture3DProj texture3DLod texture3DProjLod textureCube textureCubeLod shadow1D shadow2D shadow1DProj shadow2DProj shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod dFdx dFdy fwidth noise1 noise2 noise3 noise4"),atoms:i("true false gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_FogCoord gl_PointCoord gl_Position gl_PointSize gl_ClipVertex gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_TexCoord gl_FogFragCoord gl_FragCoord gl_FrontFacing gl_FragData gl_FragDepth gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose gl_ProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixInverseTranspose gl_TextureMatrixInverseTranspose gl_NormalScale gl_DepthRange gl_ClipPlane gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel gl_FrontLightModelProduct gl_BackLightModelProduct gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ gl_FogParameters gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits gl_MaxDrawBuffers"),indentSwitch:!1,hooks:{"#":u},modeProps:{fold:["brace","include"]}}),y("text/x-nesc",{name:"clike",keywords:i(s+"as atomic async call command component components configuration event generic implementation includes interface module new norace nx_struct nx_union post provides signal task uses abstract extends"),types:i(c),blockKeywords:i("case do else for if switch while struct"),atoms:i("null true false"),hooks:{"#":u},modeProps:{fold:["brace","include"]}}),y("text/x-objectivec",{name:"clike",keywords:i(s+"inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),types:i(c),atoms:i("YES NO NULL NILL ON OFF true false"),hooks:{"@":function(e){return e.eatWhile(/[\w\$]/),"keyword"},"#":u,indent:function(e,t,n){if("statement"==t.type&&/^@\w/.test(n))return t.indented}},modeProps:{fold:"brace"}}),y("text/x-squirrel",{name:"clike",keywords:i("base break clone continue const default delete enum extends function in class foreach local resume return this throw typeof yield constructor instanceof static"),types:i(c),blockKeywords:i("case catch class else for foreach if switch try while"),defKeywords:i("function local class"),typeFirstDefinitions:!0,atoms:i("true false null"),hooks:{"#":u},modeProps:{fold:["brace","include"]}});var x=null;y("text/x-ceylon",{name:"clike",keywords:i("abstracts alias assembly assert assign break case catch class continue dynamic else exists extends finally for function given if import in interface is let module new nonempty object of out outer package return satisfies super switch then this throw try value void while"),types:function(e){var t=e.charAt(0);return t===t.toUpperCase()&&t!==t.toLowerCase()},blockKeywords:i("case catch class dynamic else finally for function if interface module new object switch try while"),defKeywords:i("class dynamic function interface module object package value"),builtin:i("abstract actual aliased annotation by default deprecated doc final formal late license native optional sealed see serializable shared suppressWarnings tagged throws variable"),isPunctuationChar:/[\[\]{}\(\),;\:\.`]/,isOperatorChar:/[+\-*&%=<>!?|^~:\/]/,numberStart:/[\d#$]/,number:/^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,multiLineStrings:!0,typeFirstDefinitions:!0,atoms:i("true false null larger smaller equal empty finished"),indentSwitch:!1,styleDefs:!1,hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){return t.tokenize=function e(t){return function(n,r){for(var o,a=!1,i=!1;!n.eol();){if(!a&&n.match('"')&&("single"==t||n.match('""'))){i=!0;break}if(!a&&n.match("``")){x=e(t),i=!0;break}o=n.next(),a="single"==t&&!a&&"\\"==o}return i&&(r.tokenize=null),"string"}}(e.match('""')?"triple":"single"),t.tokenize(e,t)},"`":function(e,t){return!(!x||!e.match("`"))&&(t.tokenize=x,x=null,t.tokenize(e,t))},"'":function(e){return e.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},token:function(e,t,n){if(("variable"==n||"type"==n)&&"."==t.prevToken)return"variable-2"}},modeProps:{fold:["brace","import"],closeBrackets:{triples:'"'}}})}); +// CodeMirror matchbrackets +!function(t){"object"==typeof exports&&"object"==typeof module?t(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],t):t(CodeMirror)}(function(t){var e=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),n=t.Pos,r={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"};function i(t,e,i){var c=t.getLineHandle(e.line),o=e.ch-1,l=i&&i.afterCursor;null==l&&(l=/(^| )cm-fat-cursor($| )/.test(t.getWrapperElement().className));var h=!l&&o>=0&&r[c.text.charAt(o)]||r[c.text.charAt(++o)];if(!h)return null;var s=">"==h.charAt(1)?1:-1;if(i&&i.strict&&s>0!=(o==e.ch))return null;var u=t.getTokenTypeAt(n(e.line,o+1)),f=a(t,n(e.line,o+(s>0?1:0)),s,u||null,i);return null==f?null:{from:n(e.line,o),to:f&&f.pos,match:f&&f.ch==h.charAt(0),forward:s>0}}function a(t,e,i,a,c){for(var o=c&&c.maxScanLineLength||1e4,l=c&&c.maxScanLines||1e3,h=[],s=c&&c.bracketRegex?c.bracketRegex:/[(){}[\]]/,u=i>0?Math.min(e.line+l,t.lastLine()+1):Math.max(t.firstLine()-1,e.line-l),f=e.line;f!=u;f+=i){var m=t.getLine(f);if(m){var g=i>0?0:m.length-1,d=i>0?m.length:-1;if(!(m.length>o))for(f==e.line&&(g=e.ch-(i<0?1:0));g!=d;g+=i){var k=m.charAt(g);if(s.test(k)&&(void 0===a||t.getTokenTypeAt(n(f,g+1))==a))if(">"==r[k].charAt(1)==i>0)h.push(k);else{if(!h.length)return{pos:n(f,g),ch:k};h.pop()}}}}return f-i!=(i>0?t.lastLine():t.firstLine())&&null}function c(t,r,a){for(var c=t.state.matchBrackets.maxHighlightLineLength||1e3,o=[],l=t.listSelections(),h=0;h now) return false; + + var sInfo = editor.getScrollInfo(); + if (dv.mv.options.connect == "align") { + targetPos = sInfo.top; + } else { + var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen; + var mid = editor.lineAtHeight(midY, "local"); + var around = chunkBoundariesAround(dv.chunks, mid, toOrig); + var off = getOffsets(editor, toOrig ? around.edit : around.orig); + var offOther = getOffsets(other, toOrig ? around.orig : around.edit); + var ratio = (midY - off.top) / (off.bot - off.top); + var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top); + + var botDist, mix; + // Some careful tweaking to make sure no space is left out of view + // when scrolling to top or bottom. + if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) { + targetPos = targetPos * mix + sInfo.top * (1 - mix); + } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) { + var otherInfo = other.getScrollInfo(); + var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos; + if (botDistOther > botDist && (mix = botDist / halfScreen) < 1) + targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix); + } + } + + other.scrollTo(sInfo.left, targetPos); + other.state.scrollSetAt = now; + other.state.scrollSetBy = dv; + return true; + } + + function getOffsets(editor, around) { + var bot = around.after; + if (bot == null) bot = editor.lastLine() + 1; + return {top: editor.heightAtLine(around.before || 0, "local"), + bot: editor.heightAtLine(bot, "local")}; + } + + function setScrollLock(dv, val, action) { + dv.lockScroll = val; + if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv); + // 对比滚轮Toggle locked scrolling的样式 + //dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db  \u21da"; + } + + // Updating the marks for editor content + + function removeClass(editor, line, classes) { + var locs = classes.classLocation + for (var i = 0; i < locs.length; i++) { + editor.removeLineClass(line, locs[i], classes.chunk); + editor.removeLineClass(line, locs[i], classes.start); + editor.removeLineClass(line, locs[i], classes.end); + } + } + + function clearMarks(editor, arr, classes) { + for (var i = 0; i < arr.length; ++i) { + var mark = arr[i]; + if (mark instanceof CodeMirror.TextMarker) + mark.clear(); + else if (mark.parent) + removeClass(editor, mark, classes); + } + arr.length = 0; + } + + // FIXME maybe add a margin around viewport to prevent too many updates + function updateMarks(editor, diff, state, type, classes) { + var vp = editor.getViewport(); + editor.operation(function() { + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + clearMarks(editor, state.marked, classes); + markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes); + state.from = vp.from; state.to = vp.to; + } else { + if (vp.from < state.from) { + markChanges(editor, diff, type, state.marked, vp.from, state.from, classes); + state.from = vp.from; + } + if (vp.to > state.to) { + markChanges(editor, diff, type, state.marked, state.to, vp.to, classes); + state.to = vp.to; + } + } + }); + } + + function addClass(editor, lineNr, classes, main, start, end) { + var locs = classes.classLocation, line = editor.getLineHandle(lineNr); + for (var i = 0; i < locs.length; i++) { + if (main) editor.addLineClass(line, locs[i], classes.chunk); + if (start) editor.addLineClass(line, locs[i], classes.start); + if (end) editor.addLineClass(line, locs[i], classes.end); + } + return line; + } + + function markChanges(editor, diff, type, marks, from, to, classes) { + var pos = Pos(0, 0); + var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); + var cls = type == DIFF_DELETE ? classes.del : classes.insert; + function markChunk(start, end) { + var bfrom = Math.max(from, start), bto = Math.min(to, end); + for (var i = bfrom; i < bto; ++i) + marks.push(addClass(editor, i, classes, true, i == start, i == end - 1)); + // When the chunk is empty, make sure a horizontal line shows up + if (start == end && bfrom == end && bto == end) { + if (bfrom) + marks.push(addClass(editor, bfrom - 1, classes, false, false, true)); + else + marks.push(addClass(editor, bfrom, classes, false, true, false)); + } + } + + var chunkStart = 0, pending = false; + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0], str = part[1]; + if (tp == DIFF_EQUAL) { + var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1); + moveOver(pos, str); + var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0); + if (cleanTo > cleanFrom) { + if (pending) { markChunk(chunkStart, cleanFrom); pending = false } + chunkStart = cleanTo; + } + } else { + pending = true + if (tp == type) { + var end = moveOver(pos, str, true); + var a = posMax(top, pos), b = posMin(bot, end); + if (!posEq(a, b)) + marks.push(editor.markText(a, b, {className: cls})); + pos = end; + } + } + } + if (pending) markChunk(chunkStart, pos.line + 1); + } + + // Updating the gap between editor and original + + function makeConnections(dv) { + if (!dv.showDifferences) return; + + if (dv.svg) { + clear(dv.svg); + var w = dv.gap.offsetWidth; + attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight); + } + if (dv.copyButtons) clear(dv.copyButtons); + + var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport(); + var outerTop = dv.mv.wrap.getBoundingClientRect().top + var sTopEdit = outerTop - dv.edit.getScrollerElement().getBoundingClientRect().top + dv.edit.getScrollInfo().top + var sTopOrig = outerTop - dv.orig.getScrollerElement().getBoundingClientRect().top + dv.orig.getScrollInfo().top; + for (var i = 0; i < dv.chunks.length; i++) { + var ch = dv.chunks[i]; + if (ch.editFrom <= vpEdit.to && ch.editTo >= vpEdit.from && + ch.origFrom <= vpOrig.to && ch.origTo >= vpOrig.from) + drawConnectorsForChunk(dv, ch, sTopOrig, sTopEdit, w); + } + } + + function getMatchingOrigLine(editLine, chunks) { + var editStart = 0, origStart = 0; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + if (chunk.editTo > editLine && chunk.editFrom <= editLine) return null; + if (chunk.editFrom > editLine) break; + editStart = chunk.editTo; + origStart = chunk.origTo; + } + return origStart + (editLine - editStart); + } + + // Combines information about chunks and widgets/markers to return + // an array of lines, in a single editor, that probably need to be + // aligned with their counterparts in the editor next to it. + function alignableFor(cm, chunks, isOrig) { + var tracker = cm.state.trackAlignable + var start = cm.firstLine(), trackI = 0 + var result = [] + for (var i = 0;; i++) { + var chunk = chunks[i] + var chunkStart = !chunk ? 1e9 : isOrig ? chunk.origFrom : chunk.editFrom + for (; trackI < tracker.alignable.length; trackI += 2) { + var n = tracker.alignable[trackI] + 1 + if (n <= start) continue + if (n <= chunkStart) result.push(n) + else break + } + if (!chunk) break + result.push(start = isOrig ? chunk.origTo : chunk.editTo) + } + return result + } + + // Given information about alignable lines in two editors, fill in + // the result (an array of three-element arrays) to reflect the + // lines that need to be aligned with each other. + function mergeAlignable(result, origAlignable, chunks, setIndex) { + var rI = 0, origI = 0, chunkI = 0, diff = 0 + outer: for (;; rI++) { + var nextR = result[rI], nextO = origAlignable[origI] + if (!nextR && nextO == null) break + + var rLine = nextR ? nextR[0] : 1e9, oLine = nextO == null ? 1e9 : nextO + while (chunkI < chunks.length) { + var chunk = chunks[chunkI] + if (chunk.origFrom <= oLine && chunk.origTo > oLine) { + origI++ + rI-- + continue outer; + } + if (chunk.editTo > rLine) { + if (chunk.editFrom <= rLine) continue outer; + break + } + diff += (chunk.origTo - chunk.origFrom) - (chunk.editTo - chunk.editFrom) + chunkI++ + } + if (rLine == oLine - diff) { + nextR[setIndex] = oLine + origI++ + } else if (rLine < oLine - diff) { + nextR[setIndex] = rLine + diff + } else { + var record = [oLine - diff, null, null] + record[setIndex] = oLine + result.splice(rI, 0, record) + origI++ + } + } + } + + function findAlignedLines(dv, other) { + var alignable = alignableFor(dv.edit, dv.chunks, false), result = [] + if (other) for (var i = 0, j = 0; i < other.chunks.length; i++) { + var n = other.chunks[i].editTo + while (j < alignable.length && alignable[j] < n) j++ + if (j == alignable.length || alignable[j] != n) alignable.splice(j++, 0, n) + } + for (var i = 0; i < alignable.length; i++) + result.push([alignable[i], null, null]) + + mergeAlignable(result, alignableFor(dv.orig, dv.chunks, true), dv.chunks, 1) + if (other) + mergeAlignable(result, alignableFor(other.orig, other.chunks, true), other.chunks, 2) + + return result + } + + function alignChunks(dv, force) { + if (!dv.dealigned && !force) return; + if (!dv.orig.curOp) return dv.orig.operation(function() { + alignChunks(dv, force); + }); + + dv.dealigned = false; + var other = dv.mv.left == dv ? dv.mv.right : dv.mv.left; + if (other) { + ensureDiff(other); + other.dealigned = false; + } + var linesToAlign = findAlignedLines(dv, other); + + // Clear old aligners + var aligners = dv.mv.aligners; + for (var i = 0; i < aligners.length; i++) + aligners[i].clear(); + aligners.length = 0; + + var cm = [dv.edit, dv.orig], scroll = []; + if (other) cm.push(other.orig); + for (var i = 0; i < cm.length; i++) + scroll.push(cm[i].getScrollInfo().top); + + for (var ln = 0; ln < linesToAlign.length; ln++) + alignLines(cm, linesToAlign[ln], aligners); + + for (var i = 0; i < cm.length; i++) + cm[i].scrollTo(null, scroll[i]); + } + + function alignLines(cm, lines, aligners) { + var maxOffset = 0, offset = []; + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var off = cm[i].heightAtLine(lines[i], "local"); + offset[i] = off; + maxOffset = Math.max(maxOffset, off); + } + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var diff = maxOffset - offset[i]; + if (diff > 1) + aligners.push(padAbove(cm[i], lines[i], diff)); + } + } + + function padAbove(cm, line, size) { + var above = true; + if (line > cm.lastLine()) { + line--; + above = false; + } + var elt = document.createElement("div"); + elt.className = "CodeMirror-merge-spacer"; + elt.style.height = size + "px"; elt.style.minWidth = "1px"; + return cm.addLineWidget(line, elt, {height: size, above: above, mergeSpacer: true, handleMouseEvents: true}); + } + + function drawConnectorsForChunk(dv, chunk, sTopOrig, sTopEdit, w) { + var flip = dv.type == "left"; + var top = dv.orig.heightAtLine(chunk.origFrom, "local", true) - sTopOrig; + if (dv.svg) { + var topLpx = top; + var topRpx = dv.edit.heightAtLine(chunk.editFrom, "local", true) - sTopEdit; + if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; } + var botLpx = dv.orig.heightAtLine(chunk.origTo, "local", true) - sTopOrig; + var botRpx = dv.edit.heightAtLine(chunk.editTo, "local", true) - sTopEdit; + if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; } + var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx; + var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx; + attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")), + "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z", + "class", dv.classes.connect); + } + if (dv.copyButtons) { + var copy = dv.copyButtons.appendChild(elt1("div", dv.type == "left" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy")); + var editOriginals = dv.mv.options.allowEditingOriginals; + copy.title = editOriginals ? "Push to left" : "Revert chunk"; + copy.chunk = chunk; + copy.style.top = (chunk.origTo > chunk.origFrom ? top : dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit) + "px"; + + if (editOriginals) { + var topReverse = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit; + var copyReverse = dv.copyButtons.appendChild(elt1("div", dv.type == "right" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy-reverse")); + copyReverse.title = "Push to right"; + copyReverse.chunk = {editFrom: chunk.origFrom, editTo: chunk.origTo, + origFrom: chunk.editFrom, origTo: chunk.editTo}; + copyReverse.style.top = topReverse + "px"; + dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px"; + } + } + } + + function copyChunk(dv, to, from, chunk) { + if (dv.diffOutOfDate) return; + var origStart = chunk.origTo > from.lastLine() ? Pos(chunk.origFrom - 1) : Pos(chunk.origFrom, 0) + var origEnd = Pos(chunk.origTo, 0) + var editStart = chunk.editTo > to.lastLine() ? Pos(chunk.editFrom - 1) : Pos(chunk.editFrom, 0) + var editEnd = Pos(chunk.editTo, 0) + var handler = dv.mv.options.revertChunk + if (handler) + handler(dv.mv, from, origStart, origEnd, to, editStart, editEnd) + else + to.replaceRange(from.getRange(origStart, origEnd), editStart, editEnd) + } + + // Merge view, containing 0, 1, or 2 diff views. + + var MergeView = CodeMirror.MergeView = function(node, options) { + if (!(this instanceof MergeView)) return new MergeView(node, options); + + this.options = options; + var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight; + + var hasLeft = origLeft != null, hasRight = origRight != null; + var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0); + var wrap = [], left = this.left = null, right = this.right = null; + var self = this; + + if (hasLeft) { + left = this.left = new DiffView(this, "left"); + var leftPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-left"); + wrap.push(leftPane); + wrap.push(buildGap(left)); + } + + var editPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-editor"); + wrap.push(editPane); + + if (hasRight) { + right = this.right = new DiffView(this, "right"); + wrap.push(buildGap(right)); + var rightPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-right"); + wrap.push(rightPane); + } + + (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost"; + + wrap.push(elt("div", null, null, "height: 0; clear: both;")); + + var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane")); + this.edit = CodeMirror(editPane, copyObj(options)); + + if (left) left.init(leftPane, origLeft, options); + if (right) right.init(rightPane, origRight, options); + if (options.collapseIdentical) + this.editor().operation(function() { + collapseIdenticalStretches(self, options.collapseIdentical); + }); + if (options.connect == "align") { + this.aligners = []; + alignChunks(this.left || this.right, true); + } + if (left) left.registerEvents(right) + if (right) right.registerEvents(left) + + + var onResize = function() { + if (left) makeConnections(left); + if (right) makeConnections(right); + }; + CodeMirror.on(window, "resize", onResize); + var resizeInterval = setInterval(function() { + for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {} + if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); } + }, 5000); + }; + + function buildGap(dv) { + var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock"); + lock.title = "Toggle locked scrolling"; + var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); + CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); + var gapElts = [lockWrap]; + if (dv.mv.options.revertButtons !== false) { + dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); + CodeMirror.on(dv.copyButtons, "click", function(e) { + var node = e.target || e.srcElement; + if (!node.chunk) return; + if (node.className == "CodeMirror-merge-copy-reverse") { + copyChunk(dv, dv.orig, dv.edit, node.chunk); + return; + } + copyChunk(dv, dv.edit, dv.orig, node.chunk); + }); + gapElts.unshift(dv.copyButtons); + } + if (dv.mv.options.connect != "align") { + var svg = document.createElementNS && document.createElementNS(svgNS, "svg"); + if (svg && !svg.createSVGRect) svg = null; + dv.svg = svg; + if (svg) gapElts.push(svg); + } + + return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap"); + } + + MergeView.prototype = { + constructor: MergeView, + editor: function() { return this.edit; }, + rightOriginal: function() { return this.right && this.right.orig; }, + leftOriginal: function() { return this.left && this.left.orig; }, + setShowDifferences: function(val) { + if (this.right) this.right.setShowDifferences(val); + if (this.left) this.left.setShowDifferences(val); + }, + rightChunks: function() { + if (this.right) { ensureDiff(this.right); return this.right.chunks; } + }, + leftChunks: function() { + if (this.left) { ensureDiff(this.left); return this.left.chunks; } + } + }; + + function asString(obj) { + if (typeof obj == "string") return obj; + else return obj.getValue(); + } + + // Operations on diffs + + var dmp = new diff_match_patch(); + function getDiff(a, b, ignoreWhitespace) { + var diff = dmp.diff_main(a, b); + // The library sometimes leaves in empty parts, which confuse the algorithm + for (var i = 0; i < diff.length; ++i) { + var part = diff[i]; + if (ignoreWhitespace ? !/[^ \t]/.test(part[1]) : !part[1]) { + diff.splice(i--, 1); + } else if (i && diff[i - 1][0] == part[0]) { + diff.splice(i--, 1); + diff[i][1] += part[1]; + } + } + return diff; + } + + function getChunks(diff) { + var chunks = []; + var startEdit = 0, startOrig = 0; + var edit = Pos(0, 0), orig = Pos(0, 0); + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0]; + if (tp == DIFF_EQUAL) { + var startOff = !startOfLineClean(diff, i) || edit.line < startEdit || orig.line < startOrig ? 1 : 0; + var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff; + moveOver(edit, part[1], null, orig); + var endOff = endOfLineClean(diff, i) ? 1 : 0; + var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff; + if (cleanToEdit > cleanFromEdit) { + if (i) chunks.push({origFrom: startOrig, origTo: cleanFromOrig, + editFrom: startEdit, editTo: cleanFromEdit}); + startEdit = cleanToEdit; startOrig = cleanToOrig; + } + } else { + moveOver(tp == DIFF_INSERT ? edit : orig, part[1]); + } + } + if (startEdit <= edit.line || startOrig <= orig.line) + chunks.push({origFrom: startOrig, origTo: orig.line + 1, + editFrom: startEdit, editTo: edit.line + 1}); + return chunks; + } + + function endOfLineClean(diff, i) { + if (i == diff.length - 1) return true; + var next = diff[i + 1][1]; + if ((next.length == 1 && i < diff.length - 2) || next.charCodeAt(0) != 10) return false; + if (i == diff.length - 2) return true; + next = diff[i + 2][1]; + return (next.length > 1 || i == diff.length - 3) && next.charCodeAt(0) == 10; + } + + function startOfLineClean(diff, i) { + if (i == 0) return true; + var last = diff[i - 1][1]; + if (last.charCodeAt(last.length - 1) != 10) return false; + if (i == 1) return true; + last = diff[i - 2][1]; + return last.charCodeAt(last.length - 1) == 10; + } + + function chunkBoundariesAround(chunks, n, nInEdit) { + var beforeE, afterE, beforeO, afterO; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + var fromLocal = nInEdit ? chunk.editFrom : chunk.origFrom; + var toLocal = nInEdit ? chunk.editTo : chunk.origTo; + if (afterE == null) { + if (fromLocal > n) { afterE = chunk.editFrom; afterO = chunk.origFrom; } + else if (toLocal > n) { afterE = chunk.editTo; afterO = chunk.origTo; } + } + if (toLocal <= n) { beforeE = chunk.editTo; beforeO = chunk.origTo; } + else if (fromLocal <= n) { beforeE = chunk.editFrom; beforeO = chunk.origFrom; } + } + return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}}; + } + + function collapseSingle(cm, from, to) { + cm.addLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + var widget = document.createElement("span"); + widget.className = "CodeMirror-merge-collapsed-widget"; + widget.title = "Identical text collapsed. Click to expand."; + var mark = cm.markText(Pos(from, 0), Pos(to - 1), { + inclusiveLeft: true, + inclusiveRight: true, + replacedWith: widget, + clearOnEnter: true + }); + function clear() { + mark.clear(); + cm.removeLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + } + CodeMirror.on(widget, "click", clear); + return {mark: mark, clear: clear}; + } + + function collapseStretch(size, editors) { + var marks = []; + function clear() { + for (var i = 0; i < marks.length; i++) marks[i].clear(); + } + for (var i = 0; i < editors.length; i++) { + var editor = editors[i]; + var mark = collapseSingle(editor.cm, editor.line, editor.line + size); + marks.push(mark); + mark.mark.on("clear", clear); + } + return marks[0].mark; + } + + function unclearNearChunks(dv, margin, off, clear) { + for (var i = 0; i < dv.chunks.length; i++) { + var chunk = dv.chunks[i]; + for (var l = chunk.editFrom - margin; l < chunk.editTo + margin; l++) { + var pos = l + off; + if (pos >= 0 && pos < clear.length) clear[pos] = false; + } + } + } + + function collapseIdenticalStretches(mv, margin) { + if (typeof margin != "number") margin = 2; + var clear = [], edit = mv.editor(), off = edit.firstLine(); + for (var l = off, e = edit.lastLine(); l <= e; l++) clear.push(true); + if (mv.left) unclearNearChunks(mv.left, margin, off, clear); + if (mv.right) unclearNearChunks(mv.right, margin, off, clear); + + for (var i = 0; i < clear.length; i++) { + if (clear[i]) { + var line = i + off; + for (var size = 1; i < clear.length - 1 && clear[i + 1]; i++, size++) {} + if (size > margin) { + var editors = [{line: line, cm: edit}]; + if (mv.left) editors.push({line: getMatchingOrigLine(line, mv.left.chunks), cm: mv.left.orig}); + if (mv.right) editors.push({line: getMatchingOrigLine(line, mv.right.chunks), cm: mv.right.orig}); + var mark = collapseStretch(size, editors); + if (mv.options.onCollapse) mv.options.onCollapse(mv, line, size, mark); + } + } + } + } + + // General utilities + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + function elt1(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + function clear(node) { + for (var count = node.childNodes.length; count > 0; --count) + node.removeChild(node.firstChild); + } + + function attrs(elt) { + for (var i = 1; i < arguments.length; i += 2) + elt.setAttribute(arguments[i], arguments[i+1]); + } + + function copyObj(obj, target) { + if (!target) target = {}; + for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop]; + return target; + } + + function moveOver(pos, str, copy, other) { + var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0; + for (;;) { + var nl = str.indexOf("\n", at); + if (nl == -1) break; + ++out.line; + if (other) ++other.line; + at = nl + 1; + } + out.ch = (at ? 0 : out.ch) + (str.length - at); + if (other) other.ch = (at ? 0 : other.ch) + (str.length - at); + return out; + } + + // Tracks collapsed markers and line widgets, in order to be able to + // accurately align the content of two editors. + + var F_WIDGET = 1, F_WIDGET_BELOW = 2, F_MARKER = 4 + + function TrackAlignable(cm) { + this.cm = cm + this.alignable = [] + this.height = cm.doc.height + var self = this + cm.on("markerAdded", function(_, marker) { + if (!marker.collapsed) return + var found = marker.find(1) + if (found != null) self.set(found.line, F_MARKER) + }) + cm.on("markerCleared", function(_, marker, _min, max) { + if (max != null && marker.collapsed) + self.check(max, F_MARKER, self.hasMarker) + }) + cm.on("markerChanged", this.signal.bind(this)) + cm.on("lineWidgetAdded", function(_, widget, lineNo) { + if (widget.mergeSpacer) return + if (widget.above) self.set(lineNo - 1, F_WIDGET_BELOW) + else self.set(lineNo, F_WIDGET) + }) + cm.on("lineWidgetCleared", function(_, widget, lineNo) { + if (widget.mergeSpacer) return + if (widget.above) self.check(lineNo - 1, F_WIDGET_BELOW, self.hasWidgetBelow) + else self.check(lineNo, F_WIDGET, self.hasWidget) + }) + cm.on("lineWidgetChanged", this.signal.bind(this)) + cm.on("change", function(_, change) { + var start = change.from.line, nBefore = change.to.line - change.from.line + var nAfter = change.text.length - 1, end = start + nAfter + if (nBefore || nAfter) self.map(start, nBefore, nAfter) + self.check(end, F_MARKER, self.hasMarker) + if (nBefore || nAfter) self.check(change.from.line, F_MARKER, self.hasMarker) + }) + cm.on("viewportChange", function() { + if (self.cm.doc.height != self.height) self.signal() + }) + } + + TrackAlignable.prototype = { + signal: function() { + CodeMirror.signal(this, "realign") + this.height = this.cm.doc.height + }, + + set: function(n, flags) { + var pos = -1 + for (; pos < this.alignable.length; pos += 2) { + var diff = this.alignable[pos] - n + if (diff == 0) { + if ((this.alignable[pos + 1] & flags) == flags) return + this.alignable[pos + 1] |= flags + this.signal() + return + } + if (diff > 0) break + } + this.signal() + this.alignable.splice(pos, 0, n, flags) + }, + + find: function(n) { + for (var i = 0; i < this.alignable.length; i += 2) + if (this.alignable[i] == n) return i + return -1 + }, + + check: function(n, flag, pred) { + var found = this.find(n) + if (found == -1 || !(this.alignable[found + 1] & flag)) return + if (!pred.call(this, n)) { + this.signal() + var flags = this.alignable[found + 1] & ~flag + if (flags) this.alignable[found + 1] = flags + else this.alignable.splice(found, 2) + } + }, + + hasMarker: function(n) { + var handle = this.cm.getLineHandle(n) + if (handle.markedSpans) for (var i = 0; i < handle.markedSpans.length; i++) + if (handle.markedSpans[i].mark.collapsed && handle.markedSpans[i].to != null) + return true + return false + }, + + hasWidget: function(n) { + var handle = this.cm.getLineHandle(n) + if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++) + if (!handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true + return false + }, + + hasWidgetBelow: function(n) { + if (n == this.cm.lastLine()) return false + var handle = this.cm.getLineHandle(n + 1) + if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++) + if (handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true + return false + }, + + map: function(from, nBefore, nAfter) { + var diff = nAfter - nBefore, to = from + nBefore, widgetFrom = -1, widgetTo = -1 + for (var i = 0; i < this.alignable.length; i += 2) { + var n = this.alignable[i] + if (n == from && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetFrom = i + if (n == to && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetTo = i + if (n <= from) continue + else if (n < to) this.alignable.splice(i--, 2) + else this.alignable[i] += diff + } + if (widgetFrom > -1) { + var flags = this.alignable[widgetFrom + 1] + if (flags == F_WIDGET_BELOW) this.alignable.splice(widgetFrom, 2) + else this.alignable[widgetFrom + 1] = flags & ~F_WIDGET_BELOW + } + if (widgetTo > -1 && nAfter) + this.set(from + nAfter, F_WIDGET_BELOW) + } + } + + function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; } + function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; } + function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } + + function findPrevDiff(chunks, start, isOrig) { + for (var i = chunks.length - 1; i >= 0; i--) { + var chunk = chunks[i]; + var to = (isOrig ? chunk.origTo : chunk.editTo) - 1; + if (to < start) return to; + } + } + + function findNextDiff(chunks, start, isOrig) { + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + var from = (isOrig ? chunk.origFrom : chunk.editFrom); + if (from > start) return from; + } + } + + function goNearbyDiff(cm, dir) { + var found = null, views = cm.state.diffViews, line = cm.getCursor().line; + if (views) for (var i = 0; i < views.length; i++) { + var dv = views[i], isOrig = cm == dv.orig; + ensureDiff(dv); + var pos = dir < 0 ? findPrevDiff(dv.chunks, line, isOrig) : findNextDiff(dv.chunks, line, isOrig); + if (pos != null && (found == null || (dir < 0 ? pos > found : pos < found))) + found = pos; + } + if (found != null) + cm.setCursor(found, 0); + else + return CodeMirror.Pass; + } + + CodeMirror.commands.goNextDiff = function(cm) { + return goNearbyDiff(cm, 1); + }; + CodeMirror.commands.goPrevDiff = function(cm) { + return goNearbyDiff(cm, -1); + }; +}); diff --git a/public/react/public/js/monaco/vs/base/worker/workerMain.js b/public/react/public/js/monaco/vs/base/worker/workerMain.js new file mode 100755 index 000000000..9644d3dec --- /dev/null +++ b/public/react/public/js/monaco/vs/base/worker/workerMain.js @@ -0,0 +1,140 @@ +/*!----------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Version: 0.14.6(6c8f02b41db9ae5c4d15df767d47755e5c73b9d5) + * Released under the MIT license + * https://github.com/Microsoft/vscode/blob/master/LICENSE.txt + *-----------------------------------------------------------*/ +(function(){var e=["exports","require","vs/editor/common/core/position","vs/base/common/winjs.base","vs/base/common/platform","vs/editor/common/core/uint","vs/base/common/errors","vs/editor/common/core/range","vs/base/common/lifecycle","vs/base/common/cancellation","vs/base/common/event","vs/base/common/uri","vs/base/common/diff/diff","vs/base/common/async","vs/base/common/strings","vs/base/common/keyCodes","vs/editor/common/model/mirrorTextModel","vs/base/common/diff/diffChange","vs/base/common/linkedList","vs/editor/common/core/selection","vs/editor/common/core/token","vs/base/common/functional","vs/editor/common/core/characterClassifier","vs/editor/common/diff/diffComputer","vs/editor/common/model/wordHelper","vs/editor/common/modes/linkComputer","vs/editor/common/modes/supports/inplaceReplaceSupport","vs/editor/common/standalone/standaloneBase","vs/editor/common/viewModel/prefixSumComputer","vs/base/common/worker/simpleWorker","vs/editor/common/services/editorSimpleWorker"],t=function(t){ +for(var n=[],r=0,i=t.length;r=0)||"undefined"!=typeof process&&"win32"===process.platform},t}();e.Environment=t}(i||(i={}));!function(e){var t=function(){return function(e,t,n){this.type=e,this.detail=t,this.timestamp=n}}();e.LoaderEvent=t;var n=function(){function n(e){this._events=[new t(1,"",e)]}return n.prototype.record=function(n,r){this._events.push(new t(n,r,e.Utilities.getHighPerformanceTimestamp()))},n.prototype.getEvents=function(){return this._events},n}();e.LoaderEventRecorder=n;var r=function(){function e(){}return e.prototype.record=function(e,t){},e.prototype.getEvents=function(){return[]},e.INSTANCE=new e,e}();e.NullLoaderEventRecorder=r}(i||(i={}));!function(e){var t=function(){function t(){} +return t.fileUriToFilePath=function(e,t){if(t=decodeURI(t),e){if(/^file:\/\/\//.test(t))return t.substr(8);if(/^file:\/\//.test(t))return t.substr(5)}else if(/^file:\/\//.test(t))return t.substr(7);return t},t.startsWith=function(e,t){return e.length>=t.length&&e.substr(0,t.length)===t},t.endsWith=function(e,t){return e.length>=t.length&&e.substr(e.length-t.length)===t},t.containsQueryString=function(e){return/^[^\#]*\?/gi.test(e)},t.isAbsolutePath=function(e){return/^((http:\/\/)|(https:\/\/)|(file:\/\/)|(\/))/.test(e)},t.forEachProperty=function(e,t){if(e){var n=void 0;for(n in e)e.hasOwnProperty(n)&&t(n,e[n])}},t.isEmpty=function(e){var n=!0;return t.forEachProperty(e,function(){n=!1}),n},t.recursiveClone=function(e){if(!e||"object"!=typeof e)return e;var n=Array.isArray(e)?[]:{};return t.forEachProperty(e,function(e,r){n[e]=r&&"object"==typeof r?t.recursiveClone(r):r}),n},t.generateAnonymousModule=function(){return"===anonymous"+t.NEXT_ANONYMOUS_ID+++"==="},t.isAnonymousModule=function(e){ +return t.startsWith(e,"===anonymous")},t.getHighPerformanceTimestamp=function(){return this.PERFORMANCE_NOW_PROBED||(this.PERFORMANCE_NOW_PROBED=!0,this.HAS_PERFORMANCE_NOW=e.global.performance&&"function"==typeof e.global.performance.now),this.HAS_PERFORMANCE_NOW?e.global.performance.now():Date.now()},t.NEXT_ANONYMOUS_ID=1,t.PERFORMANCE_NOW_PROBED=!1,t.HAS_PERFORMANCE_NOW=!1,t}();e.Utilities=t}(i||(i={}));!function(e){var t=function(){function t(){}return t.validateConfigurationOptions=function(t){function n(e){return"load"===e.errorCode?(console.error('Loading "'+e.moduleId+'" failed'),console.error("Detail: ",e.detail),e.detail&&e.detail.stack&&console.error(e.detail.stack),console.error("Here are the modules that depend on it:"),void console.error(e.neededBy)):"factory"===e.errorCode?(console.error('The factory method of "'+e.moduleId+'" has thrown an exception'),console.error(e.detail),void(e.detail&&e.detail.stack&&console.error(e.detail.stack))):void 0} +return"string"!=typeof(t=t||{}).baseUrl&&(t.baseUrl=""),"boolean"!=typeof t.isBuild&&(t.isBuild=!1),"object"!=typeof t.paths&&(t.paths={}),"object"!=typeof t.config&&(t.config={}),void 0===t.catchError&&(t.catchError=!1),"string"!=typeof t.urlArgs&&(t.urlArgs=""),"function"!=typeof t.onError&&(t.onError=n),"object"==typeof t.ignoreDuplicateModules&&Array.isArray(t.ignoreDuplicateModules)||(t.ignoreDuplicateModules=[]),t.baseUrl.length>0&&(e.Utilities.endsWith(t.baseUrl,"/")||(t.baseUrl+="/")),Array.isArray(t.nodeModules)||(t.nodeModules=[]),("number"!=typeof t.nodeCachedDataWriteDelay||t.nodeCachedDataWriteDelay<0)&&(t.nodeCachedDataWriteDelay=7e3),"function"!=typeof t.onNodeCachedData&&(t.onNodeCachedData=function(e,t){e&&("cachedDataRejected"===e.errorCode?console.warn("Rejected cached data from file: "+e.path):"unlink"===e.errorCode||"writeFile"===e.errorCode?(console.error("Problems writing cached data file: "+e.path),console.error(e.detail)):console.error(e))}),t}, +t.mergeConfigurationOptions=function(n,r){void 0===n&&(n=null),void 0===r&&(r=null);var i=e.Utilities.recursiveClone(r||{});return e.Utilities.forEachProperty(n,function(t,n){"ignoreDuplicateModules"===t&&void 0!==i.ignoreDuplicateModules?i.ignoreDuplicateModules=i.ignoreDuplicateModules.concat(n):"paths"===t&&void 0!==i.paths?e.Utilities.forEachProperty(n,function(e,t){return i.paths[e]=t}):"config"===t&&void 0!==i.config?e.Utilities.forEachProperty(n,function(e,t){return i.config[e]=t}):i[t]=e.Utilities.recursiveClone(n)}),t.validateConfigurationOptions(i)},t}();e.ConfigurationOptionsUtil=t;var n=function(){function n(e,n){if(this._env=e,this.options=t.mergeConfigurationOptions(n),this._createIgnoreDuplicateModulesMap(),this._createNodeModulesMap(),this._createSortedPathsRules(),""===this.options.baseUrl){if(this.options.nodeRequire&&this.options.nodeRequire.main&&this.options.nodeRequire.main.filename&&this._env.isNode){ +var r=this.options.nodeRequire.main.filename,i=Math.max(r.lastIndexOf("/"),r.lastIndexOf("\\"));this.options.baseUrl=r.substring(0,i+1)}if(this.options.nodeMain&&this._env.isNode){var r=this.options.nodeMain,i=Math.max(r.lastIndexOf("/"),r.lastIndexOf("\\"));this.options.baseUrl=r.substring(0,i+1)}}}return n.prototype._createIgnoreDuplicateModulesMap=function(){this.ignoreDuplicateModulesMap={};for(var e=0;e=0){var r=t.resolveModule(e.substr(0,n)),s=t.resolveModule(e.substr(n+1)),u=this._moduleIdProvider.getModuleId(r+"!"+s),a=this._moduleIdProvider.getModuleId(r);return new o(u,a,s)}return new i(this._moduleIdProvider.getModuleId(t.resolveModule(e)))},s.prototype._normalizeDependencies=function(e,t){for(var n=[],r=0,i=0,o=e.length;i0;){var a=u.shift(),l=this._modules2[a];l&&(s=l.onDependencyError(n)||s);var c=this._inverseDependencies2[a];if(c)for(var i=0,o=c.length;i0;){var u=s.shift().dependencies;if(u)for(var i=0,o=u.length;i=r.length)t._onLoadError(e,n);else{var s=r[i],u=t.getRecorder();if(t._config.isBuild()&&"empty:"===s)return t._buildInfoPath[e]=s,t.defineModule(t._moduleIdProvider.getStrModuleId(e),[],null,null,null),void t._onLoad(e);u.record(10,s),t._scriptLoader.load(t,s,function(){t._config.isBuild()&&(t._buildInfoPath[e]=s),u.record(11,s),t._onLoad(e)},function(e){u.record(12,s),o(e)})}};o(null)}},s.prototype._loadPluginDependency=function(e,n){var r=this +;if(!this._modules2[n.id]&&!this._knownModules2[n.id]){this._knownModules2[n.id]=!0;var i=function(e){r.defineModule(r._moduleIdProvider.getStrModuleId(n.id),[],e,null,null)};i.error=function(e){r._config.onError(r._createLoadError(n.id,e))},e.load(n.pluginParam,this._createRequire(t.ROOT),i,this._config.getOptionsLiteral())}},s.prototype._resolve=function(e){for(var t=this,n=e.dependencies,r=0,s=n.length;r \n")),e.unresolvedDependenciesCount-- +}else if(this._inverseDependencies2[u.id]=this._inverseDependencies2[u.id]||[],this._inverseDependencies2[u.id].push(e.id),u instanceof o){var c=this._modules2[u.pluginId];if(c&&c.isComplete()){this._loadPluginDependency(c.exports,u);continue}var d=this._inversePluginDependencies2.get(u.pluginId);d||(d=[],this._inversePluginDependencies2.set(u.pluginId,d)),d.push(u),this._loadModule(u.pluginId)}else this._loadModule(u.id)}else e.unresolvedDependenciesCount--;else e.unresolvedDependenciesCount--;else e.exportsPassedIn=!0,e.unresolvedDependenciesCount--}0===e.unresolvedDependenciesCount&&this._onModuleComplete(e)},s.prototype._onModuleComplete=function(e){var t=this,n=this.getRecorder();if(!e.isComplete()){for(var r=e.dependencies,o=[],s=0,u=r.length;s0||this.m_modifiedCount>0)&&this.m_changes.push(new n.DiffChange(this.m_originalStart,this.m_originalCount,this.m_modifiedStart,this.m_modifiedCount)),this.m_originalCount=0,this.m_modifiedCount=0,this.m_originalStart=Number.MAX_VALUE,this.m_modifiedStart=Number.MAX_VALUE},e.prototype.AddOriginalElement=function(e,t){this.m_originalStart=Math.min(this.m_originalStart,e),this.m_modifiedStart=Math.min(this.m_modifiedStart,t),this.m_originalCount++},e.prototype.AddModifiedElement=function(e,t){ +this.m_originalStart=Math.min(this.m_originalStart,e),this.m_modifiedStart=Math.min(this.m_modifiedStart,t),this.m_modifiedCount++},e.prototype.getChanges=function(){return(this.m_originalCount>0||this.m_modifiedCount>0)&&this.MarkNextChange(),this.m_changes},e.prototype.getReverseChanges=function(){return(this.m_originalCount>0||this.m_modifiedCount>0)&&this.MarkNextChange(),this.m_changes.reverse(),this.m_changes},e}(),u=function(){function e(e,t,n){void 0===n&&(n=null),this.OriginalSequence=e,this.ModifiedSequence=t,this.ContinueProcessingPredicate=n,this.m_forwardHistory=[],this.m_reverseHistory=[]}return e.prototype.ElementsAreEqual=function(e,t){return this.OriginalSequence.getElementAtIndex(e)===this.ModifiedSequence.getElementAtIndex(t)},e.prototype.OriginalElementsAreEqual=function(e,t){return this.OriginalSequence.getElementAtIndex(e)===this.OriginalSequence.getElementAtIndex(t)},e.prototype.ModifiedElementsAreEqual=function(e,t){ +return this.ModifiedSequence.getElementAtIndex(e)===this.ModifiedSequence.getElementAtIndex(t)},e.prototype.ComputeDiff=function(e){return this._ComputeDiff(0,this.OriginalSequence.getLength()-1,0,this.ModifiedSequence.getLength()-1,e)},e.prototype._ComputeDiff=function(e,t,n,r,i){var o=this.ComputeDiffRecursive(e,t,n,r,[!1]);return i?this.ShiftChanges(o):o},e.prototype.ComputeDiffRecursive=function(e,t,r,o,s){for(s[0]=!1;e<=t&&r<=o&&this.ElementsAreEqual(e,r);)e++,r++;for(;t>=e&&o>=r&&this.ElementsAreEqual(t,o);)t--,o--;if(e>t||r>o){var u=void 0;return r<=o?(i.Assert(e===t+1,"originalStart should only be one more than originalEnd"),u=[new n.DiffChange(e,0,r,o-r+1)]):e<=t?(i.Assert(r===o+1,"modifiedStart should only be one more than modifiedEnd"),u=[new n.DiffChange(e,t-e+1,r,0)]):(i.Assert(e===t+1,"originalStart should only be one more than originalEnd"),i.Assert(r===o+1,"modifiedStart should only be one more than modifiedEnd"),u=[]),u}var a=[0],l=[0],c=this.ComputeRecursionPoint(e,t,r,o,a,l,s),d=a[0],f=l[0] +;if(null!==c)return c;if(!s[0]){var h=this.ComputeDiffRecursive(e,d,r,f,s),p=[];return p=s[0]?[new n.DiffChange(d+1,t-(d+1)+1,f+1,o-(f+1)+1)]:this.ComputeDiffRecursive(d+1,t,f+1,o,s),this.ConcatenateChanges(h,p)}return[new n.DiffChange(e,t-e+1,r,o-r+1)]},e.prototype.WALKTRACE=function(e,t,r,i,o,u,a,l,c,d,f,h,p,m,g,_,v,y){var b,C=null,S=null,E=new s,L=t,N=r,P=p[0]-_[0]-i,A=Number.MIN_VALUE,M=this.m_forwardHistory.length-1;do{(b=P+e)===L||b=0&&(e=(c=this.m_forwardHistory[M])[0],L=1,N=c.length-1)}while(--M>=-1);if(C=E.getReverseChanges(),y[0]){var w=p[0]+1,D=_[0]+1;if(null!==C&&C.length>0){var I=C[C.length-1];w=Math.max(w,I.getOriginalEnd()),D=Math.max(D,I.getModifiedEnd())}S=[new n.DiffChange(w,h-w+1,D,g-D+1)]}else{E=new s,L=u,N=a,P=p[0]-_[0]-l,A=Number.MAX_VALUE, +M=v?this.m_reverseHistory.length-1:this.m_reverseHistory.length-2;do{(b=P+o)===L||b=d[b+1]?(m=(f=d[b+1]-1)-P-l,f>A&&E.MarkNextChange(),A=f+1,E.AddOriginalElement(f+1,m+1),P=b+1-o):(m=(f=d[b-1])-P-l,f>A&&E.MarkNextChange(),A=f,E.AddModifiedElement(f+1,m+1),P=b-1-o),M>=0&&(o=(d=this.m_reverseHistory[M])[0],L=1,N=d.length-1)}while(--M>=-1);S=E.getChanges()}return this.ConcatenateChanges(C,S)},e.prototype.ComputeRecursionPoint=function(e,t,r,i,s,u,a){var l,c,d,f=0,h=0,p=0,m=0;e--,r--,s[0]=0,u[0]=0,this.m_forwardHistory=[],this.m_reverseHistory=[];var g=t-e+(i-r),_=g+1,v=new Array(_),y=new Array(_),b=i-r,C=t-e,S=e-r,E=t-i,L=(C-b)%2==0;v[b]=e,y[C]=t,a[0]=!1;var N,P;for(d=1;d<=g/2+1;d++){var A=0,M=0;for(f=this.ClipDiagonalBound(b-d,d,b,_),h=this.ClipDiagonalBound(b+d,d,b,_),N=f;N<=h;N+=2){for(c=(l=N===f||NA+M&&(A=l,M=c),!L&&Math.abs(N-C)<=d-1&&l>=y[N])return s[0]=l,u[0]=c, +P<=y[N]&&d<=1448?this.WALKTRACE(b,f,h,S,C,p,m,E,v,y,l,t,s,c,i,u,L,a):null}var w=(A-e+(M-r)-d)/2;if(null!==this.ContinueProcessingPredicate&&!this.ContinueProcessingPredicate(A,this.OriginalSequence,w))return a[0]=!0,s[0]=A,u[0]=M,w>0&&d<=1448?this.WALKTRACE(b,f,h,S,C,p,m,E,v,y,l,t,s,c,i,u,L,a):(e++,r++,[new n.DiffChange(e,t-e+1,r,i-r+1)]);for(p=this.ClipDiagonalBound(C-d,d,C,_),m=this.ClipDiagonalBound(C+d,d,C,_),N=p;N<=m;N+=2){for(c=(l=N===p||N=y[N+1]?y[N+1]-1:y[N-1])-(N-C)-E,P=l;l>e&&c>r&&this.ElementsAreEqual(l,c);)l--,c--;if(y[N]=l,L&&Math.abs(N-b)<=d&&l<=v[N])return s[0]=l,u[0]=c,P>=v[N]&&d<=1448?this.WALKTRACE(b,f,h,S,C,p,m,E,v,y,l,t,s,c,i,u,L,a):null}if(d<=1447){var D=new Array(h-f+2);D[0]=b-f+1,o.Copy(v,f,D,1,h-f+1),this.m_forwardHistory.push(D),(D=new Array(m-p+2))[0]=C-p+1,o.Copy(y,p,D,1,m-p+1),this.m_reverseHistory.push(D)}}return this.WALKTRACE(b,f,h,S,C,p,m,E,v,y,l,t,s,c,i,u,L,a)},e.prototype.ShiftChanges=function(e){var t;do{t=!1 +;for(l=0;l0,s=n.modifiedLength>0;n.originalStart+n.originalLength=0;l--){var n=e[l],r=0,i=0;if(l>0){var c=e[l-1];c.originalLength>0&&(r=c.originalStart+c.originalLength),c.modifiedLength>0&&(i=c.modifiedStart+c.modifiedLength)}for(var o=n.originalLength>0,s=n.modifiedLength>0,d=0,f=this._boundaryScore(n.originalStart,n.originalLength,n.modifiedStart,n.modifiedLength),h=1;;h++){ +var p=n.originalStart-h,m=n.modifiedStart-h;if(pf&&(f=g,d=h)}n.originalStart-=d,n.modifiedStart-=d}return e},e.prototype._OriginalIsBoundary=function(e){if(e<=0||e>=this.OriginalSequence.getLength()-1)return!0;var t=this.OriginalSequence.getElementAtIndex(e);return"string"==typeof t&&/^\s*$/.test(t)},e.prototype._OriginalRegionIsBoundary=function(e,t){if(this._OriginalIsBoundary(e)||this._OriginalIsBoundary(e-1))return!0;if(t>0){var n=e+t;if(this._OriginalIsBoundary(n-1)||this._OriginalIsBoundary(n))return!0}return!1},e.prototype._ModifiedIsBoundary=function(e){if(e<=0||e>=this.ModifiedSequence.getLength()-1)return!0;var t=this.ModifiedSequence.getElementAtIndex(e);return"string"==typeof t&&/^\s*$/.test(t)},e.prototype._ModifiedRegionIsBoundary=function(e,t){ +if(this._ModifiedIsBoundary(e)||this._ModifiedIsBoundary(e-1))return!0;if(t>0){var n=e+t;if(this._ModifiedIsBoundary(n-1)||this._ModifiedIsBoundary(n))return!0}return!1},e.prototype._boundaryScore=function(e,t,n,r){return(this._OriginalRegionIsBoundary(e,t)?1:0)+(this._ModifiedRegionIsBoundary(n,r)?1:0)},e.prototype.ConcatenateChanges=function(e,t){var n=[],r=null;return 0===e.length||0===t.length?t.length>0?t:e:this.ChangesOverlap(e[e.length-1],t[0],n)?(r=new Array(e.length+t.length-1),o.Copy(e,0,r,0,e.length-1),r[e.length-1]=n[0],o.Copy(t,1,r,e.length,t.length-1),r):(r=new Array(e.length+t.length),o.Copy(e,0,r,0,e.length),o.Copy(t,0,r,e.length,t.length),r)},e.prototype.ChangesOverlap=function(e,t,r){if(i.Assert(e.originalStart<=t.originalStart,"Left change is not less than or equal to right change"),i.Assert(e.modifiedStart<=t.modifiedStart,"Left change is not less than or equal to right change"),e.originalStart+e.originalLength>=t.originalStart||e.modifiedStart+e.modifiedLength>=t.modifiedStart){ +var o=e.originalStart,s=e.originalLength,u=e.modifiedStart,a=e.modifiedLength;return e.originalStart+e.originalLength>=t.originalStart&&(s=t.originalStart+t.originalLength-e.originalStart),e.modifiedStart+e.modifiedLength>=t.modifiedStart&&(a=t.modifiedStart+t.modifiedLength-e.modifiedStart),r[0]=new n.DiffChange(o,s,u,a),!0}return r[0]=null,!1},e.prototype.ClipDiagonalBound=function(e,t,n,r){if(e>=0&&e>>0)>>>0},t.createKeybinding=function(e,t){if(0===e)return null;var r=(65535&e)>>>0,i=(4294901760&e)>>>16;return 0!==i?new a(n(r,t),n(i,t)):n(r,t)},t.createSimpleKeybinding=n;var u=function(){function e(e,t,n,r,i){this.type=1,this.ctrlKey=e,this.shiftKey=t,this.altKey=n,this.metaKey=r,this.keyCode=i}return e.prototype.equals=function(e){return 1===e.type&&(this.ctrlKey===e.ctrlKey&&this.shiftKey===e.shiftKey&&this.altKey===e.altKey&&this.metaKey===e.metaKey&&this.keyCode===e.keyCode)},e.prototype.isModifierKey=function(){return 0===this.keyCode||5===this.keyCode||57===this.keyCode||6===this.keyCode||4===this.keyCode}, +e.prototype.isDuplicateModifierCase=function(){return this.ctrlKey&&5===this.keyCode||this.shiftKey&&4===this.keyCode||this.altKey&&6===this.keyCode||this.metaKey&&57===this.keyCode},e}();t.SimpleKeybinding=u;var a=function(){return function(e,t){this.type=2,this.firstPart=e,this.chordPart=t}}();t.ChordKeybinding=a;var l=function(){return function(e,t,n,r,i,o){this.ctrlKey=e,this.shiftKey=t,this.altKey=n,this.metaKey=r,this.keyLabel=i,this.keyAriaLabel=o}}();t.ResolvedKeybindingPart=l;var c=function(){return function(){}}();t.ResolvedKeybinding=c}),r(e[8],t([1,0]),function(e,t){"use strict";function n(e){for(var t=[],r=1;r=0,r=c.indexOf("Macintosh")>=0,i=c.indexOf("Linux")>=0,s=!0,navigator.language}var d;!function(e){e[e.Web=0]="Web",e[e.Mac=1]="Mac",e[e.Linux=2]="Linux",e[e.Windows=3]="Windows"}(d=t.Platform||(t.Platform={}));t.isWindows=n,t.isMacintosh=r,t.isLinux=i,t.isNative=o,t.isWeb=s;var f="object"==typeof self?self:"object"==typeof global?global:{};t.globals=f;var h=null;t.setImmediate=function(e){return null===h&&(h=t.globals.setImmediate?t.globals.setImmediate.bind(t.globals):"undefined"!=typeof process&&"function"==typeof process.nextTick?process.nextTick.bind(process):t.globals.setTimeout.bind(t.globals)),h(e)},t.OS=r?2:n?1:3}),r(e[14],t([1,0]),function(e,t){"use strict";function n(e){return e.replace(/[\-\\\{\}\*\+\?\|\^\$\.\[\]\(\)\#]/g,"\\$&")}function r(e,t){if(!e||!t)return e;var n=t.length +;if(0===n||0===e.length)return e;for(var r=0;e.indexOf(t,r)===r;)r+=n;return e.substring(r)}function i(e,t){if(!e||!t)return e;var n=t.length,r=e.length;if(0===n||0===r)return e;for(var i=r,o=-1;;){if(-1===(o=e.lastIndexOf(t,i-1))||o+n!==i)break;if(0===o)return"";i=o}return e.substring(0,i)}function o(e,t){return et?1:0}function s(e){return e>=97&&e<=122}function u(e){return e>=65&&e<=90}function a(e){return s(e)||u(e)}function l(e,t,n){if(void 0===n&&(n=e.length),"string"!=typeof e||"string"!=typeof t)return!1;for(var r=0;r=11904&&e<=55215||e>=63744&&e<=64255||e>=65281&&e<=65374}Object.defineProperty(t,"__esModule",{value:!0}),t.empty="",t.isFalsyOrWhitespace=function(e){return!e||"string"!=typeof e||0===e.trim().length},t.pad=function(e,t,n){ +void 0===n&&(n="0");for(var r=""+e,i=[r],o=r.length;o=t.length?e:t[r]})},t.escape=function(e){return e.replace(/[<|>|&]/g,function(e){switch(e){case"<":return"<";case">":return">";case"&":return"&";default:return e}})},t.escapeRegExpCharacters=n,t.trim=function(e,t){return void 0===t&&(t=" "),i(r(e,t),t)},t.ltrim=r,t.rtrim=i,t.convertSimple2RegExpPattern=function(e){return e.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g,"\\$&").replace(/[\*]/g,".*")},t.startsWith=function(e,t){if(e.length0?e.indexOf(t,n)===n:0===n&&e===t},t.createRegExp=function(e,t,r){if(void 0===r&&(r={}), +!e)throw new Error("Cannot create regex from empty string");t||(e=n(e)),r.wholeWord&&(/\B/.test(e.charAt(0))||(e="\\b"+e),/\B/.test(e.charAt(e.length-1))||(e+="\\b"));var i="";return r.global&&(i+="g"),r.matchCase||(i+="i"),r.multiline&&(i+="m"),new RegExp(e,i)},t.regExpLeadsToEndlessLoop=function(e){return"^"!==e.source&&"^$"!==e.source&&"$"!==e.source&&"^\\s*$"!==e.source&&e.exec("")&&0===e.lastIndex},t.firstNonWhitespaceIndex=function(e){for(var t=0,n=e.length;t=0;n--){var r=e.charCodeAt(n);if(32!==r&&9!==r)return n}return-1},t.compare=o,t.compareIgnoreCase=function(e,t){for(var n=Math.min(e.length,t.length),r=0;rt.length?1:0},t.isLowerAsciiLetter=s,t.isUpperAsciiLetter=u,t.equalsIgnoreCase=function(e,t){return(e?e.length:0)===(t?t.length:0)&&l(e,t)},t.startsWithIgnoreCase=function(e,t){var n=t.length;return!(t.length>e.length)&&l(e,t,n)},t.commonPrefixLength=function(e,t){var n,r=Math.min(e.length,t.length);for(n=0;n0&&65279===e.charCodeAt(0)},t.safeBtoa=function(e){return btoa(encodeURIComponent(e))},t.repeat=function(e,t){for(var n="",r=0;r=97&&o<=122||o>=65&&o<=90||o>=48&&o<=57||45===o||46===o||95===o||126===o||t&&47===o)-1!==r&&(n+=encodeURIComponent(e.substring(r,i)),r=-1),void 0!==n&&(n+=e.charAt(i));else{void 0===n&&(n=e.substr(0,i));var s=g[o];void 0!==s?(-1!==r&&(n+=encodeURIComponent(e.substring(r,i)),r=-1),n+=s):-1===r&&(r=i)}}return-1!==r&&(n+=encodeURIComponent(e.substring(r))), +void 0!==n?n:e}function i(e){var t;return t=e.authority&&e.path.length>1&&"file"===e.scheme?"//"+e.authority+e.path:47===e.path.charCodeAt(0)&&(e.path.charCodeAt(1)>=65&&e.path.charCodeAt(1)<=90||e.path.charCodeAt(1)>=97&&e.path.charCodeAt(1)<=122)&&58===e.path.charCodeAt(2)?e.path[1].toLowerCase()+e.path.substr(2):e.path,n.isWindows&&(t=t.replace(/\//g,"\\")),t}function s(e,t){var n=t?function(e){for(var t=void 0,n=0;n=3&&47===u.charCodeAt(0)&&58===u.charCodeAt(2)){ +(h=u.charCodeAt(1))>=65&&h<=90&&(u="/"+String.fromCharCode(h+32)+":"+u.substr(3))}else if(u.length>=2&&58===u.charCodeAt(1)){var h=u.charCodeAt(0);h>=65&&h<=90&&(u=String.fromCharCode(h+32)+":"+u.substr(2))}i+=n(u,!0)}return a&&(i+="?",i+=n(a,!1)),l&&(i+="#",i+=t?l:r(l,!1)),i}Object.defineProperty(t,"__esModule",{value:!0});var u,a=/^\w[\w\d+.-]*$/,l=/^\//,c=/^\/\//,d="",f="/",h=/^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/,p=function(){function e(e,t,n,r,i){"object"==typeof e?(this.scheme=e.scheme||d,this.authority=e.authority||d,this.path=e.path||d,this.query=e.query||d,this.fragment=e.fragment||d):(this.scheme=e||d,this.authority=t||d,this.path=function(e,t){switch(e){case"https":case"http":case"file":t?t[0]!==f&&(t=f+t):t=f}return t}(this.scheme,n||d),this.query=r||d,this.fragment=i||d,function(e){if(e.scheme&&!a.test(e.scheme))throw new Error("[UriError]: Scheme contains illegal characters.");if(e.path)if(e.authority){ +if(!l.test(e.path))throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character')}else if(c.test(e.path))throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")')}(this))}return e.isUri=function(t){return t instanceof e||!!t&&("string"==typeof t.authority&&"string"==typeof t.fragment&&"string"==typeof t.path&&"string"==typeof t.query&&"string"==typeof t.scheme)},Object.defineProperty(e.prototype,"fsPath",{get:function(){return i(this)},enumerable:!0,configurable:!0}),e.prototype.with=function(e){if(!e)return this;var t=e.scheme,n=e.authority,r=e.path,i=e.query,o=e.fragment;return void 0===t?t=this.scheme:null===t&&(t=d),void 0===n?n=this.authority:null===n&&(n=d),void 0===r?r=this.path:null===r&&(r=d),void 0===i?i=this.query:null===i&&(i=d),void 0===o?o=this.fragment:null===o&&(o=d), +t===this.scheme&&n===this.authority&&r===this.path&&i===this.query&&o===this.fragment?this:new m(t,n,r,i,o)},e.parse=function(e){var t=h.exec(e);return t?new m(t[2]||d,decodeURIComponent(t[4]||d),decodeURIComponent(t[5]||d),decodeURIComponent(t[7]||d),decodeURIComponent(t[9]||d)):new m(d,d,d,d,d)},e.file=function(e){var t=d;if(n.isWindows&&(e=e.replace(/\\/g,f)),e[0]===f&&e[1]===f){var r=e.indexOf(f,2);-1===r?(t=e.substring(2),e=f):(t=e.substring(2,r),e=e.substring(r)||f)}return new m("file",t,e,d,d)},e.from=function(e){return new m(e.scheme,e.authority,e.path,e.query,e.fragment)},e.prototype.toString=function(e){return void 0===e&&(e=!1),s(this,e)},e.prototype.toJSON=function(){return this},e.revive=function(t){if(t){if(t instanceof e)return t;var n=new m(t);return n._fsPath=t.fsPath,n._formatted=t.external,n}return t},e}();t.default=p;var m=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t._formatted=null,t._fsPath=null,t}return o(t,e), +Object.defineProperty(t.prototype,"fsPath",{get:function(){return this._fsPath||(this._fsPath=i(this)),this._fsPath},enumerable:!0,configurable:!0}),t.prototype.toString=function(e){return void 0===e&&(e=!1),e?s(this,!0):(this._formatted||(this._formatted=s(this,!1)),this._formatted)},t.prototype.toJSON=function(){var e={$mid:1};return this._fsPath&&(e.fsPath=this._fsPath),this._formatted&&(e.external=this._formatted),this.path&&(e.path=this.path),this.scheme&&(e.scheme=this.scheme),this.authority&&(e.authority=this.authority),this.query&&(e.query=this.query),this.fragment&&(e.fragment=this.fragment),e},t}(p),g=(u={},u[58]="%3A",u[47]="%2F",u[63]="%3F",u[35]="%23",u[91]="%5B",u[93]="%5D",u[64]="%40",u[33]="%21",u[36]="%24",u[38]="%26",u[39]="%27",u[40]="%28",u[41]="%29",u[42]="%2A",u[43]="%2B",u[44]="%2C",u[59]="%3B",u[61]="%3D",u[32]="%20",u)});var s;!function(){var e=Object.create(null);e["WinJS/Core/_WinJS"]={};var t=function(t,n,r){var i={},o=!1,s=n.map(function(t){return"exports"===t?(o=!0,i):e[t] +}),u=r.apply({},s);e[t]=o?i:u};t("WinJS/Core/_Global",[],function(){"use strict";return"undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{}}),t("WinJS/Core/_BaseCoreUtils",["WinJS/Core/_Global"],function(e){"use strict";var t=null;return{hasWinRT:!!e.Windows,markSupportedForProcessing:function(e){return e.supportedForProcessing=!0,e},_setImmediate:function(n){null===t&&(t=e.setImmediate?e.setImmediate.bind(e):"undefined"!=typeof process&&"function"==typeof process.nextTick?process.nextTick.bind(process):e.setTimeout.bind(e)),t(n)}}}),t("WinJS/Core/_WriteProfilerMark",["WinJS/Core/_Global"],function(e){"use strict";return e.msWriteProfilerMark||function(){}}),t("WinJS/Core/_Base",["WinJS/Core/_WinJS","WinJS/Core/_Global","WinJS/Core/_BaseCoreUtils","WinJS/Core/_WriteProfilerMark"],function(e,t,n,r){"use strict";function i(e,t,n){var r,i,o,s=Object.keys(t),u=Array.isArray(e);for(i=0,o=s.length;i"),o}var s=e;s.Namespace||(s.Namespace=Object.create(Object.prototype));var u={uninitialized:1,working:2,initialized:3};Object.defineProperties(s.Namespace,{defineWithParent:{value:o,writable:!0,enumerable:!0,configurable:!0},define:{value:function(e,n){return o(t,e,n)},writable:!0, +enumerable:!0,configurable:!0},_lazy:{value:function(e){var t,n,i=u.uninitialized;return{setName:function(e){t=e},get:function(){switch(i){case u.initialized:return n;case u.uninitialized:i=u.working;try{r("WinJS.Namespace._lazy:"+t+",StartTM"),n=e()}finally{r("WinJS.Namespace._lazy:"+t+",StopTM"),i=u.uninitialized}return e=null,i=u.initialized,n;case u.working:throw"Illegal: reentrancy on initialization";default:throw"Illegal"}},set:function(e){switch(i){case u.working:throw"Illegal: reentrancy on initialization";default:i=u.initialized,n=e}},enumerable:!0,configurable:!0}},writable:!0,enumerable:!0,configurable:!0},_moduleDefine:{value:function(e,r,o){var s=[e],u=null;return r&&(u=n(t,r),s.push(u)),i(s,o,r||""),u},writable:!0,enumerable:!0,configurable:!0}})}(),function(){function t(e,t,r){return e=e||function(){},n.markSupportedForProcessing(e),t&&i(e.prototype,t),r&&i(e,r),e}e.Namespace.define("WinJS.Class",{define:t,derive:function(e,r,o,s){if(e){r=r||function(){};var u=e.prototype +;return r.prototype=Object.create(u),n.markSupportedForProcessing(r),Object.defineProperty(r.prototype,"constructor",{value:r,writable:!0,configurable:!0,enumerable:!0}),o&&i(r.prototype,o),s&&i(r,s),r}return t(r,o,s)},mix:function(e){e=e||function(){};var t,n;for(t=1,n=arguments.length;t0;){var i=this._deliveryQueue.shift(),o=i[0],s=i[1];try{"function"==typeof o?o.call(void 0,s):o[0].call(o[1],s)}catch(r){n.onUnexpectedError(r)}}}},e.prototype.dispose=function(){this._listeners&&(this._listeners=void 0),this._deliveryQueue&&(this._deliveryQueue.length=0),this._disposed=!0},e._noop=function(){},e}();t.Emitter=a;var l=function(){function e(){var e=this;this.hasListeners=!1,this.events=[],this.emitter=new a({onFirstListenerAdd:function(){ +return e.onFirstListenerAdd()},onLastListenerRemove:function(){return e.onLastListenerRemove()}})}return Object.defineProperty(e.prototype,"event",{get:function(){return this.emitter.event},enumerable:!0,configurable:!0}),e.prototype.add=function(e){var t=this,n={event:e,listener:null};this.events.push(n),this.hasListeners&&this.hook(n);return i.toDisposable(r.once(function(){t.hasListeners&&t.unhook(n);var e=t.events.indexOf(n);t.events.splice(e,1)}))},e.prototype.onFirstListenerAdd=function(){var e=this;this.hasListeners=!0,this.events.forEach(function(t){return e.hook(t)})},e.prototype.onLastListenerRemove=function(){var e=this;this.hasListeners=!1,this.events.forEach(function(t){return e.unhook(t)})},e.prototype.hook=function(e){var t=this;e.listener=e.event(function(e){return t.emitter.fire(e)})},e.prototype.unhook=function(e){e.listener.dispose(),e.listener=null},e.prototype.dispose=function(){this.emitter.dispose()},e}();t.EventMultiplexer=l,t.once=function(e){return function(t,n,r){ +void 0===n&&(n=null);var i=e(function(e){return i.dispose(),t.call(n,e)},null,r);return i}},t.anyEvent=function(){for(var e=[],t=0;t1)&&l.fire(e),u=0},n)})},onLastListenerRemove:function(){i.dispose()}});return l.event};var c=function(){function e(){this.buffers=[]}return e.prototype.wrapEvent=function(e){var t=this;return function(n,r,i){return e(function(e){var i=t.buffers[t.buffers.length-1];i?i.push(function(){return n.call(r,e)}):n.call(r,e)},void 0,i)}},e.prototype.bufferEvents=function(e){var t=[];this.buffers.push(t),e(),this.buffers.pop(),t.forEach(function(e){ +return e()})},e}();t.EventBufferer=c,t.mapEvent=s,t.filterEvent=u;var d=function(){function e(e){this._event=e}return Object.defineProperty(e.prototype,"event",{get:function(){return this._event},enumerable:!0,configurable:!0}),e.prototype.map=function(t){return new e(s(this._event,t))},e.prototype.filter=function(t){return new e(u(this._event,t))},e.prototype.on=function(e,t,n){return this._event(e,t,n)},e}();t.chain=function(e){return new d(e)};var f=function(){function e(){this.emitter=new a,this.event=this.emitter.event,this.disposable=i.Disposable.None}return Object.defineProperty(e.prototype,"input",{set:function(e){this.disposable.dispose(),this.disposable=e(this.emitter.fire,this.emitter)},enumerable:!0,configurable:!0}),e.prototype.dispose=function(){this.disposable.dispose(),this.emitter.dispose()},e}();t.Relay=f}),r(e[9],t([1,0,10]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r,i=Object.freeze(function(e,t){var n=setTimeout(e.bind(t),0);return{ +dispose:function(){clearTimeout(n)}}});!function(e){e.None=Object.freeze({isCancellationRequested:!1,onCancellationRequested:n.Event.None}),e.Cancelled=Object.freeze({isCancellationRequested:!0,onCancellationRequested:i})}(r=t.CancellationToken||(t.CancellationToken={}));var o=function(){function e(){this._isCancelled=!1}return e.prototype.cancel=function(){this._isCancelled||(this._isCancelled=!0,this._emitter&&(this._emitter.fire(void 0),this.dispose()))},Object.defineProperty(e.prototype,"isCancellationRequested",{get:function(){return this._isCancelled},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onCancellationRequested",{get:function(){return this._isCancelled?i:(this._emitter||(this._emitter=new n.Emitter),this._emitter.event)},enumerable:!0,configurable:!0}),e.prototype.dispose=function(){this._emitter&&(this._emitter.dispose(),this._emitter=void 0)},e}(),s=function(){function e(){}return Object.defineProperty(e.prototype,"token",{get:function(){ +return this._token||(this._token=new o),this._token},enumerable:!0,configurable:!0}),e.prototype.cancel=function(){this._token?this._token instanceof o&&this._token.cancel():this._token=r.Cancelled},e.prototype.dispose=function(){this._token?this._token instanceof o&&this._token.dispose():this._token=r.None},e}();t.CancellationTokenSource=s}),r(e[13],t([1,0,6,3,9,8]),function(e,t,n,r,i,s){"use strict";function u(e){return e&&"function"==typeof e.then}function a(e){var t=new i.CancellationTokenSource,r=e(t.token),o=new Promise(function(e,i){t.token.onCancellationRequested(function(){i(n.canceled())}),Promise.resolve(r).then(function(n){t.dispose(),e(n)},function(e){t.dispose(),i(e)})});return new(function(){function e(){}return e.prototype.cancel=function(){t.cancel()},e.prototype.then=function(e,t){return o.then(e,t)},e.prototype.catch=function(e){return this.then(void 0,e)},e}())}function l(e,t){return function(e){return r.TPromise.is(e)&&"function"==typeof e.done}(e)?new r.TPromise(function(r,i,o){ +e.done(function(e){try{t(e)}catch(e){n.onUnexpectedError(e)}r(e)},function(e){try{t(e)}catch(e){n.onUnexpectedError(e)}i(e)},function(e){o(e)})},function(){e.cancel()}):(e.then(function(e){return t()},function(e){return t()}),e)}Object.defineProperty(t,"__esModule",{value:!0}),t.isThenable=u,t.toThenable=function(e){return u(e)?e:r.TPromise.as(e)},t.createCancelablePromise=a,t.asWinJsPromise=function(e){var t=new i.CancellationTokenSource;return new r.TPromise(function(n,i,o){var s=e(t.token);s instanceof r.TPromise?s.then(function(e){t.dispose(),n(e)},function(e){t.dispose(),i(e)},o):u(s)?s.then(function(e){t.dispose(),n(e)},function(e){t.dispose(),i(e)}):(t.dispose(),n(s))},function(){t.cancel()})},t.wireCancellationToken=function(e,t,i){var o=e.onCancellationRequested(function(){return t.cancel()});return i&&(t=t.then(void 0,function(e){if(!n.isPromiseCanceledError(e))return r.TPromise.wrapError(e)})),l(t,function(){return o.dispose()})};var c=function(){function e(){this.activePromise=null, +this.queuedPromise=null,this.queuedPromiseFactory=null}return e.prototype.queue=function(e){var t=this;if(this.activePromise){if(this.queuedPromiseFactory=e,!this.queuedPromise){var n=function(){t.queuedPromise=null;var e=t.queue(t.queuedPromiseFactory);return t.queuedPromiseFactory=null,e};this.queuedPromise=new r.TPromise(function(e,r,i){t.activePromise.then(n,n,i).done(e)},function(){t.activePromise.cancel()})}return new r.TPromise(function(e,n,r){t.queuedPromise.then(e,n,r)},function(){})}return this.activePromise=e(),new r.TPromise(function(e,n,r){t.activePromise.done(function(n){t.activePromise=null,e(n)},function(e){t.activePromise=null,n(e)},r)},function(){t.activePromise.cancel()})},e}();t.Throttler=c;var d=function(){function e(e){this.defaultDelay=e,this.timeout=null,this.completionPromise=null,this.onSuccess=null,this.task=null}return e.prototype.trigger=function(e,t){var n=this;return void 0===t&&(t=this.defaultDelay),this.task=e,this.cancelTimeout(), +this.completionPromise||(this.completionPromise=new r.TPromise(function(e){n.onSuccess=e},function(){}).then(function(){n.completionPromise=null,n.onSuccess=null;var e=n.task;return n.task=null,e()})),this.timeout=setTimeout(function(){n.timeout=null,n.onSuccess(null)},t),this.completionPromise},e.prototype.cancel=function(){this.cancelTimeout(),this.completionPromise&&(this.completionPromise.cancel(),this.completionPromise=null)},e.prototype.cancelTimeout=function(){null!==this.timeout&&(clearTimeout(this.timeout),this.timeout=null)},e}();t.Delayer=d;var f=function(e){function t(t){var r,i,o,s=this;return s=e.call(this,function(e,t,n){r=e,i=t,o=n},function(){i(n.canceled())})||this,t.then(r,i,o),s}return o(t,e),t}(r.TPromise);t.ShallowCancelThenPromise=f,t.timeout=function(e){return a(function(t){return new Promise(function(r,i){var o=setTimeout(r,e);t.onCancellationRequested(function(e){clearTimeout(o),i(n.canceled())})})})},t.always=l,t.first2=function(e,t,n){void 0===t&&(t=function(e){return!!e}), +void 0===n&&(n=null);var r=0,i=e.length,o=function(){return r>=i?Promise.resolve(n):(0,e[r++])().then(function(e){return t(e)?Promise.resolve(e):o()})};return o()},t.first=function(e,t,n){void 0===t&&(t=function(e){return!!e}),void 0===n&&(n=null);var i=0,o=e.length,s=function(){return i>=o?r.TPromise.as(n):(0,e[i++])().then(function(e){return t(e)?r.TPromise.as(e):s()})};return s()},t.setDisposableTimeout=function(e,t){for(var n=[],r=2;rn||e===n&&t>r?(this.startLineNumber=n,this.startColumn=r,this.endLineNumber=e,this.endColumn=t):(this.startLineNumber=e,this.startColumn=t,this.endLineNumber=n,this.endColumn=r)} +return e.prototype.isEmpty=function(){return e.isEmpty(this)},e.isEmpty=function(e){return e.startLineNumber===e.endLineNumber&&e.startColumn===e.endColumn},e.prototype.containsPosition=function(t){return e.containsPosition(this,t)},e.containsPosition=function(e,t){return!(t.lineNumbere.endLineNumber)&&(!(t.lineNumber===e.startLineNumber&&t.columne.endColumn))},e.prototype.containsRange=function(t){return e.containsRange(this,t)},e.containsRange=function(e,t){return!(t.startLineNumbere.endLineNumber||t.endLineNumber>e.endLineNumber)&&(!(t.startLineNumber===e.startLineNumber&&t.startColumne.endColumn)))},e.prototype.plusRange=function(t){return e.plusRange(this,t)},e.plusRange=function(t,n){var r,i,o,s;return n.startLineNumbert.endLineNumber?(o=n.endLineNumber,s=n.endColumn):n.endLineNumber===t.endLineNumber?(o=n.endLineNumber,s=Math.max(n.endColumn,t.endColumn)):(o=t.endLineNumber,s=t.endColumn),new e(r,i,o,s)},e.prototype.intersectRanges=function(t){return e.intersectRanges(this,t)},e.intersectRanges=function(t,n){var r=t.startLineNumber,i=t.startColumn,o=t.endLineNumber,s=t.endColumn,u=n.startLineNumber,a=n.startColumn,l=n.endLineNumber,c=n.endColumn;return rl?(o=l,s=c):o===l&&(s=Math.min(s,c)),r>o?null:r===o&&i>s?null:new e(r,i,o,s)},e.prototype.equalsRange=function(t){return e.equalsRange(this,t)},e.equalsRange=function(e,t){return!!e&&!!t&&e.startLineNumber===t.startLineNumber&&e.startColumn===t.startColumn&&e.endLineNumber===t.endLineNumber&&e.endColumn===t.endColumn},e.prototype.getEndPosition=function(){ +return new n.Position(this.endLineNumber,this.endColumn)},e.prototype.getStartPosition=function(){return new n.Position(this.startLineNumber,this.startColumn)},e.prototype.toString=function(){return"["+this.startLineNumber+","+this.startColumn+" -> "+this.endLineNumber+","+this.endColumn+"]"},e.prototype.setEndPosition=function(t,n){return new e(this.startLineNumber,this.startColumn,t,n)},e.prototype.setStartPosition=function(t,n){return new e(t,n,this.endLineNumber,this.endColumn)},e.prototype.collapseToStart=function(){return e.collapseToStart(this)},e.collapseToStart=function(t){return new e(t.startLineNumber,t.startColumn,t.startLineNumber,t.startColumn)},e.fromPositions=function(t,n){return void 0===n&&(n=t),new e(t.lineNumber,t.column,n.lineNumber,n.column)},e.lift=function(t){return t?new e(t.startLineNumber,t.startColumn,t.endLineNumber,t.endColumn):null},e.isIRange=function(e){ +return e&&"number"==typeof e.startLineNumber&&"number"==typeof e.startColumn&&"number"==typeof e.endLineNumber&&"number"==typeof e.endColumn},e.areIntersectingOrTouching=function(e,t){return!(e.endLineNumbere.startLineNumber},e}();t.Range=r}),r(e[19],t([1,0,7,2]),function(e,t,n,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i;!function(e){e[e.LTR=0]="LTR",e[e.RTL=1]="RTL"}(i=t.SelectionDirection||(t.SelectionDirection={}));var s=function(e){function t(t,n,r,i){var o=e.call(this,t,n,r,i)||this;return o.selectionStartLineNumber=t,o.selectionStartColumn=n,o.positionLineNumber=r,o.positionColumn=i,o}return o(t,e),t.prototype.clone=function(){return new t(this.selectionStartLineNumber,this.selectionStartColumn,this.positionLineNumber,this.positionColumn)},t.prototype.toString=function(){return"["+this.selectionStartLineNumber+","+this.selectionStartColumn+" -> "+this.positionLineNumber+","+this.positionColumn+"]"}, +t.prototype.equalsSelection=function(e){return t.selectionsEqual(this,e)},t.selectionsEqual=function(e,t){return e.selectionStartLineNumber===t.selectionStartLineNumber&&e.selectionStartColumn===t.selectionStartColumn&&e.positionLineNumber===t.positionLineNumber&&e.positionColumn===t.positionColumn},t.prototype.getDirection=function(){return this.selectionStartLineNumber===this.startLineNumber&&this.selectionStartColumn===this.startColumn?i.LTR:i.RTL},t.prototype.setEndPosition=function(e,n){return this.getDirection()===i.LTR?new t(this.startLineNumber,this.startColumn,e,n):new t(e,n,this.startLineNumber,this.startColumn)},t.prototype.getPosition=function(){return new r.Position(this.positionLineNumber,this.positionColumn)},t.prototype.setStartPosition=function(e,n){return this.getDirection()===i.LTR?new t(e,n,this.endLineNumber,this.endColumn):new t(this.endLineNumber,this.endColumn,e,n)},t.fromPositions=function(e,n){return void 0===n&&(n=e),new t(e.lineNumber,e.column,n.lineNumber,n.column)}, +t.liftSelection=function(e){return new t(e.selectionStartLineNumber,e.selectionStartColumn,e.positionLineNumber,e.positionColumn)},t.selectionsArrEqual=function(e,t){if(e&&!t||!e&&t)return!1;if(!e&&!t)return!0;if(e.length!==t.length)return!1;for(var n=0,r=e.length;n4294967295?4294967295:0|e}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t,n){for(var r=new Uint8Array(e*t),i=0,o=e*t;i255?255:0|e},t.toUint32=n,t.toUint32Array=function(e){for(var t=e.length,r=new Uint32Array(t),i=0;i=0&&e<256?this._asciiMap[e]=r:this._map.set(e,r)},e.prototype.get=function(e){return e>=0&&e<256?this._asciiMap[e]:this._map.get(e)||this._defaultValue},e}();t.CharacterClassifier=r;var i=function(){function e(){this._actual=new r(0)}return e.prototype.add=function(e){this._actual.set(e,1)},e.prototype.has=function(e){return 1===this._actual.get(e)},e}();t.CharacterSet=i}),r(e[23],t([1,0,12,14]),function(e,t,n,r){"use strict";function i(e,t,r,i){return new n.LcsDiff(e,t,r).ComputeDiff(i)}Object.defineProperty(t,"__esModule",{value:!0});var o=5e3,s=3,u=function(){function e(t){for(var n=[],r=[],i=0,o=t.length;i1&&_>1;){if((S=p.charCodeAt(g-2))!==(E=m.charCodeAt(_-2)))break;g--,_--}(g>1||_>1)&&this._pushTrimWhitespaceCharChange(o,s+1,1,g,a+1,1,_);for(var v=u._getLastNonBlankColumn(p,1),y=u._getLastNonBlankColumn(m,1),b=p.length+1,C=m.length+1;v/?",t.DEFAULT_WORD_REGEXP=function(e){void 0===e&&(e="") +;for(var n="(-?\\d*\\.\\d\\w*)|([^",r=0;r=0||(n+="\\"+t.USUAL_WORD_SEPARATORS[r]);return n+="\\s]+)",new RegExp(n,"g")}(),t.ensureValidWordDefinition=function(e){var n=t.DEFAULT_WORD_REGEXP;if(e&&e instanceof RegExp)if(e.global)n=e;else{var r="g";e.ignoreCase&&(r+="i"),e.multiline&&(r+="m"),n=new RegExp(e.source,r)}return n.lastIndex=0,n},t.getWordAtText=function(e,t,n,r){t.lastIndex=0;var i=t.exec(n);if(!i)return null;var o=i[0].indexOf(" ")>=0?function(e,t,n,r){var i=e-1-r;t.lastIndex=0;for(var o;o=t.exec(n);){if(o.index>i)return null;if(t.lastIndex>=i)return{word:o[0],startColumn:r+1+o.index,endColumn:r+1+t.lastIndex}}return null}(e,t,n,r):function(e,t,n,r){var i=e-1-r,o=n.lastIndexOf(" ",i-1)+1,s=n.indexOf(" ",i);-1===s&&(s=n.length),t.lastIndex=o;for(var u;u=t.exec(n);)if(u.index<=i&&t.lastIndex>=i)return{word:u[0],startColumn:r+1+u.index,endColumn:r+1+t.lastIndex};return null}(e,t,n,r);return t.lastIndex=0,o}}), +r(e[25],t([1,0,22,5]),function(e,t,n,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e){for(var t=0,n=0,i=0,o=e.length;it&&(t=a),u>n&&(n=u),l>n&&(n=l)}t++,n++;for(var c=new r.Uint8Matrix(n,t,0),i=0,o=e.length;i=this._maxCharCode?0:this._states.get(e,t)},e}(),o=null,s=null,u=function(){function e(){}return e._createLink=function(e,t,n,r,i){var o=i-1;do{var s=t.charCodeAt(o);if(2!==e.get(s))break;o--}while(o>r);if(r>0){var u=t.charCodeAt(r-1),a=t.charCodeAt(o);(40===u&&41===a||91===u&&93===a||123===u&&125===a)&&o--}return{range:{startLineNumber:n,startColumn:r+1,endLineNumber:n,endColumn:o+2},url:t.substring(r,o+1)}},e.computeLinks=function(t){ +for(var r=(null===o&&(o=new i([[1,104,2],[1,72,2],[1,102,6],[1,70,6],[2,116,3],[2,84,3],[3,116,4],[3,84,4],[4,112,5],[4,80,5],[5,115,9],[5,83,9],[5,58,10],[6,105,7],[6,73,7],[7,108,8],[7,76,8],[8,101,9],[8,69,9],[9,58,10],[10,47,11],[11,47,12]])),o),u=function(){if(null===s){for(s=new n.CharacterClassifier(0),e=0;e<" \t<>'\"、。。、,.:;?!@#$%&*‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…".length;e++)s.set(" \t<>'\"、。。、,.:;?!@#$%&*‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…".charCodeAt(e),1);for(var e=0;e<".,;".length;e++)s.set(".,;".charCodeAt(e),2)}return s}(),a=[],l=1,c=t.getLineCount();l<=c;l++){for(var d=t.getLineContent(l),f=d.length,h=0,p=0,m=0,g=1,_=!1,v=!1,y=!1;h=0?((r+=n?1:-1)<0?r=e.length-1:r%=e.length,e[r]):null},e.INSTANCE=new e,e}();t.BasicInplaceReplace=n}),r(e[27],t([1,0,10,15,2,7,19,3,9,20,11]),function(e,t,n,r,i,o,s,u,a,l,c){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var d;!function(e){e[e.Unnecessary=1]="Unnecessary"}(d=t.MarkerTag||(t.MarkerTag={}));var f;!function(e){e[e.Hint=1]="Hint",e[e.Info=2]="Info",e[e.Warning=4]="Warning",e[e.Error=8]="Error"}(f=t.MarkerSeverity||(t.MarkerSeverity={}));var h=function(){function e(){}return e.chord=function(e,t){ +return r.KeyChord(e,t)},e.CtrlCmd=2048,e.Shift=1024,e.Alt=512,e.WinCtrl=256,e}();t.KeyMod=h;var p;!function(e){e[e.Unknown=0]="Unknown",e[e.Backspace=1]="Backspace",e[e.Tab=2]="Tab",e[e.Enter=3]="Enter",e[e.Shift=4]="Shift",e[e.Ctrl=5]="Ctrl",e[e.Alt=6]="Alt",e[e.PauseBreak=7]="PauseBreak",e[e.CapsLock=8]="CapsLock",e[e.Escape=9]="Escape",e[e.Space=10]="Space",e[e.PageUp=11]="PageUp",e[e.PageDown=12]="PageDown",e[e.End=13]="End",e[e.Home=14]="Home",e[e.LeftArrow=15]="LeftArrow",e[e.UpArrow=16]="UpArrow",e[e.RightArrow=17]="RightArrow",e[e.DownArrow=18]="DownArrow",e[e.Insert=19]="Insert",e[e.Delete=20]="Delete",e[e.KEY_0=21]="KEY_0",e[e.KEY_1=22]="KEY_1",e[e.KEY_2=23]="KEY_2",e[e.KEY_3=24]="KEY_3",e[e.KEY_4=25]="KEY_4",e[e.KEY_5=26]="KEY_5",e[e.KEY_6=27]="KEY_6",e[e.KEY_7=28]="KEY_7",e[e.KEY_8=29]="KEY_8",e[e.KEY_9=30]="KEY_9",e[e.KEY_A=31]="KEY_A",e[e.KEY_B=32]="KEY_B",e[e.KEY_C=33]="KEY_C",e[e.KEY_D=34]="KEY_D",e[e.KEY_E=35]="KEY_E",e[e.KEY_F=36]="KEY_F",e[e.KEY_G=37]="KEY_G",e[e.KEY_H=38]="KEY_H", +e[e.KEY_I=39]="KEY_I",e[e.KEY_J=40]="KEY_J",e[e.KEY_K=41]="KEY_K",e[e.KEY_L=42]="KEY_L",e[e.KEY_M=43]="KEY_M",e[e.KEY_N=44]="KEY_N",e[e.KEY_O=45]="KEY_O",e[e.KEY_P=46]="KEY_P",e[e.KEY_Q=47]="KEY_Q",e[e.KEY_R=48]="KEY_R",e[e.KEY_S=49]="KEY_S",e[e.KEY_T=50]="KEY_T",e[e.KEY_U=51]="KEY_U",e[e.KEY_V=52]="KEY_V",e[e.KEY_W=53]="KEY_W",e[e.KEY_X=54]="KEY_X",e[e.KEY_Y=55]="KEY_Y",e[e.KEY_Z=56]="KEY_Z",e[e.Meta=57]="Meta",e[e.ContextMenu=58]="ContextMenu",e[e.F1=59]="F1",e[e.F2=60]="F2",e[e.F3=61]="F3",e[e.F4=62]="F4",e[e.F5=63]="F5",e[e.F6=64]="F6",e[e.F7=65]="F7",e[e.F8=66]="F8",e[e.F9=67]="F9",e[e.F10=68]="F10",e[e.F11=69]="F11",e[e.F12=70]="F12",e[e.F13=71]="F13",e[e.F14=72]="F14",e[e.F15=73]="F15",e[e.F16=74]="F16",e[e.F17=75]="F17",e[e.F18=76]="F18",e[e.F19=77]="F19",e[e.NumLock=78]="NumLock",e[e.ScrollLock=79]="ScrollLock",e[e.US_SEMICOLON=80]="US_SEMICOLON",e[e.US_EQUAL=81]="US_EQUAL",e[e.US_COMMA=82]="US_COMMA",e[e.US_MINUS=83]="US_MINUS",e[e.US_DOT=84]="US_DOT",e[e.US_SLASH=85]="US_SLASH", +e[e.US_BACKTICK=86]="US_BACKTICK",e[e.US_OPEN_SQUARE_BRACKET=87]="US_OPEN_SQUARE_BRACKET",e[e.US_BACKSLASH=88]="US_BACKSLASH",e[e.US_CLOSE_SQUARE_BRACKET=89]="US_CLOSE_SQUARE_BRACKET",e[e.US_QUOTE=90]="US_QUOTE",e[e.OEM_8=91]="OEM_8",e[e.OEM_102=92]="OEM_102",e[e.NUMPAD_0=93]="NUMPAD_0",e[e.NUMPAD_1=94]="NUMPAD_1",e[e.NUMPAD_2=95]="NUMPAD_2",e[e.NUMPAD_3=96]="NUMPAD_3",e[e.NUMPAD_4=97]="NUMPAD_4",e[e.NUMPAD_5=98]="NUMPAD_5",e[e.NUMPAD_6=99]="NUMPAD_6",e[e.NUMPAD_7=100]="NUMPAD_7",e[e.NUMPAD_8=101]="NUMPAD_8",e[e.NUMPAD_9=102]="NUMPAD_9",e[e.NUMPAD_MULTIPLY=103]="NUMPAD_MULTIPLY",e[e.NUMPAD_ADD=104]="NUMPAD_ADD",e[e.NUMPAD_SEPARATOR=105]="NUMPAD_SEPARATOR",e[e.NUMPAD_SUBTRACT=106]="NUMPAD_SUBTRACT",e[e.NUMPAD_DECIMAL=107]="NUMPAD_DECIMAL",e[e.NUMPAD_DIVIDE=108]="NUMPAD_DIVIDE",e[e.KEY_IN_COMPOSITION=109]="KEY_IN_COMPOSITION",e[e.ABNT_C1=110]="ABNT_C1",e[e.ABNT_C2=111]="ABNT_C2",e[e.MAX_VALUE=112]="MAX_VALUE"}(p=t.KeyCode||(t.KeyCode={})),t.createMonacoBaseAPI=function(){return{editor:void 0,languages:void 0, +CancellationTokenSource:a.CancellationTokenSource,Emitter:n.Emitter,KeyCode:p,KeyMod:h,Position:i.Position,Range:o.Range,Selection:s.Selection,SelectionDirection:s.SelectionDirection,MarkerSeverity:f,MarkerTag:d,Promise:u.TPromise,Uri:c.default,Token:l.Token}}}),r(e[28],t([1,0,5]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){return function(e,t){this.index=e,this.remainder=t}}();t.PrefixSumIndexOfResult=r;var i=function(){function e(e){this.values=e,this.prefixSum=new Uint32Array(e.length),this.prefixSumValidIndex=new Int32Array(1),this.prefixSumValidIndex[0]=-1}return e.prototype.getCount=function(){return this.values.length},e.prototype.insertValues=function(e,t){e=n.toUint32(e);var r=this.values,i=this.prefixSum,o=t.length;return 0!==o&&(this.values=new Uint32Array(r.length+o),this.values.set(r.subarray(0,e),0),this.values.set(r.subarray(e),e+o),this.values.set(t,e),e-1=0&&this.prefixSum.set(i.subarray(0,this.prefixSumValidIndex[0]+1)),!0)},e.prototype.changeValue=function(e,t){return e=n.toUint32(e),t=n.toUint32(t),this.values[e]!==t&&(this.values[e]=t,e-1=r.length)return!1;var o=r.length-e;return t>=o&&(t=o),0!==t&&(this.values=new Uint32Array(r.length-t),this.values.set(r.subarray(0,e),0),this.values.set(r.subarray(e+t),e),this.prefixSum=new Uint32Array(this.values.length),e-1=0&&this.prefixSum.set(i.subarray(0,this.prefixSumValidIndex[0]+1)),!0)},e.prototype.getTotalValue=function(){return 0===this.values.length?0:this._getAccumulatedValue(this.values.length-1)},e.prototype.getAccumulatedValue=function(e){ +return e<0?0:(e=n.toUint32(e),this._getAccumulatedValue(e))},e.prototype._getAccumulatedValue=function(e){if(e<=this.prefixSumValidIndex[0])return this.prefixSum[e];var t=this.prefixSumValidIndex[0]+1;0===t&&(this.prefixSum[0]=this.values[0],t++),e>=this.values.length&&(e=this.values.length-1);for(var n=t;n<=e;n++)this.prefixSum[n]=this.prefixSum[n-1]+this.values[n];return this.prefixSumValidIndex[0]=Math.max(this.prefixSumValidIndex[0],e),this.prefixSum[e]},e.prototype.getIndexOf=function(e){e=Math.floor(e),this.getTotalValue();for(var t,n,i,o=0,s=this.values.length-1;o<=s;)if(t=o+(s-o)/2|0,n=this.prefixSum[t],i=n-this.values[t],e=n))break;o=t+1}return new r(t,e-i)},e}();t.PrefixSumComputer=i;var o=function(){function e(e){this._cacheAccumulatedValueStart=0,this._cache=null,this._actual=new i(e),this._bustCache()}return e.prototype._bustCache=function(){this._cacheAccumulatedValueStart=0,this._cache=null},e.prototype.insertValues=function(e,t){ +this._actual.insertValues(e,t)&&this._bustCache()},e.prototype.changeValue=function(e,t){this._actual.changeValue(e,t)&&this._bustCache()},e.prototype.removeValues=function(e,t){this._actual.removeValues(e,t)&&this._bustCache()},e.prototype.getTotalValue=function(){return this._actual.getTotalValue()},e.prototype.getAccumulatedValue=function(e){return this._actual.getAccumulatedValue(e)},e.prototype.getIndexOf=function(e){if(e=Math.floor(e),null!==this._cache){var t=e-this._cacheAccumulatedValueStart;if(t>=0&&t=n._lines.length))return t=n._lines[i],s=n._wordenize(t,e),o=0,i+=1,u();r.done=!0,r.value=void 0}return r};return{next:u}},t.prototype._wordenize=function(e,t){var n,r=[];for(t.lastIndex=0;(n=t.exec(e))&&0!==n[0].length;)r.push({start:n.index,end:n.index+n[0].length});return r},t.prototype.getValueInRange=function(e){if((e=this._validateRange(e)).startLineNumber===e.endLineNumber)return this._lines[e.startLineNumber-1].substring(e.startColumn-1,e.endColumn-1) +;var t=this._eol,n=e.startLineNumber-1,r=e.endLineNumber-1,i=[];i.push(this._lines[n].substring(e.startColumn-1));for(var o=n+1;othis._lines.length)t=this._lines.length,n=this._lines[t-1].length+1,r=!0;else{var i=this._lines[t-1].length+1;n<1?(n=1,r=!0):n>i&&(n=i,r=!0)}return r?{lineNumber:t,column:n}:e},t}(l.MirrorTextModel),g=function(){function t(e){this._foreignModuleFactory=e,this._foreignModule=null}return t.prototype.computeDiff=function(e,t,n){var i=this._getModel(e),o=this._getModel(t);if(!i||!o)return null;var u=i.getLinesContent(),a=o.getLinesContent(),l=new s.DiffComputer(u,a,{shouldComputeCharChanges:!0,shouldPostProcessCharChanges:!0,shouldIgnoreTrimWhitespace:n,shouldMakePrettyDiff:!0});return r.TPromise.as(l.computeDiff())},t.prototype.computeMoreMinimalEdits=function(e,n){var o=this._getModel(e);if(!o)return r.TPromise.as(n);for(var s,a=[],l=0,c=n;lt._diffLimit)a.push({range:f,text:h});else for(var g=u.stringDiff(m,h,!1),_=o.offsetAt(i.Range.lift(f).getStartPosition()),v=0,y=g;v0;)self.onmessage(r.shift())},0)})}(e.data)):r.push(e)}}()}).call(this); +//# sourceMappingURL=../../../../min-maps/vs/base/worker/workerMain.js.map \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/apex/apex.js b/public/react/public/js/monaco/vs/basic-languages/apex/apex.js new file mode 100755 index 000000000..487a50640 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/apex/apex.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/apex/apex",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"<",close:">"}],folding:{markers:{start:new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:))")}}};var s=[];["abstract","activate","and","any","array","as","asc","assert","autonomous","begin","bigdecimal","blob","boolean","break","bulk","by","case","cast","catch","char","class","collect","commit","const","continue","convertcurrency","decimal","default","delete","desc","do","double","else","end","enum","exception","exit","export","extends","false","final","finally","float","for","from","future","get","global","goto","group","having","hint","if","implements","import","in","inner","insert","instanceof","int","interface","into","join","last_90_days","last_month","last_n_days","last_week","like","limit","list","long","loop","map","merge","native","new","next_90_days","next_month","next_n_days","next_week","not","null","nulls","number","object","of","on","or","outer","override","package","parallel","pragma","private","protected","public","retrieve","return","returning","rollback","savepoint","search","select","set","short","sort","stat","static","strictfp","super","switch","synchronized","system","testmethod","then","this","this_month","this_week","throw","throws","today","tolabel","tomorrow","transaction","transient","trigger","true","try","type","undelete","update","upsert","using","virtual","void","volatile","webservice","when","where","while","yesterday"].forEach(function(e){var t;s.push(e),s.push(e.toUpperCase()),s.push((t=e).charAt(0).toUpperCase()+t.substr(1))}),t.language={defaultToken:"",tokenPostfix:".apex",keywords:s,operators:["=",">","<","!","~","?",":","==","<=",">=","!=","&&","||","++","--","+","-","*","/","&","|","^","%","<<",">>",">>>","+=","-=","*=","/=","&=","|=","^=","%=","<<=",">>=",">>>="],symbols:/[=>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/@\s*[a-zA-Z_\$][\w\$]*/,"annotation"],[/(@digits)[eE]([\-+]?(@digits))?[fFdD]?/,"number.float"],[/(@digits)\.(@digits)([eE][\-+]?(@digits))?[fFdD]?/,"number.float"],[/(@digits)[fFdD]/,"number.float"],[/(@digits)[lL]?/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/"/,"string",'@string."'],[/'/,"string","@string.'"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@apexdoc"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],apexdoc:[[/[^\/*]+/,"comment.doc"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"']+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/["']/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/azcli/azcli.js b/public/react/public/js/monaco/vs/basic-languages/azcli/azcli.js new file mode 100755 index 000000000..2d77af895 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/azcli/azcli.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/azcli/azcli",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={comments:{lineComment:"#"}},t.language={defaultToken:"keyword",ignoreCase:!0,tokenPostfix:".azcli",str:/[^#\s]/,tokenizer:{root:[{include:"@comment"},[/\s-+@str*\s*/,{cases:{"@eos":{token:"key.identifier",next:"@popall"},"@default":{token:"key.identifier",next:"@type"}}}],[/^-+@str*\s*/,{cases:{"@eos":{token:"key.identifier",next:"@popall"},"@default":{token:"key.identifier",next:"@type"}}}]],type:[{include:"@comment"},[/-+@str*\s*/,{cases:{"@eos":{token:"key.identifier",next:"@popall"},"@default":"key.identifier"}}],[/@str+\s*/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}]],comment:[[/#.*$/,{cases:{"@eos":{token:"comment",next:"@popall"}}}]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/bat/bat.js b/public/react/public/js/monaco/vs/basic-languages/bat/bat.js new file mode 100755 index 000000000..72f0f46fa --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/bat/bat.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/bat/bat",["require","exports"],function(e,s){"use strict";Object.defineProperty(s,"__esModule",{value:!0}),s.conf={comments:{lineComment:"REM"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}],surroundingPairs:[{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}],folding:{markers:{start:new RegExp("^\\s*(::\\s*|REM\\s+)#region"),end:new RegExp("^\\s*(::\\s*|REM\\s+)#endregion")}}},s.language={defaultToken:"",ignoreCase:!0,tokenPostfix:".bat",brackets:[{token:"delimiter.bracket",open:"{",close:"}"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"delimiter.square",open:"[",close:"]"}],keywords:/call|defined|echo|errorlevel|exist|for|goto|if|pause|set|shift|start|title|not|pushd|popd/,symbols:/[=>","cond->>","when","while","when-not","when-let","when-first","do","future","comment","doto","locking","proxy","println","type","meta","var","as->","reify","deftype","defrecord","defprotocol","extend","extend-protocol","extend-type","specify","specify!","try","catch","finally","let","letfn","binding","loop","for","seq","doseq","dotimes","when-let","if-let","when-some","if-some","this-as","defmethod","testing","deftest","are","use-fixtures","use","remove","run","run*","fresh","alt!","alt!!","go","go-loop","thread","boolean","str"],constants:["true","false","nil"],operators:["=","not=","<","<=",">",">=","and","or","not","inc","dec","max","min","rem","bit-and","bit-or","bit-xor","bit-not"],tokenizer:{root:[[/0[xX][0-9a-fA-F]+/,"number.hex"],[/[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?/,"number.float"],[/(?:\b(?:(ns|def|defn|defn-|defmacro|defmulti|defonce|ns|ns-unmap|fn))(?![\w-]))(\s+)((?:\w|\-|\!|\?)*)/,["keyword","white","variable"]],[/[a-zA-Z_#][a-zA-Z0-9_\-\?\!\*]*/,{cases:{"@keywords":"keyword","@constants":"constant","@operators":"operators","@default":"identifier"}}],[/\/#"(?:\.|(?:\")|[^""\n])*"\/g/,"regexp"],{include:"@whitespace"},{include:"@strings"}],whitespace:[[/[ \t\r\n]+/,"white"],[/;;.*$/,"comment"]],strings:[[/"$/,"string","@popall"],[/"(?=.)/,"string","@multiLineString"]],multiLineString:[[/\\./,"string.escape"],[/"/,"string","@popall"],[/.(?=.*")/,"string"],[/.*\\$/,"string"],[/.*$/,"string","@popall"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/coffee/coffee.js b/public/react/public/js/monaco/vs/basic-languages/coffee/coffee.js new file mode 100755 index 000000000..f347acc4c --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/coffee/coffee.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/coffee/coffee",["require","exports"],function(e,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\@\#%\^\&\*\(\)\=\$\-\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{blockComment:["###","###"],lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*#region\\b"),end:new RegExp("^\\s*#endregion\\b")}}},r.language={defaultToken:"",ignoreCase:!0,tokenPostfix:".coffee",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"}],regEx:/\/(?!\/\/)(?:[^\/\\]|\\.)*\/[igm]*/,keywords:["and","or","is","isnt","not","on","yes","@","no","off","true","false","null","this","new","delete","typeof","in","instanceof","return","throw","break","continue","debugger","if","else","switch","for","while","do","try","catch","finally","class","extends","super","undefined","then","unless","until","loop","of","by","when"],symbols:/[=>"}],keywords:["abstract","amp","array","auto","bool","break","case","catch","char","class","const","constexpr","const_cast","continue","cpu","decltype","default","delegate","delete","do","double","dynamic_cast","each","else","enum","event","explicit","export","extern","false","final","finally","float","for","friend","gcnew","generic","goto","if","in","initonly","inline","int","interface","interior_ptr","internal","literal","long","mutable","namespace","new","noexcept","nullptr","__nullptr","operator","override","partial","pascal","pin_ptr","private","property","protected","public","ref","register","reinterpret_cast","restrict","return","safe_cast","sealed","short","signed","sizeof","static","static_assert","static_cast","struct","switch","template","this","thread_local","throw","tile_static","true","try","typedef","typeid","typename","union","unsigned","using","virtual","void","volatile","wchar_t","where","while","_asm","_based","_cdecl","_declspec","_fastcall","_if_exists","_if_not_exists","_inline","_multiple_inheritance","_pascal","_single_inheritance","_stdcall","_virtual_inheritance","_w64","__abstract","__alignof","__asm","__assume","__based","__box","__builtin_alignof","__cdecl","__clrcall","__declspec","__delegate","__event","__except","__fastcall","__finally","__forceinline","__gc","__hook","__identifier","__if_exists","__if_not_exists","__inline","__int128","__int16","__int32","__int64","__int8","__interface","__leave","__m128","__m128d","__m128i","__m256","__m256d","__m256i","__m64","__multiple_inheritance","__newslot","__nogc","__noop","__nounwind","__novtordisp","__pascal","__pin","__pragma","__property","__ptr32","__ptr64","__raise","__restrict","__resume","__sealed","__single_inheritance","__stdcall","__super","__thiscall","__try","__try_cast","__typeof","__unaligned","__unhook","__uuidof","__value","__virtual_inheritance","__w64","__wchar_t"],operators:["=",">","<","!","~","?",":","==","<=",">=","!=","&&","||","++","--","+","-","*","/","&","|","^","%","<<",">>",">>>","+=","-=","*=","/=","&=","|=","^=","%=","<<=",">>=",">>>="],symbols:/[=>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/\d*\d+[eE]([\-+]?\d+)?(@floatsuffix)/,"number.float"],[/\d*\.\d+([eE][\-+]?\d+)?(@floatsuffix)/,"number.float"],[/0[xX][0-9a-fA-F']*[0-9a-fA-F](@integersuffix)/,"number.hex"],[/0[0-7']*[0-7](@integersuffix)/,"number.octal"],[/0[bB][0-1']*[0-1](@integersuffix)/,"number.binary"],[/\d[\d']*\d(@integersuffix)/,"number"],[/\d(@integersuffix)/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@doccomment"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],doccomment:[[/[^\/*]+/,"comment.doc"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],raw:[[/(.*)(\))(?:([^ ()\\\t]*))(\")/,{cases:{"$3==$S2":["string.raw","string.raw.end","string.raw.end",{token:"string.raw.end",next:"@pop"}],"@default":["string.raw","string.raw","string.raw","string.raw"]}}],[/.*/,"string.raw"]],include:[[/(\s*)(<)([^<>]*)(>)/,["","keyword.directive.include.begin","string.include.identifier",{token:"keyword.directive.include.end",next:"@pop"}]],[/(\s*)(")([^"]*)(")/,["","keyword.directive.include.begin","string.include.identifier",{token:"keyword.directive.include.end",next:"@pop"}]]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/csharp/csharp.js b/public/react/public/js/monaco/vs/basic-languages/csharp/csharp.js new file mode 100755 index 000000000..a06dac637 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/csharp/csharp.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/csharp/csharp",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"'",close:"'",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"<",close:">"},{open:"'",close:"'"},{open:'"',close:'"'}],folding:{markers:{start:new RegExp("^\\s*#region\\b"),end:new RegExp("^\\s*#endregion\\b")}}},t.language={defaultToken:"",tokenPostfix:".cs",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],keywords:["extern","alias","using","bool","decimal","sbyte","byte","short","ushort","int","uint","long","ulong","char","float","double","object","dynamic","string","assembly","is","as","ref","out","this","base","new","typeof","void","checked","unchecked","default","delegate","var","const","if","else","switch","case","while","do","for","foreach","in","break","continue","goto","return","throw","try","catch","finally","lock","yield","from","let","where","join","on","equals","into","orderby","ascending","descending","select","group","by","namespace","partial","class","field","event","method","param","property","public","protected","internal","private","abstract","sealed","static","struct","readonly","volatile","virtual","override","params","get","set","add","remove","operator","true","false","implicit","explicit","interface","enum","null","async","await","fixed","sizeof","stackalloc","unsafe","nameof","when"],namespaceFollows:["namespace","using"],parenFollows:["if","for","while","switch","foreach","using","catch","when"],operators:["=","??","||","&&","|","^","&","==","!=","<=",">=","<<","+","-","*","/","%","!","~","++","--","+=","-=","*=","/=","%=","&=","|=","^=","<<=",">>=",">>","=>"],symbols:/[=>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/[0-9_]*\.[0-9_]+([eE][\-+]?\d+)?[fFdD]?/,"number.float"],[/0[xX][0-9a-fA-F_]+/,"number.hex"],[/0[bB][01_]+/,"number.hex"],[/[0-9_]+/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,{token:"string.quote",next:"@string"}],[/\$\@"/,{token:"string.quote",next:"@litinterpstring"}],[/\@"/,{token:"string.quote",next:"@litstring"}],[/\$"/,{token:"string.quote",next:"@interpolatedstring"}],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],qualified:[[/[a-zA-Z_][\w]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],[/\./,"delimiter"],["","","@pop"]],namespace:[{include:"@whitespace"},[/[A-Z]\w*/,"namespace"],[/[\.=]/,"delimiter"],["","","@pop"]],comment:[[/[^\/*]+/,"comment"],["\\*/","comment","@pop"],[/[\/*]/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,{token:"string.quote",next:"@pop"}]],litstring:[[/[^"]+/,"string"],[/""/,"string.escape"],[/"/,{token:"string.quote",next:"@pop"}]],litinterpstring:[[/[^"{]+/,"string"],[/""/,"string.escape"],[/{{/,"string.escape"],[/}}/,"string.escape"],[/{/,{token:"string.quote",next:"root.litinterpstring"}],[/"/,{token:"string.quote",next:"@pop"}]],interpolatedstring:[[/[^\\"{]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/{{/,"string.escape"],[/}}/,"string.escape"],[/{/,{token:"string.quote",next:"root.interpolatedstring"}],[/"/,{token:"string.quote",next:"@pop"}]],whitespace:[[/^[ \t\v\f]*#((r)|(load))(?=\s)/,"directive.csx"],[/^[ \t\v\f]*#\w.*$/,"namespace.cpp"],[/[ \t\v\f\r\n]+/,""],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/csp/csp.js b/public/react/public/js/monaco/vs/basic-languages/csp/csp.js new file mode 100755 index 000000000..6593e96f5 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/csp/csp.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/csp/csp",["require","exports"],function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.conf={brackets:[],autoClosingPairs:[],surroundingPairs:[]},e.language={keywords:[],typeKeywords:[],tokenPostfix:".csp",operators:[],symbols:/[=>",token:"delimiter.angle"}],tokenizer:{root:[{include:"@selector"}],selector:[{include:"@comments"},{include:"@import"},{include:"@strings"},["[@](keyframes|-webkit-keyframes|-moz-keyframes|-o-keyframes)",{token:"keyword",next:"@keyframedeclaration"}],["[@](page|content|font-face|-moz-document)",{token:"keyword"}],["[@](charset|namespace)",{token:"keyword",next:"@declarationbody"}],["(url-prefix)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],["(url)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],{include:"@selectorname"},["[\\*]","tag"],["[>\\+,]","delimiter"],["\\[",{token:"delimiter.bracket",next:"@selectorattribute"}],["{",{token:"delimiter.bracket",next:"@selectorbody"}]],selectorbody:[{include:"@comments"},["[*_]?@identifier@ws:(?=(\\s|\\d|[^{;}]*[;}]))","attribute.name","@rulevalue"],["}",{token:"delimiter.bracket",next:"@pop"}]],selectorname:[["(\\.|#(?=[^{])|%|(@identifier)|:)+","tag"]],selectorattribute:[{include:"@term"},["]",{token:"delimiter.bracket",next:"@pop"}]],term:[{include:"@comments"},["(url-prefix)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],["(url)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],{include:"@functioninvocation"},{include:"@numbers"},{include:"@name"},["([<>=\\+\\-\\*\\/\\^\\|\\~,])","delimiter"],[",","delimiter"]],rulevalue:[{include:"@comments"},{include:"@strings"},{include:"@term"},["!important","keyword"],[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],warndebug:[["[@](warn|debug)",{token:"keyword",next:"@declarationbody"}]],import:[["[@](import)",{token:"keyword",next:"@declarationbody"}]],urldeclaration:[{include:"@strings"},["[^)\r\n]+","string"],["\\)",{token:"delimiter.parenthesis",next:"@pop"}]],parenthizedterm:[{include:"@term"},["\\)",{token:"delimiter.parenthesis",next:"@pop"}]],declarationbody:[{include:"@term"},[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],comments:[["\\/\\*","comment","@comment"],["\\/\\/+.*","comment"]],comment:[["\\*\\/","comment","@pop"],[/[^*/]+/,"comment"],[/./,"comment"]],name:[["@identifier","attribute.value"]],numbers:[["-?(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?",{token:"attribute.value.number",next:"@units"}],["#[0-9a-fA-F_]+(?!\\w)","attribute.value.hex"]],units:[["(em|ex|ch|rem|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?","attribute.value.unit","@pop"]],keyframedeclaration:[["@identifier","attribute.value"],["{",{token:"delimiter.bracket",switchTo:"@keyframebody"}]],keyframebody:[{include:"@term"},["{",{token:"delimiter.bracket",next:"@selectorbody"}],["}",{token:"delimiter.bracket",next:"@pop"}]],functioninvocation:[["@identifier\\(",{token:"attribute.value",next:"@functionarguments"}]],functionarguments:[["\\$@identifier@ws:","attribute.name"],["[,]","delimiter"],{include:"@term"},["\\)",{token:"attribute.value",next:"@pop"}]],strings:[['~?"',{token:"string",next:"@stringenddoublequote"}],["~?'",{token:"string",next:"@stringendquote"}]],stringenddoublequote:[["\\\\.","string"],['"',{token:"string",next:"@pop"}],[/[^\\"]+/,"string"],[".","string"]],stringendquote:[["\\\\.","string"],["'",{token:"string",next:"@pop"}],[/[^\\']+/,"string"],[".","string"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/dockerfile/dockerfile.js b/public/react/public/js/monaco/vs/basic-languages/dockerfile/dockerfile.js new file mode 100755 index 000000000..074f981d9 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/dockerfile/dockerfile.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/dockerfile/dockerfile",["require","exports"],function(e,s){"use strict";Object.defineProperty(s,"__esModule",{value:!0}),s.conf={brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},s.language={defaultToken:"",tokenPostfix:".dockerfile",instructions:/FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|ARG|VOLUME|LABEL|USER|WORKDIR|COPY|CMD|STOPSIGNAL|SHELL|HEALTHCHECK|ENTRYPOINT/,instructionAfter:/ONBUILD/,variableAfter:/ENV/,variable:/\${?[\w]+}?/,tokenizer:{root:[{include:"@whitespace"},{include:"@comment"},[/(@instructionAfter)(\s+)/,["keyword",{token:"",next:"@instructions"}]],["","keyword","@instructions"]],instructions:[[/(@variableAfter)(\s+)([\w]+)/,["keyword","",{token:"variable",next:"@arguments"}]],[/(@instructions)/,"keyword","@arguments"]],arguments:[{include:"@whitespace"},{include:"@strings"},[/(@variable)/,{cases:{"@eos":{token:"variable",next:"@popall"},"@default":"variable"}}],[/\\/,{cases:{"@eos":"","@default":""}}],[/./,{cases:{"@eos":{token:"",next:"@popall"},"@default":""}}]],whitespace:[[/\s+/,{cases:{"@eos":{token:"",next:"@popall"},"@default":""}}]],comment:[[/(^#.*$)/,"comment","@popall"]],strings:[[/'$/,"string","@popall"],[/'/,"string","@stringBody"],[/"$/,"string","@popall"],[/"/,"string","@dblStringBody"]],stringBody:[[/[^\\\$']/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}],[/\\./,"string.escape"],[/'$/,"string","@popall"],[/'/,"string","@pop"],[/(@variable)/,"variable"],[/\\$/,"string"],[/$/,"string","@popall"]],dblStringBody:[[/[^\\\$"]/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}],[/\\./,"string.escape"],[/"$/,"string","@popall"],[/"/,"string","@pop"],[/(@variable)/,"variable"],[/\\$/,"string"],[/$/,"string","@popall"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/fsharp/fsharp.js b/public/react/public/js/monaco/vs/basic-languages/fsharp/fsharp.js new file mode 100755 index 000000000..a2aaee420 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/fsharp/fsharp.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/fsharp/fsharp",["require","exports"],function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.conf={comments:{lineComment:"//",blockComment:["(*","*)"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*//\\s*#region\\b|^\\s*\\(\\*\\s*#region(.*)\\*\\)"),end:new RegExp("^\\s*//\\s*#endregion\\b|^\\s*\\(\\*\\s*#endregion\\s*\\*\\)")}}},n.language={defaultToken:"",tokenPostfix:".fs",keywords:["abstract","and","atomic","as","assert","asr","base","begin","break","checked","component","const","constraint","constructor","continue","class","default","delegate","do","done","downcast","downto","elif","else","end","exception","eager","event","external","extern","false","finally","for","fun","function","fixed","functor","global","if","in","include","inherit","inline","interface","internal","land","lor","lsl","lsr","lxor","lazy","let","match","member","mod","module","mutable","namespace","method","mixin","new","not","null","of","open","or","object","override","private","parallel","process","protected","pure","public","rec","return","static","sealed","struct","sig","then","to","true","tailcall","trait","try","type","upcast","use","val","void","virtual","volatile","when","while","with","yield"],symbols:/[=>\]/,"annotation"],[/^#(if|else|endif)/,"keyword"],[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,"delimiter"],[/\d*\d+[eE]([\-+]?\d+)?(@floatsuffix)/,"number.float"],[/\d*\.\d+([eE][\-+]?\d+)?(@floatsuffix)/,"number.float"],[/0x[0-9a-fA-F]+LF/,"number.float"],[/0x[0-9a-fA-F]+(@integersuffix)/,"number.hex"],[/0b[0-1]+(@integersuffix)/,"number.bin"],[/\d+(@integersuffix)/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"""/,"string",'@string."""'],[/"/,"string",'@string."'],[/\@"/,{token:"string.quote",next:"@litstring"}],[/'[^\\']'B?/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\(\*(?!\))/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\*]+/,"comment"],[/\*\)/,"comment","@pop"],[/\*/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/("""|"B?)/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}]],litstring:[[/[^"]+/,"string"],[/""/,"string.escape"],[/"/,{token:"string.quote",next:"@pop"}]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/go/go.js b/public/react/public/js/monaco/vs/basic-languages/go/go.js new file mode 100755 index 000000000..c7cd00457 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/go/go.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/go/go",["require","exports"],function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.conf={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"`",close:"`",notIn:["string"]},{open:'"',close:'"',notIn:["string"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"`",close:"`"},{open:'"',close:'"'},{open:"'",close:"'"}]},n.language={defaultToken:"",tokenPostfix:".go",keywords:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var","bool","true","false","uint8","uint16","uint32","uint64","int8","int16","int32","int64","float32","float64","complex64","complex128","byte","rune","uint","int","uintptr","string","nil"],operators:["+","-","*","/","%","&","|","^","<<",">>","&^","+=","-=","*=","/=","%=","&=","|=","^=","<<=",">>=","&^=","&&","||","<-","++","--","==","<",">","=","!","!=","<=",">=",":=","...","(",")","","]","{","}",",",";",".",":"],symbols:/[=>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/\d*\d+[eE]([\-+]?\d+)?/,"number.float"],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float"],[/0[xX][0-9a-fA-F']*[0-9a-fA-F]/,"number.hex"],[/0[0-7']*[0-7]/,"number.octal"],[/0[bB][0-1']*[0-1]/,"number.binary"],[/\d[\d']*/,"number"],[/\d/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"],[/`/,"string","@rawstring"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@doccomment"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],doccomment:[[/[^\/*]+/,"comment.doc"],[/\/\*/,"comment.doc.invalid"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],rawstring:[[/[^\`]/,"string"],[/`/,"string","@pop"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/handlebars/handlebars.js b/public/react/public/js/monaco/vs/basic-languages/handlebars/handlebars.js new file mode 100755 index 000000000..f6d002cea --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/handlebars/handlebars.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/handlebars/handlebars",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n="undefined"==typeof monaco?self.monaco:monaco,a=["area","base","br","col","embed","hr","img","input","keygen","link","menuitem","meta","param","source","track","wbr"];t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g,comments:{blockComment:["{{!--","--}}"]},brackets:[["\x3c!--","--\x3e"],["<",">"],["{{","}}"],["{","}"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"<",close:">"},{open:'"',close:'"'},{open:"'",close:"'"}],onEnterRules:[{beforeText:new RegExp("<(?!(?:"+a.join("|")+"))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$","i"),afterText:/^<\/(\w[\w\d]*)\s*>$/i,action:{indentAction:n.languages.IndentAction.IndentOutdent}},{beforeText:new RegExp("<(?!(?:"+a.join("|")+"))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$","i"),action:{indentAction:n.languages.IndentAction.Indent}}]},t.language={defaultToken:"",tokenPostfix:"",tokenizer:{root:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.root"}],[/)/,["delimiter.html","tag.html","delimiter.html"]],[/(<)(script)/,["delimiter.html",{token:"tag.html",next:"@script"}]],[/(<)(style)/,["delimiter.html",{token:"tag.html",next:"@style"}]],[/(<)([:\w]+)/,["delimiter.html",{token:"tag.html",next:"@otherTag"}]],[/(<\/)(\w+)/,["delimiter.html",{token:"tag.html",next:"@otherTag"}]],[/]+/,"metatag.content.html"],[/>/,"metatag.html","@pop"]],comment:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.comment"}],[/-->/,"comment.html","@pop"],[/[^-]+/,"comment.content.html"],[/./,"comment.content.html"]],otherTag:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.otherTag"}],[/\/?>/,"delimiter.html","@pop"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/]],script:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.script"}],[/type/,"attribute.name","@scriptAfterType"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.text/javascript",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/(<\/)(script\s*)(>)/,["delimiter.html","tag.html",{token:"delimiter.html",next:"@pop"}]]],scriptAfterType:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.scriptAfterType"}],[/=/,"delimiter","@scriptAfterTypeEquals"],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.text/javascript",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptAfterTypeEquals:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.scriptAfterTypeEquals"}],[/"([^"]*)"/,{token:"attribute.value",switchTo:"@scriptWithCustomType.$1"}],[/'([^']*)'/,{token:"attribute.value",switchTo:"@scriptWithCustomType.$1"}],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.text/javascript",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptWithCustomType:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.scriptWithCustomType.$S2"}],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.$S2",nextEmbedded:"$S2"}],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptEmbedded:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInEmbeddedState.scriptEmbedded.$S2",nextEmbedded:"@pop"}],[/<\/script/,{token:"@rematch",next:"@pop",nextEmbedded:"@pop"}]],style:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.style"}],[/type/,"attribute.name","@styleAfterType"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/>/,{token:"delimiter.html",next:"@styleEmbedded.text/css",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/(<\/)(style\s*)(>)/,["delimiter.html","tag.html",{token:"delimiter.html",next:"@pop"}]]],styleAfterType:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.styleAfterType"}],[/=/,"delimiter","@styleAfterTypeEquals"],[/>/,{token:"delimiter.html",next:"@styleEmbedded.text/css",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleAfterTypeEquals:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.styleAfterTypeEquals"}],[/"([^"]*)"/,{token:"attribute.value",switchTo:"@styleWithCustomType.$1"}],[/'([^']*)'/,{token:"attribute.value",switchTo:"@styleWithCustomType.$1"}],[/>/,{token:"delimiter.html",next:"@styleEmbedded.text/css",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleWithCustomType:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInSimpleState.styleWithCustomType.$S2"}],[/>/,{token:"delimiter.html",next:"@styleEmbedded.$S2",nextEmbedded:"$S2"}],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleEmbedded:[[/\{\{/,{token:"@rematch",switchTo:"@handlebarsInEmbeddedState.styleEmbedded.$S2",nextEmbedded:"@pop"}],[/<\/style/,{token:"@rematch",next:"@pop",nextEmbedded:"@pop"}]],handlebarsInSimpleState:[[/\{\{\{?/,"delimiter.handlebars"],[/\}\}\}?/,{token:"delimiter.handlebars",switchTo:"@$S2.$S3"}],{include:"handlebarsRoot"}],handlebarsInEmbeddedState:[[/\{\{\{?/,"delimiter.handlebars"],[/\}\}\}?/,{token:"delimiter.handlebars",switchTo:"@$S2.$S3",nextEmbedded:"$S3"}],{include:"handlebarsRoot"}],handlebarsRoot:[[/[#/][^\s}]+/,"keyword.helper.handlebars"],[/else\b/,"keyword.helper.handlebars"],[/[\s]+/],[/[^}]/,"variable.parameter.handlebars"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/html/html.js b/public/react/public/js/monaco/vs/basic-languages/html/html.js new file mode 100755 index 000000000..b1d3a9375 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/html/html.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/html/html",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n="undefined"==typeof monaco?self.monaco:monaco,i=["area","base","br","col","embed","hr","img","input","keygen","link","menuitem","meta","param","source","track","wbr"];t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g,comments:{blockComment:["\x3c!--","--\x3e"]},brackets:[["\x3c!--","--\x3e"],["<",">"],["{","}"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:'"',close:'"'},{open:"'",close:"'"},{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"<",close:">"}],onEnterRules:[{beforeText:new RegExp("<(?!(?:"+i.join("|")+"))([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$","i"),afterText:/^<\/([_:\w][_:\w-.\d]*)\s*>$/i,action:{indentAction:n.languages.IndentAction.IndentOutdent}},{beforeText:new RegExp("<(?!(?:"+i.join("|")+"))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$","i"),action:{indentAction:n.languages.IndentAction.Indent}}],folding:{markers:{start:new RegExp("^\\s*\x3c!--\\s*#region\\b.*--\x3e"),end:new RegExp("^\\s*\x3c!--\\s*#endregion\\b.*--\x3e")}}},t.language={defaultToken:"",tokenPostfix:".html",ignoreCase:!0,tokenizer:{root:[[/)/,["delimiter","tag","","delimiter"]],[/(<)(script)/,["delimiter",{token:"tag",next:"@script"}]],[/(<)(style)/,["delimiter",{token:"tag",next:"@style"}]],[/(<)((?:[\w\-]+:)?[\w\-]+)/,["delimiter",{token:"tag",next:"@otherTag"}]],[/(<\/)((?:[\w\-]+:)?[\w\-]+)/,["delimiter",{token:"tag",next:"@otherTag"}]],[/]+/,"metatag.content"],[/>/,"metatag","@pop"]],comment:[[/-->/,"comment","@pop"],[/[^-]+/,"comment.content"],[/./,"comment.content"]],otherTag:[[/\/?>/,"delimiter","@pop"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/]],script:[[/type/,"attribute.name","@scriptAfterType"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/>/,{token:"delimiter",next:"@scriptEmbedded",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/(<\/)(script\s*)(>)/,["delimiter","tag",{token:"delimiter",next:"@pop"}]]],scriptAfterType:[[/=/,"delimiter","@scriptAfterTypeEquals"],[/>/,{token:"delimiter",next:"@scriptEmbedded",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptAfterTypeEquals:[[/"([^"]*)"/,{token:"attribute.value",switchTo:"@scriptWithCustomType.$1"}],[/'([^']*)'/,{token:"attribute.value",switchTo:"@scriptWithCustomType.$1"}],[/>/,{token:"delimiter",next:"@scriptEmbedded",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptWithCustomType:[[/>/,{token:"delimiter",next:"@scriptEmbedded.$S2",nextEmbedded:"$S2"}],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptEmbedded:[[/<\/script/,{token:"@rematch",next:"@pop",nextEmbedded:"@pop"}],[/[^<]+/,""]],style:[[/type/,"attribute.name","@styleAfterType"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/>/,{token:"delimiter",next:"@styleEmbedded",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/(<\/)(style\s*)(>)/,["delimiter","tag",{token:"delimiter",next:"@pop"}]]],styleAfterType:[[/=/,"delimiter","@styleAfterTypeEquals"],[/>/,{token:"delimiter",next:"@styleEmbedded",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleAfterTypeEquals:[[/"([^"]*)"/,{token:"attribute.value",switchTo:"@styleWithCustomType.$1"}],[/'([^']*)'/,{token:"attribute.value",switchTo:"@styleWithCustomType.$1"}],[/>/,{token:"delimiter",next:"@styleEmbedded",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleWithCustomType:[[/>/,{token:"delimiter",next:"@styleEmbedded.$S2",nextEmbedded:"$S2"}],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleEmbedded:[[/<\/style/,{token:"@rematch",next:"@pop",nextEmbedded:"@pop"}],[/[^<]+/,""]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/ini/ini.js b/public/react/public/js/monaco/vs/basic-languages/ini/ini.js new file mode 100755 index 000000000..e4e7b3ae7 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/ini/ini.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/ini/ini",["require","exports"],function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.conf={comments:{lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},n.language={defaultToken:"",tokenPostfix:".ini",escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/^\[[^\]]*\]/,"metatag"],[/(^\w+)(\s*)(\=)/,["key","","delimiter"]],{include:"@whitespace"},[/\d+/,"number"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/"/,"string",'@string."'],[/'/,"string","@string.'"]],whitespace:[[/[ \t\r\n]+/,""],[/^\s*[#;].*$/,"comment"]],string:[[/[^\\"']+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/["']/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/java/java.js b/public/react/public/js/monaco/vs/basic-languages/java/java.js new file mode 100755 index 000000000..b4af7502f --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/java/java.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/java/java",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"<",close:">"}],folding:{markers:{start:new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:))")}}},t.language={defaultToken:"",tokenPostfix:".java",keywords:["abstract","continue","for","new","switch","assert","default","goto","package","synchronized","boolean","do","if","private","this","break","double","implements","protected","throw","byte","else","import","public","throws","case","enum","instanceof","return","transient","catch","extends","int","short","try","char","final","interface","static","void","class","finally","long","strictfp","volatile","const","float","native","super","while","true","false"],operators:["=",">","<","!","~","?",":","==","<=",">=","!=","&&","||","++","--","+","-","*","/","&","|","^","%","<<",">>",">>>","+=","-=","*=","/=","&=","|=","^=","%=","<<=",">>=",">>>="],symbols:/[=>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/@\s*[a-zA-Z_\$][\w\$]*/,"annotation"],[/(@digits)[eE]([\-+]?(@digits))?[fFdD]?/,"number.float"],[/(@digits)\.(@digits)([eE][\-+]?(@digits))?[fFdD]?/,"number.float"],[/0[xX](@hexdigits)[Ll]?/,"number.hex"],[/0(@octaldigits)[Ll]?/,"number.octal"],[/0[bB](@binarydigits)[Ll]?/,"number.binary"],[/(@digits)[fFdD]/,"number.float"],[/(@digits)[lL]?/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@javadoc"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],javadoc:[[/[^\/*]+/,"comment.doc"],[/\/\*/,"comment.doc.invalid"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/javascript/javascript.js b/public/react/public/js/monaco/vs/basic-languages/javascript/javascript.js new file mode 100755 index 000000000..678fb442c --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/javascript/javascript.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/typescript/typescript",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n="undefined"==typeof monaco?self.monaco:monaco;t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],onEnterRules:[{beforeText:/^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,afterText:/^\s*\*\/$/,action:{indentAction:n.languages.IndentAction.IndentOutdent,appendText:" * "}},{beforeText:/^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,action:{indentAction:n.languages.IndentAction.None,appendText:" * "}},{beforeText:/^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,action:{indentAction:n.languages.IndentAction.None,appendText:"* "}},{beforeText:/^(\t|(\ \ ))*\ \*\/\s*$/,action:{indentAction:n.languages.IndentAction.None,removeText:1}}],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"',notIn:["string"]},{open:"'",close:"'",notIn:["string","comment"]},{open:"`",close:"`",notIn:["string","comment"]},{open:"/**",close:" */",notIn:["string"]}],folding:{markers:{start:new RegExp("^\\s*//\\s*#?region\\b"),end:new RegExp("^\\s*//\\s*#?endregion\\b")}}},t.language={defaultToken:"invalid",tokenPostfix:".ts",keywords:["abstract","as","break","case","catch","class","continue","const","constructor","debugger","declare","default","delete","do","else","enum","export","extends","false","finally","for","from","function","get","if","implements","import","in","infer","instanceof","interface","is","keyof","let","module","namespace","never","new","null","package","private","protected","public","readonly","require","global","return","set","static","super","switch","symbol","this","throw","true","try","type","typeof","unique","var","void","while","with","yield","async","await","of"],typeKeywords:["any","boolean","number","object","string","undefined"],operators:["<=",">=","==","!=","===","!==","=>","+","-","**","*","/","%","++","--","<<",">",">>>","&","|","^","!","~","&&","||","?",":","=","+=","-=","*=","**=","/=","%=","<<=",">>=",">>>=","&=","|=","^=","@"],symbols:/[=>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/(@digits)[eE]([\-+]?(@digits))?/,"number.float"],[/(@digits)\.(@digits)([eE][\-+]?(@digits))?/,"number.float"],[/0[xX](@hexdigits)/,"number.hex"],[/0(@octaldigits)/,"number.octal"],[/0[bB](@binarydigits)/,"number.binary"],[/(@digits)/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string_double"],[/'/,"string","@string_single"],[/`/,"string","@string_backtick"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@jsdoc"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],jsdoc:[[/[^\/*]+/,"comment.doc"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],regexp:[[/(\{)(\d+(?:,\d*)?)(\})/,["regexp.escape.control","regexp.escape.control","regexp.escape.control"]],[/(\[)(\^?)(?=(?:[^\]\\\/]|\\.)+)/,["regexp.escape.control",{token:"regexp.escape.control",next:"@regexrange"}]],[/(\()(\?:|\?=|\?!)/,["regexp.escape.control","regexp.escape.control"]],[/[()]/,"regexp.escape.control"],[/@regexpctl/,"regexp.escape.control"],[/[^\\\/]/,"regexp"],[/@regexpesc/,"regexp.escape"],[/\\\./,"regexp.invalid"],["/",{token:"regexp",bracket:"@close"},"@pop"]],regexrange:[[/-/,"regexp.escape.control"],[/\^/,"regexp.invalid"],[/@regexpesc/,"regexp.escape"],[/[^\]]/,"regexp"],[/\]/,"@brackets.regexp.escape.control","@pop"]],string_double:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],string_single:[[/[^\\']+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/'/,"string","@pop"]],string_backtick:[[/\$\{/,{token:"delimiter.bracket",next:"@bracketCounting"}],[/[^\\`$]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/`/,"string","@pop"]],bracketCounting:[[/\{/,"delimiter.bracket","@bracketCounting"],[/\}/,"delimiter.bracket","@pop"],{include:"common"}]}}}),define("vs/basic-languages/javascript/javascript",["require","exports","../typescript/typescript"],function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});"undefined"==typeof monaco?self.monaco:monaco;t.conf=n.conf,t.language={defaultToken:"invalid",tokenPostfix:".js",keywords:["break","case","catch","class","continue","const","constructor","debugger","default","delete","do","else","export","extends","false","finally","for","from","function","get","if","import","in","instanceof","let","new","null","return","set","super","switch","symbol","this","throw","true","try","typeof","undefined","var","void","while","with","yield","async","await","of"],typeKeywords:[],operators:n.language.operators,symbols:n.language.symbols,escapes:n.language.escapes,digits:n.language.digits,octaldigits:n.language.octaldigits,binarydigits:n.language.binarydigits,hexdigits:n.language.hexdigits,regexpctl:n.language.regexpctl,regexpesc:n.language.regexpesc,tokenizer:n.language.tokenizer}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/less/less.js b/public/react/public/js/monaco/vs/basic-languages/less/less.js new file mode 100755 index 000000000..891e58be6 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/less/less.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/less/less",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(#?-?\d*\.\d\w*%?)|([@#!.:]?[\w-?]+%?)|[@#!.]/g,comments:{blockComment:["/*","*/"],lineComment:"//"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*\\/\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\/"),end:new RegExp("^\\s*\\/\\*\\s*#endregion\\b.*\\*\\/")}}},t.language={defaultToken:"",tokenPostfix:".less",identifier:"-?-?([a-zA-Z]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",identifierPlus:"-?-?([a-zA-Z:.]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-:.]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.bracket"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],tokenizer:{root:[{include:"@nestedJSBegin"},["[ \\t\\r\\n]+",""],{include:"@comments"},{include:"@keyword"},{include:"@strings"},{include:"@numbers"},["[*_]?[a-zA-Z\\-\\s]+(?=:.*(;|(\\\\$)))","attribute.name","@attribute"],["url(\\-prefix)?\\(",{token:"tag",next:"@urldeclaration"}],["[{}()\\[\\]]","@brackets"],["[,:;]","delimiter"],["#@identifierPlus","tag.id"],["&","tag"],["\\.@identifierPlus(?=\\()","tag.class","@attribute"],["\\.@identifierPlus","tag.class"],["@identifierPlus","tag"],{include:"@operators"},["@(@identifier(?=[:,\\)]))","variable","@attribute"],["@(@identifier)","variable"],["@","key","@atRules"]],nestedJSBegin:[["``","delimiter.backtick"],["`",{token:"delimiter.backtick",next:"@nestedJSEnd",nextEmbedded:"text/javascript"}]],nestedJSEnd:[["`",{token:"delimiter.backtick",next:"@pop",nextEmbedded:"@pop"}]],operators:[["[<>=\\+\\-\\*\\/\\^\\|\\~]","operator"]],keyword:[["(@[\\s]*import|![\\s]*important|true|false|when|iscolor|isnumber|isstring|iskeyword|isurl|ispixel|ispercentage|isem|hue|saturation|lightness|alpha|lighten|darken|saturate|desaturate|fadein|fadeout|fade|spin|mix|round|ceil|floor|percentage)\\b","keyword"]],urldeclaration:[{include:"@strings"},["[^)\r\n]+","string"],["\\)",{token:"tag",next:"@pop"}]],attribute:[{include:"@nestedJSBegin"},{include:"@comments"},{include:"@strings"},{include:"@numbers"},{include:"@keyword"},["[a-zA-Z\\-]+(?=\\()","attribute.value","@attribute"],[">","operator","@pop"],["@identifier","attribute.value"],{include:"@operators"},["@(@identifier)","variable"],["[)\\}]","@brackets","@pop"],["[{}()\\[\\]>]","@brackets"],["[;]","delimiter","@pop"],["[,=:]","delimiter"],["\\s",""],[".","attribute.value"]],comments:[["\\/\\*","comment","@comment"],["\\/\\/+.*","comment"]],comment:[["\\*\\/","comment","@pop"],[".","comment"]],numbers:[["(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?",{token:"attribute.value.number",next:"@units"}],["#[0-9a-fA-F_]+(?!\\w)","attribute.value.hex"]],units:[["(em|ex|ch|rem|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?","attribute.value.unit","@pop"]],strings:[['~?"',{token:"string.delimiter",next:"@stringsEndDoubleQuote"}],["~?'",{token:"string.delimiter",next:"@stringsEndQuote"}]],stringsEndDoubleQuote:[['\\\\"',"string"],['"',{token:"string.delimiter",next:"@popall"}],[".","string"]],stringsEndQuote:[["\\\\'","string"],["'",{token:"string.delimiter",next:"@popall"}],[".","string"]],atRules:[{include:"@comments"},{include:"@strings"},["[()]","delimiter"],["[\\{;]","delimiter","@pop"],[".","key"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/lua/lua.js b/public/react/public/js/monaco/vs/basic-languages/lua/lua.js new file mode 100755 index 000000000..f25ccf29f --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/lua/lua.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/lua/lua",["require","exports"],function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.conf={comments:{lineComment:"--",blockComment:["--[[","]]"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},n.language={defaultToken:"",tokenPostfix:".lua",keywords:["and","break","do","else","elseif","end","false","for","function","goto","if","in","local","nil","not","or","repeat","return","then","true","until","while"],brackets:[{token:"delimiter.bracket",open:"{",close:"}"},{token:"delimiter.array",open:"[",close:"]"},{token:"delimiter.parenthesis",open:"(",close:")"}],operators:["+","-","*","/","%","^","#","==","~=","<=",">=","<",">","=",";",":",",",".","..","..."],symbols:/[=>",notIn:["string"]}],surroundingPairs:[{open:"(",close:")"},{open:"[",close:"]"},{open:"`",close:"`"}],folding:{markers:{start:new RegExp("^\\s*\x3c!--\\s*#?region\\b.*--\x3e"),end:new RegExp("^\\s*\x3c!--\\s*#?endregion\\b.*--\x3e")}}},t.language={defaultToken:"",tokenPostfix:".md",control:/[\\`*_\[\]{}()#+\-\.!]/,noncontrol:/[^\\`*_\[\]{}()#+\-\.!]/,escapes:/\\(?:@control)/,jsescapes:/\\(?:[btnfr\\"']|[0-7][0-7]?|[0-3][0-7]{2})/,empty:["area","base","basefont","br","col","frame","hr","img","input","isindex","link","meta","param"],tokenizer:{root:[[/^(\s{0,3})(#+)((?:[^\\#]|@escapes)+)((?:#+)?)/,["white","keyword",s,s]],[/^\s*(=+|\-+)\s*$/,"keyword"],[/^\s*((\*[ ]?)+)\s*$/,"meta.separator"],[/^\s*>+/,"comment"],[/^\s*([\*\-+:]|\d+\.)\s/,"keyword"],[/^(\t|[ ]{4})[^ ].*$/,n],[/^\s*~~~\s*((?:\w|[\/\-#])+)?\s*$/,{token:n,next:"@codeblock"}],[/^\s*```\s*((?:\w|[\/\-#])+)\s*$/,{token:n,next:"@codeblockgh",nextEmbedded:"$1"}],[/^\s*```\s*$/,{token:n,next:"@codeblock"}],{include:"@linecontent"}],codeblock:[[/^\s*~~~\s*$/,{token:n,next:"@pop"}],[/^\s*```\s*$/,{token:n,next:"@pop"}],[/.*$/,o]],codeblockgh:[[/```\s*$/,{token:o,next:"@pop",nextEmbedded:"@pop"}],[/[^`]+/,o]],linecontent:[[/&\w+;/,"string.escape"],[/@escapes/,"escape"],[/\b__([^\\_]|@escapes|_(?!_))+__\b/,"strong"],[/\*\*([^\\*]|@escapes|\*(?!\*))+\*\*/,"strong"],[/\b_[^_]+_\b/,"emphasis"],[/\*([^\\*]|@escapes)+\*/,"emphasis"],[/`([^\\`]|@escapes)+`/,"variable"],[/\{[^}]+\}/,"string.target"],[/(!?\[)((?:[^\]\\]|@escapes)*)(\]\([^\)]+\))/,["string.link","","string.link"]],[/(!?\[)((?:[^\]\\]|@escapes)*)(\])/,"string.link"],{include:"html"}],html:[[/<(\w+)\/>/,"tag"],[/<(\w+)/,{cases:{"@empty":{token:"tag",next:"@tag.$1"},"@default":{token:"tag",next:"@tag.$1"}}}],[/<\/(\w+)\s*>/,{token:"tag"}],[//,"comment","@pop"],[//,"comment.html","@pop"],[/[^-]+/,"comment.content.html"],[/./,"comment.content.html"]],otherTag:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInSimpleState.otherTag"}],[/\/?>/,"delimiter.html","@pop"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/]],script:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInSimpleState.script"}],[/type/,"attribute.name","@scriptAfterType"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.text/javascript",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/(<\/)(script\s*)(>)/,["delimiter.html","tag.html",{token:"delimiter.html",next:"@pop"}]]],scriptAfterType:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInSimpleState.scriptAfterType"}],[/=/,"delimiter","@scriptAfterTypeEquals"],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.text/javascript",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptAfterTypeEquals:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInSimpleState.scriptAfterTypeEquals"}],[/"([^"]*)"/,{token:"attribute.value",switchTo:"@scriptWithCustomType.$1"}],[/'([^']*)'/,{token:"attribute.value",switchTo:"@scriptWithCustomType.$1"}],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.text/javascript",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptWithCustomType:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInSimpleState.scriptWithCustomType.$S2"}],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.$S2",nextEmbedded:"$S2"}],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptEmbedded:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInEmbeddedState.scriptEmbedded.$S2",nextEmbedded:"@pop"}],[/<\/script/,{token:"@rematch",next:"@pop",nextEmbedded:"@pop"}]],style:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInSimpleState.style"}],[/type/,"attribute.name","@styleAfterType"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/>/,{token:"delimiter.html",next:"@styleEmbedded.text/css",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/(<\/)(style\s*)(>)/,["delimiter.html","tag.html",{token:"delimiter.html",next:"@pop"}]]],styleAfterType:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInSimpleState.styleAfterType"}],[/=/,"delimiter","@styleAfterTypeEquals"],[/>/,{token:"delimiter.html",next:"@styleEmbedded.text/css",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleAfterTypeEquals:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInSimpleState.styleAfterTypeEquals"}],[/"([^"]*)"/,{token:"attribute.value",switchTo:"@styleWithCustomType.$1"}],[/'([^']*)'/,{token:"attribute.value",switchTo:"@styleWithCustomType.$1"}],[/>/,{token:"delimiter.html",next:"@styleEmbedded.text/css",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleWithCustomType:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInSimpleState.styleWithCustomType.$S2"}],[/>/,{token:"delimiter.html",next:"@styleEmbedded.$S2",nextEmbedded:"$S2"}],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleEmbedded:[[/<\?((php)|=)?/,{token:"@rematch",switchTo:"@phpInEmbeddedState.styleEmbedded.$S2",nextEmbedded:"@pop"}],[/<\/style/,{token:"@rematch",next:"@pop",nextEmbedded:"@pop"}]],phpInSimpleState:[[/<\?((php)|=)?/,"metatag.php"],[/\?>/,{token:"metatag.php",switchTo:"@$S2.$S3"}],{include:"phpRoot"}],phpInEmbeddedState:[[/<\?((php)|=)?/,"metatag.php"],[/\?>/,{token:"metatag.php",switchTo:"@$S2.$S3",nextEmbedded:"$S3"}],{include:"phpRoot"}],phpRoot:[[/[a-zA-Z_]\w*/,{cases:{"@phpKeywords":{token:"keyword.php"},"@phpCompileTimeConstants":{token:"constant.php"},"@default":"identifier.php"}}],[/[$a-zA-Z_]\w*/,{cases:{"@phpPreDefinedVariables":{token:"variable.predefined.php"},"@default":"variable.php"}}],[/[{}]/,"delimiter.bracket.php"],[/[\[\]]/,"delimiter.array.php"],[/[()]/,"delimiter.parenthesis.php"],[/[ \t\r\n]+/],[/#/,"comment.php","@phpLineComment"],[/\/\//,"comment.php","@phpLineComment"],[/\/\*/,"comment.php","@phpComment"],[/"/,"string.php","@phpDoubleQuoteString"],[/'/,"string.php","@phpSingleQuoteString"],[/[\+\-\*\%\&\|\^\~\!\=\<\>\/\?\;\:\.\,\@]/,"delimiter.php"],[/\d*\d+[eE]([\-+]?\d+)?/,"number.float.php"],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float.php"],[/0[xX][0-9a-fA-F']*[0-9a-fA-F]/,"number.hex.php"],[/0[0-7']*[0-7]/,"number.octal.php"],[/0[bB][0-1']*[0-1]/,"number.binary.php"],[/\d[\d']*/,"number.php"],[/\d/,"number.php"]],phpComment:[[/\*\//,"comment.php","@pop"],[/[^*]+/,"comment.php"],[/./,"comment.php"]],phpLineComment:[[/\?>/,{token:"@rematch",next:"@pop"}],[/.$/,"comment.php","@pop"],[/[^?]+$/,"comment.php","@pop"],[/[^?]+/,"comment.php"],[/./,"comment.php"]],phpDoubleQuoteString:[[/[^\\"]+/,"string.php"],[/@escapes/,"string.escape.php"],[/\\./,"string.escape.invalid.php"],[/"/,"string.php","@pop"]],phpSingleQuoteString:[[/[^\\']+/,"string.php"],[/@escapes/,"string.escape.php"],[/\\./,"string.escape.invalid.php"],[/'/,"string.php","@pop"]]},phpKeywords:["abstract","and","array","as","break","callable","case","catch","cfunction","class","clone","const","continue","declare","default","do","else","elseif","enddeclare","endfor","endforeach","endif","endswitch","endwhile","extends","false","final","for","foreach","function","global","goto","if","implements","interface","instanceof","insteadof","namespace","new","null","object","old_function","or","private","protected","public","resource","static","switch","throw","trait","try","true","use","var","while","xor","die","echo","empty","exit","eval","include","include_once","isset","list","require","require_once","return","print","unset","yield","__construct"],phpCompileTimeConstants:["__CLASS__","__DIR__","__FILE__","__LINE__","__NAMESPACE__","__METHOD__","__FUNCTION__","__TRAIT__"],phpPreDefinedVariables:["$GLOBALS","$_SERVER","$_GET","$_POST","$_FILES","$_REQUEST","$_SESSION","$_ENV","$_COOKIE","$php_errormsg","$HTTP_RAW_POST_DATA","$http_response_header","$argc","$argv"],escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/postiats/postiats.js b/public/react/public/js/monaco/vs/basic-languages/postiats/postiats.js new file mode 100755 index 000000000..9cd96cbde --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/postiats/postiats.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/postiats/postiats",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={comments:{lineComment:"//",blockComment:["(*","*)"]},brackets:[["{","}"],["[","]"],["(",")"],["<",">"]],autoClosingPairs:[{open:'"',close:'"',notIn:["string","comment"]},{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]}]},t.language={tokenPostfix:".pats",defaultToken:"invalid",keywords:["abstype","abst0ype","absprop","absview","absvtype","absviewtype","absvt0ype","absviewt0ype","as","and","assume","begin","classdec","datasort","datatype","dataprop","dataview","datavtype","dataviewtype","do","end","extern","extype","extvar","exception","fn","fnx","fun","prfn","prfun","praxi","castfn","if","then","else","ifcase","in","infix","infixl","infixr","prefix","postfix","implmnt","implement","primplmnt","primplement","import","let","local","macdef","macrodef","nonfix","symelim","symintr","overload","of","op","rec","sif","scase","sortdef","sta","stacst","stadef","static","staload","dynload","try","tkindef","typedef","propdef","viewdef","vtypedef","viewtypedef","prval","var","prvar","when","where","with","withtype","withprop","withview","withvtype","withviewtype"],keywords_dlr:["$delay","$ldelay","$arrpsz","$arrptrsize","$d2ctype","$effmask","$effmask_ntm","$effmask_exn","$effmask_ref","$effmask_wrt","$effmask_all","$extern","$extkind","$extype","$extype_struct","$extval","$extfcall","$extmcall","$literal","$myfilename","$mylocation","$myfunction","$lst","$lst_t","$lst_vt","$list","$list_t","$list_vt","$rec","$rec_t","$rec_vt","$record","$record_t","$record_vt","$tup","$tup_t","$tup_vt","$tuple","$tuple_t","$tuple_vt","$break","$continue","$raise","$showtype","$vcopyenv_v","$vcopyenv_vt","$tempenver","$solver_assert","$solver_verify"],keywords_srp:["#if","#ifdef","#ifndef","#then","#elif","#elifdef","#elifndef","#else","#endif","#error","#prerr","#print","#assert","#undef","#define","#include","#require","#pragma","#codegen2","#codegen3"],irregular_keyword_list:["val+","val-","val","case+","case-","case","addr@","addr","fold@","free@","fix@","fix","lam@","lam","llam@","llam","viewt@ype+","viewt@ype-","viewt@ype","viewtype+","viewtype-","viewtype","view+","view-","view@","view","type+","type-","type","vtype+","vtype-","vtype","vt@ype+","vt@ype-","vt@ype","viewt@ype+","viewt@ype-","viewt@ype","viewtype+","viewtype-","viewtype","prop+","prop-","prop","type+","type-","type","t@ype","t@ype+","t@ype-","abst@ype","abstype","absviewt@ype","absvt@ype","for*","for","while*","while"],keywords_types:["bool","double","byte","int","short","char","void","unit","long","float","string","strptr"],keywords_effects:["0","fun","clo","prf","funclo","cloptr","cloref","ref","ntm","1"],operators:["@","!","|","`",":","$",".","=","#","~","..","...","=>","=<>","=/=>","=>>","=/=>>","<",">","><",".<",">.",".<>.","->","-<>"],brackets:[{open:",(",close:")",token:"delimiter.parenthesis"},{open:"`(",close:")",token:"delimiter.parenthesis"},{open:"%(",close:")",token:"delimiter.parenthesis"},{open:"'(",close:")",token:"delimiter.parenthesis"},{open:"'{",close:"}",token:"delimiter.parenthesis"},{open:"@(",close:")",token:"delimiter.parenthesis"},{open:"@{",close:"}",token:"delimiter.brace"},{open:"@[",close:"]",token:"delimiter.square"},{open:"#[",close:"]",token:"delimiter.square"},{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],symbols:/[=>]/,digit:/[0-9]/,digitseq0:/@digit*/,xdigit:/[0-9A-Za-z]/,xdigitseq0:/@xdigit*/,INTSP:/[lLuU]/,FLOATSP:/[fFlL]/,fexponent:/[eE][+-]?[0-9]+/,fexponent_bin:/[pP][+-]?[0-9]+/,deciexp:/\.[0-9]*@fexponent?/,hexiexp:/\.[0-9a-zA-Z]*@fexponent_bin?/,irregular_keywords:/val[+-]?|case[+-]?|addr\@?|fold\@|free\@|fix\@?|lam\@?|llam\@?|prop[+-]?|type[+-]?|view[+-@]?|viewt@?ype[+-]?|t@?ype[+-]?|v(iew)?t@?ype[+-]?|abst@?ype|absv(iew)?t@?ype|for\*?|while\*?/,ESCHAR:/[ntvbrfa\\\?'"\(\[\{]/,start:"root",tokenizer:{root:[{regex:/[ \t\r\n]+/,action:{token:""}},{regex:/\(\*\)/,action:{token:"invalid"}},{regex:/\(\*/,action:{token:"comment",next:"lexing_COMMENT_block_ml"}},{regex:/\(/,action:"@brackets"},{regex:/\)/,action:"@brackets"},{regex:/\[/,action:"@brackets"},{regex:/\]/,action:"@brackets"},{regex:/\{/,action:"@brackets"},{regex:/\}/,action:"@brackets"},{regex:/,\(/,action:"@brackets"},{regex:/,/,action:{token:"delimiter.comma"}},{regex:/;/,action:{token:"delimiter.semicolon"}},{regex:/@\(/,action:"@brackets"},{regex:/@\[/,action:"@brackets"},{regex:/@\{/,action:"@brackets"},{regex:/:/,action:{token:"@rematch",next:"@pop"}}],lexing_EXTCODE:[{regex:/^%}/,action:{token:"@rematch",next:"@pop",nextEmbedded:"@pop"}},{regex:/[^%]+/,action:""}],lexing_DQUOTE:[{regex:/"/,action:{token:"string.quote",next:"@pop"}},{regex:/(\{\$)(@IDENTFST@IDENTRST*)(\})/,action:[{token:"string.escape"},{token:"identifier"},{token:"string.escape"}]},{regex:/\\$/,action:{token:"string.escape"}},{regex:/\\(@ESCHAR|[xX]@xdigit+|@digit+)/,action:{token:"string.escape"}},{regex:/[^\\"]+/,action:{token:"string"}}]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/powerquery/powerquery.js b/public/react/public/js/monaco/vs/basic-languages/powerquery/powerquery.js new file mode 100755 index 000000000..0d33e2580 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/powerquery/powerquery.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/powerquery/powerquery",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["[","]"],["(",")"],["{","}"]],autoClosingPairs:[{open:'"',close:'"',notIn:["string","comment","identifier"]},{open:"[",close:"]",notIn:["string","comment","identifier"]},{open:"(",close:")",notIn:["string","comment","identifier"]},{open:"{",close:"}",notIn:["string","comment","identifier"]}]},t.language={defaultToken:"",tokenPostfix:".pq",ignoreCase:!1,brackets:[{open:"[",close:"]",token:"delimiter.square"},{open:"{",close:"}",token:"delimiter.brackets"},{open:"(",close:")",token:"delimiter.parenthesis"}],operatorKeywords:["and","not","or"],keywords:["as","each","else","error","false","if","in","is","let","meta","otherwise","section","shared","then","true","try","type"],constructors:["#binary","#date","#datetime","#datetimezone","#duration","#table","#time"],constants:["#infinity","#nan","#sections","#shared"],typeKeywords:["action","any","anynonnull","none","null","logical","number","time","date","datetime","datetimezone","duration","text","binary","list","record","table","function"],builtinFunctions:["Access.Database","Action.Return","Action.Sequence","Action.Try","ActiveDirectory.Domains","AdoDotNet.DataSource","AdoDotNet.Query","AdobeAnalytics.Cubes","AnalysisServices.Database","AnalysisServices.Databases","AzureStorage.BlobContents","AzureStorage.Blobs","AzureStorage.Tables","Binary.Buffer","Binary.Combine","Binary.Compress","Binary.Decompress","Binary.End","Binary.From","Binary.FromList","Binary.FromText","Binary.InferContentType","Binary.Length","Binary.ToList","Binary.ToText","BinaryFormat.7BitEncodedSignedInteger","BinaryFormat.7BitEncodedUnsignedInteger","BinaryFormat.Binary","BinaryFormat.Byte","BinaryFormat.ByteOrder","BinaryFormat.Choice","BinaryFormat.Decimal","BinaryFormat.Double","BinaryFormat.Group","BinaryFormat.Length","BinaryFormat.List","BinaryFormat.Null","BinaryFormat.Record","BinaryFormat.SignedInteger16","BinaryFormat.SignedInteger32","BinaryFormat.SignedInteger64","BinaryFormat.Single","BinaryFormat.Text","BinaryFormat.Transform","BinaryFormat.UnsignedInteger16","BinaryFormat.UnsignedInteger32","BinaryFormat.UnsignedInteger64","Byte.From","Character.FromNumber","Character.ToNumber","Combiner.CombineTextByDelimiter","Combiner.CombineTextByEachDelimiter","Combiner.CombineTextByLengths","Combiner.CombineTextByPositions","Combiner.CombineTextByRanges","Comparer.Equals","Comparer.FromCulture","Comparer.Ordinal","Comparer.OrdinalIgnoreCase","Csv.Document","Cube.AddAndExpandDimensionColumn","Cube.AddMeasureColumn","Cube.ApplyParameter","Cube.AttributeMemberId","Cube.AttributeMemberProperty","Cube.CollapseAndRemoveColumns","Cube.Dimensions","Cube.DisplayFolders","Cube.Measures","Cube.Parameters","Cube.Properties","Cube.PropertyKey","Cube.ReplaceDimensions","Cube.Transform","Currency.From","DB2.Database","Date.AddDays","Date.AddMonths","Date.AddQuarters","Date.AddWeeks","Date.AddYears","Date.Day","Date.DayOfWeek","Date.DayOfWeekName","Date.DayOfYear","Date.DaysInMonth","Date.EndOfDay","Date.EndOfMonth","Date.EndOfQuarter","Date.EndOfWeek","Date.EndOfYear","Date.From","Date.FromText","Date.IsInCurrentDay","Date.IsInCurrentMonth","Date.IsInCurrentQuarter","Date.IsInCurrentWeek","Date.IsInCurrentYear","Date.IsInNextDay","Date.IsInNextMonth","Date.IsInNextNDays","Date.IsInNextNMonths","Date.IsInNextNQuarters","Date.IsInNextNWeeks","Date.IsInNextNYears","Date.IsInNextQuarter","Date.IsInNextWeek","Date.IsInNextYear","Date.IsInPreviousDay","Date.IsInPreviousMonth","Date.IsInPreviousNDays","Date.IsInPreviousNMonths","Date.IsInPreviousNQuarters","Date.IsInPreviousNWeeks","Date.IsInPreviousNYears","Date.IsInPreviousQuarter","Date.IsInPreviousWeek","Date.IsInPreviousYear","Date.IsInYearToDate","Date.IsLeapYear","Date.Month","Date.MonthName","Date.QuarterOfYear","Date.StartOfDay","Date.StartOfMonth","Date.StartOfQuarter","Date.StartOfWeek","Date.StartOfYear","Date.ToRecord","Date.ToText","Date.WeekOfMonth","Date.WeekOfYear","Date.Year","DateTime.AddZone","DateTime.Date","DateTime.FixedLocalNow","DateTime.From","DateTime.FromFileTime","DateTime.FromText","DateTime.IsInCurrentHour","DateTime.IsInCurrentMinute","DateTime.IsInCurrentSecond","DateTime.IsInNextHour","DateTime.IsInNextMinute","DateTime.IsInNextNHours","DateTime.IsInNextNMinutes","DateTime.IsInNextNSeconds","DateTime.IsInNextSecond","DateTime.IsInPreviousHour","DateTime.IsInPreviousMinute","DateTime.IsInPreviousNHours","DateTime.IsInPreviousNMinutes","DateTime.IsInPreviousNSeconds","DateTime.IsInPreviousSecond","DateTime.LocalNow","DateTime.Time","DateTime.ToRecord","DateTime.ToText","DateTimeZone.FixedLocalNow","DateTimeZone.FixedUtcNow","DateTimeZone.From","DateTimeZone.FromFileTime","DateTimeZone.FromText","DateTimeZone.LocalNow","DateTimeZone.RemoveZone","DateTimeZone.SwitchZone","DateTimeZone.ToLocal","DateTimeZone.ToRecord","DateTimeZone.ToText","DateTimeZone.ToUtc","DateTimeZone.UtcNow","DateTimeZone.ZoneHours","DateTimeZone.ZoneMinutes","Decimal.From","Diagnostics.ActivityId","Diagnostics.Trace","DirectQueryCapabilities.From","Double.From","Duration.Days","Duration.From","Duration.FromText","Duration.Hours","Duration.Minutes","Duration.Seconds","Duration.ToRecord","Duration.ToText","Duration.TotalDays","Duration.TotalHours","Duration.TotalMinutes","Duration.TotalSeconds","Embedded.Value","Error.Record","Excel.CurrentWorkbook","Excel.Workbook","Exchange.Contents","Expression.Constant","Expression.Evaluate","Expression.Identifier","Facebook.Graph","File.Contents","Folder.Contents","Folder.Files","Function.From","Function.Invoke","Function.InvokeAfter","Function.IsDataSource","GoogleAnalytics.Accounts","Guid.From","HdInsight.Containers","HdInsight.Contents","HdInsight.Files","Hdfs.Contents","Hdfs.Files","Informix.Database","Int16.From","Int32.From","Int64.From","Int8.From","ItemExpression.From","Json.Document","Json.FromValue","Lines.FromBinary","Lines.FromText","Lines.ToBinary","Lines.ToText","List.Accumulate","List.AllTrue","List.Alternate","List.AnyTrue","List.Average","List.Buffer","List.Combine","List.Contains","List.ContainsAll","List.ContainsAny","List.Count","List.Covariance","List.DateTimeZones","List.DateTimes","List.Dates","List.Difference","List.Distinct","List.Durations","List.FindText","List.First","List.FirstN","List.Generate","List.InsertRange","List.Intersect","List.IsDistinct","List.IsEmpty","List.Last","List.LastN","List.MatchesAll","List.MatchesAny","List.Max","List.MaxN","List.Median","List.Min","List.MinN","List.Mode","List.Modes","List.NonNullCount","List.Numbers","List.PositionOf","List.PositionOfAny","List.Positions","List.Product","List.Random","List.Range","List.RemoveFirstN","List.RemoveItems","List.RemoveLastN","List.RemoveMatchingItems","List.RemoveNulls","List.RemoveRange","List.Repeat","List.ReplaceMatchingItems","List.ReplaceRange","List.ReplaceValue","List.Reverse","List.Select","List.Single","List.SingleOrDefault","List.Skip","List.Sort","List.StandardDeviation","List.Sum","List.Times","List.Transform","List.TransformMany","List.Union","List.Zip","Logical.From","Logical.FromText","Logical.ToText","MQ.Queue","MySQL.Database","Number.Abs","Number.Acos","Number.Asin","Number.Atan","Number.Atan2","Number.BitwiseAnd","Number.BitwiseNot","Number.BitwiseOr","Number.BitwiseShiftLeft","Number.BitwiseShiftRight","Number.BitwiseXor","Number.Combinations","Number.Cos","Number.Cosh","Number.Exp","Number.Factorial","Number.From","Number.FromText","Number.IntegerDivide","Number.IsEven","Number.IsNaN","Number.IsOdd","Number.Ln","Number.Log","Number.Log10","Number.Mod","Number.Permutations","Number.Power","Number.Random","Number.RandomBetween","Number.Round","Number.RoundAwayFromZero","Number.RoundDown","Number.RoundTowardZero","Number.RoundUp","Number.Sign","Number.Sin","Number.Sinh","Number.Sqrt","Number.Tan","Number.Tanh","Number.ToText","OData.Feed","Odbc.DataSource","Odbc.Query","OleDb.DataSource","OleDb.Query","Oracle.Database","Percentage.From","PostgreSQL.Database","RData.FromBinary","Record.AddField","Record.Combine","Record.Field","Record.FieldCount","Record.FieldNames","Record.FieldOrDefault","Record.FieldValues","Record.FromList","Record.FromTable","Record.HasFields","Record.RemoveFields","Record.RenameFields","Record.ReorderFields","Record.SelectFields","Record.ToList","Record.ToTable","Record.TransformFields","Replacer.ReplaceText","Replacer.ReplaceValue","RowExpression.Column","RowExpression.From","Salesforce.Data","Salesforce.Reports","SapBusinessWarehouse.Cubes","SapHana.Database","SharePoint.Contents","SharePoint.Files","SharePoint.Tables","Single.From","Soda.Feed","Splitter.SplitByNothing","Splitter.SplitTextByAnyDelimiter","Splitter.SplitTextByDelimiter","Splitter.SplitTextByEachDelimiter","Splitter.SplitTextByLengths","Splitter.SplitTextByPositions","Splitter.SplitTextByRanges","Splitter.SplitTextByRepeatedLengths","Splitter.SplitTextByWhitespace","Sql.Database","Sql.Databases","SqlExpression.SchemaFrom","SqlExpression.ToExpression","Sybase.Database","Table.AddColumn","Table.AddIndexColumn","Table.AddJoinColumn","Table.AddKey","Table.AggregateTableColumn","Table.AlternateRows","Table.Buffer","Table.Column","Table.ColumnCount","Table.ColumnNames","Table.ColumnsOfType","Table.Combine","Table.CombineColumns","Table.Contains","Table.ContainsAll","Table.ContainsAny","Table.DemoteHeaders","Table.Distinct","Table.DuplicateColumn","Table.ExpandListColumn","Table.ExpandRecordColumn","Table.ExpandTableColumn","Table.FillDown","Table.FillUp","Table.FilterWithDataTable","Table.FindText","Table.First","Table.FirstN","Table.FirstValue","Table.FromColumns","Table.FromList","Table.FromPartitions","Table.FromRecords","Table.FromRows","Table.FromValue","Table.Group","Table.HasColumns","Table.InsertRows","Table.IsDistinct","Table.IsEmpty","Table.Join","Table.Keys","Table.Last","Table.LastN","Table.MatchesAllRows","Table.MatchesAnyRows","Table.Max","Table.MaxN","Table.Min","Table.MinN","Table.NestedJoin","Table.Partition","Table.PartitionValues","Table.Pivot","Table.PositionOf","Table.PositionOfAny","Table.PrefixColumns","Table.Profile","Table.PromoteHeaders","Table.Range","Table.RemoveColumns","Table.RemoveFirstN","Table.RemoveLastN","Table.RemoveMatchingRows","Table.RemoveRows","Table.RemoveRowsWithErrors","Table.RenameColumns","Table.ReorderColumns","Table.Repeat","Table.ReplaceErrorValues","Table.ReplaceKeys","Table.ReplaceMatchingRows","Table.ReplaceRelationshipIdentity","Table.ReplaceRows","Table.ReplaceValue","Table.ReverseRows","Table.RowCount","Table.Schema","Table.SelectColumns","Table.SelectRows","Table.SelectRowsWithErrors","Table.SingleRow","Table.Skip","Table.Sort","Table.SplitColumn","Table.ToColumns","Table.ToList","Table.ToRecords","Table.ToRows","Table.TransformColumnNames","Table.TransformColumnTypes","Table.TransformColumns","Table.TransformRows","Table.Transpose","Table.Unpivot","Table.UnpivotOtherColumns","Table.View","Table.ViewFunction","TableAction.DeleteRows","TableAction.InsertRows","TableAction.UpdateRows","Tables.GetRelationships","Teradata.Database","Text.AfterDelimiter","Text.At","Text.BeforeDelimiter","Text.BetweenDelimiters","Text.Clean","Text.Combine","Text.Contains","Text.End","Text.EndsWith","Text.Format","Text.From","Text.FromBinary","Text.Insert","Text.Length","Text.Lower","Text.Middle","Text.NewGuid","Text.PadEnd","Text.PadStart","Text.PositionOf","Text.PositionOfAny","Text.Proper","Text.Range","Text.Remove","Text.RemoveRange","Text.Repeat","Text.Replace","Text.ReplaceRange","Text.Select","Text.Split","Text.SplitAny","Text.Start","Text.StartsWith","Text.ToBinary","Text.ToList","Text.Trim","Text.TrimEnd","Text.TrimStart","Text.Upper","Time.EndOfHour","Time.From","Time.FromText","Time.Hour","Time.Minute","Time.Second","Time.StartOfHour","Time.ToRecord","Time.ToText","Type.AddTableKey","Type.ClosedRecord","Type.Facets","Type.ForFunction","Type.ForRecord","Type.FunctionParameters","Type.FunctionRequiredParameters","Type.FunctionReturn","Type.Is","Type.IsNullable","Type.IsOpenRecord","Type.ListItem","Type.NonNullable","Type.OpenRecord","Type.RecordFields","Type.ReplaceFacets","Type.ReplaceTableKeys","Type.TableColumn","Type.TableKeys","Type.TableRow","Type.TableSchema","Type.Union","Uri.BuildQueryString","Uri.Combine","Uri.EscapeDataString","Uri.Parts","Value.Add","Value.As","Value.Compare","Value.Divide","Value.Equals","Value.Firewall","Value.FromText","Value.Is","Value.Metadata","Value.Multiply","Value.NativeQuery","Value.NullableEquals","Value.RemoveMetadata","Value.ReplaceMetadata","Value.ReplaceType","Value.Subtract","Value.Type","ValueAction.NativeStatement","ValueAction.Replace","Variable.Value","Web.Contents","Web.Page","WebAction.Request","Xml.Document","Xml.Tables"],builtinConstants:["BinaryEncoding.Base64","BinaryEncoding.Hex","BinaryOccurrence.Optional","BinaryOccurrence.Repeating","BinaryOccurrence.Required","ByteOrder.BigEndian","ByteOrder.LittleEndian","Compression.Deflate","Compression.GZip","CsvStyle.QuoteAfterDelimiter","CsvStyle.QuoteAlways","Culture.Current","Day.Friday","Day.Monday","Day.Saturday","Day.Sunday","Day.Thursday","Day.Tuesday","Day.Wednesday","ExtraValues.Error","ExtraValues.Ignore","ExtraValues.List","GroupKind.Global","GroupKind.Local","JoinAlgorithm.Dynamic","JoinAlgorithm.LeftHash","JoinAlgorithm.LeftIndex","JoinAlgorithm.PairwiseHash","JoinAlgorithm.RightHash","JoinAlgorithm.RightIndex","JoinAlgorithm.SortMerge","JoinKind.FullOuter","JoinKind.Inner","JoinKind.LeftAnti","JoinKind.LeftOuter","JoinKind.RightAnti","JoinKind.RightOuter","JoinSide.Left","JoinSide.Right","MissingField.Error","MissingField.Ignore","MissingField.UseNull","Number.E","Number.Epsilon","Number.NaN","Number.NegativeInfinity","Number.PI","Number.PositiveInfinity","Occurrence.All","Occurrence.First","Occurrence.Last","Occurrence.Optional","Occurrence.Repeating","Occurrence.Required","Order.Ascending","Order.Descending","Precision.Decimal","Precision.Double","QuoteStyle.Csv","QuoteStyle.None","RelativePosition.FromEnd","RelativePosition.FromStart","RoundingMode.AwayFromZero","RoundingMode.Down","RoundingMode.ToEven","RoundingMode.TowardZero","RoundingMode.Up","SapHanaDistribution.All","SapHanaDistribution.Connection","SapHanaDistribution.Off","SapHanaDistribution.Statement","SapHanaRangeOperator.Equals","SapHanaRangeOperator.GreaterThan","SapHanaRangeOperator.GreaterThanOrEquals","SapHanaRangeOperator.LessThan","SapHanaRangeOperator.LessThanOrEquals","SapHanaRangeOperator.NotEquals","TextEncoding.Ascii","TextEncoding.BigEndianUnicode","TextEncoding.Unicode","TextEncoding.Utf16","TextEncoding.Utf8","TextEncoding.Windows","TraceLevel.Critical","TraceLevel.Error","TraceLevel.Information","TraceLevel.Verbose","TraceLevel.Warning","WebMethod.Delete","WebMethod.Get","WebMethod.Head","WebMethod.Patch","WebMethod.Post","WebMethod.Put"],builtinTypes:["Action.Type","Any.Type","Binary.Type","BinaryEncoding.Type","BinaryOccurrence.Type","Byte.Type","ByteOrder.Type","Character.Type","Compression.Type","CsvStyle.Type","Currency.Type","Date.Type","DateTime.Type","DateTimeZone.Type","Day.Type","Decimal.Type","Double.Type","Duration.Type","ExtraValues.Type","Function.Type","GroupKind.Type","Guid.Type","Int16.Type","Int32.Type","Int64.Type","Int8.Type","JoinAlgorithm.Type","JoinKind.Type","JoinSide.Type","List.Type","Logical.Type","MissingField.Type","None.Type","Null.Type","Number.Type","Occurrence.Type","Order.Type","Password.Type","Percentage.Type","Precision.Type","QuoteStyle.Type","Record.Type","RelativePosition.Type","RoundingMode.Type","SapHanaDistribution.Type","SapHanaRangeOperator.Type","Single.Type","Table.Type","Text.Type","TextEncoding.Type","Time.Type","TraceLevel.Type","Type.Type","Uri.Type","WebMethod.Type"],tokenizer:{root:[[/#"[\w \.]+"/,"identifier.quote"],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float"],[/0[xX][0-9a-fA-F]+/,"number.hex"],[/\d+([eE][\-+]?\d+)?/,"number"],[/(#?[a-z]+)\b/,{cases:{"@typeKeywords":"type","@keywords":"keyword","@constants":"constant","@constructors":"constructor","@operatorKeywords":"operators","@default":"identifier"}}],[/\b([A-Z][a-zA-Z0-9]+\.Type)\b/,{cases:{"@builtinTypes":"type","@default":"identifier"}}],[/\b([A-Z][a-zA-Z0-9]+\.[A-Z][a-zA-Z0-9]+)\b/,{cases:{"@builtinFunctions":"keyword.function","@builtinConstants":"constant","@default":"identifier"}}],[/\b([a-zA-Z_][\w\.]*)\b/,"identifier"],{include:"@whitespace"},{include:"@comments"},{include:"@strings"},[/[{}()\[\]]/,"@brackets"],[/([=\+<>\-\*&@\?\/!])|([<>]=)|(<>)|(=>)|(\.\.\.)|(\.\.)/,"operators"],[/[,;]/,"delimiter"]],whitespace:[[/\s+/,"white"]],comments:[["\\/\\*","comment","@comment"],["\\/\\/+.*","comment"]],comment:[["\\*\\/","comment","@pop"],[".","comment"]],strings:[['"',"string","@string"]],string:[['""',"string.escape"],['"',"string","@pop"],[".","string"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/powershell/powershell.js b/public/react/public/js/monaco/vs/basic-languages/powershell/powershell.js new file mode 100755 index 000000000..0ccf2e578 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/powershell/powershell.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/powershell/powershell",["require","exports"],function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\@\#%\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"#",blockComment:["<#","#>"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"',notIn:["string"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*#region\\b"),end:new RegExp("^\\s*#endregion\\b")}}},n.language={defaultToken:"",ignoreCase:!0,tokenPostfix:".ps1",brackets:[{token:"delimiter.curly",open:"{",close:"}"},{token:"delimiter.square",open:"[",close:"]"},{token:"delimiter.parenthesis",open:"(",close:")"}],keywords:["begin","break","catch","class","continue","data","define","do","dynamicparam","else","elseif","end","exit","filter","finally","for","foreach","from","function","if","in","param","process","return","switch","throw","trap","try","until","using","var","while","workflow","parallel","sequence","inlinescript","configuration"],helpKeywords:/SYNOPSIS|DESCRIPTION|PARAMETER|EXAMPLE|INPUTS|OUTPUTS|NOTES|LINK|COMPONENT|ROLE|FUNCTIONALITY|FORWARDHELPTARGETNAME|FORWARDHELPCATEGORY|REMOTEHELPRUNSPACE|EXTERNALHELP/,symbols:/[=>/,"comment","@pop"],[/(\.)(@helpKeywords)(?!\w)/,{token:"comment.keyword.$2"}],[/[\.#]/,"comment"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/pug/pug.js b/public/react/public/js/monaco/vs/basic-languages/pug/pug.js new file mode 100755 index 000000000..aea89b545 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/pug/pug.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/pug/pug",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={comments:{lineComment:"//"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]},{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]}],folding:{offSide:!0}},t.language={defaultToken:"",tokenPostfix:".pug",ignoreCase:!0,brackets:[{token:"delimiter.curly",open:"{",close:"}"},{token:"delimiter.array",open:"[",close:"]"},{token:"delimiter.parenthesis",open:"(",close:")"}],keywords:["append","block","case","default","doctype","each","else","extends","for","if","in","include","mixin","typeof","unless","var","when"],tags:["a","abbr","acronym","address","area","article","aside","audio","b","base","basefont","bdi","bdo","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","tracks","tt","u","ul","video","wbr"],symbols:/[\+\-\*\%\&\|\!\=\/\.\,\:]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/^(\s*)([a-zA-Z_-][\w-]*)/,{cases:{"$2@tags":{cases:{"@eos":["","tag"],"@default":["",{token:"tag",next:"@tag.$1"}]}},"$2@keywords":["",{token:"keyword.$2"}],"@default":["",""]}}],[/^(\s*)(#[a-zA-Z_-][\w-]*)/,{cases:{"@eos":["","tag.id"],"@default":["",{token:"tag.id",next:"@tag.$1"}]}}],[/^(\s*)(\.[a-zA-Z_-][\w-]*)/,{cases:{"@eos":["","tag.class"],"@default":["",{token:"tag.class",next:"@tag.$1"}]}}],[/^(\s*)(\|.*)$/,""],{include:"@whitespace"},[/[a-zA-Z_$][\w$]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":""}}],[/[{}()\[\]]/,"@brackets"],[/@symbols/,"delimiter"],[/\d+\.\d+([eE][\-+]?\d+)?/,"number.float"],[/\d+/,"number"],[/"/,"string",'@string."'],[/'/,"string","@string.'"]],tag:[[/(\.)(\s*$)/,[{token:"delimiter",next:"@blockText.$S2."},""]],[/\s+/,{token:"",next:"@simpleText"}],[/#[a-zA-Z_-][\w-]*/,{cases:{"@eos":{token:"tag.id",next:"@pop"},"@default":"tag.id"}}],[/\.[a-zA-Z_-][\w-]*/,{cases:{"@eos":{token:"tag.class",next:"@pop"},"@default":"tag.class"}}],[/\(/,{token:"delimiter.parenthesis",next:"@attributeList"}]],simpleText:[[/[^#]+$/,{token:"",next:"@popall"}],[/[^#]+/,{token:""}],[/(#{)([^}]*)(})/,{cases:{"@eos":["interpolation.delimiter","interpolation",{token:"interpolation.delimiter",next:"@popall"}],"@default":["interpolation.delimiter","interpolation","interpolation.delimiter"]}}],[/#$/,{token:"",next:"@popall"}],[/#/,""]],attributeList:[[/\s+/,""],[/(\w+)(\s*=\s*)("|')/,["attribute.name","delimiter",{token:"attribute.value",next:"@value.$3"}]],[/\w+/,"attribute.name"],[/,/,{cases:{"@eos":{token:"attribute.delimiter",next:"@popall"},"@default":"attribute.delimiter"}}],[/\)$/,{token:"delimiter.parenthesis",next:"@popall"}],[/\)/,{token:"delimiter.parenthesis",next:"@pop"}]],whitespace:[[/^(\s*)(\/\/.*)$/,{token:"comment",next:"@blockText.$1.comment"}],[/[ \t\r\n]+/,""],[//,{token:"comment",next:"@pop"}],[//,"comment.html","@pop"],[/[^-]+/,"comment.content.html"],[/./,"comment.content.html"]],otherTag:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInSimpleState.otherTag"}],[/\/?>/,"delimiter.html","@pop"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/]],script:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInSimpleState.script"}],[/type/,"attribute.name","@scriptAfterType"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.text/javascript",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/(<\/)(script\s*)(>)/,["delimiter.html","tag.html",{token:"delimiter.html",next:"@pop"}]]],scriptAfterType:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInSimpleState.scriptAfterType"}],[/=/,"delimiter","@scriptAfterTypeEquals"],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.text/javascript",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptAfterTypeEquals:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInSimpleState.scriptAfterTypeEquals"}],[/"([^"]*)"/,{token:"attribute.value",switchTo:"@scriptWithCustomType.$1"}],[/'([^']*)'/,{token:"attribute.value",switchTo:"@scriptWithCustomType.$1"}],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.text/javascript",nextEmbedded:"text/javascript"}],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptWithCustomType:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInSimpleState.scriptWithCustomType.$S2"}],[/>/,{token:"delimiter.html",next:"@scriptEmbedded.$S2",nextEmbedded:"$S2"}],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/],[/<\/script\s*>/,{token:"@rematch",next:"@pop"}]],scriptEmbedded:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInEmbeddedState.scriptEmbedded.$S2",nextEmbedded:"@pop"}],[/<\/script/,{token:"@rematch",next:"@pop",nextEmbedded:"@pop"}]],style:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInSimpleState.style"}],[/type/,"attribute.name","@styleAfterType"],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/>/,{token:"delimiter.html",next:"@styleEmbedded.text/css",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/(<\/)(style\s*)(>)/,["delimiter.html","tag.html",{token:"delimiter.html",next:"@pop"}]]],styleAfterType:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInSimpleState.styleAfterType"}],[/=/,"delimiter","@styleAfterTypeEquals"],[/>/,{token:"delimiter.html",next:"@styleEmbedded.text/css",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleAfterTypeEquals:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInSimpleState.styleAfterTypeEquals"}],[/"([^"]*)"/,{token:"attribute.value",switchTo:"@styleWithCustomType.$1"}],[/'([^']*)'/,{token:"attribute.value",switchTo:"@styleWithCustomType.$1"}],[/>/,{token:"delimiter.html",next:"@styleEmbedded.text/css",nextEmbedded:"text/css"}],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleWithCustomType:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInSimpleState.styleWithCustomType.$S2"}],[/>/,{token:"delimiter.html",next:"@styleEmbedded.$S2",nextEmbedded:"$S2"}],[/"([^"]*)"/,"attribute.value"],[/'([^']*)'/,"attribute.value"],[/[\w\-]+/,"attribute.name"],[/=/,"delimiter"],[/[ \t\r\n]+/],[/<\/style\s*>/,{token:"@rematch",next:"@pop"}]],styleEmbedded:[[/@[^@]/,{token:"@rematch",switchTo:"@razorInEmbeddedState.styleEmbedded.$S2",nextEmbedded:"@pop"}],[/<\/style/,{token:"@rematch",next:"@pop",nextEmbedded:"@pop"}]],razorInSimpleState:[[/@\*/,"comment.cs","@razorBlockCommentTopLevel"],[/@[{(]/,"metatag.cs","@razorRootTopLevel"],[/(@)(\s*[\w]+)/,["metatag.cs",{token:"identifier.cs",switchTo:"@$S2.$S3"}]],[/[})]/,{token:"metatag.cs",switchTo:"@$S2.$S3"}],[/\*@/,{token:"comment.cs",switchTo:"@$S2.$S3"}]],razorInEmbeddedState:[[/@\*/,"comment.cs","@razorBlockCommentTopLevel"],[/@[{(]/,"metatag.cs","@razorRootTopLevel"],[/(@)(\s*[\w]+)/,["metatag.cs",{token:"identifier.cs",switchTo:"@$S2.$S3",nextEmbedded:"$S3"}]],[/[})]/,{token:"metatag.cs",switchTo:"@$S2.$S3",nextEmbedded:"$S3"}],[/\*@/,{token:"comment.cs",switchTo:"@$S2.$S3",nextEmbedded:"$S3"}]],razorBlockCommentTopLevel:[[/\*@/,"@rematch","@pop"],[/[^*]+/,"comment.cs"],[/./,"comment.cs"]],razorBlockComment:[[/\*@/,"comment.cs","@pop"],[/[^*]+/,"comment.cs"],[/./,"comment.cs"]],razorRootTopLevel:[[/\{/,"delimiter.bracket.cs","@razorRoot"],[/\(/,"delimiter.parenthesis.cs","@razorRoot"],[/[})]/,"@rematch","@pop"],{include:"razorCommon"}],razorRoot:[[/\{/,"delimiter.bracket.cs","@razorRoot"],[/\(/,"delimiter.parenthesis.cs","@razorRoot"],[/\}/,"delimiter.bracket.cs","@pop"],[/\)/,"delimiter.parenthesis.cs","@pop"],{include:"razorCommon"}],razorCommon:[[/[a-zA-Z_]\w*/,{cases:{"@razorKeywords":{token:"keyword.cs"},"@default":"identifier.cs"}}],[/[\[\]]/,"delimiter.array.cs"],[/[ \t\r\n]+/],[/\/\/.*$/,"comment.cs"],[/@\*/,"comment.cs","@razorBlockComment"],[/"([^"]*)"/,"string.cs"],[/'([^']*)'/,"string.cs"],[/(<)(\w+)(\/>)/,["delimiter.html","tag.html","delimiter.html"]],[/(<)(\w+)(>)/,["delimiter.html","tag.html","delimiter.html"]],[/(<\/)(\w+)(>)/,["delimiter.html","tag.html","delimiter.html"]],[/[\+\-\*\%\&\|\^\~\!\=\<\>\/\?\;\:\.\,]/,"delimiter.cs"],[/\d*\d+[eE]([\-+]?\d+)?/,"number.float.cs"],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float.cs"],[/0[xX][0-9a-fA-F']*[0-9a-fA-F]/,"number.hex.cs"],[/0[0-7']*[0-7]/,"number.octal.cs"],[/0[bB][0-1']*[0-1]/,"number.binary.cs"],[/\d[\d']*/,"number.cs"],[/\d/,"number.cs"]]},razorKeywords:["abstract","as","async","await","base","bool","break","by","byte","case","catch","char","checked","class","const","continue","decimal","default","delegate","do","double","descending","explicit","event","extern","else","enum","false","finally","fixed","float","for","foreach","from","goto","group","if","implicit","in","int","interface","internal","into","is","lock","long","nameof","new","null","namespace","object","operator","out","override","orderby","params","private","protected","public","readonly","ref","return","switch","struct","sbyte","sealed","short","sizeof","stackalloc","static","string","select","this","throw","true","try","typeof","uint","ulong","unchecked","unsafe","ushort","using","var","virtual","volatile","void","when","while","where","yield","model","inject"],escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/redis/redis.js b/public/react/public/js/monaco/vs/basic-languages/redis/redis.js new file mode 100755 index 000000000..1fc8c4327 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/redis/redis.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/redis/redis",["require","exports"],function(E,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.conf={brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},e.language={defaultToken:"",tokenPostfix:".redis",ignoreCase:!0,brackets:[{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"}],keywords:["APPEND","AUTH","BGREWRITEAOF","BGSAVE","BITCOUNT","BITFIELD","BITOP","BITPOS","BLPOP","BRPOP","BRPOPLPUSH","CLIENT","KILL","LIST","GETNAME","PAUSE","REPLY","SETNAME","CLUSTER","ADDSLOTS","COUNT-FAILURE-REPORTS","COUNTKEYSINSLOT","DELSLOTS","FAILOVER","FORGET","GETKEYSINSLOT","INFO","KEYSLOT","MEET","NODES","REPLICATE","RESET","SAVECONFIG","SET-CONFIG-EPOCH","SETSLOT","SLAVES","SLOTS","COMMAND","COUNT","GETKEYS","CONFIG","GET","REWRITE","SET","RESETSTAT","DBSIZE","DEBUG","OBJECT","SEGFAULT","DECR","DECRBY","DEL","DISCARD","DUMP","ECHO","EVAL","EVALSHA","EXEC","EXISTS","EXPIRE","EXPIREAT","FLUSHALL","FLUSHDB","GEOADD","GEOHASH","GEOPOS","GEODIST","GEORADIUS","GEORADIUSBYMEMBER","GETBIT","GETRANGE","GETSET","HDEL","HEXISTS","HGET","HGETALL","HINCRBY","HINCRBYFLOAT","HKEYS","HLEN","HMGET","HMSET","HSET","HSETNX","HSTRLEN","HVALS","INCR","INCRBY","INCRBYFLOAT","KEYS","LASTSAVE","LINDEX","LINSERT","LLEN","LPOP","LPUSH","LPUSHX","LRANGE","LREM","LSET","LTRIM","MGET","MIGRATE","MONITOR","MOVE","MSET","MSETNX","MULTI","PERSIST","PEXPIRE","PEXPIREAT","PFADD","PFCOUNT","PFMERGE","PING","PSETEX","PSUBSCRIBE","PUBSUB","PTTL","PUBLISH","PUNSUBSCRIBE","QUIT","RANDOMKEY","READONLY","READWRITE","RENAME","RENAMENX","RESTORE","ROLE","RPOP","RPOPLPUSH","RPUSH","RPUSHX","SADD","SAVE","SCARD","SCRIPT","FLUSH","LOAD","SDIFF","SDIFFSTORE","SELECT","SETBIT","SETEX","SETNX","SETRANGE","SHUTDOWN","SINTER","SINTERSTORE","SISMEMBER","SLAVEOF","SLOWLOG","SMEMBERS","SMOVE","SORT","SPOP","SRANDMEMBER","SREM","STRLEN","SUBSCRIBE","SUNION","SUNIONSTORE","SWAPDB","SYNC","TIME","TOUCH","TTL","TYPE","UNSUBSCRIBE","UNLINK","UNWATCH","WAIT","WATCH","ZADD","ZCARD","ZCOUNT","ZINCRBY","ZINTERSTORE","ZLEXCOUNT","ZRANGE","ZRANGEBYLEX","ZREVRANGEBYLEX","ZRANGEBYSCORE","ZRANK","ZREM","ZREMRANGEBYLEX","ZREMRANGEBYRANK","ZREMRANGEBYSCORE","ZREVRANGE","ZREVRANGEBYSCORE","ZREVRANK","ZSCORE","ZUNIONSTORE","SCAN","SSCAN","HSCAN","ZSCAN"],operators:[],builtinFunctions:[],builtinVariables:[],pseudoColumns:[],tokenizer:{root:[{include:"@whitespace"},{include:"@pseudoColumns"},{include:"@numbers"},{include:"@strings"},{include:"@scopes"},[/[;,.]/,"delimiter"],[/[()]/,"@brackets"],[/[\w@#$]+/,{cases:{"@keywords":"keyword","@operators":"operator","@builtinVariables":"predefined","@builtinFunctions":"predefined","@default":"identifier"}}],[/[<>=!%&+\-*/|~^]/,"operator"]],whitespace:[[/\s+/,"white"]],pseudoColumns:[[/[$][A-Za-z_][\w@#$]*/,{cases:{"@pseudoColumns":"predefined","@default":"identifier"}}]],numbers:[[/0[xX][0-9a-fA-F]*/,"number"],[/[$][+-]*\d*(\.\d*)?/,"number"],[/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/,"number"]],strings:[[/'/,{token:"string",next:"@string"}],[/"/,{token:"string.double",next:"@stringDouble"}]],string:[[/[^']+/,"string"],[/''/,"string"],[/'/,{token:"string",next:"@pop"}]],stringDouble:[[/[^"]+/,"string.double"],[/""/,"string.double"],[/"/,{token:"string.double",next:"@pop"}]],scopes:[]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/redshift/redshift.js b/public/react/public/js/monaco/vs/basic-languages/redshift/redshift.js new file mode 100755 index 000000000..e548606c5 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/redshift/redshift.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/redshift/redshift",["require","exports"],function(e,_){"use strict";Object.defineProperty(_,"__esModule",{value:!0}),_.conf={comments:{lineComment:"--",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},_.language={defaultToken:"",tokenPostfix:".sql",ignoreCase:!0,brackets:[{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"}],keywords:["AES128","AES256","ALL","ALLOWOVERWRITE","ANALYSE","ANALYZE","AND","ANY","ARRAY","AS","ASC","AUTHORIZATION","BACKUP","BETWEEN","BINARY","BLANKSASNULL","BOTH","BYTEDICT","BZIP2","CASE","CAST","CHECK","COLLATE","COLUMN","CONSTRAINT","CREATE","CREDENTIALS","CROSS","CURRENT_DATE","CURRENT_TIME","CURRENT_TIMESTAMP","CURRENT_USER","CURRENT_USER_ID","DEFAULT","DEFERRABLE","DEFLATE","DEFRAG","DELTA","DELTA32K","DESC","DISABLE","DISTINCT","DO","ELSE","EMPTYASNULL","ENABLE","ENCODE","ENCRYPT","ENCRYPTION","END","EXCEPT","EXPLICIT","FALSE","FOR","FOREIGN","FREEZE","FROM","FULL","GLOBALDICT256","GLOBALDICT64K","GRANT","GROUP","GZIP","HAVING","IDENTITY","IGNORE","ILIKE","IN","INITIALLY","INNER","INTERSECT","INTO","IS","ISNULL","JOIN","LEADING","LEFT","LIKE","LIMIT","LOCALTIME","LOCALTIMESTAMP","LUN","LUNS","LZO","LZOP","MINUS","MOSTLY13","MOSTLY32","MOSTLY8","NATURAL","NEW","NOT","NOTNULL","NULL","NULLS","OFF","OFFLINE","OFFSET","OID","OLD","ON","ONLY","OPEN","OR","ORDER","OUTER","OVERLAPS","PARALLEL","PARTITION","PERCENT","PERMISSIONS","PLACING","PRIMARY","RAW","READRATIO","RECOVER","REFERENCES","RESPECT","REJECTLOG","RESORT","RESTORE","RIGHT","SELECT","SESSION_USER","SIMILAR","SNAPSHOT","SOME","SYSDATE","SYSTEM","TABLE","TAG","TDES","TEXT255","TEXT32K","THEN","TIMESTAMP","TO","TOP","TRAILING","TRUE","TRUNCATECOLUMNS","UNION","UNIQUE","USER","USING","VERBOSE","WALLET","WHEN","WHERE","WITH","WITHOUT"],operators:["AND","BETWEEN","IN","LIKE","NOT","OR","IS","NULL","INTERSECT","UNION","INNER","JOIN","LEFT","OUTER","RIGHT"],builtinFunctions:["current_schema","current_schemas","has_database_privilege","has_schema_privilege","has_table_privilege","age","current_time","current_timestamp","localtime","isfinite","now","ascii","get_bit","get_byte","set_bit","set_byte","to_ascii","approximate percentile_disc","avg","count","listagg","max","median","min","percentile_cont","stddev_samp","stddev_pop","sum","var_samp","var_pop","bit_and","bit_or","bool_and","bool_or","cume_dist","first_value","lag","last_value","lead","nth_value","ratio_to_report","dense_rank","ntile","percent_rank","rank","row_number","case","coalesce","decode","greatest","least","nvl","nvl2","nullif","add_months","at time zone","convert_timezone","current_date","date_cmp","date_cmp_timestamp","date_cmp_timestamptz","date_part_year","dateadd","datediff","date_part","date_trunc","extract","getdate","interval_cmp","last_day","months_between","next_day","sysdate","timeofday","timestamp_cmp","timestamp_cmp_date","timestamp_cmp_timestamptz","timestamptz_cmp","timestamptz_cmp_date","timestamptz_cmp_timestamp","timezone","to_timestamp","trunc","abs","acos","asin","atan","atan2","cbrt","ceil","ceiling","checksum","cos","cot","degrees","dexp","dlog1","dlog10","exp","floor","ln","log","mod","pi","power","radians","random","round","sin","sign","sqrt","tan","to_hex","bpcharcmp","btrim","bttext_pattern_cmp","char_length","character_length","charindex","chr","concat","crc32","func_sha1","initcap","left and rights","len","length","lower","lpad and rpads","ltrim","md5","octet_length","position","quote_ident","quote_literal","regexp_count","regexp_instr","regexp_replace","regexp_substr","repeat","replace","replicate","reverse","rtrim","split_part","strpos","strtol","substring","textlen","translate","trim","upper","cast","convert","to_char","to_date","to_number","json_array_length","json_extract_array_element_text","json_extract_path_text","current_setting","pg_cancel_backend","pg_terminate_backend","set_config","current_database","current_user","current_user_id","pg_backend_pid","pg_last_copy_count","pg_last_copy_id","pg_last_query_id","pg_last_unload_count","session_user","slice_num","user","version","abbrev","acosd","any","area","array_agg","array_append","array_cat","array_dims","array_fill","array_length","array_lower","array_ndims","array_position","array_positions","array_prepend","array_remove","array_replace","array_to_json","array_to_string","array_to_tsvector","array_upper","asind","atan2d","atand","bit","bit_length","bound_box","box","brin_summarize_new_values","broadcast","cardinality","center","circle","clock_timestamp","col_description","concat_ws","convert_from","convert_to","corr","cosd","cotd","covar_pop","covar_samp","current_catalog","current_query","current_role","currval","cursor_to_xml","diameter","div","encode","enum_first","enum_last","enum_range","every","family","format","format_type","generate_series","generate_subscripts","get_current_ts_config","gin_clean_pending_list","grouping","has_any_column_privilege","has_column_privilege","has_foreign_data_wrapper_privilege","has_function_privilege","has_language_privilege","has_sequence_privilege","has_server_privilege","has_tablespace_privilege","has_type_privilege","height","host","hostmask","inet_client_addr","inet_client_port","inet_merge","inet_same_family","inet_server_addr","inet_server_port","isclosed","isempty","isopen","json_agg","json_object","json_object_agg","json_populate_record","json_populate_recordset","json_to_record","json_to_recordset","jsonb_agg","jsonb_object_agg","justify_days","justify_hours","justify_interval","lastval","left","line","localtimestamp","lower_inc","lower_inf","lpad","lseg","make_date","make_interval","make_time","make_timestamp","make_timestamptz","masklen","mode","netmask","network","nextval","npoints","num_nonnulls","num_nulls","numnode","obj_description","overlay","parse_ident","path","pclose","percentile_disc","pg_advisory_lock","pg_advisory_lock_shared","pg_advisory_unlock","pg_advisory_unlock_all","pg_advisory_unlock_shared","pg_advisory_xact_lock","pg_advisory_xact_lock_shared","pg_backup_start_time","pg_blocking_pids","pg_client_encoding","pg_collation_is_visible","pg_column_size","pg_conf_load_time","pg_control_checkpoint","pg_control_init","pg_control_recovery","pg_control_system","pg_conversion_is_visible","pg_create_logical_replication_slot","pg_create_physical_replication_slot","pg_create_restore_point","pg_current_xlog_flush_location","pg_current_xlog_insert_location","pg_current_xlog_location","pg_database_size","pg_describe_object","pg_drop_replication_slot","pg_export_snapshot","pg_filenode_relation","pg_function_is_visible","pg_get_constraintdef","pg_get_expr","pg_get_function_arguments","pg_get_function_identity_arguments","pg_get_function_result","pg_get_functiondef","pg_get_indexdef","pg_get_keywords","pg_get_object_address","pg_get_owned_sequence","pg_get_ruledef","pg_get_serial_sequence","pg_get_triggerdef","pg_get_userbyid","pg_get_viewdef","pg_has_role","pg_identify_object","pg_identify_object_as_address","pg_index_column_has_property","pg_index_has_property","pg_indexam_has_property","pg_indexes_size","pg_is_in_backup","pg_is_in_recovery","pg_is_other_temp_schema","pg_is_xlog_replay_paused","pg_last_committed_xact","pg_last_xact_replay_timestamp","pg_last_xlog_receive_location","pg_last_xlog_replay_location","pg_listening_channels","pg_logical_emit_message","pg_logical_slot_get_binary_changes","pg_logical_slot_get_changes","pg_logical_slot_peek_binary_changes","pg_logical_slot_peek_changes","pg_ls_dir","pg_my_temp_schema","pg_notification_queue_usage","pg_opclass_is_visible","pg_operator_is_visible","pg_opfamily_is_visible","pg_options_to_table","pg_postmaster_start_time","pg_read_binary_file","pg_read_file","pg_relation_filenode","pg_relation_filepath","pg_relation_size","pg_reload_conf","pg_replication_origin_create","pg_replication_origin_drop","pg_replication_origin_oid","pg_replication_origin_progress","pg_replication_origin_session_is_setup","pg_replication_origin_session_progress","pg_replication_origin_session_reset","pg_replication_origin_session_setup","pg_replication_origin_xact_reset","pg_replication_origin_xact_setup","pg_rotate_logfile","pg_size_bytes","pg_size_pretty","pg_sleep","pg_sleep_for","pg_sleep_until","pg_start_backup","pg_stat_file","pg_stop_backup","pg_switch_xlog","pg_table_is_visible","pg_table_size","pg_tablespace_databases","pg_tablespace_location","pg_tablespace_size","pg_total_relation_size","pg_trigger_depth","pg_try_advisory_lock","pg_try_advisory_lock_shared","pg_try_advisory_xact_lock","pg_try_advisory_xact_lock_shared","pg_ts_config_is_visible","pg_ts_dict_is_visible","pg_ts_parser_is_visible","pg_ts_template_is_visible","pg_type_is_visible","pg_typeof","pg_xact_commit_timestamp","pg_xlog_location_diff","pg_xlog_replay_pause","pg_xlog_replay_resume","pg_xlogfile_name","pg_xlogfile_name_offset","phraseto_tsquery","plainto_tsquery","point","polygon","popen","pqserverversion","query_to_xml","querytree","quote_nullable","radius","range_merge","regexp_matches","regexp_split_to_array","regexp_split_to_table","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","right","row_security_active","row_to_json","rpad","scale","set_masklen","setseed","setval","setweight","shobj_description","sind","sprintf","statement_timestamp","stddev","string_agg","string_to_array","strip","substr","table_to_xml","table_to_xml_and_xmlschema","tand","text","to_json","to_regclass","to_regnamespace","to_regoper","to_regoperator","to_regproc","to_regprocedure","to_regrole","to_regtype","to_tsquery","to_tsvector","transaction_timestamp","ts_debug","ts_delete","ts_filter","ts_headline","ts_lexize","ts_parse","ts_rank","ts_rank_cd","ts_rewrite","ts_stat","ts_token_type","tsquery_phrase","tsvector_to_array","tsvector_update_trigger","tsvector_update_trigger_column","txid_current","txid_current_snapshot","txid_snapshot_xip","txid_snapshot_xmax","txid_snapshot_xmin","txid_visible_in_snapshot","unnest","upper_inc","upper_inf","variance","width","width_bucket","xml_is_well_formed","xml_is_well_formed_content","xml_is_well_formed_document","xmlagg","xmlcomment","xmlconcat","xmlelement","xmlexists","xmlforest","xmlparse","xmlpi","xmlroot","xmlserialize","xpath","xpath_exists"],builtinVariables:[],pseudoColumns:[],tokenizer:{root:[{include:"@comments"},{include:"@whitespace"},{include:"@pseudoColumns"},{include:"@numbers"},{include:"@strings"},{include:"@complexIdentifiers"},{include:"@scopes"},[/[;,.]/,"delimiter"],[/[()]/,"@brackets"],[/[\w@#$]+/,{cases:{"@keywords":"keyword","@operators":"operator","@builtinVariables":"predefined","@builtinFunctions":"predefined","@default":"identifier"}}],[/[<>=!%&+\-*/|~^]/,"operator"]],whitespace:[[/\s+/,"white"]],comments:[[/--+.*/,"comment"],[/\/\*/,{token:"comment.quote",next:"@comment"}]],comment:[[/[^*/]+/,"comment"],[/\*\//,{token:"comment.quote",next:"@pop"}],[/./,"comment"]],pseudoColumns:[[/[$][A-Za-z_][\w@#$]*/,{cases:{"@pseudoColumns":"predefined","@default":"identifier"}}]],numbers:[[/0[xX][0-9a-fA-F]*/,"number"],[/[$][+-]*\d*(\.\d*)?/,"number"],[/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/,"number"]],strings:[[/'/,{token:"string",next:"@string"}]],string:[[/[^']+/,"string"],[/''/,"string"],[/'/,{token:"string",next:"@pop"}]],complexIdentifiers:[[/"/,{token:"identifier.quote",next:"@quotedIdentifier"}]],quotedIdentifier:[[/[^"]+/,"identifier"],[/""/,"identifier"],[/"/,{token:"identifier.quote",next:"@pop"}]],scopes:[]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/ruby/ruby.js b/public/react/public/js/monaco/vs/basic-languages/ruby/ruby.js new file mode 100755 index 000000000..3c0bd105a --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/ruby/ruby.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/ruby/ruby",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={comments:{lineComment:"#",blockComment:["=begin","=end"]},brackets:[["(",")"],["{","}"],["[","]"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},t.language={tokenPostfix:".ruby",keywords:["__LINE__","__ENCODING__","__FILE__","BEGIN","END","alias","and","begin","break","case","class","def","defined?","do","else","elsif","end","ensure","for","false","if","in","module","next","nil","not","or","redo","rescue","retry","return","self","super","then","true","undef","unless","until","when","while","yield"],keywordops:["::","..","...","?",":","=>"],builtins:["require","public","private","include","extend","attr_reader","protected","private_class_method","protected_class_method","new"],declarations:["module","class","def","case","do","begin","for","if","while","until","unless"],linedecls:["def","case","do","begin","for","if","while","until","unless"],operators:["^","&","|","<=>","==","===","!~","=~",">",">=","<","<=","<<",">>","+","-","*","/","%","**","~","+@","-@","[]","[]=","`","+=","-=","*=","**=","/=","^=","%=","<<=",">>=","&=","&&=","||=","|="],brackets:[{open:"(",close:")",token:"delimiter.parenthesis"},{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"}],symbols:/[=>"}],[/%([qws])(@delim)/,{token:"string.$1.delim",switchTo:"@qstring.$1.$2.$2"}],[/%r\(/,{token:"regexp.delim",switchTo:"@pregexp.(.)"}],[/%r\[/,{token:"regexp.delim",switchTo:"@pregexp.[.]"}],[/%r\{/,{token:"regexp.delim",switchTo:"@pregexp.{.}"}],[/%r"}],[/%r(@delim)/,{token:"regexp.delim",switchTo:"@pregexp.$1.$1"}],[/%(x|W|Q?)\(/,{token:"string.$1.delim",switchTo:"@qqstring.$1.(.)"}],[/%(x|W|Q?)\[/,{token:"string.$1.delim",switchTo:"@qqstring.$1.[.]"}],[/%(x|W|Q?)\{/,{token:"string.$1.delim",switchTo:"@qqstring.$1.{.}"}],[/%(x|W|Q?)"}],[/%(x|W|Q?)(@delim)/,{token:"string.$1.delim",switchTo:"@qqstring.$1.$2.$2"}],[/%([rqwsxW]|Q?)./,{token:"invalid",next:"@pop"}],[/./,{token:"invalid",next:"@pop"}]],qstring:[[/\\$/,"string.$S2.escape"],[/\\./,"string.$S2.escape"],[/./,{cases:{"$#==$S4":{token:"string.$S2.delim",next:"@pop"},"$#==$S3":{token:"string.$S2.delim",next:"@push"},"@default":"string.$S2"}}]],qqstring:[[/#/,"string.$S2.escape","@interpolated"],{include:"@qstring"}],whitespace:[[/[ \t\r\n]+/,""],[/^\s*=begin\b/,"comment","@comment"],[/#.*$/,"comment"]],comment:[[/[^=]+/,"comment"],[/^\s*=begin\b/,"comment.invalid"],[/^\s*=end\b.*/,"comment","@pop"],[/[=]/,"comment"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/rust/rust.js b/public/react/public/js/monaco/vs/basic-languages/rust/rust.js new file mode 100755 index 000000000..eee038d10 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/rust/rust.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/rust/rust",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"[",close:"]"},{open:"{",close:"}"},{open:"(",close:")"},{open:"'",close:"'",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*#pragma\\s+region\\b"),end:new RegExp("^\\s*#pragma\\s+endregion\\b")}}},t.language={tokenPostfix:".rust",defaultToken:"invalid",keywords:["as","box","break","const","continue","crate","else","enum","extern","false","fn","for","if","impl","in","let","loop","match","mod","move","mut","pub","ref","return","self","static","struct","super","trait","true","type","unsafe","use","where","while","catch","default","union","static","abstract","alignof","become","do","final","macro","offsetof","override","priv","proc","pure","sizeof","typeof","unsized","virtual","yield"],typeKeywords:["Self","m32","m64","m128","f80","f16","f128","int","uint","float","char","bool","u8","u16","u32","u64","f32","f64","i8","i16","i32","i64","str","Option","Either","c_float","c_double","c_void","FILE","fpos_t","DIR","dirent","c_char","c_schar","c_uchar","c_short","c_ushort","c_int","c_uint","c_long","c_ulong","size_t","ptrdiff_t","clock_t","time_t","c_longlong","c_ulonglong","intptr_t","uintptr_t","off_t","dev_t","ino_t","pid_t","mode_t","ssize_t"],constants:["true","false","Some","None","Left","Right","Ok","Err"],supportConstants:["EXIT_FAILURE","EXIT_SUCCESS","RAND_MAX","EOF","SEEK_SET","SEEK_CUR","SEEK_END","_IOFBF","_IONBF","_IOLBF","BUFSIZ","FOPEN_MAX","FILENAME_MAX","L_tmpnam","TMP_MAX","O_RDONLY","O_WRONLY","O_RDWR","O_APPEND","O_CREAT","O_EXCL","O_TRUNC","S_IFIFO","S_IFCHR","S_IFBLK","S_IFDIR","S_IFREG","S_IFMT","S_IEXEC","S_IWRITE","S_IREAD","S_IRWXU","S_IXUSR","S_IWUSR","S_IRUSR","F_OK","R_OK","W_OK","X_OK","STDIN_FILENO","STDOUT_FILENO","STDERR_FILENO"],supportMacros:["format!","print!","println!","panic!","format_args!","unreachable!","write!","writeln!"],operators:["!","!=","%","%=","&","&=","&&","*","*=","+","+=","-","-=","->",".","..","...","/","/=",":",";","<<","<<=","<","<=","=","==","=>",">",">=",">>",">>=","@","^","^=","|","|=","||","_","?","#"],escapes:/\\([nrt0\"''\\]|x\h{2}|u\{\h{1,6}\})/,delimiters:/[,]/,symbols:/[\#\!\%\&\*\+\-\.\/\:\;\<\=\>\@\^\|_\?]+/,intSuffixes:/[iu](8|16|32|64|128|size)/,floatSuffixes:/f(32|64)/,tokenizer:{root:[[/[a-zA-Z][a-zA-Z0-9_]*!?|_[a-zA-Z0-9_]+/,{cases:{"@typeKeywords":"keyword.type","@keywords":"keyword","@supportConstants":"keyword","@supportMacros":"keyword","@constants":"keyword","@default":"identifier"}}],[/\$/,"identifier"],[/'[a-zA-Z_][a-zA-Z0-9_]*(?=[^\'])/,"identifier"],[/'\S'/,"string.byteliteral"],[/"/,{token:"string.quote",bracket:"@open",next:"@string"}],{include:"@numbers"},{include:"@whitespace"},[/@delimiters/,{cases:{"@keywords":"keyword","@default":"delimiter"}}],[/[{}()\[\]<>]/,"@brackets"],[/@symbols/,{cases:{"@operators":"operator","@default":""}}]],whitespace:[[/[ \t\r\n]+/,"white"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\/\*/,"comment","@push"],["\\*/","comment","@pop"],[/[\/*]/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,{token:"string.quote",bracket:"@close",next:"@pop"}]],numbers:[[/(0o[0-7_]+)(@intSuffixes)?/,{token:"number"}],[/(0b[0-1_]+)(@intSuffixes)?/,{token:"number"}],[/[\d][\d_]*(\.[\d][\d_]*)?[eE][+-][\d_]+(@floatSuffixes)?/,{token:"number"}],[/\b(\d\.?[\d_]*)(@floatSuffixes)?\b/,{token:"number"}],[/(0x[\da-fA-F]+)_?(@intSuffixes)?/,{token:"number"}],[/[\d][\d_]*(@intSuffixes?)?/,{token:"number"}]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/sb/sb.js b/public/react/public/js/monaco/vs/basic-languages/sb/sb.js new file mode 100755 index 000000000..40908e61a --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/sb/sb.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/sb/sb",["require","exports"],function(e,o){"use strict";Object.defineProperty(o,"__esModule",{value:!0}),o.conf={comments:{lineComment:"'"},brackets:[["(",")"],["[","]"],["If","EndIf"],["While","EndWhile"],["For","EndFor"],["Sub","EndSub"]],autoClosingPairs:[{open:'"',close:'"',notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]}]},o.language={defaultToken:"",tokenPostfix:".sb",ignoreCase:!0,brackets:[{token:"delimiter.array",open:"[",close:"]"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"keyword.tag-if",open:"If",close:"EndIf"},{token:"keyword.tag-while",open:"While",close:"EndWhile"},{token:"keyword.tag-for",open:"For",close:"EndFor"},{token:"keyword.tag-sub",open:"Sub",close:"EndSub"}],keywords:["Else","ElseIf","EndFor","EndIf","EndSub","EndWhile","For","Goto","If","Step","Sub","Then","To","While"],tagwords:["If","Sub","While","For"],operators:[">","<","<>","<=",">=","And","Or","+","-","*","/","="],identifier:/[a-zA-Z_][\w]*/,symbols:/[=><:+\-*\/%\.,]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[{include:"@whitespace"},[/(@identifier)(?=[.])/,"type"],[/@identifier/,{cases:{"@keywords":{token:"keyword.$0"},"@operators":"operator","@default":"variable.name"}}],[/([.])(@identifier)/,{cases:{$2:["delimiter","type.member"],"@default":""}}],[/\d*\.\d+/,"number.float"],[/\d+/,"number"],[/[()\[\]]/,"@brackets"],[/@symbols/,{cases:{"@operators":"operator","@default":"delimiter"}}],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"]],whitespace:[[/[ \t\r\n]+/,""],[/(\').*$/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"C?/,"string","@pop"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/scheme/scheme.js b/public/react/public/js/monaco/vs/basic-languages/scheme/scheme.js new file mode 100755 index 000000000..fe2456803 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/scheme/scheme.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/scheme/scheme",["require","exports"],function(e,o){"use strict";Object.defineProperty(o,"__esModule",{value:!0}),o.conf={comments:{lineComment:";",blockComment:["#|","|#"]},brackets:[["(",")"],["{","}"],["[","]"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}]},o.language={defaultToken:"",ignoreCase:!0,tokenPostfix:".scheme",brackets:[{open:"(",close:")",token:"delimiter.parenthesis"},{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"}],keywords:["case","do","let","loop","if","else","when","cons","car","cdr","cond","lambda","lambda*","syntax-rules","format","set!","quote","eval","append","list","list?","member?","load"],constants:["#t","#f"],operators:["eq?","eqv?","equal?","and","or","not","null?"],tokenizer:{root:[[/#[xXoObB][0-9a-fA-F]+/,"number.hex"],[/[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?/,"number.float"],[/(?:\b(?:(define|define-syntax|define-macro))\b)(\s+)((?:\w|\-|\!|\?)*)/,["keyword","white","variable"]],{include:"@whitespace"},{include:"@strings"},[/[a-zA-Z_#][a-zA-Z0-9_\-\?\!\*]*/,{cases:{"@keywords":"keyword","@constants":"constant","@operators":"operators","@default":"identifier"}}]],comment:[[/[^\|#]+/,"comment"],[/#\|/,"comment","@push"],[/\|#/,"comment","@pop"],[/[\|#]/,"comment"]],whitespace:[[/[ \t\r\n]+/,"white"],[/#\|/,"comment","@comment"],[/;.*$/,"comment"]],strings:[[/"$/,"string","@popall"],[/"(?=.)/,"string","@multiLineString"]],multiLineString:[[/\\./,"string.escape"],[/"/,"string","@popall"],[/.(?=.*")/,"string"],[/.*\\$/,"string"],[/.*$/,"string","@popall"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/scss/scss.js b/public/react/public/js/monaco/vs/basic-languages/scss/scss.js new file mode 100755 index 000000000..86a3f53fd --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/scss/scss.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/scss/scss",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(#?-?\d*\.\d\w*%?)|([@$#!.:]?[\w-?]+%?)|[@#!.]/g,comments:{blockComment:["/*","*/"],lineComment:"//"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*\\/\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\/"),end:new RegExp("^\\s*\\/\\*\\s*#endregion\\b.*\\*\\/")}}},t.language={defaultToken:"",tokenPostfix:".scss",ws:"[ \t\n\r\f]*",identifier:"-?-?([a-zA-Z]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.bracket"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],tokenizer:{root:[{include:"@selector"}],selector:[{include:"@comments"},{include:"@import"},{include:"@variabledeclaration"},{include:"@warndebug"},["[@](include)",{token:"keyword",next:"@includedeclaration"}],["[@](keyframes|-webkit-keyframes|-moz-keyframes|-o-keyframes)",{token:"keyword",next:"@keyframedeclaration"}],["[@](page|content|font-face|-moz-document)",{token:"keyword"}],["[@](charset|namespace)",{token:"keyword",next:"@declarationbody"}],["[@](function)",{token:"keyword",next:"@functiondeclaration"}],["[@](mixin)",{token:"keyword",next:"@mixindeclaration"}],["url(\\-prefix)?\\(",{token:"meta",next:"@urldeclaration"}],{include:"@controlstatement"},{include:"@selectorname"},["[&\\*]","tag"],["[>\\+,]","delimiter"],["\\[",{token:"delimiter.bracket",next:"@selectorattribute"}],["{",{token:"delimiter.curly",next:"@selectorbody"}]],selectorbody:[["[*_]?@identifier@ws:(?=(\\s|\\d|[^{;}]*[;}]))","attribute.name","@rulevalue"],{include:"@selector"},["[@](extend)",{token:"keyword",next:"@extendbody"}],["[@](return)",{token:"keyword",next:"@declarationbody"}],["}",{token:"delimiter.curly",next:"@pop"}]],selectorname:[["#{",{token:"meta",next:"@variableinterpolation"}],["(\\.|#(?=[^{])|%|(@identifier)|:)+","tag"]],selectorattribute:[{include:"@term"},["]",{token:"delimiter.bracket",next:"@pop"}]],term:[{include:"@comments"},["url(\\-prefix)?\\(",{token:"meta",next:"@urldeclaration"}],{include:"@functioninvocation"},{include:"@numbers"},{include:"@strings"},{include:"@variablereference"},["(and\\b|or\\b|not\\b)","operator"],{include:"@name"},["([<>=\\+\\-\\*\\/\\^\\|\\~,])","operator"],[",","delimiter"],["!default","literal"],["\\(",{token:"delimiter.parenthesis",next:"@parenthizedterm"}]],rulevalue:[{include:"@term"},["!important","literal"],[";","delimiter","@pop"],["{",{token:"delimiter.curly",switchTo:"@nestedproperty"}],["(?=})",{token:"",next:"@pop"}]],nestedproperty:[["[*_]?@identifier@ws:","attribute.name","@rulevalue"],{include:"@comments"},["}",{token:"delimiter.curly",next:"@pop"}]],warndebug:[["[@](warn|debug)",{token:"keyword",next:"@declarationbody"}]],import:[["[@](import)",{token:"keyword",next:"@declarationbody"}]],variabledeclaration:[["\\$@identifier@ws:","variable.decl","@declarationbody"]],urldeclaration:[{include:"@strings"},["[^)\r\n]+","string"],["\\)",{token:"meta",next:"@pop"}]],parenthizedterm:[{include:"@term"},["\\)",{token:"delimiter.parenthesis",next:"@pop"}]],declarationbody:[{include:"@term"},[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],extendbody:[{include:"@selectorname"},["!optional","literal"],[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],variablereference:[["\\$@identifier","variable.ref"],["\\.\\.\\.","operator"],["#{",{token:"meta",next:"@variableinterpolation"}]],variableinterpolation:[{include:"@variablereference"},["}",{token:"meta",next:"@pop"}]],comments:[["\\/\\*","comment","@comment"],["\\/\\/+.*","comment"]],comment:[["\\*\\/","comment","@pop"],[".","comment"]],name:[["@identifier","attribute.value"]],numbers:[["(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?",{token:"number",next:"@units"}],["#[0-9a-fA-F_]+(?!\\w)","number.hex"]],units:[["(em|ex|ch|rem|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?","number","@pop"]],functiondeclaration:[["@identifier@ws\\(",{token:"meta",next:"@parameterdeclaration"}],["{",{token:"delimiter.curly",switchTo:"@functionbody"}]],mixindeclaration:[["@identifier@ws\\(",{token:"meta",next:"@parameterdeclaration"}],["@identifier","meta"],["{",{token:"delimiter.curly",switchTo:"@selectorbody"}]],parameterdeclaration:[["\\$@identifier@ws:","variable.decl"],["\\.\\.\\.","operator"],[",","delimiter"],{include:"@term"},["\\)",{token:"meta",next:"@pop"}]],includedeclaration:[{include:"@functioninvocation"},["@identifier","meta"],[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}],["{",{token:"delimiter.curly",switchTo:"@selectorbody"}]],keyframedeclaration:[["@identifier","meta"],["{",{token:"delimiter.curly",switchTo:"@keyframebody"}]],keyframebody:[{include:"@term"},["{",{token:"delimiter.curly",next:"@selectorbody"}],["}",{token:"delimiter.curly",next:"@pop"}]],controlstatement:[["[@](if|else|for|while|each|media)",{token:"keyword.flow",next:"@controlstatementdeclaration"}]],controlstatementdeclaration:[["(in|from|through|if|to)\\b",{token:"keyword.flow"}],{include:"@term"},["{",{token:"delimiter.curly",switchTo:"@selectorbody"}]],functionbody:[["[@](return)",{token:"keyword"}],{include:"@variabledeclaration"},{include:"@term"},{include:"@controlstatement"},[";","delimiter"],["}",{token:"delimiter.curly",next:"@pop"}]],functioninvocation:[["@identifier\\(",{token:"meta",next:"@functionarguments"}]],functionarguments:[["\\$@identifier@ws:","attribute.name"],["[,]","delimiter"],{include:"@term"},["\\)",{token:"meta",next:"@pop"}]],strings:[['~?"',{token:"string.delimiter",next:"@stringenddoublequote"}],["~?'",{token:"string.delimiter",next:"@stringendquote"}]],stringenddoublequote:[["\\\\.","string"],['"',{token:"string.delimiter",next:"@pop"}],[".","string"]],stringendquote:[["\\\\.","string"],["'",{token:"string.delimiter",next:"@pop"}],[".","string"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/shell/shell.js b/public/react/public/js/monaco/vs/basic-languages/shell/shell.js new file mode 100755 index 000000000..85ac99fc4 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/shell/shell.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/shell/shell",["require","exports"],function(e,s){"use strict";Object.defineProperty(s,"__esModule",{value:!0}),s.conf={comments:{lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"`",close:"`"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"`",close:"`"}]},s.language={defaultToken:"",ignoreCase:!0,tokenPostfix:".shell",brackets:[{token:"delimiter.bracket",open:"{",close:"}"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"delimiter.square",open:"[",close:"]"}],keywords:["if","then","do","else","elif","while","until","for","in","esac","fi","fin","fil","done","exit","set","unset","export","function"],builtins:["ab","awk","bash","beep","cat","cc","cd","chown","chmod","chroot","clear","cp","curl","cut","diff","echo","find","gawk","gcc","get","git","grep","hg","kill","killall","ln","ls","make","mkdir","openssl","mv","nc","node","npm","ping","ps","restart","rm","rmdir","sed","service","sh","shopt","shred","source","sort","sleep","ssh","start","stop","su","sudo","svn","tee","telnet","top","touch","vi","vim","wall","wc","wget","who","write","yes","zsh"],symbols:/[=>"]],autoClosingPairs:[{open:'"',close:'"',notIn:["string","comment"]},{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]}]},e.language={defaultToken:"",tokenPostfix:".sol",brackets:[{token:"delimiter.curly",open:"{",close:"}"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"delimiter.square",open:"[",close:"]"},{token:"delimiter.angle",open:"<",close:">"}],keywords:["pragma","solidity","contract","library","using","struct","function","modifier","address","string","bool","Int","Uint","Byte","Fixed","Ufixed","int","int8","int16","int24","int32","int40","int48","int56","int64","int72","int80","int88","int96","int104","int112","int120","int128","int136","int144","int152","int160","int168","int176","int184","int192","int200","int208","int216","int224","int232","int240","int248","int256","uint","uint8","uint16","uint24","uint32","uint40","uint48","uint56","uint64","uint72","uint80","uint88","uint96","uint104","uint112","uint120","uint128","uint136","uint144","uint152","uint160","uint168","uint176","uint184","uint192","uint200","uint208","uint216","uint224","uint232","uint240","uint248","uint256","byte","bytes","bytes1","bytes2","bytes3","bytes4","bytes5","bytes6","bytes7","bytes8","bytes9","bytes10","bytes11","bytes12","bytes13","bytes14","bytes15","bytes16","bytes17","bytes18","bytes19","bytes20","bytes21","bytes22","bytes23","bytes24","bytes25","bytes26","bytes27","bytes28","bytes29","bytes30","bytes31","bytes32","fixed","fixed0x8","fixed0x16","fixed0x24","fixed0x32","fixed0x40","fixed0x48","fixed0x56","fixed0x64","fixed0x72","fixed0x80","fixed0x88","fixed0x96","fixed0x104","fixed0x112","fixed0x120","fixed0x128","fixed0x136","fixed0x144","fixed0x152","fixed0x160","fixed0x168","fixed0x176","fixed0x184","fixed0x192","fixed0x200","fixed0x208","fixed0x216","fixed0x224","fixed0x232","fixed0x240","fixed0x248","fixed0x256","fixed8x8","fixed8x16","fixed8x24","fixed8x32","fixed8x40","fixed8x48","fixed8x56","fixed8x64","fixed8x72","fixed8x80","fixed8x88","fixed8x96","fixed8x104","fixed8x112","fixed8x120","fixed8x128","fixed8x136","fixed8x144","fixed8x152","fixed8x160","fixed8x168","fixed8x176","fixed8x184","fixed8x192","fixed8x200","fixed8x208","fixed8x216","fixed8x224","fixed8x232","fixed8x240","fixed8x248","fixed16x8","fixed16x16","fixed16x24","fixed16x32","fixed16x40","fixed16x48","fixed16x56","fixed16x64","fixed16x72","fixed16x80","fixed16x88","fixed16x96","fixed16x104","fixed16x112","fixed16x120","fixed16x128","fixed16x136","fixed16x144","fixed16x152","fixed16x160","fixed16x168","fixed16x176","fixed16x184","fixed16x192","fixed16x200","fixed16x208","fixed16x216","fixed16x224","fixed16x232","fixed16x240","fixed24x8","fixed24x16","fixed24x24","fixed24x32","fixed24x40","fixed24x48","fixed24x56","fixed24x64","fixed24x72","fixed24x80","fixed24x88","fixed24x96","fixed24x104","fixed24x112","fixed24x120","fixed24x128","fixed24x136","fixed24x144","fixed24x152","fixed24x160","fixed24x168","fixed24x176","fixed24x184","fixed24x192","fixed24x200","fixed24x208","fixed24x216","fixed24x224","fixed24x232","fixed32x8","fixed32x16","fixed32x24","fixed32x32","fixed32x40","fixed32x48","fixed32x56","fixed32x64","fixed32x72","fixed32x80","fixed32x88","fixed32x96","fixed32x104","fixed32x112","fixed32x120","fixed32x128","fixed32x136","fixed32x144","fixed32x152","fixed32x160","fixed32x168","fixed32x176","fixed32x184","fixed32x192","fixed32x200","fixed32x208","fixed32x216","fixed32x224","fixed40x8","fixed40x16","fixed40x24","fixed40x32","fixed40x40","fixed40x48","fixed40x56","fixed40x64","fixed40x72","fixed40x80","fixed40x88","fixed40x96","fixed40x104","fixed40x112","fixed40x120","fixed40x128","fixed40x136","fixed40x144","fixed40x152","fixed40x160","fixed40x168","fixed40x176","fixed40x184","fixed40x192","fixed40x200","fixed40x208","fixed40x216","fixed48x8","fixed48x16","fixed48x24","fixed48x32","fixed48x40","fixed48x48","fixed48x56","fixed48x64","fixed48x72","fixed48x80","fixed48x88","fixed48x96","fixed48x104","fixed48x112","fixed48x120","fixed48x128","fixed48x136","fixed48x144","fixed48x152","fixed48x160","fixed48x168","fixed48x176","fixed48x184","fixed48x192","fixed48x200","fixed48x208","fixed56x8","fixed56x16","fixed56x24","fixed56x32","fixed56x40","fixed56x48","fixed56x56","fixed56x64","fixed56x72","fixed56x80","fixed56x88","fixed56x96","fixed56x104","fixed56x112","fixed56x120","fixed56x128","fixed56x136","fixed56x144","fixed56x152","fixed56x160","fixed56x168","fixed56x176","fixed56x184","fixed56x192","fixed56x200","fixed64x8","fixed64x16","fixed64x24","fixed64x32","fixed64x40","fixed64x48","fixed64x56","fixed64x64","fixed64x72","fixed64x80","fixed64x88","fixed64x96","fixed64x104","fixed64x112","fixed64x120","fixed64x128","fixed64x136","fixed64x144","fixed64x152","fixed64x160","fixed64x168","fixed64x176","fixed64x184","fixed64x192","fixed72x8","fixed72x16","fixed72x24","fixed72x32","fixed72x40","fixed72x48","fixed72x56","fixed72x64","fixed72x72","fixed72x80","fixed72x88","fixed72x96","fixed72x104","fixed72x112","fixed72x120","fixed72x128","fixed72x136","fixed72x144","fixed72x152","fixed72x160","fixed72x168","fixed72x176","fixed72x184","fixed80x8","fixed80x16","fixed80x24","fixed80x32","fixed80x40","fixed80x48","fixed80x56","fixed80x64","fixed80x72","fixed80x80","fixed80x88","fixed80x96","fixed80x104","fixed80x112","fixed80x120","fixed80x128","fixed80x136","fixed80x144","fixed80x152","fixed80x160","fixed80x168","fixed80x176","fixed88x8","fixed88x16","fixed88x24","fixed88x32","fixed88x40","fixed88x48","fixed88x56","fixed88x64","fixed88x72","fixed88x80","fixed88x88","fixed88x96","fixed88x104","fixed88x112","fixed88x120","fixed88x128","fixed88x136","fixed88x144","fixed88x152","fixed88x160","fixed88x168","fixed96x8","fixed96x16","fixed96x24","fixed96x32","fixed96x40","fixed96x48","fixed96x56","fixed96x64","fixed96x72","fixed96x80","fixed96x88","fixed96x96","fixed96x104","fixed96x112","fixed96x120","fixed96x128","fixed96x136","fixed96x144","fixed96x152","fixed96x160","fixed104x8","fixed104x16","fixed104x24","fixed104x32","fixed104x40","fixed104x48","fixed104x56","fixed104x64","fixed104x72","fixed104x80","fixed104x88","fixed104x96","fixed104x104","fixed104x112","fixed104x120","fixed104x128","fixed104x136","fixed104x144","fixed104x152","fixed112x8","fixed112x16","fixed112x24","fixed112x32","fixed112x40","fixed112x48","fixed112x56","fixed112x64","fixed112x72","fixed112x80","fixed112x88","fixed112x96","fixed112x104","fixed112x112","fixed112x120","fixed112x128","fixed112x136","fixed112x144","fixed120x8","fixed120x16","fixed120x24","fixed120x32","fixed120x40","fixed120x48","fixed120x56","fixed120x64","fixed120x72","fixed120x80","fixed120x88","fixed120x96","fixed120x104","fixed120x112","fixed120x120","fixed120x128","fixed120x136","fixed128x8","fixed128x16","fixed128x24","fixed128x32","fixed128x40","fixed128x48","fixed128x56","fixed128x64","fixed128x72","fixed128x80","fixed128x88","fixed128x96","fixed128x104","fixed128x112","fixed128x120","fixed128x128","fixed136x8","fixed136x16","fixed136x24","fixed136x32","fixed136x40","fixed136x48","fixed136x56","fixed136x64","fixed136x72","fixed136x80","fixed136x88","fixed136x96","fixed136x104","fixed136x112","fixed136x120","fixed144x8","fixed144x16","fixed144x24","fixed144x32","fixed144x40","fixed144x48","fixed144x56","fixed144x64","fixed144x72","fixed144x80","fixed144x88","fixed144x96","fixed144x104","fixed144x112","fixed152x8","fixed152x16","fixed152x24","fixed152x32","fixed152x40","fixed152x48","fixed152x56","fixed152x64","fixed152x72","fixed152x80","fixed152x88","fixed152x96","fixed152x104","fixed160x8","fixed160x16","fixed160x24","fixed160x32","fixed160x40","fixed160x48","fixed160x56","fixed160x64","fixed160x72","fixed160x80","fixed160x88","fixed160x96","fixed168x8","fixed168x16","fixed168x24","fixed168x32","fixed168x40","fixed168x48","fixed168x56","fixed168x64","fixed168x72","fixed168x80","fixed168x88","fixed176x8","fixed176x16","fixed176x24","fixed176x32","fixed176x40","fixed176x48","fixed176x56","fixed176x64","fixed176x72","fixed176x80","fixed184x8","fixed184x16","fixed184x24","fixed184x32","fixed184x40","fixed184x48","fixed184x56","fixed184x64","fixed184x72","fixed192x8","fixed192x16","fixed192x24","fixed192x32","fixed192x40","fixed192x48","fixed192x56","fixed192x64","fixed200x8","fixed200x16","fixed200x24","fixed200x32","fixed200x40","fixed200x48","fixed200x56","fixed208x8","fixed208x16","fixed208x24","fixed208x32","fixed208x40","fixed208x48","fixed216x8","fixed216x16","fixed216x24","fixed216x32","fixed216x40","fixed224x8","fixed224x16","fixed224x24","fixed224x32","fixed232x8","fixed232x16","fixed232x24","fixed240x8","fixed240x16","fixed248x8","ufixed","ufixed0x8","ufixed0x16","ufixed0x24","ufixed0x32","ufixed0x40","ufixed0x48","ufixed0x56","ufixed0x64","ufixed0x72","ufixed0x80","ufixed0x88","ufixed0x96","ufixed0x104","ufixed0x112","ufixed0x120","ufixed0x128","ufixed0x136","ufixed0x144","ufixed0x152","ufixed0x160","ufixed0x168","ufixed0x176","ufixed0x184","ufixed0x192","ufixed0x200","ufixed0x208","ufixed0x216","ufixed0x224","ufixed0x232","ufixed0x240","ufixed0x248","ufixed0x256","ufixed8x8","ufixed8x16","ufixed8x24","ufixed8x32","ufixed8x40","ufixed8x48","ufixed8x56","ufixed8x64","ufixed8x72","ufixed8x80","ufixed8x88","ufixed8x96","ufixed8x104","ufixed8x112","ufixed8x120","ufixed8x128","ufixed8x136","ufixed8x144","ufixed8x152","ufixed8x160","ufixed8x168","ufixed8x176","ufixed8x184","ufixed8x192","ufixed8x200","ufixed8x208","ufixed8x216","ufixed8x224","ufixed8x232","ufixed8x240","ufixed8x248","ufixed16x8","ufixed16x16","ufixed16x24","ufixed16x32","ufixed16x40","ufixed16x48","ufixed16x56","ufixed16x64","ufixed16x72","ufixed16x80","ufixed16x88","ufixed16x96","ufixed16x104","ufixed16x112","ufixed16x120","ufixed16x128","ufixed16x136","ufixed16x144","ufixed16x152","ufixed16x160","ufixed16x168","ufixed16x176","ufixed16x184","ufixed16x192","ufixed16x200","ufixed16x208","ufixed16x216","ufixed16x224","ufixed16x232","ufixed16x240","ufixed24x8","ufixed24x16","ufixed24x24","ufixed24x32","ufixed24x40","ufixed24x48","ufixed24x56","ufixed24x64","ufixed24x72","ufixed24x80","ufixed24x88","ufixed24x96","ufixed24x104","ufixed24x112","ufixed24x120","ufixed24x128","ufixed24x136","ufixed24x144","ufixed24x152","ufixed24x160","ufixed24x168","ufixed24x176","ufixed24x184","ufixed24x192","ufixed24x200","ufixed24x208","ufixed24x216","ufixed24x224","ufixed24x232","ufixed32x8","ufixed32x16","ufixed32x24","ufixed32x32","ufixed32x40","ufixed32x48","ufixed32x56","ufixed32x64","ufixed32x72","ufixed32x80","ufixed32x88","ufixed32x96","ufixed32x104","ufixed32x112","ufixed32x120","ufixed32x128","ufixed32x136","ufixed32x144","ufixed32x152","ufixed32x160","ufixed32x168","ufixed32x176","ufixed32x184","ufixed32x192","ufixed32x200","ufixed32x208","ufixed32x216","ufixed32x224","ufixed40x8","ufixed40x16","ufixed40x24","ufixed40x32","ufixed40x40","ufixed40x48","ufixed40x56","ufixed40x64","ufixed40x72","ufixed40x80","ufixed40x88","ufixed40x96","ufixed40x104","ufixed40x112","ufixed40x120","ufixed40x128","ufixed40x136","ufixed40x144","ufixed40x152","ufixed40x160","ufixed40x168","ufixed40x176","ufixed40x184","ufixed40x192","ufixed40x200","ufixed40x208","ufixed40x216","ufixed48x8","ufixed48x16","ufixed48x24","ufixed48x32","ufixed48x40","ufixed48x48","ufixed48x56","ufixed48x64","ufixed48x72","ufixed48x80","ufixed48x88","ufixed48x96","ufixed48x104","ufixed48x112","ufixed48x120","ufixed48x128","ufixed48x136","ufixed48x144","ufixed48x152","ufixed48x160","ufixed48x168","ufixed48x176","ufixed48x184","ufixed48x192","ufixed48x200","ufixed48x208","ufixed56x8","ufixed56x16","ufixed56x24","ufixed56x32","ufixed56x40","ufixed56x48","ufixed56x56","ufixed56x64","ufixed56x72","ufixed56x80","ufixed56x88","ufixed56x96","ufixed56x104","ufixed56x112","ufixed56x120","ufixed56x128","ufixed56x136","ufixed56x144","ufixed56x152","ufixed56x160","ufixed56x168","ufixed56x176","ufixed56x184","ufixed56x192","ufixed56x200","ufixed64x8","ufixed64x16","ufixed64x24","ufixed64x32","ufixed64x40","ufixed64x48","ufixed64x56","ufixed64x64","ufixed64x72","ufixed64x80","ufixed64x88","ufixed64x96","ufixed64x104","ufixed64x112","ufixed64x120","ufixed64x128","ufixed64x136","ufixed64x144","ufixed64x152","ufixed64x160","ufixed64x168","ufixed64x176","ufixed64x184","ufixed64x192","ufixed72x8","ufixed72x16","ufixed72x24","ufixed72x32","ufixed72x40","ufixed72x48","ufixed72x56","ufixed72x64","ufixed72x72","ufixed72x80","ufixed72x88","ufixed72x96","ufixed72x104","ufixed72x112","ufixed72x120","ufixed72x128","ufixed72x136","ufixed72x144","ufixed72x152","ufixed72x160","ufixed72x168","ufixed72x176","ufixed72x184","ufixed80x8","ufixed80x16","ufixed80x24","ufixed80x32","ufixed80x40","ufixed80x48","ufixed80x56","ufixed80x64","ufixed80x72","ufixed80x80","ufixed80x88","ufixed80x96","ufixed80x104","ufixed80x112","ufixed80x120","ufixed80x128","ufixed80x136","ufixed80x144","ufixed80x152","ufixed80x160","ufixed80x168","ufixed80x176","ufixed88x8","ufixed88x16","ufixed88x24","ufixed88x32","ufixed88x40","ufixed88x48","ufixed88x56","ufixed88x64","ufixed88x72","ufixed88x80","ufixed88x88","ufixed88x96","ufixed88x104","ufixed88x112","ufixed88x120","ufixed88x128","ufixed88x136","ufixed88x144","ufixed88x152","ufixed88x160","ufixed88x168","ufixed96x8","ufixed96x16","ufixed96x24","ufixed96x32","ufixed96x40","ufixed96x48","ufixed96x56","ufixed96x64","ufixed96x72","ufixed96x80","ufixed96x88","ufixed96x96","ufixed96x104","ufixed96x112","ufixed96x120","ufixed96x128","ufixed96x136","ufixed96x144","ufixed96x152","ufixed96x160","ufixed104x8","ufixed104x16","ufixed104x24","ufixed104x32","ufixed104x40","ufixed104x48","ufixed104x56","ufixed104x64","ufixed104x72","ufixed104x80","ufixed104x88","ufixed104x96","ufixed104x104","ufixed104x112","ufixed104x120","ufixed104x128","ufixed104x136","ufixed104x144","ufixed104x152","ufixed112x8","ufixed112x16","ufixed112x24","ufixed112x32","ufixed112x40","ufixed112x48","ufixed112x56","ufixed112x64","ufixed112x72","ufixed112x80","ufixed112x88","ufixed112x96","ufixed112x104","ufixed112x112","ufixed112x120","ufixed112x128","ufixed112x136","ufixed112x144","ufixed120x8","ufixed120x16","ufixed120x24","ufixed120x32","ufixed120x40","ufixed120x48","ufixed120x56","ufixed120x64","ufixed120x72","ufixed120x80","ufixed120x88","ufixed120x96","ufixed120x104","ufixed120x112","ufixed120x120","ufixed120x128","ufixed120x136","ufixed128x8","ufixed128x16","ufixed128x24","ufixed128x32","ufixed128x40","ufixed128x48","ufixed128x56","ufixed128x64","ufixed128x72","ufixed128x80","ufixed128x88","ufixed128x96","ufixed128x104","ufixed128x112","ufixed128x120","ufixed128x128","ufixed136x8","ufixed136x16","ufixed136x24","ufixed136x32","ufixed136x40","ufixed136x48","ufixed136x56","ufixed136x64","ufixed136x72","ufixed136x80","ufixed136x88","ufixed136x96","ufixed136x104","ufixed136x112","ufixed136x120","ufixed144x8","ufixed144x16","ufixed144x24","ufixed144x32","ufixed144x40","ufixed144x48","ufixed144x56","ufixed144x64","ufixed144x72","ufixed144x80","ufixed144x88","ufixed144x96","ufixed144x104","ufixed144x112","ufixed152x8","ufixed152x16","ufixed152x24","ufixed152x32","ufixed152x40","ufixed152x48","ufixed152x56","ufixed152x64","ufixed152x72","ufixed152x80","ufixed152x88","ufixed152x96","ufixed152x104","ufixed160x8","ufixed160x16","ufixed160x24","ufixed160x32","ufixed160x40","ufixed160x48","ufixed160x56","ufixed160x64","ufixed160x72","ufixed160x80","ufixed160x88","ufixed160x96","ufixed168x8","ufixed168x16","ufixed168x24","ufixed168x32","ufixed168x40","ufixed168x48","ufixed168x56","ufixed168x64","ufixed168x72","ufixed168x80","ufixed168x88","ufixed176x8","ufixed176x16","ufixed176x24","ufixed176x32","ufixed176x40","ufixed176x48","ufixed176x56","ufixed176x64","ufixed176x72","ufixed176x80","ufixed184x8","ufixed184x16","ufixed184x24","ufixed184x32","ufixed184x40","ufixed184x48","ufixed184x56","ufixed184x64","ufixed184x72","ufixed192x8","ufixed192x16","ufixed192x24","ufixed192x32","ufixed192x40","ufixed192x48","ufixed192x56","ufixed192x64","ufixed200x8","ufixed200x16","ufixed200x24","ufixed200x32","ufixed200x40","ufixed200x48","ufixed200x56","ufixed208x8","ufixed208x16","ufixed208x24","ufixed208x32","ufixed208x40","ufixed208x48","ufixed216x8","ufixed216x16","ufixed216x24","ufixed216x32","ufixed216x40","ufixed224x8","ufixed224x16","ufixed224x24","ufixed224x32","ufixed232x8","ufixed232x16","ufixed232x24","ufixed240x8","ufixed240x16","ufixed248x8","event","enum","let","mapping","private","public","external","inherited","payable","true","false","var","import","constant","if","else","for","else","for","while","do","break","continue","throw","returns","return","suicide","new","is","this","super"],operators:["=",">","<","!","~","?",":","==","<=",">=","!=","&&","||","++","--","+","-","*","/","&","|","^","%","<<",">>",">>>","+=","-=","*=","/=","&=","|=","^=","%=","<<=",">>=",">>>="],symbols:/[=>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/\d*\d+[eE]([\-+]?\d+)?(@floatsuffix)/,"number.float"],[/\d*\.\d+([eE][\-+]?\d+)?(@floatsuffix)/,"number.float"],[/0[xX][0-9a-fA-F']*[0-9a-fA-F](@integersuffix)/,"number.hex"],[/0[0-7']*[0-7](@integersuffix)/,"number.octal"],[/0[bB][0-1']*[0-1](@integersuffix)/,"number.binary"],[/\d[\d']*\d(@integersuffix)/,"number"],[/\d(@integersuffix)/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@doccomment"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],doccomment:[[/[^\/*]+/,"comment.doc"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/sql/sql.js b/public/react/public/js/monaco/vs/basic-languages/sql/sql.js new file mode 100755 index 000000000..f24ff8b38 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/sql/sql.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/sql/sql",["require","exports"],function(E,T){"use strict";Object.defineProperty(T,"__esModule",{value:!0}),T.conf={comments:{lineComment:"--",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},T.language={defaultToken:"",tokenPostfix:".sql",ignoreCase:!0,brackets:[{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"}],keywords:["ABORT_AFTER_WAIT","ABSENT","ABSOLUTE","ACCENT_SENSITIVITY","ACTION","ACTIVATION","ACTIVE","ADD","ADDRESS","ADMIN","AES","AES_128","AES_192","AES_256","AFFINITY","AFTER","AGGREGATE","ALGORITHM","ALL_CONSTRAINTS","ALL_ERRORMSGS","ALL_INDEXES","ALL_LEVELS","ALL_SPARSE_COLUMNS","ALLOW_CONNECTIONS","ALLOW_MULTIPLE_EVENT_LOSS","ALLOW_PAGE_LOCKS","ALLOW_ROW_LOCKS","ALLOW_SINGLE_EVENT_LOSS","ALLOW_SNAPSHOT_ISOLATION","ALLOWED","ALTER","ANONYMOUS","ANSI_DEFAULTS","ANSI_NULL_DEFAULT","ANSI_NULL_DFLT_OFF","ANSI_NULL_DFLT_ON","ANSI_NULLS","ANSI_PADDING","ANSI_WARNINGS","APPEND","APPLICATION","APPLICATION_LOG","ARITHABORT","ARITHIGNORE","AS","ASC","ASSEMBLY","ASYMMETRIC","ASYNCHRONOUS_COMMIT","AT","ATOMIC","ATTACH","ATTACH_REBUILD_LOG","AUDIT","AUDIT_GUID","AUTHENTICATION","AUTHORIZATION","AUTO","AUTO_CLEANUP","AUTO_CLOSE","AUTO_CREATE_STATISTICS","AUTO_SHRINK","AUTO_UPDATE_STATISTICS","AUTO_UPDATE_STATISTICS_ASYNC","AUTOMATED_BACKUP_PREFERENCE","AUTOMATIC","AVAILABILITY","AVAILABILITY_MODE","BACKUP","BACKUP_PRIORITY","BASE64","BATCHSIZE","BEGIN","BEGIN_DIALOG","BIGINT","BINARY","BINDING","BIT","BLOCKERS","BLOCKSIZE","BOUNDING_BOX","BREAK","BROKER","BROKER_INSTANCE","BROWSE","BUCKET_COUNT","BUFFER","BUFFERCOUNT","BULK","BULK_LOGGED","BY","CACHE","CALL","CALLED","CALLER","CAP_CPU_PERCENT","CASCADE","CASE","CATALOG","CATCH","CELLS_PER_OBJECT","CERTIFICATE","CHANGE_RETENTION","CHANGE_TRACKING","CHANGES","CHAR","CHARACTER","CHECK","CHECK_CONSTRAINTS","CHECK_EXPIRATION","CHECK_POLICY","CHECKALLOC","CHECKCATALOG","CHECKCONSTRAINTS","CHECKDB","CHECKFILEGROUP","CHECKIDENT","CHECKPOINT","CHECKTABLE","CLASSIFIER_FUNCTION","CLEANTABLE","CLEANUP","CLEAR","CLOSE","CLUSTER","CLUSTERED","CODEPAGE","COLLATE","COLLECTION","COLUMN","COLUMN_SET","COLUMNS","COLUMNSTORE","COLUMNSTORE_ARCHIVE","COMMIT","COMMITTED","COMPATIBILITY_LEVEL","COMPRESSION","COMPUTE","CONCAT","CONCAT_NULL_YIELDS_NULL","CONFIGURATION","CONNECT","CONSTRAINT","CONTAINMENT","CONTENT","CONTEXT","CONTINUE","CONTINUE_AFTER_ERROR","CONTRACT","CONTRACT_NAME","CONTROL","CONVERSATION","COOKIE","COPY_ONLY","COUNTER","CPU","CREATE","CREATE_NEW","CREATION_DISPOSITION","CREDENTIAL","CRYPTOGRAPHIC","CUBE","CURRENT","CURRENT_DATE","CURSOR","CURSOR_CLOSE_ON_COMMIT","CURSOR_DEFAULT","CYCLE","DATA","DATA_COMPRESSION","DATA_PURITY","DATABASE","DATABASE_DEFAULT","DATABASE_MIRRORING","DATABASE_SNAPSHOT","DATAFILETYPE","DATE","DATE_CORRELATION_OPTIMIZATION","DATEFIRST","DATEFORMAT","DATETIME","DATETIME2","DATETIMEOFFSET","DAY","DAYOFYEAR","DAYS","DB_CHAINING","DBCC","DBREINDEX","DDL_DATABASE_LEVEL_EVENTS","DEADLOCK_PRIORITY","DEALLOCATE","DEC","DECIMAL","DECLARE","DECRYPTION","DEFAULT","DEFAULT_DATABASE","DEFAULT_FULLTEXT_LANGUAGE","DEFAULT_LANGUAGE","DEFAULT_SCHEMA","DEFINITION","DELAY","DELAYED_DURABILITY","DELETE","DELETED","DENSITY_VECTOR","DENY","DEPENDENTS","DES","DESC","DESCRIPTION","DESX","DHCP","DIAGNOSTICS","DIALOG","DIFFERENTIAL","DIRECTORY_NAME","DISABLE","DISABLE_BROKER","DISABLED","DISK","DISTINCT","DISTRIBUTED","DOCUMENT","DOUBLE","DROP","DROP_EXISTING","DROPCLEANBUFFERS","DUMP","DURABILITY","DYNAMIC","EDITION","ELEMENTS","ELSE","EMERGENCY","EMPTY","EMPTYFILE","ENABLE","ENABLE_BROKER","ENABLED","ENCRYPTION","END","ENDPOINT","ENDPOINT_URL","ERRLVL","ERROR","ERROR_BROKER_CONVERSATIONS","ERRORFILE","ESCAPE","ESTIMATEONLY","EVENT","EVENT_RETENTION_MODE","EXEC","EXECUTABLE","EXECUTE","EXIT","EXPAND","EXPIREDATE","EXPIRY_DATE","EXPLICIT","EXTENDED_LOGICAL_CHECKS","EXTENSION","EXTERNAL","EXTERNAL_ACCESS","FAIL_OPERATION","FAILOVER","FAILOVER_MODE","FAILURE_CONDITION_LEVEL","FALSE","FAN_IN","FAST","FAST_FORWARD","FETCH","FIELDTERMINATOR","FILE","FILEGROUP","FILEGROWTH","FILELISTONLY","FILENAME","FILEPATH","FILESTREAM","FILESTREAM_ON","FILETABLE_COLLATE_FILENAME","FILETABLE_DIRECTORY","FILETABLE_FULLPATH_UNIQUE_CONSTRAINT_NAME","FILETABLE_NAMESPACE","FILETABLE_PRIMARY_KEY_CONSTRAINT_NAME","FILETABLE_STREAMID_UNIQUE_CONSTRAINT_NAME","FILLFACTOR","FILTERING","FIRE_TRIGGERS","FIRST","FIRSTROW","FLOAT","FMTONLY","FOLLOWING","FOR","FORCE","FORCE_FAILOVER_ALLOW_DATA_LOSS","FORCE_SERVICE_ALLOW_DATA_LOSS","FORCED","FORCEPLAN","FORCESCAN","FORCESEEK","FOREIGN","FORMATFILE","FORMSOF","FORWARD_ONLY","FREE","FREEPROCCACHE","FREESESSIONCACHE","FREESYSTEMCACHE","FROM","FULL","FULLSCAN","FULLTEXT","FUNCTION","GB","GEOGRAPHY_AUTO_GRID","GEOGRAPHY_GRID","GEOMETRY_AUTO_GRID","GEOMETRY_GRID","GET","GLOBAL","GO","GOTO","GOVERNOR","GRANT","GRIDS","GROUP","GROUP_MAX_REQUESTS","HADR","HASH","HASHED","HAVING","HEADERONLY","HEALTH_CHECK_TIMEOUT","HELP","HIERARCHYID","HIGH","HINT","HISTOGRAM","HOLDLOCK","HONOR_BROKER_PRIORITY","HOUR","HOURS","IDENTITY","IDENTITY_INSERT","IDENTITY_VALUE","IDENTITYCOL","IF","IGNORE_CONSTRAINTS","IGNORE_DUP_KEY","IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX","IGNORE_TRIGGERS","IMAGE","IMMEDIATE","IMPERSONATE","IMPLICIT_TRANSACTIONS","IMPORTANCE","INCLUDE","INCREMENT","INCREMENTAL","INDEX","INDEXDEFRAG","INFINITE","INFLECTIONAL","INIT","INITIATOR","INPUT","INPUTBUFFER","INSENSITIVE","INSERT","INSERTED","INSTEAD","INT","INTEGER","INTO","IO","IP","ISABOUT","ISOLATION","JOB","KB","KEEP","KEEP_CDC","KEEP_NULLS","KEEP_REPLICATION","KEEPDEFAULTS","KEEPFIXED","KEEPIDENTITY","KEEPNULLS","KERBEROS","KEY","KEY_SOURCE","KEYS","KEYSET","KILL","KILOBYTES_PER_BATCH","LABELONLY","LANGUAGE","LAST","LASTROW","LEVEL","LEVEL_1","LEVEL_2","LEVEL_3","LEVEL_4","LIFETIME","LIMIT","LINENO","LIST","LISTENER","LISTENER_IP","LISTENER_PORT","LOAD","LOADHISTORY","LOB_COMPACTION","LOCAL","LOCAL_SERVICE_NAME","LOCK_ESCALATION","LOCK_TIMEOUT","LOGIN","LOGSPACE","LOOP","LOW","MANUAL","MARK","MARK_IN_USE_FOR_REMOVAL","MASTER","MAX_CPU_PERCENT","MAX_DISPATCH_LATENCY","MAX_DOP","MAX_DURATION","MAX_EVENT_SIZE","MAX_FILES","MAX_IOPS_PER_VOLUME","MAX_MEMORY","MAX_MEMORY_PERCENT","MAX_QUEUE_READERS","MAX_ROLLOVER_FILES","MAX_SIZE","MAXDOP","MAXERRORS","MAXLENGTH","MAXRECURSION","MAXSIZE","MAXTRANSFERSIZE","MAXVALUE","MB","MEDIADESCRIPTION","MEDIANAME","MEDIAPASSWORD","MEDIUM","MEMBER","MEMORY_OPTIMIZED","MEMORY_OPTIMIZED_DATA","MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT","MEMORY_PARTITION_MODE","MERGE","MESSAGE","MESSAGE_FORWARD_SIZE","MESSAGE_FORWARDING","MICROSECOND","MILLISECOND","MIN_CPU_PERCENT","MIN_IOPS_PER_VOLUME","MIN_MEMORY_PERCENT","MINUTE","MINUTES","MINVALUE","MIRROR","MIRROR_ADDRESS","MODIFY","MONEY","MONTH","MOVE","MULTI_USER","MUST_CHANGE","NAME","NANOSECOND","NATIONAL","NATIVE_COMPILATION","NCHAR","NEGOTIATE","NESTED_TRIGGERS","NEW_ACCOUNT","NEW_BROKER","NEW_PASSWORD","NEWNAME","NEXT","NO","NO_BROWSETABLE","NO_CHECKSUM","NO_COMPRESSION","NO_EVENT_LOSS","NO_INFOMSGS","NO_TRUNCATE","NO_WAIT","NOCHECK","NOCOUNT","NOEXEC","NOEXPAND","NOFORMAT","NOINDEX","NOINIT","NOLOCK","NON","NON_TRANSACTED_ACCESS","NONCLUSTERED","NONE","NORECOMPUTE","NORECOVERY","NORESEED","NORESET","NOREWIND","NORMAL","NOSKIP","NOTIFICATION","NOTRUNCATE","NOUNLOAD","NOWAIT","NTEXT","NTLM","NUMANODE","NUMERIC","NUMERIC_ROUNDABORT","NVARCHAR","OBJECT","OF","OFF","OFFLINE","OFFSET","OFFSETS","OLD_ACCOUNT","OLD_PASSWORD","ON","ON_FAILURE","ONLINE","ONLY","OPEN","OPEN_EXISTING","OPENTRAN","OPTIMISTIC","OPTIMIZE","OPTION","ORDER","OUT","OUTPUT","OUTPUTBUFFER","OVER","OVERRIDE","OWNER","OWNERSHIP","PAD_INDEX","PAGE","PAGE_VERIFY","PAGECOUNT","PAGLOCK","PARAMETERIZATION","PARSEONLY","PARTIAL","PARTITION","PARTITIONS","PARTNER","PASSWORD","PATH","PER_CPU","PER_NODE","PERCENT","PERMISSION_SET","PERSISTED","PHYSICAL_ONLY","PLAN","POISON_MESSAGE_HANDLING","POOL","POPULATION","PORT","PRECEDING","PRECISION","PRIMARY","PRIMARY_ROLE","PRINT","PRIOR","PRIORITY","PRIORITY_LEVEL","PRIVATE","PRIVILEGES","PROC","PROCCACHE","PROCEDURE","PROCEDURE_NAME","PROCESS","PROFILE","PROPERTY","PROPERTY_DESCRIPTION","PROPERTY_INT_ID","PROPERTY_SET_GUID","PROVIDER","PROVIDER_KEY_NAME","PUBLIC","PUT","QUARTER","QUERY","QUERY_GOVERNOR_COST_LIMIT","QUEUE","QUEUE_DELAY","QUOTED_IDENTIFIER","RAISERROR","RANGE","RAW","RC2","RC4","RC4_128","READ","READ_COMMITTED_SNAPSHOT","READ_ONLY","READ_ONLY_ROUTING_LIST","READ_ONLY_ROUTING_URL","READ_WRITE","READ_WRITE_FILEGROUPS","READCOMMITTED","READCOMMITTEDLOCK","READONLY","READPAST","READTEXT","READUNCOMMITTED","READWRITE","REAL","REBUILD","RECEIVE","RECOMPILE","RECONFIGURE","RECOVERY","RECURSIVE","RECURSIVE_TRIGGERS","REFERENCES","REGENERATE","RELATED_CONVERSATION","RELATED_CONVERSATION_GROUP","RELATIVE","REMOTE","REMOTE_PROC_TRANSACTIONS","REMOTE_SERVICE_NAME","REMOVE","REORGANIZE","REPAIR_ALLOW_DATA_LOSS","REPAIR_FAST","REPAIR_REBUILD","REPEATABLE","REPEATABLEREAD","REPLICA","REPLICATION","REQUEST_MAX_CPU_TIME_SEC","REQUEST_MAX_MEMORY_GRANT_PERCENT","REQUEST_MEMORY_GRANT_TIMEOUT_SEC","REQUIRED","RESAMPLE","RESEED","RESERVE_DISK_SPACE","RESET","RESOURCE","RESTART","RESTORE","RESTRICT","RESTRICTED_USER","RESULT","RESUME","RETAINDAYS","RETENTION","RETURN","RETURNS","REVERT","REVOKE","REWIND","REWINDONLY","ROBUST","ROLE","ROLLBACK","ROLLUP","ROOT","ROUTE","ROW","ROWCOUNT","ROWGUIDCOL","ROWLOCK","ROWS","ROWS_PER_BATCH","ROWTERMINATOR","ROWVERSION","RSA_1024","RSA_2048","RSA_512","RULE","SAFE","SAFETY","SAMPLE","SAVE","SCHEDULER","SCHEMA","SCHEMA_AND_DATA","SCHEMA_ONLY","SCHEMABINDING","SCHEME","SCROLL","SCROLL_LOCKS","SEARCH","SECOND","SECONDARY","SECONDARY_ONLY","SECONDARY_ROLE","SECONDS","SECRET","SECURITY_LOG","SECURITYAUDIT","SELECT","SELECTIVE","SELF","SEND","SENT","SEQUENCE","SERIALIZABLE","SERVER","SERVICE","SERVICE_BROKER","SERVICE_NAME","SESSION","SESSION_TIMEOUT","SET","SETS","SETUSER","SHOW_STATISTICS","SHOWCONTIG","SHOWPLAN","SHOWPLAN_ALL","SHOWPLAN_TEXT","SHOWPLAN_XML","SHRINKDATABASE","SHRINKFILE","SHUTDOWN","SID","SIGNATURE","SIMPLE","SINGLE_BLOB","SINGLE_CLOB","SINGLE_NCLOB","SINGLE_USER","SINGLETON","SIZE","SKIP","SMALLDATETIME","SMALLINT","SMALLMONEY","SNAPSHOT","SORT_IN_TEMPDB","SOURCE","SPARSE","SPATIAL","SPATIAL_WINDOW_MAX_CELLS","SPECIFICATION","SPLIT","SQL","SQL_VARIANT","SQLPERF","STANDBY","START","START_DATE","STARTED","STARTUP_STATE","STAT_HEADER","STATE","STATEMENT","STATIC","STATISTICAL_SEMANTICS","STATISTICS","STATISTICS_INCREMENTAL","STATISTICS_NORECOMPUTE","STATS","STATS_STREAM","STATUS","STATUSONLY","STOP","STOP_ON_ERROR","STOPAT","STOPATMARK","STOPBEFOREMARK","STOPLIST","STOPPED","SUBJECT","SUBSCRIPTION","SUPPORTED","SUSPEND","SWITCH","SYMMETRIC","SYNCHRONOUS_COMMIT","SYNONYM","SYSNAME","SYSTEM","TABLE","TABLERESULTS","TABLESAMPLE","TABLOCK","TABLOCKX","TAKE","TAPE","TARGET","TARGET_RECOVERY_TIME","TB","TCP","TEXT","TEXTIMAGE_ON","TEXTSIZE","THEN","THESAURUS","THROW","TIES","TIME","TIMEOUT","TIMER","TIMESTAMP","TINYINT","TO","TOP","TORN_PAGE_DETECTION","TRACEOFF","TRACEON","TRACESTATUS","TRACK_CAUSALITY","TRACK_COLUMNS_UPDATED","TRAN","TRANSACTION","TRANSFER","TRANSFORM_NOISE_WORDS","TRIGGER","TRIPLE_DES","TRIPLE_DES_3KEY","TRUE","TRUNCATE","TRUNCATEONLY","TRUSTWORTHY","TRY","TSQL","TWO_DIGIT_YEAR_CUTOFF","TYPE","TYPE_WARNING","UNBOUNDED","UNCHECKED","UNCOMMITTED","UNDEFINED","UNIQUE","UNIQUEIDENTIFIER","UNKNOWN","UNLIMITED","UNLOAD","UNSAFE","UPDATE","UPDATETEXT","UPDATEUSAGE","UPDLOCK","URL","USE","USED","USER","USEROPTIONS","USING","VALID_XML","VALIDATION","VALUE","VALUES","VARBINARY","VARCHAR","VARYING","VERIFYONLY","VERSION","VIEW","VIEW_METADATA","VIEWS","VISIBILITY","WAIT_AT_LOW_PRIORITY","WAITFOR","WEEK","WEIGHT","WELL_FORMED_XML","WHEN","WHERE","WHILE","WINDOWS","WITH","WITHIN","WITHOUT","WITNESS","WORK","WORKLOAD","WRITETEXT","XACT_ABORT","XLOCK","XMAX","XMIN","XML","XMLDATA","XMLNAMESPACES","XMLSCHEMA","XQUERY","XSINIL","YEAR","YMAX","YMIN"],operators:["ALL","AND","ANY","BETWEEN","EXISTS","IN","LIKE","NOT","OR","SOME","EXCEPT","INTERSECT","UNION","APPLY","CROSS","FULL","INNER","JOIN","LEFT","OUTER","RIGHT","CONTAINS","FREETEXT","IS","NULL","PIVOT","UNPIVOT","MATCHED"],builtinFunctions:["AVG","CHECKSUM_AGG","COUNT","COUNT_BIG","GROUPING","GROUPING_ID","MAX","MIN","SUM","STDEV","STDEVP","VAR","VARP","CUME_DIST","FIRST_VALUE","LAG","LAST_VALUE","LEAD","PERCENTILE_CONT","PERCENTILE_DISC","PERCENT_RANK","COLLATE","COLLATIONPROPERTY","TERTIARY_WEIGHTS","FEDERATION_FILTERING_VALUE","CAST","CONVERT","PARSE","TRY_CAST","TRY_CONVERT","TRY_PARSE","ASYMKEY_ID","ASYMKEYPROPERTY","CERTPROPERTY","CERT_ID","CRYPT_GEN_RANDOM","DECRYPTBYASYMKEY","DECRYPTBYCERT","DECRYPTBYKEY","DECRYPTBYKEYAUTOASYMKEY","DECRYPTBYKEYAUTOCERT","DECRYPTBYPASSPHRASE","ENCRYPTBYASYMKEY","ENCRYPTBYCERT","ENCRYPTBYKEY","ENCRYPTBYPASSPHRASE","HASHBYTES","IS_OBJECTSIGNED","KEY_GUID","KEY_ID","KEY_NAME","SIGNBYASYMKEY","SIGNBYCERT","SYMKEYPROPERTY","VERIFYSIGNEDBYCERT","VERIFYSIGNEDBYASYMKEY","CURSOR_STATUS","DATALENGTH","IDENT_CURRENT","IDENT_INCR","IDENT_SEED","IDENTITY","SQL_VARIANT_PROPERTY","CURRENT_TIMESTAMP","DATEADD","DATEDIFF","DATEFROMPARTS","DATENAME","DATEPART","DATETIME2FROMPARTS","DATETIMEFROMPARTS","DATETIMEOFFSETFROMPARTS","DAY","EOMONTH","GETDATE","GETUTCDATE","ISDATE","MONTH","SMALLDATETIMEFROMPARTS","SWITCHOFFSET","SYSDATETIME","SYSDATETIMEOFFSET","SYSUTCDATETIME","TIMEFROMPARTS","TODATETIMEOFFSET","YEAR","CHOOSE","COALESCE","IIF","NULLIF","ABS","ACOS","ASIN","ATAN","ATN2","CEILING","COS","COT","DEGREES","EXP","FLOOR","LOG","LOG10","PI","POWER","RADIANS","RAND","ROUND","SIGN","SIN","SQRT","SQUARE","TAN","APP_NAME","APPLOCK_MODE","APPLOCK_TEST","ASSEMBLYPROPERTY","COL_LENGTH","COL_NAME","COLUMNPROPERTY","DATABASE_PRINCIPAL_ID","DATABASEPROPERTYEX","DB_ID","DB_NAME","FILE_ID","FILE_IDEX","FILE_NAME","FILEGROUP_ID","FILEGROUP_NAME","FILEGROUPPROPERTY","FILEPROPERTY","FULLTEXTCATALOGPROPERTY","FULLTEXTSERVICEPROPERTY","INDEX_COL","INDEXKEY_PROPERTY","INDEXPROPERTY","OBJECT_DEFINITION","OBJECT_ID","OBJECT_NAME","OBJECT_SCHEMA_NAME","OBJECTPROPERTY","OBJECTPROPERTYEX","ORIGINAL_DB_NAME","PARSENAME","SCHEMA_ID","SCHEMA_NAME","SCOPE_IDENTITY","SERVERPROPERTY","STATS_DATE","TYPE_ID","TYPE_NAME","TYPEPROPERTY","DENSE_RANK","NTILE","RANK","ROW_NUMBER","PUBLISHINGSERVERNAME","OPENDATASOURCE","OPENQUERY","OPENROWSET","OPENXML","CERTENCODED","CERTPRIVATEKEY","CURRENT_USER","HAS_DBACCESS","HAS_PERMS_BY_NAME","IS_MEMBER","IS_ROLEMEMBER","IS_SRVROLEMEMBER","LOGINPROPERTY","ORIGINAL_LOGIN","PERMISSIONS","PWDENCRYPT","PWDCOMPARE","SESSION_USER","SESSIONPROPERTY","SUSER_ID","SUSER_NAME","SUSER_SID","SUSER_SNAME","SYSTEM_USER","USER","USER_ID","USER_NAME","ASCII","CHAR","CHARINDEX","CONCAT","DIFFERENCE","FORMAT","LEFT","LEN","LOWER","LTRIM","NCHAR","PATINDEX","QUOTENAME","REPLACE","REPLICATE","REVERSE","RIGHT","RTRIM","SOUNDEX","SPACE","STR","STUFF","SUBSTRING","UNICODE","UPPER","BINARY_CHECKSUM","CHECKSUM","CONNECTIONPROPERTY","CONTEXT_INFO","CURRENT_REQUEST_ID","ERROR_LINE","ERROR_NUMBER","ERROR_MESSAGE","ERROR_PROCEDURE","ERROR_SEVERITY","ERROR_STATE","FORMATMESSAGE","GETANSINULL","GET_FILESTREAM_TRANSACTION_CONTEXT","HOST_ID","HOST_NAME","ISNULL","ISNUMERIC","MIN_ACTIVE_ROWVERSION","NEWID","NEWSEQUENTIALID","ROWCOUNT_BIG","XACT_STATE","TEXTPTR","TEXTVALID","COLUMNS_UPDATED","EVENTDATA","TRIGGER_NESTLEVEL","UPDATE","CHANGETABLE","CHANGE_TRACKING_CONTEXT","CHANGE_TRACKING_CURRENT_VERSION","CHANGE_TRACKING_IS_COLUMN_IN_MASK","CHANGE_TRACKING_MIN_VALID_VERSION","CONTAINSTABLE","FREETEXTTABLE","SEMANTICKEYPHRASETABLE","SEMANTICSIMILARITYDETAILSTABLE","SEMANTICSIMILARITYTABLE","FILETABLEROOTPATH","GETFILENAMESPACEPATH","GETPATHLOCATOR","PATHNAME","GET_TRANSMISSION_STATUS"],builtinVariables:["@@DATEFIRST","@@DBTS","@@LANGID","@@LANGUAGE","@@LOCK_TIMEOUT","@@MAX_CONNECTIONS","@@MAX_PRECISION","@@NESTLEVEL","@@OPTIONS","@@REMSERVER","@@SERVERNAME","@@SERVICENAME","@@SPID","@@TEXTSIZE","@@VERSION","@@CURSOR_ROWS","@@FETCH_STATUS","@@DATEFIRST","@@PROCID","@@ERROR","@@IDENTITY","@@ROWCOUNT","@@TRANCOUNT","@@CONNECTIONS","@@CPU_BUSY","@@IDLE","@@IO_BUSY","@@PACKET_ERRORS","@@PACK_RECEIVED","@@PACK_SENT","@@TIMETICKS","@@TOTAL_ERRORS","@@TOTAL_READ","@@TOTAL_WRITE"],pseudoColumns:["$ACTION","$IDENTITY","$ROWGUID","$PARTITION"],tokenizer:{root:[{include:"@comments"},{include:"@whitespace"},{include:"@pseudoColumns"},{include:"@numbers"},{include:"@strings"},{include:"@complexIdentifiers"},{include:"@scopes"},[/[;,.]/,"delimiter"],[/[()]/,"@brackets"],[/[\w@#$]+/,{cases:{"@keywords":"keyword","@operators":"operator","@builtinVariables":"predefined","@builtinFunctions":"predefined","@default":"identifier"}}],[/[<>=!%&+\-*/|~^]/,"operator"]],whitespace:[[/\s+/,"white"]],comments:[[/--+.*/,"comment"],[/\/\*/,{token:"comment.quote",next:"@comment"}]],comment:[[/[^*/]+/,"comment"],[/\*\//,{token:"comment.quote",next:"@pop"}],[/./,"comment"]],pseudoColumns:[[/[$][A-Za-z_][\w@#$]*/,{cases:{"@pseudoColumns":"predefined","@default":"identifier"}}]],numbers:[[/0[xX][0-9a-fA-F]*/,"number"],[/[$][+-]*\d*(\.\d*)?/,"number"],[/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/,"number"]],strings:[[/N'/,{token:"string",next:"@string"}],[/'/,{token:"string",next:"@string"}]],string:[[/[^']+/,"string"],[/''/,"string"],[/'/,{token:"string",next:"@pop"}]],complexIdentifiers:[[/\[/,{token:"identifier.quote",next:"@bracketedIdentifier"}],[/"/,{token:"identifier.quote",next:"@quotedIdentifier"}]],bracketedIdentifier:[[/[^\]]+/,"identifier"],[/]]/,"identifier"],[/]/,{token:"identifier.quote",next:"@pop"}]],quotedIdentifier:[[/[^"]+/,"identifier"],[/""/,"identifier"],[/"/,{token:"identifier.quote",next:"@pop"}]],scopes:[[/BEGIN\s+(DISTRIBUTED\s+)?TRAN(SACTION)?\b/i,"keyword"],[/BEGIN\s+TRY\b/i,{token:"keyword.try"}],[/END\s+TRY\b/i,{token:"keyword.try"}],[/BEGIN\s+CATCH\b/i,{token:"keyword.catch"}],[/END\s+CATCH\b/i,{token:"keyword.catch"}],[/(BEGIN|CASE)\b/i,{token:"keyword.block"}],[/END\b/i,{token:"keyword.block"}],[/WHEN\b/i,{token:"keyword.choice"}],[/THEN\b/i,{token:"keyword.choice"}]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/st/st.js b/public/react/public/js/monaco/vs/basic-languages/st/st.js new file mode 100755 index 000000000..d3582138e --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/st/st.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/st/st",["require","exports"],function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.conf={comments:{lineComment:"//",blockComment:["(*","*)"]},brackets:[["{","}"],["[","]"],["(",")"],["var","end_var"],["var_input","end_var"],["var_output","end_var"],["var_in_out","end_var"],["var_temp","end_var"],["var_global","end_var"],["var_access","end_var"],["var_external","end_var"],["type","end_type"],["struct","end_struct"],["program","end_program"],["function","end_function"],["function_block","end_function_block"],["action","end_action"],["step","end_step"],["initial_step","end_step"],["transaction","end_transaction"],["configuration","end_configuration"],["tcp","end_tcp"],["recource","end_recource"],["channel","end_channel"],["library","end_library"],["folder","end_folder"],["binaries","end_binaries"],["includes","end_includes"],["sources","end_sources"]],autoClosingPairs:[{open:"[",close:"]"},{open:"{",close:"}"},{open:"(",close:")"},{open:"/*",close:"*/"},{open:"'",close:"'",notIn:["string_sq"]},{open:'"',close:'"',notIn:["string_dq"]},{open:"var",close:"end_var"},{open:"var_input",close:"end_var"},{open:"var_output",close:"end_var"},{open:"var_in_out",close:"end_var"},{open:"var_temp",close:"end_var"},{open:"var_global",close:"end_var"},{open:"var_access",close:"end_var"},{open:"var_external",close:"end_var"},{open:"type",close:"end_type"},{open:"struct",close:"end_struct"},{open:"program",close:"end_program"},{open:"function",close:"end_function"},{open:"function_block",close:"end_function_block"},{open:"action",close:"end_action"},{open:"step",close:"end_step"},{open:"initial_step",close:"end_step"},{open:"transaction",close:"end_transaction"},{open:"configuration",close:"end_configuration"},{open:"tcp",close:"end_tcp"},{open:"recource",close:"end_recource"},{open:"channel",close:"end_channel"},{open:"library",close:"end_library"},{open:"folder",close:"end_folder"},{open:"binaries",close:"end_binaries"},{open:"includes",close:"end_includes"},{open:"sources",close:"end_sources"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"var",close:"end_var"},{open:"var_input",close:"end_var"},{open:"var_output",close:"end_var"},{open:"var_in_out",close:"end_var"},{open:"var_temp",close:"end_var"},{open:"var_global",close:"end_var"},{open:"var_access",close:"end_var"},{open:"var_external",close:"end_var"},{open:"type",close:"end_type"},{open:"struct",close:"end_struct"},{open:"program",close:"end_program"},{open:"function",close:"end_function"},{open:"function_block",close:"end_function_block"},{open:"action",close:"end_action"},{open:"step",close:"end_step"},{open:"initial_step",close:"end_step"},{open:"transaction",close:"end_transaction"},{open:"configuration",close:"end_configuration"},{open:"tcp",close:"end_tcp"},{open:"recource",close:"end_recource"},{open:"channel",close:"end_channel"},{open:"library",close:"end_library"},{open:"folder",close:"end_folder"},{open:"binaries",close:"end_binaries"},{open:"includes",close:"end_includes"},{open:"sources",close:"end_sources"}],folding:{markers:{start:new RegExp("^\\s*#pragma\\s+region\\b"),end:new RegExp("^\\s*#pragma\\s+endregion\\b")}}},n.language={defaultToken:"",tokenPostfix:".st",ignoreCase:!0,brackets:[{token:"delimiter.curly",open:"{",close:"}"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"delimiter.square",open:"[",close:"]"}],keywords:["if","end_if","elsif","else","case","of","to","do","with","by","while","repeat","end_while","end_repeat","end_case","for","end_for","task","retain","non_retain","constant","with","at","exit","return","interval","priority","address","port","on_channel","then","iec","file","uses","version","packagetype","displayname","copyright","summary","vendor","common_source","from"],constant:["false","true","null"],defineKeywords:["var","var_input","var_output","var_in_out","var_temp","var_global","var_access","var_external","end_var","type","end_type","struct","end_struct","program","end_program","function","end_function","function_block","end_function_block","configuration","end_configuration","tcp","end_tcp","recource","end_recource","channel","end_channel","library","end_library","folder","end_folder","binaries","end_binaries","includes","end_includes","sources","end_sources","action","end_action","step","initial_step","end_step","transaction","end_transaction"],typeKeywords:["int","sint","dint","lint","usint","uint","udint","ulint","real","lreal","time","date","time_of_day","date_and_time","string","bool","byte","world","dworld","array","pointer","lworld"],operators:["=",">","<",":",":=","<=",">=","<>","&","+","-","*","**","MOD","^","or","and","not","xor","abs","acos","asin","atan","cos","exp","expt","ln","log","sin","sqrt","tan","sel","max","min","limit","mux","shl","shr","rol","ror","indexof","sizeof","adr","adrinst","bitadr","is_valid"],builtinVariables:[],builtinFunctions:["sr","rs","tp","ton","tof","eq","ge","le","lt","ne","round","trunc","ctd","сtu","ctud","r_trig","f_trig","move","concat","delete","find","insert","left","len","replace","right","rtc"],symbols:/[=>`?!+*\\\/]/,operatorstart:/[\/=\-+!*%<>&|^~?\u00A1-\u00A7\u00A9\u00AB\u00AC\u00AE\u00B0-\u00B1\u00B6\u00BB\u00BF\u00D7\u00F7\u2016-\u2017\u2020-\u2027\u2030-\u203E\u2041-\u2053\u2055-\u205E\u2190-\u23FF\u2500-\u2775\u2794-\u2BFF\u2E00-\u2E7F\u3001-\u3003\u3008-\u3030]/,operatorend:/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE00-\uFE0F\uFE20-\uFE2F\uE0100-\uE01EF]/,operators:/(@operatorstart)((@operatorstart)|(@operatorend))*/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[{include:"@comment"},{include:"@attribute"},{include:"@literal"},{include:"@keyword"},{include:"@invokedmethod"},{include:"@symbol"}],symbol:[[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/[.]/,"delimiter"],[/@operators/,"operator"],[/@symbols/,"operator"]],comment:[[/\/\/\/.*$/,"comment.doc"],[/\/\*\*/,"comment.doc","@commentdocbody"],[/\/\/.*$/,"comment"],[/\/\*/,"comment","@commentbody"]],commentdocbody:[[/\/\*/,"comment","@commentbody"],[/\*\//,"comment.doc","@pop"],[/\:[a-zA-Z]+\:/,"comment.doc.param"],[/./,"comment.doc"]],commentbody:[[/\/\*/,"comment","@commentbody"],[/\*\//,"comment","@pop"],[/./,"comment"]],attribute:[[/\@@identifier/,{cases:{"@attributes":"keyword.control","@default":""}}]],literal:[[/"/,{token:"string.quote",next:"@stringlit"}],[/0[b]([01]_?)+/,"number.binary"],[/0[o]([0-7]_?)+/,"number.octal"],[/0[x]([0-9a-fA-F]_?)+([pP][\-+](\d_?)+)?/,"number.hex"],[/(\d_?)*\.(\d_?)+([eE][\-+]?(\d_?)+)?/,"number.float"],[/(\d_?)+/,"number"]],stringlit:[[/\\\(/,{token:"operator",next:"@interpolatedexpression"}],[/@escapes/,"string"],[/\\./,"string.escape.invalid"],[/"/,{token:"string.quote",next:"@pop"}],[/./,"string"]],interpolatedexpression:[[/\(/,{token:"operator",next:"@interpolatedexpression"}],[/\)/,{token:"operator",next:"@pop"}],{include:"@literal"},{include:"@keyword"},{include:"@symbol"}],keyword:[[/`/,{token:"operator",next:"@escapedkeyword"}],[/@identifier/,{cases:{"@keywords":"keyword","[A-Z][a-zA-Z0-9$]*":"type.identifier","@default":"identifier"}}]],escapedkeyword:[[/`/,{token:"operator",next:"@pop"}],[/./,"identifier"]],invokedmethod:[[/([.])(@identifier)/,{cases:{$2:["delimeter","type.identifier"],"@default":""}}]]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/typescript/typescript.js b/public/react/public/js/monaco/vs/basic-languages/typescript/typescript.js new file mode 100755 index 000000000..24650ea2e --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/typescript/typescript.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/typescript/typescript",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n="undefined"==typeof monaco?self.monaco:monaco;t.conf={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],onEnterRules:[{beforeText:/^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,afterText:/^\s*\*\/$/,action:{indentAction:n.languages.IndentAction.IndentOutdent,appendText:" * "}},{beforeText:/^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,action:{indentAction:n.languages.IndentAction.None,appendText:" * "}},{beforeText:/^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,action:{indentAction:n.languages.IndentAction.None,appendText:"* "}},{beforeText:/^(\t|(\ \ ))*\ \*\/\s*$/,action:{indentAction:n.languages.IndentAction.None,removeText:1}}],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"',notIn:["string"]},{open:"'",close:"'",notIn:["string","comment"]},{open:"`",close:"`",notIn:["string","comment"]},{open:"/**",close:" */",notIn:["string"]}],folding:{markers:{start:new RegExp("^\\s*//\\s*#?region\\b"),end:new RegExp("^\\s*//\\s*#?endregion\\b")}}},t.language={defaultToken:"invalid",tokenPostfix:".ts",keywords:["abstract","as","break","case","catch","class","continue","const","constructor","debugger","declare","default","delete","do","else","enum","export","extends","false","finally","for","from","function","get","if","implements","import","in","infer","instanceof","interface","is","keyof","let","module","namespace","never","new","null","package","private","protected","public","readonly","require","global","return","set","static","super","switch","symbol","this","throw","true","try","type","typeof","unique","var","void","while","with","yield","async","await","of"],typeKeywords:["any","boolean","number","object","string","undefined"],operators:["<=",">=","==","!=","===","!==","=>","+","-","**","*","/","%","++","--","<<",">",">>>","&","|","^","!","~","&&","||","?",":","=","+=","-=","*=","**=","/=","%=","<<=",">>=",">>>=","&=","|=","^=","@"],symbols:/[=>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/(@digits)[eE]([\-+]?(@digits))?/,"number.float"],[/(@digits)\.(@digits)([eE][\-+]?(@digits))?/,"number.float"],[/0[xX](@hexdigits)/,"number.hex"],[/0(@octaldigits)/,"number.octal"],[/0[bB](@binarydigits)/,"number.binary"],[/(@digits)/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string_double"],[/'/,"string","@string_single"],[/`/,"string","@string_backtick"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@jsdoc"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],jsdoc:[[/[^\/*]+/,"comment.doc"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],regexp:[[/(\{)(\d+(?:,\d*)?)(\})/,["regexp.escape.control","regexp.escape.control","regexp.escape.control"]],[/(\[)(\^?)(?=(?:[^\]\\\/]|\\.)+)/,["regexp.escape.control",{token:"regexp.escape.control",next:"@regexrange"}]],[/(\()(\?:|\?=|\?!)/,["regexp.escape.control","regexp.escape.control"]],[/[()]/,"regexp.escape.control"],[/@regexpctl/,"regexp.escape.control"],[/[^\\\/]/,"regexp"],[/@regexpesc/,"regexp.escape"],[/\\\./,"regexp.invalid"],["/",{token:"regexp",bracket:"@close"},"@pop"]],regexrange:[[/-/,"regexp.escape.control"],[/\^/,"regexp.invalid"],[/@regexpesc/,"regexp.escape"],[/[^\]]/,"regexp"],[/\]/,"@brackets.regexp.escape.control","@pop"]],string_double:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],string_single:[[/[^\\']+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/'/,"string","@pop"]],string_backtick:[[/\$\{/,{token:"delimiter.bracket",next:"@bracketCounting"}],[/[^\\`$]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/`/,"string","@pop"]],bracketCounting:[[/\{/,"delimiter.bracket","@bracketCounting"],[/\}/,"delimiter.bracket","@pop"],{include:"common"}]}}}); \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/basic-languages/vb/vb.js b/public/react/public/js/monaco/vs/basic-languages/vb/vb.js new file mode 100755 index 000000000..f885c5781 --- /dev/null +++ b/public/react/public/js/monaco/vs/basic-languages/vb/vb.js @@ -0,0 +1,7 @@ +/*!----------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * monaco-languages version: 1.5.1(d085b3bad82f8b59df390ce976adef0c83a9289e) + * Released under the MIT license + * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md + *-----------------------------------------------------------------------------*/ +define("vs/basic-languages/vb/vb",["require","exports"],function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.conf={comments:{lineComment:"'",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"],["<",">"],["addhandler","end addhandler"],["class","end class"],["enum","end enum"],["event","end event"],["function","end function"],["get","end get"],["if","end if"],["interface","end interface"],["module","end module"],["namespace","end namespace"],["operator","end operator"],["property","end property"],["raiseevent","end raiseevent"],["removehandler","end removehandler"],["select","end select"],["set","end set"],["structure","end structure"],["sub","end sub"],["synclock","end synclock"],["try","end try"],["while","end while"],["with","end with"],["using","end using"],["do","loop"],["for","next"]],autoClosingPairs:[{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]},{open:"<",close:">",notIn:["string","comment"]}],folding:{markers:{start:new RegExp("^\\s*#Region\\b"),end:new RegExp("^\\s*#End Region\\b")}}},n.language={defaultToken:"",tokenPostfix:".vb",ignoreCase:!0,brackets:[{token:"delimiter.bracket",open:"{",close:"}"},{token:"delimiter.array",open:"[",close:"]"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"delimiter.angle",open:"<",close:">"},{token:"keyword.tag-addhandler",open:"addhandler",close:"end addhandler"},{token:"keyword.tag-class",open:"class",close:"end class"},{token:"keyword.tag-enum",open:"enum",close:"end enum"},{token:"keyword.tag-event",open:"event",close:"end event"},{token:"keyword.tag-function",open:"function",close:"end function"},{token:"keyword.tag-get",open:"get",close:"end get"},{token:"keyword.tag-if",open:"if",close:"end if"},{token:"keyword.tag-interface",open:"interface",close:"end interface"},{token:"keyword.tag-module",open:"module",close:"end module"},{token:"keyword.tag-namespace",open:"namespace",close:"end namespace"},{token:"keyword.tag-operator",open:"operator",close:"end operator"},{token:"keyword.tag-property",open:"property",close:"end property"},{token:"keyword.tag-raiseevent",open:"raiseevent",close:"end raiseevent"},{token:"keyword.tag-removehandler",open:"removehandler",close:"end removehandler"},{token:"keyword.tag-select",open:"select",close:"end select"},{token:"keyword.tag-set",open:"set",close:"end set"},{token:"keyword.tag-structure",open:"structure",close:"end structure"},{token:"keyword.tag-sub",open:"sub",close:"end sub"},{token:"keyword.tag-synclock",open:"synclock",close:"end synclock"},{token:"keyword.tag-try",open:"try",close:"end try"},{token:"keyword.tag-while",open:"while",close:"end while"},{token:"keyword.tag-with",open:"with",close:"end with"},{token:"keyword.tag-using",open:"using",close:"end using"},{token:"keyword.tag-do",open:"do",close:"loop"},{token:"keyword.tag-for",open:"for",close:"next"}],keywords:["AddHandler","AddressOf","Alias","And","AndAlso","As","Async","Boolean","ByRef","Byte","ByVal","Call","Case","Catch","CBool","CByte","CChar","CDate","CDbl","CDec","Char","CInt","Class","CLng","CObj","Const","Continue","CSByte","CShort","CSng","CStr","CType","CUInt","CULng","CUShort","Date","Decimal","Declare","Default","Delegate","Dim","DirectCast","Do","Double","Each","Else","ElseIf","End","EndIf","Enum","Erase","Error","Event","Exit","False","Finally","For","Friend","Function","Get","GetType","GetXMLNamespace","Global","GoSub","GoTo","Handles","If","Implements","Imports","In","Inherits","Integer","Interface","Is","IsNot","Let","Lib","Like","Long","Loop","Me","Mod","Module","MustInherit","MustOverride","MyBase","MyClass","NameOf","Namespace","Narrowing","New","Next","Not","Nothing","NotInheritable","NotOverridable","Object","Of","On","Operator","Option","Optional","Or","OrElse","Out","Overloads","Overridable","Overrides","ParamArray","Partial","Private","Property","Protected","Public","RaiseEvent","ReadOnly","ReDim","RemoveHandler","Resume","Return","SByte","Select","Set","Shadows","Shared","Short","Single","Static","Step","Stop","String","Structure","Sub","SyncLock","Then","Throw","To","True","Try","TryCast","TypeOf","UInteger","ULong","UShort","Using","Variant","Wend","When","While","Widening","With","WithEvents","WriteOnly","Xor"],tagwords:["If","Sub","Select","Try","Class","Enum","Function","Get","Interface","Module","Namespace","Operator","Set","Structure","Using","While","With","Do","Loop","For","Next","Property","Continue","AddHandler","RemoveHandler","Event","RaiseEvent","SyncLock"],symbols:/[=>"]],autoClosingPairs:[{open:"<",close:">"},{open:"'",close:"'"},{open:'"',close:'"'}],surroundingPairs:[{open:"<",close:">"},{open:"'",close:"'"},{open:'"',close:'"'}]},t.language={defaultToken:"",tokenPostfix:".xml",ignoreCase:!0,qualifiedName:/(?:[\w\.\-]+:)?[\w\.\-]+/,tokenizer:{root:[[/[^<&]+/,""],{include:"@whitespace"},[/(<)(@qualifiedName)/,[{token:"delimiter"},{token:"tag",next:"@tag"}]],[/(<\/)(@qualifiedName)(\s*)(>)/,[{token:"delimiter"},{token:"tag"},"",{token:"delimiter"}]],[/(<\?)(@qualifiedName)/,[{token:"delimiter"},{token:"metatag",next:"@tag"}]],[/(<\!)(@qualifiedName)/,[{token:"delimiter"},{token:"metatag",next:"@tag"}]],[/<\!\[CDATA\[/,{token:"delimiter.cdata",next:"@cdata"}],[/&\w+;/,"string.escape"]],cdata:[[/[^\]]+/,""],[/\]\]>/,{token:"delimiter.cdata",next:"@pop"}],[/\]/,""]],tag:[[/[ \t\r\n]+/,""],[/(@qualifiedName)(\s*=\s*)("[^"]*"|'[^']*')/,["attribute.name","","attribute.value"]],[/(@qualifiedName)(\s*=\s*)("[^">?\/]*|'[^'>?\/]*)(?=[\?\/]\>)/,["attribute.name","","attribute.value"]],[/(@qualifiedName)(\s*=\s*)("[^">]*|'[^'>]*)/,["attribute.name","","attribute.value"]],[/@qualifiedName/,"attribute.name"],[/\?>/,{token:"delimiter",next:"@pop"}],[/(\/)(>)/,[{token:"tag"},{token:"delimiter",next:"@pop"}]],[/>/,{token:"delimiter",next:"@pop"}]],whitespace:[[/[ \t\r\n]+/,""],[//,{token:"comment",next:"@pop"}],[//,m.html=u(m.html,"i").replace("comment",m._comment).replace("tag",m._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),m.paragraph=u(m.paragraph).replace("hr",m.hr).replace("heading",m.heading).replace("lheading",m.lheading).replace("tag",m._tag).getRegex(),m.blockquote=u(m.blockquote).replace("paragraph",m.paragraph).getRegex(),m.normal=h({},m),m.gfm=h({},m.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}), +m.gfm.paragraph=u(m.paragraph).replace("(?!","(?!"+m.gfm.fences.source.replace("\\1","\\2")+"|"+m.list.source.replace("\\1","\\3")+"|").getRegex(),m.tables=h({},m.gfm,{nptable:/^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,table:/^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/}),m.pedantic=h({},m.normal,{html:u("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",m._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/}),t.rules=m,t.lex=function(e,n){return new t(n).lex(e)},t.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)}, +t.prototype.token=function(e,t){e=e.replace(/^ +$/gm,"");for(var n,i,o,r,s,a,l,u,d,c,h,g,v;e;)if((o=this.rules.newline.exec(e))&&(e=e.substring(o[0].length),o[0].length>1&&this.tokens.push({type:"space"})),o=this.rules.code.exec(e))e=e.substring(o[0].length),o=o[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",text:this.options.pedantic?o:f(o,"\n")});else if(o=this.rules.fences.exec(e))e=e.substring(o[0].length),this.tokens.push({type:"code",lang:o[2],text:o[3]||""});else if(o=this.rules.heading.exec(e))e=e.substring(o[0].length),this.tokens.push({type:"heading",depth:o[1].length,text:o[2]});else if(t&&(o=this.rules.nptable.exec(e))&&(a={type:"table",header:p(o[1].replace(/^ *| *\| *$/g,"")),align:o[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:o[3]?o[3].replace(/\n$/,"").split("\n"):[]}).header.length===a.align.length){for(e=e.substring(o[0].length), +u=0;u ?/gm,""),this.token(o,t),this.tokens.push({type:"blockquote_end"});else if(o=this.rules.list.exec(e)){for(e=e.substring(o[0].length),h=(r=o[2]).length>1,this.tokens.push({type:"list_start",ordered:h,start:h?+r:""}),n=!1,c=(o=o[0].match(this.rules.item)).length,u=0;u1&&s.length>1||(e=o.slice(u+1).join("\n")+e,u=c-1)),i=n||/\n\n(?!\s*$)/.test(a),u!==c-1&&(n="\n"===a.charAt(a.length-1),i||(i=n)),v=void 0,(g=/^\[[ xX]\] /.test(a))&&(v=" "!==a[1],a=a.replace(/^\[[ xX]\] +/,"")),this.tokens.push({type:i?"loose_item_start":"list_item_start",task:g,checked:v}),this.token(a,!1),this.tokens.push({type:"list_item_end"});this.tokens.push({type:"list_end"})}else if(o=this.rules.html.exec(e))e=e.substring(o[0].length),this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&("pre"===o[1]||"script"===o[1]||"style"===o[1]),text:o[0]});else if(t&&(o=this.rules.def.exec(e)))e=e.substring(o[0].length),o[3]&&(o[3]=o[3].substring(1,o[3].length-1)),d=o[1].toLowerCase().replace(/\s+/g," "),this.tokens.links[d]||(this.tokens.links[d]={href:o[2],title:o[3]});else if(t&&(o=this.rules.table.exec(e))&&(a={type:"table",header:p(o[1].replace(/^ *| *\| *$/g,"")), +align:o[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:o[3]?o[3].replace(/(?: *\| *)?\n$/,"").split("\n"):[]}).header.length===a.align.length){for(e=e.substring(o[0].length),u=0;u?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:c,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)|^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)/,em:/^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*][\s\S]*?[^\s])\*(?!\*)|^_([^\s_])_(?!_)|^\*([^\s*])\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:c,text:/^[\s\S]+?(?=[\\?@\[\]\\^_`{|}~])/g,v._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/, +v._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,v.autolink=u(v.autolink).replace("scheme",v._scheme).replace("email",v._email).getRegex(),v._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,v.tag=u(v.tag).replace("comment",m._comment).replace("attribute",v._attribute).getRegex(),v._label=/(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/,v._href=/\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?)/,v._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,v.link=u(v.link).replace("label",v._label).replace("href",v._href).replace("title",v._title).getRegex(),v.reflink=u(v.reflink).replace("label",v._label).getRegex(),v.normal=h({},v),v.pedantic=h({},v.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/, +link:u(/^!?\[(label)\]\((.*?)\)/).replace("label",v._label).getRegex(),reflink:u(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",v._label).getRegex()}),v.gfm=h({},v.normal,{escape:u(v.escape).replace("])","~|])").getRegex(),url:u(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("email",v._email).getRegex(),_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:u(v.text).replace("]|","~]|").replace("|","|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&'*+/=?^_`{\\|}~-]+@|").getRegex()}),v.breaks=h({},v.gfm,{br:u(v.br).replace("{2,}","*").getRegex(),text:u(v.gfm.text).replace("{2,}","*").getRegex()}),n.rules=v,n.output=function(e,t,i){return new n(t,i).output(e)},n.prototype.output=function(e){for(var t,i,o,r,s,l="";e;)if(s=this.rules.escape.exec(e))e=e.substring(s[0].length),l+=s[1];else if(s=this.rules.autolink.exec(e))e=e.substring(s[0].length),o="@"===s[2]?"mailto:"+(i=a(this.mangle(s[1]))):i=a(s[1]), +l+=this.renderer.link(o,null,i);else if(this.inLink||!(s=this.rules.url.exec(e))){if(s=this.rules.tag.exec(e))!this.inLink&&/^/i.test(s[0])&&(this.inLink=!1),e=e.substring(s[0].length),l+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(s[0]):a(s[0]):s[0];else if(s=this.rules.link.exec(e))e=e.substring(s[0].length),this.inLink=!0,o=s[2],this.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(o))?(o=t[1],r=t[3]):r="":r=s[3]?s[3].slice(1,-1):"",o=o.trim().replace(/^<([\s\S]*)>$/,"$1"),l+=this.outputLink(s,{href:n.escapes(o),title:n.escapes(r)}),this.inLink=!1;else if((s=this.rules.reflink.exec(e))||(s=this.rules.nolink.exec(e))){if(e=e.substring(s[0].length),t=(s[2]||s[1]).replace(/\s+/g," "),!(t=this.links[t.toLowerCase()])||!t.href){l+=s[0].charAt(0),e=s[0].substring(1)+e;continue}this.inLink=!0,l+=this.outputLink(s,t),this.inLink=!1}else if(s=this.rules.strong.exec(e))e=e.substring(s[0].length), +l+=this.renderer.strong(this.output(s[4]||s[3]||s[2]||s[1]));else if(s=this.rules.em.exec(e))e=e.substring(s[0].length),l+=this.renderer.em(this.output(s[6]||s[5]||s[4]||s[3]||s[2]||s[1]));else if(s=this.rules.code.exec(e))e=e.substring(s[0].length),l+=this.renderer.codespan(a(s[2].trim(),!0));else if(s=this.rules.br.exec(e))e=e.substring(s[0].length),l+=this.renderer.br();else if(s=this.rules.del.exec(e))e=e.substring(s[0].length),l+=this.renderer.del(this.output(s[1]));else if(s=this.rules.text.exec(e))e=e.substring(s[0].length),l+=this.renderer.text(a(this.smartypants(s[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else s[0]=this.rules._backpedal.exec(s[0])[0],e=e.substring(s[0].length),"@"===s[2]?o="mailto:"+(i=a(s[0])):(i=a(s[0]),o="www."===s[1]?"http://"+i:i),l+=this.renderer.link(o,null,i);return l},n.escapes=function(e){return e?e.replace(n.rules._escapes,"$1"):e},n.prototype.outputLink=function(e,t){var n=t.href,i=t.title?a(t.title):null +;return"!"!==e[0].charAt(0)?this.renderer.link(n,i,this.output(e[1])):this.renderer.image(n,i,a(e[1]))},n.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},n.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",i=e.length,o=0;o.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},i.prototype.code=function(e,t,n){if(this.options.highlight){var i=this.options.highlight(e,t);null!=i&&i!==e&&(n=!0,e=i)}return t?'
                                      '+(n?e:a(e,!0))+"
                                      \n":"
                                      "+(n?e:a(e,!0))+"
                                      "},i.prototype.blockquote=function(e){return"
                                      \n"+e+"
                                      \n"},i.prototype.html=function(e){return e},i.prototype.heading=function(e,t,n){ +return this.options.headerIds?"'+e+"\n":""+e+"\n"},i.prototype.hr=function(){return this.options.xhtml?"
                                      \n":"
                                      \n"},i.prototype.list=function(e,t,n){var i=t?"ol":"ul";return"<"+i+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},i.prototype.listitem=function(e){return"
                                    • "+e+"
                                    • \n"},i.prototype.checkbox=function(e){return" "},i.prototype.paragraph=function(e){return"

                                      "+e+"

                                      \n"},i.prototype.table=function(e,t){return t&&(t=""+t+""),"\n\n"+e+"\n"+t+"
                                      \n"},i.prototype.tablerow=function(e){return"\n"+e+"\n"},i.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},i.prototype.strong=function(e){return""+e+""},i.prototype.em=function(e){ +return""+e+""},i.prototype.codespan=function(e){return""+e+""},i.prototype.br=function(){return this.options.xhtml?"
                                      ":"
                                      "},i.prototype.del=function(e){return""+e+""},i.prototype.link=function(e,t,n){if(this.options.sanitize){try{var i=decodeURIComponent(l(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return n}if(0===i.indexOf("javascript:")||0===i.indexOf("vbscript:")||0===i.indexOf("data:"))return n}this.options.baseUrl&&!y.test(e)&&(e=d(this.options.baseUrl,e));try{e=encodeURI(e).replace(/%25/g,"%")}catch(e){return n}var o='
                                      "},i.prototype.image=function(e,t,n){this.options.baseUrl&&!y.test(e)&&(e=d(this.options.baseUrl,e));var i=''+n+'":">"},i.prototype.text=function(e){return e},o.prototype.strong=o.prototype.em=o.prototype.codespan=o.prototype.del=o.prototype.text=function(e){return e}, +o.prototype.link=o.prototype.image=function(e,t,n){return""+n},o.prototype.br=function(){return""},s.parse=function(e,t){return new s(t).parse(e)},s.prototype.parse=function(e){this.inline=new n(e.links,this.options),this.inlineText=new n(e.links,h({},this.options,{renderer:new o})),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},s.prototype.next=function(){return this.token=this.tokens.pop()},s.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},s.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},s.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,l(this.inlineText.output(this.token.text)));case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,i,o="",r="";for(n="", +e=0;e=0,i=d.indexOf("Macintosh")>=0,o=d.indexOf("Linux")>=0,s=!0, +navigator.language}var c;!function(e){e[e.Web=0]="Web",e[e.Mac=1]="Mac",e[e.Linux=2]="Linux",e[e.Windows=3]="Windows"}(c=t.Platform||(t.Platform={}));t.isWindows=n,t.isMacintosh=i,t.isLinux=o,t.isNative=r,t.isWeb=s;var h="object"==typeof self?self:"object"==typeof global?global:{};t.globals=h;var p=null;t.setImmediate=function(e){return null===p&&(p=t.globals.setImmediate?t.globals.setImmediate.bind(t.globals):"undefined"!=typeof process&&"function"==typeof process.nextTick?process.nextTick.bind(process):t.globals.setTimeout.bind(t.globals)),p(e)},t.OS=i?2:n?1:3}),define(t[228],n([1,0,18]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n.globals.performance&&"function"==typeof n.globals.performance.now,o=function(){function e(e){this._highResolution=i&&e,this._startTime=this._now(),this._stopTime=-1}return e.create=function(t){return void 0===t&&(t=!0),new e(t)},e.prototype.elapsed=function(){ +return-1!==this._stopTime?this._stopTime-this._startTime:this._now()-this._startTime},e.prototype._now=function(){return this._highResolution?n.globals.performance.now():(new Date).getTime()},e}();t.StopWatch=o}),define(t[6],n([1,0]),function(e,t){"use strict";function n(e){return e.replace(/[\-\\\{\}\*\+\?\|\^\$\.\[\]\(\)\#]/g,"\\$&")}function i(e,t){if(!e||!t)return e;var n=t.length;if(0===n||0===e.length)return e;for(var i=0;e.indexOf(t,i)===i;)i+=n;return e.substring(i)}function o(e,t){if(!e||!t)return e;var n=t.length,i=e.length;if(0===n||0===i)return e;for(var o=i,r=-1;;){if(-1===(r=e.lastIndexOf(t,o-1))||r+n!==o)break;if(0===r)return"";o=r}return e.substring(0,o)}function r(e,t){return et?1:0}function s(e){return e>=97&&e<=122}function a(e){return e>=65&&e<=90}function l(e){return s(e)||a(e)}function u(e,t,n){if(void 0===n&&(n=e.length),"string"!=typeof e||"string"!=typeof t)return!1;for(var i=0;i=11904&&e<=55215||e>=63744&&e<=64255||e>=65281&&e<=65374}Object.defineProperty(t,"__esModule",{value:!0}),t.empty="",t.isFalsyOrWhitespace=function(e){return!e||"string"!=typeof e||0===e.trim().length},t.pad=function(e,t,n){void 0===n&&(n="0");for(var i=""+e,o=[i],r=i.length;r=t.length?e:t[i]})},t.escape=function(e){return e.replace(/[<|>|&]/g,function(e){switch(e){case"<":return"<";case">":return">";case"&":return"&";default:return e}})},t.escapeRegExpCharacters=n,t.trim=function(e,t){return void 0===t&&(t=" "),o(i(e,t),t)},t.ltrim=i,t.rtrim=o,t.convertSimple2RegExpPattern=function(e){ +return e.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g,"\\$&").replace(/[\*]/g,".*")},t.startsWith=function(e,t){if(e.length0?e.indexOf(t,n)===n:0===n&&e===t},t.createRegExp=function(e,t,i){if(void 0===i&&(i={}),!e)throw new Error("Cannot create regex from empty string");t||(e=n(e)),i.wholeWord&&(/\B/.test(e.charAt(0))||(e="\\b"+e),/\B/.test(e.charAt(e.length-1))||(e+="\\b"));var o="";return i.global&&(o+="g"),i.matchCase||(o+="i"),i.multiline&&(o+="m"),new RegExp(e,o)},t.regExpLeadsToEndlessLoop=function(e){return"^"!==e.source&&"^$"!==e.source&&"$"!==e.source&&"^\\s*$"!==e.source&&e.exec("")&&0===e.lastIndex},t.firstNonWhitespaceIndex=function(e){for(var t=0,n=e.length;t=0;n--){var i=e.charCodeAt(n);if(32!==i&&9!==i)return n}return-1},t.compare=r,t.compareIgnoreCase=function(e,t){for(var n=Math.min(e.length,t.length),i=0;it.length?1:0},t.isLowerAsciiLetter=s,t.isUpperAsciiLetter=a,t.equalsIgnoreCase=function(e,t){return(e?e.length:0)===(t?t.length:0)&&u(e,t)},t.startsWithIgnoreCase=function(e,t){var n=t.length;return!(t.length>e.length)&&u(e,t,n)},t.commonPrefixLength=function(e,t){var n,i=Math.min(e.length,t.length);for(n=0;n0&&65279===e.charCodeAt(0)},t.safeBtoa=function(e){return btoa(encodeURIComponent(e))},t.repeat=function(e,t){for(var n="",i=0;i0&&!h(e.charCodeAt(n-1)))return n}return e.length}function g(e,t,n,i){if(n===e.length)return[];if(i===t.length)return null;if(e[n]!==t[i].toLowerCase())return null;var o=null,r=i+1;for(o=g(e,t,n+1,i+1);!o&&(r=f(t,r))60)return null;var n=function(e){for(var t=0,n=0,i=0,o=0,r=0,s=0;s.2&&t<.8&&i>.6&&o<.2}(n)){if(!function(e){var t=e.upperPercent;return 0===e.lowerPercent&&t>.6}(n))return null;t=t.toLowerCase()}var i=null,o=0;for(e=e.toLowerCase();o=e.length)return!1;switch(e.charCodeAt(t)){case 95:case 45:case 46:case 32:case 47:case 92:case 39:case 34:case 58:return!0;default:return!1}}function C(e,t){if(t<0||t>=e.length)return!1;switch(e.charCodeAt(t)){case 32:case 9:return!0;default:return!1}}function b(e,t,n,i){var o=e.length>100?100:e.length,r=t.length>100?100:t.length,s=0;for(void 0===n&&(n=o);sr)){for(var a=e.toLowerCase(),l=t.toLowerCase(),u=s,d=0;u1?1:c),f=x[u-1][d]+-1,g=x[u][d-1]+-1;g>=f?g>p?(x[u][d]=g,I[u][d]=4):g===p?(x[u][d]=g,I[u][d]=6):(x[u][d]=p,I[u][d]=2):f>p?(x[u][d]=f,I[u][d]=1):f===p?(x[u][d]=f,I[u][d]=3):(x[u][d]=p,I[u][d]=2)}if(M&&(console.log(_(x,e,o,t,r)),console.log(_(I,e,o,t,r)),console.log(_(N,e,o,t,r))),T=0,k=-100,R=s, +O=i,S(o,r,o===r?1:0,new P,!1),0!==T)return[k,D.toArray()]}}}function S(e,t,n,i,o){if(!(T>=10||n<-25)){for(var r=0;e>R&&t>0;){var s=N[e][t],a=I[e][t];if(4===a)t-=1,o?n-=5:i.isEmpty()||(n-=1),o=!1,r=0;else{if(!(2&a))return;if(4&a&&S(e,t-1,i.isEmpty()?n:n-1,i.slice(),o),n+=s,e-=1,t-=1,i.unshift(t),o=!0,1===s){if(r+=1,e===R&&!O)return}else n+=1+r*(s-1),r=0}}T+=1,(n-=t>=3?9:3*t)>k&&(k=n,D=i)}}function w(e,t,n){return function(e,t,n,i){var o=b(e,t,i);if(o&&!n)return o;if(e.length>=3)for(var r=Math.min(7,e.length-1),s=1;s=e.length)return;var n=e[t],i=e[t+1];if(n===i)return;return e.slice(0,t)+i+n+e.slice(t+2)}(e,s);if(a){var l=b(a,t,i);l&&(l[0]-=3,(!o||l[0]>o[0])&&(o=l))}}return o}(e,t,!0,n)}Object.defineProperty(t,"__esModule",{value:!0}),t.or=o,t.matchesPrefix=function(e,t,i){return!i||i.length0?[{start:0,end:t.length}]:[]:null}.bind(void 0,!0),t.matchesContiguousSubString=r,t.matchesSubString=s,t.isUpper=u, +t.matchesCamelCase=m,t.fuzzyContiguousFilter=o(t.matchesPrefix,m,r);var E=o(t.matchesPrefix,m,s),L=new i.LRUCache(1e4);t.matchesFuzzy=function(e,i,o){if(void 0===o&&(o=!1),"string"!=typeof e||"string"!=typeof i)return null;var r=L.get(e);r||(r=new RegExp(n.convertSimple2RegExpPattern(e),"i"),L.set(e,r));var s=r.exec(i);return s?[{start:s.index,end:s.index+s[0].length}]:o?E(e,i):t.fuzzyContiguousFilter(e,i)},t.anyScore=function(e,t,n){e=e.toLowerCase(),t=t.toLowerCase();for(var i=[],o=0,r=0;r=0&&(i.push(s),o=s+1)}return[i.length,i]},t.createMatches=function(e){var t=[];if(!e)return t;for(var n,i=0,o=e;i0)&&".."!==m&&(p=-1===g?"":p.slice(0,g),d=!0)}else a(e,u,f,".")&&(s||p||f=65&&i<=90||i>=97&&i<=122)&&58===e.charCodeAt(1))return 47===(i=e.charCodeAt(2))||92===i?e.slice(0,2)+t:e.slice(0,2);var s=e.indexOf("://") +;if(-1!==s)for(s+=3;s=65&&t<=90||t>=97&&t<=122)&&e.length>2&&58===e.charCodeAt(1)){var n=e.charCodeAt(2);if(47===n||92===n)return!0}return!1}function d(e){return e&&47===e.charCodeAt(0)}Object.defineProperty(t,"__esModule",{value:!0}),t.sep="/",t.nativeSep=n.isWindows?"\\":"/",t.dirname=o,t.basename=r,t.extname=function(e){var t=~(e=r(e)).lastIndexOf(".");return t?e.substring(~t):""};var c=/(\/\.\.?\/)|(\/\.\.?)$|^(\.\.?\/)|(\/\/+)|(\\)/,h=/(\\\.\.?\\)|(\\\.\.?)$|^(\.\.?\\)|(\\\\+)|(\/)/;t.normalize=s,t.getRoot=l,t.join=function(){for(var e="",n=0;n0){var o=e.charCodeAt(e.length-1);if(47!==o&&92!==o){var r=i.charCodeAt(0);47!==r&&92!==r&&(e+=t.sep)}}e+=i}return s(e)},t.isEqualOrParent=function(e,n,o,r){if(void 0===r&&(r=t.nativeSep),e===n)return!0;if(!e||!n)return!1;if(n.length>e.length)return!1;if(o){ +if(!i.startsWithIgnoreCase(e,n))return!1;if(n.length===e.length)return!0;var s=n.length;return n.charAt(n.length-1)===r&&s--,e.charAt(s)===r}return n.charAt(n.length-1)!==r&&(n+=r),0===e.indexOf(n)},t.isAbsolute=function(e){return n.isWindows?u(e):d(e)},t.isAbsolute_win32=u,t.isAbsolute_posix=d}),define(t[161],n([1,0,50,6]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.basenameOrAuthority=function(e){return n.basename(e.path)||e.authority},t.isEqual=function(e,t,n){return!(e!==t)||!(!e||!t)&&(n?i.equalsIgnoreCase(e.toString(),t.toString()):e.toString()===t.toString())},t.dirname=function(e){var t=n.dirname(e.path);return e.authority&&t&&!n.isAbsolute(t)?null:e.with({path:t})}}),define(t[33],n([1,0]),function(e,t){"use strict";function n(e){return typeof e===l.string||e instanceof String}function i(e){return!(typeof e!==l.object||null===e||Array.isArray(e)||e instanceof RegExp||e instanceof Date)}function o(e){return typeof e===l.undefined}function r(e){return o(e)||null===e +}function s(e){return typeof e===l.function}function a(e,t){if(n(t)){if(typeof e!==t)throw new Error("argument does not match constraint: typeof "+t)}else if(s(t)){if(e instanceof t)return;if(!r(e)&&e.constructor===t)return;if(1===t.length&&!0===t.call(void 0,e))return;throw new Error("argument does not match one of these constraints: arg instanceof constraint, arg.constructor === constraint, nor constraint(arg) === true")}}Object.defineProperty(t,"__esModule",{value:!0});var l={number:"number",string:"string",undefined:"undefined",object:"object",function:"function"};t.isArray=function(e){return Array.isArray?Array.isArray(e):!(!e||typeof e.length!==l.number||e.constructor!==Array)},t.isString=n,t.isObject=i,t.isNumber=function(e){return(typeof e===l.number||e instanceof Number)&&!isNaN(e)},t.isBoolean=function(e){return!0===e||!1===e},t.isUndefined=o,t.isUndefinedOrNull=r;var u=Object.prototype.hasOwnProperty;t.isEmptyObject=function(e){if(!i(e))return!1;for(var t in e)if(u.call(e,t))return!1;return!0}, +t.isFunction=s,t.validateConstraints=function(e,t){for(var n=Math.min(e.length,t.length),i=0;i0;){var n=t.shift();Object.freeze(n);for(var i in n)if(a.call(n,i)){var o=n[i];"object"!=typeof o||Object.isFrozen(o)||t.push(o)}}return e};var a=Object.prototype.hasOwnProperty;t.mixin=o,t.assign=function(e){for(var t=[],n=1;n=97&&r<=122||r>=65&&r<=90||r>=48&&r<=57||45===r||46===r||95===r||126===r||t&&47===r)-1!==i&&(n+=encodeURIComponent(e.substring(i,o)),i=-1),void 0!==n&&(n+=e.charAt(o));else{void 0===n&&(n=e.substr(0,o));var s=m[r];void 0!==s?(-1!==i&&(n+=encodeURIComponent(e.substring(i,o)),i=-1),n+=s):-1===i&&(i=o)}}return-1!==i&&(n+=encodeURIComponent(e.substring(i))),void 0!==n?n:e}function r(e){var t +;return t=e.authority&&e.path.length>1&&"file"===e.scheme?"//"+e.authority+e.path:47===e.path.charCodeAt(0)&&(e.path.charCodeAt(1)>=65&&e.path.charCodeAt(1)<=90||e.path.charCodeAt(1)>=97&&e.path.charCodeAt(1)<=122)&&58===e.path.charCodeAt(2)?e.path[1].toLowerCase()+e.path.substr(2):e.path,n.isWindows&&(t=t.replace(/\//g,"\\")),t}function s(e,t){var n=t?function(e){for(var t=void 0,n=0;n=3&&47===a.charCodeAt(0)&&58===a.charCodeAt(2)){ +(p=a.charCodeAt(1))>=65&&p<=90&&(a="/"+String.fromCharCode(p+32)+":"+a.substr(3))}else if(a.length>=2&&58===a.charCodeAt(1)){var p=a.charCodeAt(0);p>=65&&p<=90&&(a=String.fromCharCode(p+32)+":"+a.substr(2))}o+=n(a,!0)}return l&&(o+="?",o+=n(l,!1)),u&&(o+="#",o+=t?u:i(u,!1)),o}Object.defineProperty(t,"__esModule",{value:!0});var a,l=/^\w[\w\d+.-]*$/,u=/^\//,d=/^\/\//,c="",h="/",p=/^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/,f=function(){function e(e,t,n,i,o){"object"==typeof e?(this.scheme=e.scheme||c,this.authority=e.authority||c,this.path=e.path||c,this.query=e.query||c,this.fragment=e.fragment||c):(this.scheme=e||c,this.authority=t||c,this.path=function(e,t){switch(e){case"https":case"http":case"file":t?t[0]!==h&&(t=h+t):t=h}return t}(this.scheme,n||c),this.query=i||c,this.fragment=o||c,function(e){if(e.scheme&&!l.test(e.scheme))throw new Error("[UriError]: Scheme contains illegal characters.");if(e.path)if(e.authority){ +if(!u.test(e.path))throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character')}else if(d.test(e.path))throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")')}(this))}return e.isUri=function(t){return t instanceof e||!!t&&("string"==typeof t.authority&&"string"==typeof t.fragment&&"string"==typeof t.path&&"string"==typeof t.query&&"string"==typeof t.scheme)},Object.defineProperty(e.prototype,"fsPath",{get:function(){return r(this)},enumerable:!0,configurable:!0}),e.prototype.with=function(e){if(!e)return this;var t=e.scheme,n=e.authority,i=e.path,o=e.query,r=e.fragment;return void 0===t?t=this.scheme:null===t&&(t=c),void 0===n?n=this.authority:null===n&&(n=c),void 0===i?i=this.path:null===i&&(i=c),void 0===o?o=this.query:null===o&&(o=c),void 0===r?r=this.fragment:null===r&&(r=c), +t===this.scheme&&n===this.authority&&i===this.path&&o===this.query&&r===this.fragment?this:new g(t,n,i,o,r)},e.parse=function(e){var t=p.exec(e);return t?new g(t[2]||c,decodeURIComponent(t[4]||c),decodeURIComponent(t[5]||c),decodeURIComponent(t[7]||c),decodeURIComponent(t[9]||c)):new g(c,c,c,c,c)},e.file=function(e){var t=c;if(n.isWindows&&(e=e.replace(/\\/g,h)),e[0]===h&&e[1]===h){var i=e.indexOf(h,2);-1===i?(t=e.substring(2),e=h):(t=e.substring(2,i),e=e.substring(i)||h)}return new g("file",t,e,c,c)},e.from=function(e){return new g(e.scheme,e.authority,e.path,e.query,e.fragment)},e.prototype.toString=function(e){return void 0===e&&(e=!1),s(this,e)},e.prototype.toJSON=function(){return this},e.revive=function(t){if(t){if(t instanceof e)return t;var n=new g(t);return n._fsPath=t.fsPath,n._formatted=t.external,n}return t},e}();t.default=f;var g=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t._formatted=null,t._fsPath=null,t}return o(t,e), +Object.defineProperty(t.prototype,"fsPath",{get:function(){return this._fsPath||(this._fsPath=r(this)),this._fsPath},enumerable:!0,configurable:!0}),t.prototype.toString=function(e){return void 0===e&&(e=!1),e?s(this,!0):(this._formatted||(this._formatted=s(this,!1)),this._formatted)},t.prototype.toJSON=function(){var e={$mid:1};return this._fsPath&&(e.fsPath=this._fsPath),this._formatted&&(e.external=this._formatted),this.path&&(e.path=this.path),this.scheme&&(e.scheme=this.scheme),this.authority&&(e.authority=this.authority),this.query&&(e.query=this.query),this.fragment&&(e.fragment=this.fragment),e},t}(f),m=(a={},a[58]="%3A",a[47]="%2F",a[63]="%3F",a[35]="%23",a[91]="%5B",a[93]="%5D",a[64]="%40",a[33]="%21",a[36]="%24",a[38]="%26",a[39]="%27",a[40]="%28",a[41]="%29",a[42]="%2A",a[43]="%2B",a[44]="%2C",a[59]="%3B",a[61]="%3D",a[32]="%20",a)}),define(t[201],n([1,0,31,50,6,61,18,161]),function(e,t,n,i,o,r,s,a){"use strict";function l(e){return s.isWindows&&e&&":"===e[1]}function u(e){ +return l(e)?e.charAt(0).toUpperCase()+e.slice(1):e}function d(e,t){if(s.isWindows||!e||!t)return e;var n=c.original===t?c.normalized:void 0;return n||(n=""+o.rtrim(t,i.sep)+i.sep,c={original:t,normalized:n}),(s.isLinux?o.startsWith(e,n):o.startsWithIgnoreCase(e,n))&&(e="~/"+e.substr(n.length)),e}Object.defineProperty(t,"__esModule",{value:!0}),t.getPathLabel=function(e,t,c){if(!e)return null;"string"==typeof e&&(e=n.default.file(e));var h=c?c.getWorkspaceFolder(e):null;if(h){var p=c.getWorkspace().folders.length>1,f=void 0;if(f=a.isEqual(h.uri,e,!s.isLinux)?"":i.normalize(o.ltrim(e.path.substr(h.uri.path.length),i.sep),!0),p){var g=h&&h.name?h.name:i.basename(h.uri.fsPath);f=f?g+" • "+f:g}return f}if(e.scheme!==r.Schemas.file&&e.scheme!==r.Schemas.untitled)return e.with({query:null,fragment:null}).toString(!0);if(l(e.fsPath))return i.normalize(u(e.fsPath),!0);var m=i.normalize(e.fsPath,!0);return!s.isWindows&&t&&(m=d(m,t.userHome)),m},t.getBaseLabel=function(e){if(!e)return null +;"string"==typeof e&&(e=n.default.file(e));var t=i.basename(e.path)||(e.scheme===r.Schemas.file?e.fsPath:e.path);return l(t)?u(t):t},t.normalizeDriveLetter=u;var c=Object.create(null);t.tildify=d}),define(t[480],n([1,0,31]),function(e,t,n){"use strict";function i(e,t){if(!e||t>200)return e;if("object"==typeof e){switch(e.$mid){case 1:return n.default.revive(e);case 2:return new RegExp(e.source,e.flags)}for(var o in e)Object.hasOwnProperty.call(e,o)&&(e[o]=i(e[o],t+1))}return e}Object.defineProperty(t,"__esModule",{value:!0}),t.parse=function(e){var t=JSON.parse(e);return t=i(t,0)},t.revive=i});var s;!function(){var e=Object.create(null);e["WinJS/Core/_WinJS"]={};var t=function(t,n,i){var o={},r=!1,s=n.map(function(t){return"exports"===t?(r=!0,o):e[t]}),a=i.apply({},s);e[t]=r?o:a};t("WinJS/Core/_Global",[],function(){"use strict";return"undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{}}),t("WinJS/Core/_BaseCoreUtils",["WinJS/Core/_Global"],function(e){ +"use strict";var t=null;return{hasWinRT:!!e.Windows,markSupportedForProcessing:function(e){return e.supportedForProcessing=!0,e},_setImmediate:function(n){null===t&&(t=e.setImmediate?e.setImmediate.bind(e):"undefined"!=typeof process&&"function"==typeof process.nextTick?process.nextTick.bind(process):e.setTimeout.bind(e)),t(n)}}}),t("WinJS/Core/_WriteProfilerMark",["WinJS/Core/_Global"],function(e){"use strict";return e.msWriteProfilerMark||function(){}}),t("WinJS/Core/_Base",["WinJS/Core/_WinJS","WinJS/Core/_Global","WinJS/Core/_BaseCoreUtils","WinJS/Core/_WriteProfilerMark"],function(e,t,n,i){"use strict";function o(e,t,n){var i,o,r,s=Object.keys(t),a=Array.isArray(e);for(o=0,r=s.length;o"),r}var s=e;s.Namespace||(s.Namespace=Object.create(Object.prototype));var a={uninitialized:1,working:2,initialized:3};Object.defineProperties(s.Namespace,{defineWithParent:{value:r,writable:!0,enumerable:!0,configurable:!0},define:{value:function(e,n){return r(t,e,n)},writable:!0,enumerable:!0,configurable:!0},_lazy:{value:function(e){var t,n,o=a.uninitialized;return{setName:function(e){t=e},get:function(){switch(o){case a.initialized:return n;case a.uninitialized:o=a.working;try{i("WinJS.Namespace._lazy:"+t+",StartTM"),n=e() +}finally{i("WinJS.Namespace._lazy:"+t+",StopTM"),o=a.uninitialized}return e=null,o=a.initialized,n;case a.working:throw"Illegal: reentrancy on initialization";default:throw"Illegal"}},set:function(e){switch(o){case a.working:throw"Illegal: reentrancy on initialization";default:o=a.initialized,n=e}},enumerable:!0,configurable:!0}},writable:!0,enumerable:!0,configurable:!0},_moduleDefine:{value:function(e,i,r){var s=[e],a=null;return i&&(a=n(t,i),s.push(a)),o(s,r,i||""),a},writable:!0,enumerable:!0,configurable:!0}})}(),function(){function t(e,t,i){return e=e||function(){},n.markSupportedForProcessing(e),t&&o(e.prototype,t),i&&o(e,i),e}e.Namespace.define("WinJS.Class",{define:t,derive:function(e,i,r,s){if(e){i=i||function(){};var a=e.prototype;return i.prototype=Object.create(a),n.markSupportedForProcessing(i),Object.defineProperty(i.prototype,"constructor",{value:i,writable:!0,configurable:!0,enumerable:!0}),r&&o(i.prototype,r),s&&o(i,s),i}return t(i,r,s)},mix:function(e){e=e||function(){};var t,n +;for(t=1,n=arguments.length;t0;){var o=this._deliveryQueue.shift(),r=o[0],s=o[1];try{"function"==typeof r?r.call(void 0,s):r[0].call(r[1],s)}catch(i){n.onUnexpectedError(i)}}}},e.prototype.dispose=function(){this._listeners&&(this._listeners=void 0),this._deliveryQueue&&(this._deliveryQueue.length=0),this._disposed=!0},e._noop=function(){},e}();t.Emitter=l;var u=function(){function e(){var e=this;this.hasListeners=!1,this.events=[],this.emitter=new l({onFirstListenerAdd:function(){return e.onFirstListenerAdd()},onLastListenerRemove:function(){return e.onLastListenerRemove()}})}return Object.defineProperty(e.prototype,"event",{get:function(){return this.emitter.event},enumerable:!0,configurable:!0}),e.prototype.add=function(e){ +var t=this,n={event:e,listener:null};this.events.push(n),this.hasListeners&&this.hook(n);return o.toDisposable(i.once(function(){t.hasListeners&&t.unhook(n);var e=t.events.indexOf(n);t.events.splice(e,1)}))},e.prototype.onFirstListenerAdd=function(){var e=this;this.hasListeners=!0,this.events.forEach(function(t){return e.hook(t)})},e.prototype.onLastListenerRemove=function(){var e=this;this.hasListeners=!1,this.events.forEach(function(t){return e.unhook(t)})},e.prototype.hook=function(e){var t=this;e.listener=e.event(function(e){return t.emitter.fire(e)})},e.prototype.unhook=function(e){e.listener.dispose(),e.listener=null},e.prototype.dispose=function(){this.emitter.dispose()},e}();t.EventMultiplexer=u,t.once=function(e){return function(t,n,i){void 0===n&&(n=null);var o=e(function(e){return o.dispose(),t.call(n,e)},null,i);return o}},t.anyEvent=function(){for(var e=[],t=0;t1)&&u.fire(e),a=0},n)})},onLastListenerRemove:function(){o.dispose()}});return u.event};var d=function(){function e(){this.buffers=[]}return e.prototype.wrapEvent=function(e){var t=this;return function(n,i,o){return e(function(e){var o=t.buffers[t.buffers.length-1];o?o.push(function(){return n.call(i,e)}):n.call(i,e)},void 0,o)}},e.prototype.bufferEvents=function(e){var t=[];this.buffers.push(t),e(),this.buffers.pop(),t.forEach(function(e){return e()})},e}();t.EventBufferer=d,t.mapEvent=s,t.filterEvent=a;var c=function(){function e(e){this._event=e}return Object.defineProperty(e.prototype,"event",{get:function(){return this._event},enumerable:!0,configurable:!0}),e.prototype.map=function(t){ +return new e(s(this._event,t))},e.prototype.filter=function(t){return new e(a(this._event,t))},e.prototype.on=function(e,t,n){return this._event(e,t,n)},e}();t.chain=function(e){return new c(e)};var h=function(){function e(){this.emitter=new l,this.event=this.emitter.event,this.disposable=o.Disposable.None}return Object.defineProperty(e.prototype,"input",{set:function(e){this.disposable.dispose(),this.disposable=e(this.emitter.fire,this.emitter)},enumerable:!0,configurable:!0}),e.prototype.dispose=function(){this.disposable.dispose(),this.emitter.dispose()},e}();t.Relay=h}),define(t[30],n([1,0,9]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(){this._zoomLevel=0,this._lastZoomLevelChangeTime=0,this._onDidChangeZoomLevel=new n.Emitter,this.onDidChangeZoomLevel=this._onDidChangeZoomLevel.event,this._accessibilitySupport=0,this._onDidChangeAccessibilitySupport=new n.Emitter,this.onDidChangeAccessibilitySupport=this._onDidChangeAccessibilitySupport.event +}return e.prototype.getZoomLevel=function(){return this._zoomLevel},e.prototype.getTimeSinceLastZoomLevelChanged=function(){return Date.now()-this._lastZoomLevelChangeTime},e.prototype.getPixelRatio=function(){var e=document.createElement("canvas").getContext("2d");return(window.devicePixelRatio||1)/(e.webkitBackingStorePixelRatio||e.mozBackingStorePixelRatio||e.msBackingStorePixelRatio||e.oBackingStorePixelRatio||e.backingStorePixelRatio||1)},e.prototype.getAccessibilitySupport=function(){return this._accessibilitySupport},e.INSTANCE=new e,e}();t.getZoomLevel=function(){return i.INSTANCE.getZoomLevel()},t.getTimeSinceLastZoomLevelChanged=function(){return i.INSTANCE.getTimeSinceLastZoomLevelChanged()},t.onDidChangeZoomLevel=function(e){return i.INSTANCE.onDidChangeZoomLevel(e)},t.getPixelRatio=function(){return i.INSTANCE.getPixelRatio()},t.getAccessibilitySupport=function(){return i.INSTANCE.getAccessibilitySupport()},t.onDidChangeAccessibilitySupport=function(e){ +return i.INSTANCE.onDidChangeAccessibilitySupport(e)};var o=navigator.userAgent;t.isIE=o.indexOf("Trident")>=0,t.isEdge=o.indexOf("Edge/")>=0,t.isEdgeOrIE=t.isIE||t.isEdge,t.isFirefox=o.indexOf("Firefox")>=0,t.isWebKit=o.indexOf("AppleWebKit")>=0,t.isChrome=o.indexOf("Chrome")>=0,t.isSafari=-1===o.indexOf("Chrome")&&o.indexOf("Safari")>=0,t.isIPad=o.indexOf("iPad")>=0,t.isEdgeWebView=t.isEdge&&o.indexOf("WebView/")>=0,t.hasClipboardSupport=function(){if(t.isIE)return!1;if(t.isEdge){var e=o.indexOf("Edge/"),n=parseInt(o.substring(e+5,o.indexOf(".",e)),10);if(!n||n>=12&&n<=16)return!1}return!0}}),define(t[87],n([1,0,9]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.domEvent=function(e,t,i){var o=function(e){return r.fire(e)},r=new n.Emitter({onFirstListenerAdd:function(){e.addEventListener(t,o,i)},onLastListenerRemove:function(){e.removeEventListener(t,o,i)}});return r.event},t.stop=function(e){return n.mapEvent(e,function(e){return e.preventDefault(),e.stopPropagation(),e})} +}),define(t[57],n([1,0,39,18,30]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=new Array(230),s=new Array(112);!function(){function e(e,t){r[e]=t,s[t]=e}for(var t=0;t=o?Promise.resolve(n):(0,e[i++])().then(function(e){return t(e)?Promise.resolve(e):r()})};return r()},t.first=function(e,t,n){void 0===t&&(t=function(e){return!!e}),void 0===n&&(n=null);var o=0,r=e.length,s=function(){return o>=r?i.TPromise.as(n):(0,e[o++])().then(function(e){return t(e)?i.TPromise.as(e):s()})};return s()},t.setDisposableTimeout=function(e,t){for(var n=[],i=2;i=0;){if(r=s+o, +(0===s||32===n.charCodeAt(s-1))&&32===n.charCodeAt(r))return this._lastStart=s,void(this._lastEnd=r+1);if(s>0&&32===n.charCodeAt(s-1)&&r===i)return this._lastStart=s-1,void(this._lastEnd=r);if(0===s&&r===i)return this._lastStart=0,void(this._lastEnd=r)}this._lastStart=-1}else this._lastStart=-1}else this._lastStart=-1},e.prototype.hasClass=function(e,t){return this._findClassName(e,t),-1!==this._lastStart},e.prototype.addClasses=function(e){for(var t=this,n=[],i=1;i0;){n.sort(E.sort);n.shift().execute()}o=!1};t.scheduleAtNextAnimationFrame=function(t,n){void 0===n&&(n=0);var o=new E(t,n);return e.push(o),i||(i=!0,p(r)),o},t.runAtThisOrScheduleAtNextAnimationFrame=function(e,i){if(o){var r=new E(e,i);return n.push(r),r}return t.scheduleAtNextAnimationFrame(e,i)}}();var L=16,x=function(e,t){return t},N=function(e){function t(t,n,o,r,s){void 0===r&&(r=x),void 0===s&&(s=L);var a=e.call(this)||this,l=null,u=0,d=a._register(new i.TimeoutTimer),c=function(){u=(new Date).getTime(),o(l),l=null} +;return a._register(h(t,n,function(e){l=r(l,e);var t=(new Date).getTime()-u;t>=s?(d.cancel(),c()):d.setIfNotSet(c,s-t)})),a}return o(t,e),t}(s.Disposable);t.addDisposableThrottledListener=function(e,t,n,i,o){return new N(e,t,n,i,o)},t.getComputedStyle=f;var I=function(e,t){return parseFloat(t)||0};t.getClientArea=function(e){if(e!==document.body)return new D(e.clientWidth,e.clientHeight);if(window.innerWidth&&window.innerHeight)return new D(window.innerWidth,window.innerHeight);if(document.body&&document.body.clientWidth&&document.body.clientWidth)return new D(document.body.clientWidth,document.body.clientHeight);if(document.documentElement&&document.documentElement.clientWidth&&document.documentElement.clientHeight)return new D(document.documentElement.clientWidth,document.documentElement.clientHeight);throw new Error("Unable to figure out browser width and height")};var M={getBorderLeftWidth:function(e){return g(e,"border-left-width","borderLeftWidth")},getBorderRightWidth:function(e){ +return g(e,"border-right-width","borderRightWidth")},getBorderTopWidth:function(e){return g(e,"border-top-width","borderTopWidth")},getBorderBottomWidth:function(e){return g(e,"border-bottom-width","borderBottomWidth")},getPaddingLeft:function(e){return g(e,"padding-left","paddingLeft")},getPaddingRight:function(e){return g(e,"padding-right","paddingRight")},getPaddingTop:function(e){return g(e,"padding-top","paddingTop")},getPaddingBottom:function(e){return g(e,"padding-bottom","paddingBottom")},getMarginLeft:function(e){return g(e,"margin-left","marginLeft")},getMarginTop:function(e){return g(e,"margin-top","marginTop")},getMarginRight:function(e){return g(e,"margin-right","marginRight")},getMarginBottom:function(e){return g(e,"margin-bottom","marginBottom")},__commaSentinel:!1},D=function(){return function(e,t){this.width=e,this.height=t}}();t.Dimension=D,t.getTopLeftOffset=function(e){ +for(var t=e.offsetParent,n=e.offsetTop,i=e.offsetLeft;null!==(e=e.parentNode)&&e!==document.body&&e!==document.documentElement;){n-=e.scrollTop;var o=f(e);o&&(i-="rtl"!==o.direction?e.scrollLeft:-e.scrollLeft),e===t&&(i+=M.getBorderLeftWidth(e),n+=M.getBorderTopWidth(e),n+=e.offsetTop,i+=e.offsetLeft,t=e.offsetParent)}return{left:i,top:n}},t.getDomNodePagePosition=function(e){var n=e.getBoundingClientRect();return{left:n.left+t.StandardWindow.scrollX,top:n.top+t.StandardWindow.scrollY,width:n.width,height:n.height}},t.StandardWindow=new(function(){function e(){}return Object.defineProperty(e.prototype,"scrollX",{get:function(){return"number"==typeof window.scrollX?window.scrollX:document.body.scrollLeft+document.documentElement.scrollLeft},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"scrollY",{get:function(){return"number"==typeof window.scrollY?window.scrollY:document.body.scrollTop+document.documentElement.scrollTop},enumerable:!0,configurable:!0}),e}()),t.getTotalWidth=function(e){ +var t=M.getMarginLeft(e)+M.getMarginRight(e);return e.offsetWidth+t},t.getContentWidth=function(e){var t=M.getBorderLeftWidth(e)+M.getBorderRightWidth(e),n=M.getPaddingLeft(e)+M.getPaddingRight(e);return e.offsetWidth-t-n},t.getContentHeight=function(e){var t=M.getBorderTopWidth(e)+M.getBorderBottomWidth(e),n=M.getPaddingTop(e)+M.getPaddingBottom(e);return e.offsetHeight-t-n},t.getTotalHeight=function(e){var t=M.getMarginTop(e)+M.getMarginBottom(e);return e.offsetHeight+t},t.isAncestor=function(e,t){for(;e;){if(e===t)return!0;e=e.parentNode}return!1},t.findParentWithClass=function(e,n,i){for(;e;){if(t.hasClass(e,n))return e;if(i)if("string"==typeof i){if(t.hasClass(e,i))return null}else if(e===i)return null;e=e.parentNode}return null},t.createStyleSheet=m;var T=null;t.createCSSRule=function(e,t,n){void 0===n&&(n=v()),n&&t&&n.sheet.insertRule(e+"{"+t+"}",0)},t.removeCSSRulesContainingSelector=function(e,t){if(void 0===t&&(t=v()),t){for(var n=function(e){ +return e&&e.sheet&&e.sheet.rules?e.sheet.rules:e&&e.sheet&&e.sheet.cssRules?e.sheet.cssRules:[]}(t),i=[],o=0;o=0;o--)t.sheet.deleteRule(i[o])}},t.isHTMLElement=function(e){return"object"==typeof HTMLElement?e instanceof HTMLElement:e&&"object"==typeof e&&1===e.nodeType&&"string"==typeof e.nodeName},t.EventType={CLICK:"click",AUXCLICK:"auxclick",DBLCLICK:"dblclick",MOUSE_UP:"mouseup",MOUSE_DOWN:"mousedown",MOUSE_OVER:"mouseover",MOUSE_MOVE:"mousemove",MOUSE_OUT:"mouseout",MOUSE_ENTER:"mouseenter",MOUSE_LEAVE:"mouseleave",CONTEXT_MENU:"contextmenu",WHEEL:"wheel",KEY_DOWN:"keydown",KEY_PRESS:"keypress",KEY_UP:"keyup",LOAD:"load",UNLOAD:"unload",ABORT:"abort",ERROR:"error",RESIZE:"resize",SCROLL:"scroll",SELECT:"select",CHANGE:"change",SUBMIT:"submit",RESET:"reset",FOCUS:"focus",FOCUS_IN:"focusin",FOCUS_OUT:"focusout",BLUR:"blur",INPUT:"input",STORAGE:"storage",DRAG_START:"dragstart",DRAG:"drag",DRAG_ENTER:"dragenter", +DRAG_LEAVE:"dragleave",DRAG_OVER:"dragover",DROP:"drop",DRAG_END:"dragend",ANIMATION_START:a.isWebKit?"webkitAnimationStart":"animationstart",ANIMATION_END:a.isWebKit?"webkitAnimationEnd":"animationend",ANIMATION_ITERATION:a.isWebKit?"webkitAnimationIteration":"animationiteration"},t.EventHelper={stop:function(e,t){e.preventDefault?e.preventDefault():e.returnValue=!1,t&&(e.stopPropagation?e.stopPropagation():e.cancelBubble=!0)}},t.saveParentsScrollTop=function(e){for(var t=[],n=0;e&&e.nodeType===e.ELEMENT_NODE;n++)t[n]=e.scrollTop,e=e.parentNode;return t},t.restoreParentsScrollTop=function(e,t){for(var n=0;e&&e.nodeType===e.ELEMENT_NODE;n++)e.scrollTop!==t[n]&&(e.scrollTop=t[n]),e=e.parentNode};var k=function(){function e(e){var n=this;this._onDidFocus=new d.Emitter,this.onDidFocus=this._onDidFocus.event,this._onDidBlur=new d.Emitter,this.onDidBlur=this._onDidBlur.event,this.disposables=[];var i=!1,o=!1;c.domEvent(e,t.EventType.FOCUS,!0)(function(){o=!1,i||(i=!0,n._onDidFocus.fire())},null,this.disposables), +c.domEvent(e,t.EventType.BLUR,!0)(function(){i&&(o=!0,window.setTimeout(function(){o&&(o=!1,i=!1,n._onDidBlur.fire())},0))},null,this.disposables)}return e.prototype.dispose=function(){this.disposables=s.dispose(this.disposables),this._onDidFocus.dispose(),this._onDidBlur.dispose()},e}();t.trackFocus=function(e){return new k(e)},t.append=function(e){for(var t=[],n=1;n0},t.prototype.startMonitoring=function(e,t,n){var o=this;if(!this.isMonitoring()){this.mouseMoveEventMerger=e,this.mouseMoveCallback=t,this.onStopCallback=n;for(var a=r.IframeUtils.getSameOriginWindowChain(),l=0;l"},c.link=function(t,n,i){ +return t===i&&(i=r.removeMarkdownEscapes(i)),n=r.removeMarkdownEscapes(n),!(t=r.removeMarkdownEscapes(t))||t.match(/^data:|javascript:/i)||t.match(/^command:/i)&&!e.isTrusted?i:''+i+""},c.paragraph=function(e){return"

                                      "+e+"

                                      "},t.codeBlockRenderer&&(c.code=function(e,n){var r=t.codeBlockRenderer(n,e),s=i.defaultGenerator.nextId(),a=Promise.all([r,d]).then(function(e){var t=e[0],n=u.querySelector('div[data-code="'+s+'"]');n&&(n.innerHTML=t)}).catch(function(e){});return t.codeBlockRenderCallback&&a.then(t.codeBlockRenderCallback),'
                                      '+o.escape(e)+"
                                      "}),t.actionHandler&&t.actionHandler.disposeables.push(n.addStandardDisposableListener(u,"click",function(e){var n=e.target;if("A"===n.tagName||(n=n.parentElement)&&"A"===n.tagName){var i=n.dataset.href;i&&t.actionHandler.callback(i,e)}}));var h={sanitize:!0,renderer:c};return u.innerHTML=s.marked(e.value,h),l(),u};var c=function(){function e(e){this.source=e,this.index=0 +}return e.prototype.eos=function(){return this.index>=this.source.length},e.prototype.next=function(){var e=this.peek();return this.advance(),e},e.prototype.peek=function(){return this.source[this.index]},e.prototype.advance=function(){this.index++},e}()});var a=this&&this.__decorate||function(e,t,n,i){var o,r=arguments.length,s=r<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,n,i);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(s=(r<3?o(s):r>3?o(t,n,s):o(t,n))||s);return r>3&&s&&Object.defineProperty(t,n,s),s};define(t[74],n([1,0,25,2,7,111]),function(e,t,n,i,o,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s;!function(e){e.Tap="-monaco-gesturetap",e.Change="-monaco-gesturechange",e.Start="-monaco-gesturestart",e.End="-monaco-gesturesend",e.Contextmenu="-monaco-gesturecontextmenu"}(s=t.EventType||(t.EventType={}));var l=function(){function e(){var e=this;this.toDispose=[],this.activeTouches={}, +this.handle=null,this.targets=[],this.toDispose.push(o.addDisposableListener(document,"touchstart",function(t){return e.onTouchStart(t)})),this.toDispose.push(o.addDisposableListener(document,"touchend",function(t){return e.onTouchEnd(t)})),this.toDispose.push(o.addDisposableListener(document,"touchmove",function(t){return e.onTouchMove(t)}))}return e.addTarget=function(t){e.isTouchDevice()&&(e.INSTANCE||(e.INSTANCE=new e),e.INSTANCE.targets.push(t))},e.isTouchDevice=function(){return"ontouchstart"in window||navigator.maxTouchPoints>0||window.navigator.msMaxTouchPoints>0},e.prototype.dispose=function(){this.handle&&(this.handle.dispose(),i.dispose(this.toDispose),this.handle=null)},e.prototype.onTouchStart=function(e){var t=Date.now();this.handle&&(this.handle.dispose(),this.handle=null);for(var n=0,i=e.targetTouches.length;n=e.HOLD_DELAY&&Math.abs(d.initialPageX-n.tail(d.rollingPageX))<30&&Math.abs(d.initialPageY-n.tail(d.rollingPageY))<30){var h=a.newGestureEvent(s.Contextmenu,d.initialTarget) +;h.pageX=n.tail(d.rollingPageX),h.pageY=n.tail(d.rollingPageY),a.dispatchEvent(h)}else if(1===o){var p=n.tail(d.rollingPageX),f=n.tail(d.rollingPageY),g=n.tail(d.rollingTimestamps)-d.rollingTimestamps[0],m=p-d.rollingPageX[0],v=f-d.rollingPageY[0],_=a.targets.filter(function(e){return d.initialTarget instanceof Node&&e.contains(d.initialTarget)});a.inertia(_,i,Math.abs(m)/g,m>0?1:-1,p,Math.abs(v)/g,v>0?1:-1,f)}a.dispatchEvent(a.newGestureEvent(s.End,d.initialTarget)),delete a.activeTouches[u.identifier]},a=this,l=0,u=t.changedTouches.length;l0&&(g=!1,p=r*i*h),l>0&&(g=!1,f=u*l*h);var m=c.newGestureEvent(s.Change);m.translationX=p,m.translationY=f,t.forEach(function(e){return e.dispatchEvent(m)}),g||c.inertia(t,o,i,r,a+p,l,u,d+f)})},e.prototype.onTouchMove=function(e){for(var t=Date.now(),i=0,o=e.changedTouches.length;i3&&(a.rollingPageX.shift(),a.rollingPageY.shift(),a.rollingTimestamps.shift()),a.rollingPageX.push(r.pageX),a.rollingPageY.push(r.pageY),a.rollingTimestamps.push(t)}else console.warn("end of an UNKNOWN touch",r)}this.dispatched&&(e.preventDefault(), +e.stopPropagation(),this.dispatched=!1)},e.SCROLL_FRICTION=-.005,e.HOLD_DELAY=700,a([r.memoize],e,"isTouchDevice",null),e}();t.Gesture=l}),define(t[138],n([1,0,7,28,376]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e){this.domNode=document.createElement("span"),this.domNode.className="monaco-highlighted-label",this.didEverRender=!1,e.appendChild(this.domNode)}return Object.defineProperty(e.prototype,"element",{get:function(){return this.domNode},enumerable:!0,configurable:!0}),e.prototype.set=function(t,n,o,r){void 0===n&&(n=[]),void 0===o&&(o=""),t||(t=""),r&&(t=e.escapeNewLines(t,n)),this.didEverRender&&this.text===t&&this.title===o&&i.equals(this.highlights,n)||(Array.isArray(n)||(n=[]),this.text=t,this.title=o,this.highlights=n,this.render())},e.prototype.render=function(){n.clearNode(this.domNode);for(var e,t=[],i=0,r=0;r"), +t.push(o.renderOcticons(this.text.substring(i,e.start))),t.push(""),i=e.end),t.push(''),t.push(o.renderOcticons(this.text.substring(e.start,e.end))),t.push(""),i=e.end);i"),t.push(o.renderOcticons(this.text.substring(i))),t.push("")),this.domNode.innerHTML=t.join(""),this.domNode.title=this.title,this.didEverRender=!0},e.prototype.dispose=function(){this.text=null,this.highlights=null},e.escapeNewLines=function(e,t){var n=0,i=0;return e.replace(/\r\n|\r|\n/,function(e,o){i="\r\n"===e?-1:0,o+=n;for(var r=0,s=t;r=o&&(a.start+=i),a.end>=o&&(a.end+=i))}return n+=i,"⏎"})},e}();t.HighlightedLabel=r}),define(t[253],n([1,0,7]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e){this.renderers=e,this.cache=new Map}return e.prototype.alloc=function(e){var t=this.getTemplateCache(e).pop();if(!t){var i=n.$(".monaco-list-row");t={domNode:i, +templateId:e,templateData:this.renderers.get(e).renderTemplate(i)}}return t},e.prototype.release=function(e){e&&this.releaseRow(e)},e.prototype.releaseRow=function(e){var t=e.domNode,i=e.templateId;n.removeClass(t,"scrolling"),function(e){try{e.parentElement.removeChild(e)}catch(e){}}(t);this.getTemplateCache(i).push(e)},e.prototype.getTemplateCache=function(e){var t=this.cache.get(e);return t||(t=[],this.cache.set(e,t)),t},e.prototype.garbageCollect=function(){var e=this;this.renderers&&(this.cache.forEach(function(t,n){for(var i=0,o=t;i0;n--){var r=e.charCodeAt(n-1);if(47===r||92===r)break}t=e.substr(n)}var s=o.indexOf(t);return-1!==s?i[s]:null};a.basenames=o,a.patterns=i,a.allBasenames=o;var l=e.filter(function(e){return!e.basenames});return l.push(a),l +}Object.defineProperty(t,"__esModule",{value:!0});var v="**",_="/",y="[/\\\\]",C="[^/\\\\]",b=/\//g;t.splitGlobAware=l;var S=/^\*\*\/\*\.[\w\.-]+$/,w=/^\*\*\/([\w\.-]+)\/?$/,E=/^{\*\*\/[\*\.]?[\w\.-]+\/?(,\*\*\/[\*\.]?[\w\.-]+\/?)*}$/,L=/^{\*\*\/[\*\.]?[\w\.-]+(\/(\*\*)?)?(,\*\*\/[\*\.]?[\w\.-]+(\/(\*\*)?)?)*}$/,x=/^\*\*((\/[\w\.-]+)+)\/?$/,N=/^([\w\.-]+(\/[\w\.-]+)*)\/?$/,I=new r.LRUCache(1e4),M=function(){return!1},D=function(){return null};t.match=function(e,t,n){return!(!e||!t)&&f(e)(t,void 0,n)},t.parse=f,t.isRelativePattern=g}),define(t[424],n([1,0,50,6,153]),function(e,t,n,i,o){"use strict";function r(e,t){void 0===t&&(t=!1);var i=function(e){return{id:e.id,mime:e.mime,filename:e.filename,extension:e.extension,filepattern:e.filepattern,firstline:e.firstline,userConfigured:e.userConfigured,filenameLowercase:e.filename?e.filename.toLowerCase():void 0,extensionLowercase:e.extension?e.extension.toLowerCase():void 0,filepatternLowercase:e.filepattern?e.filepattern.toLowerCase():void 0, +filepatternOnPath:!!e.filepattern&&e.filepattern.indexOf(n.sep)>=0}}(e);l.push(i),i.userConfigured?d.push(i):u.push(i),t&&!i.userConfigured&&l.forEach(function(e){e.mime===i.mime||e.userConfigured||(i.extension&&e.extension===i.extension&&console.warn("Overwriting extension <<"+i.extension+">> to now point to mime <<"+i.mime+">>"),i.filename&&e.filename===i.filename&&console.warn("Overwriting filename <<"+i.filename+">> to now point to mime <<"+i.mime+">>"),i.filepattern&&e.filepattern===i.filepattern&&console.warn("Overwriting filepattern <<"+i.filepattern+">> to now point to mime <<"+i.mime+">>"),i.firstline&&e.firstline===i.firstline&&console.warn("Overwriting firstline <<"+i.firstline+">> to now point to mime <<"+i.mime+">>"))})}function s(e,o){if(!e)return[t.MIME_UNKNOWN];e=e.toLowerCase();var r=n.basename(e),s=a(e,r,d);if(s)return[s,t.MIME_TEXT];var c=a(e,r,u);if(c)return[c,t.MIME_TEXT];if(o){var h=function(e){i.startsWithUTF8BOM(e)&&(e=e.substr(1));if(e.length>0)for(var t=0;t0)return n.mime}}return null}(o);if(h)return[h,t.MIME_TEXT]}return[t.MIME_UNKNOWN]}function a(e,t,n){for(var r,s,a,l=n.length-1;l>=0;l--){var u=n[l];if(t===u.filenameLowercase){r=u;break}if(u.filepattern&&(!s||u.filepattern.length>s.filepattern.length)){var d=u.filepatternOnPath?e:t;o.match(u.filepatternLowercase,d)&&(s=u)}u.extension&&(!a||u.extension.length>a.extension.length)&&i.endsWith(t,u.extensionLowercase)&&(a=u)}return r?r.mime:s?s.mime:a?a.mime:null}Object.defineProperty(t,"__esModule",{value:!0}),t.MIME_TEXT="text/plain",t.MIME_UNKNOWN="application/unknown";var l=[],u=[],d=[];t.registerTextMime=r,t.guessMimeTypes=s}),define(t[43],n([1,0,2,9]),function(e,t,n,i){"use strict";function r(e,t){var n=t-e;return function(t){return e+n*function(e){return 1-function(e){return Math.pow(e,3)}(1-e)}(t)}}Object.defineProperty(t,"__esModule",{value:!0});!function(e){e[e.Auto=1]="Auto",e[e.Hidden=2]="Hidden",e[e.Visible=3]="Visible" +}(t.ScrollbarVisibility||(t.ScrollbarVisibility={}));var s=function(){function e(e,t,n,i,o,r){t|=0,n|=0,i|=0,o|=0,r|=0,(e|=0)<0&&(e=0),n+e>t&&(n=t-e),n<0&&(n=0),i<0&&(i=0),r+i>o&&(r=o-i),r<0&&(r=0),this.width=e,this.scrollWidth=t,this.scrollLeft=n,this.height=i,this.scrollHeight=o,this.scrollTop=r}return e.prototype.equals=function(e){return this.width===e.width&&this.scrollWidth===e.scrollWidth&&this.scrollLeft===e.scrollLeft&&this.height===e.height&&this.scrollHeight===e.scrollHeight&&this.scrollTop===e.scrollTop},e.prototype.withScrollDimensions=function(t){return new e(void 0!==t.width?t.width:this.width,void 0!==t.scrollWidth?t.scrollWidth:this.scrollWidth,this.scrollLeft,void 0!==t.height?t.height:this.height,void 0!==t.scrollHeight?t.scrollHeight:this.scrollHeight,this.scrollTop)},e.prototype.withScrollPosition=function(t){return new e(this.width,this.scrollWidth,void 0!==t.scrollLeft?t.scrollLeft:this.scrollLeft,this.height,this.scrollHeight,void 0!==t.scrollTop?t.scrollTop:this.scrollTop)}, +e.prototype.createScrollEvent=function(e){var t=this.width!==e.width,n=this.scrollWidth!==e.scrollWidth,i=this.scrollLeft!==e.scrollLeft,o=this.height!==e.height,r=this.scrollHeight!==e.scrollHeight,s=this.scrollTop!==e.scrollTop;return{width:this.width,scrollWidth:this.scrollWidth,scrollLeft:this.scrollLeft,height:this.height,scrollHeight:this.scrollHeight,scrollTop:this.scrollTop,widthChanged:t,scrollWidthChanged:n,scrollLeftChanged:i,heightChanged:o,scrollHeightChanged:r,scrollTopChanged:s}},e}();t.ScrollState=s;var a=function(e){function t(t,n){var o=e.call(this)||this;return o._onScroll=o._register(new i.Emitter),o.onScroll=o._onScroll.event,o._smoothScrollDuration=t,o._scheduleAtNextAnimationFrame=n,o._state=new s(0,0,0,0,0,0),o._smoothScrolling=null,o}return o(t,e),t.prototype.dispose=function(){this._smoothScrolling&&(this._smoothScrolling.dispose(),this._smoothScrolling=null),e.prototype.dispose.call(this)},t.prototype.setSmoothScrollDuration=function(e){this._smoothScrollDuration=e}, +t.prototype.validateScrollPosition=function(e){return this._state.withScrollPosition(e)},t.prototype.getScrollDimensions=function(){return this._state},t.prototype.setScrollDimensions=function(e){var t=this._state.withScrollDimensions(e);this._setState(t),this._smoothScrolling&&this._smoothScrolling.acceptScrollDimensions(this._state)},t.prototype.getFutureScrollPosition=function(){return this._smoothScrolling?this._smoothScrolling.to:this._state},t.prototype.getCurrentScrollPosition=function(){return this._state},t.prototype.setScrollPositionNow=function(e){var t=this._state.withScrollPosition(e);this._smoothScrolling&&(this._smoothScrolling.dispose(),this._smoothScrolling=null),this._setState(t)},t.prototype.setScrollPositionSmooth=function(e){var t=this;if(0===this._smoothScrollDuration)return this.setScrollPositionNow(e);if(this._smoothScrolling){e={scrollLeft:void 0===e.scrollLeft?this._smoothScrolling.to.scrollLeft:e.scrollLeft, +scrollTop:void 0===e.scrollTop?this._smoothScrolling.to.scrollTop:e.scrollTop};i=this._state.withScrollPosition(e);if(this._smoothScrolling.to.scrollLeft===i.scrollLeft&&this._smoothScrolling.to.scrollTop===i.scrollTop)return;var n=this._smoothScrolling.combine(this._state,i,this._smoothScrollDuration);this._smoothScrolling.dispose(),this._smoothScrolling=n}else{var i=this._state.withScrollPosition(e);this._smoothScrolling=u.start(this._state,i,this._smoothScrollDuration)}this._smoothScrolling.animationFrameDisposable=this._scheduleAtNextAnimationFrame(function(){t._smoothScrolling&&(t._smoothScrolling.animationFrameDisposable=null,t._performSmoothScrolling())})},t.prototype._performSmoothScrolling=function(){var e=this,t=this._smoothScrolling.tick(),n=this._state.withScrollPosition(t);if(this._setState(n),t.isDone)return this._smoothScrolling.dispose(),void(this._smoothScrolling=null);this._smoothScrolling.animationFrameDisposable=this._scheduleAtNextAnimationFrame(function(){ +e._smoothScrolling&&(e._smoothScrolling.animationFrameDisposable=null,e._performSmoothScrolling())})},t.prototype._setState=function(e){var t=this._state;t.equals(e)||(this._state=e,this._onScroll.fire(this._state.createScrollEvent(t)))},t}(n.Disposable);t.Scrollable=a;var l=function(){return function(e,t,n){this.scrollLeft=e,this.scrollTop=t,this.isDone=n}}();t.SmoothScrollingUpdate=l;var u=function(){function e(e,t,n,i){this.from=e,this.to=t,this.duration=i,this._startTime=n,this.animationFrameDisposable=null,this._initAnimations()}return e.prototype._initAnimations=function(){this.scrollLeft=this._initAnimation(this.from.scrollLeft,this.to.scrollLeft,this.to.width),this.scrollTop=this._initAnimation(this.from.scrollTop,this.to.scrollTop,this.to.height)},e.prototype._initAnimation=function(e,t,n){if(Math.abs(e-t)>2.5*n){var i=void 0,o=void 0;return e140)i._setDesiredScrollPositionNow(a.getScrollPosition());else{var l=i._sliderMousePosition(e)-o;i._setDesiredScrollPositionNow(a.getDesiredScrollPositionFromDelta(l))}},function(){i.slider.toggleClassName("active",!1),i._host.onDragEnd(),t()}),this._host.onDragStart()},t.prototype._setDesiredScrollPositionNow=function(e){var t={};this.writeScrollPosition(t,e),this._scrollable.setScrollPositionNow(t)},t}(s.Widget);t.AbstractScrollbar=d}),define(t[428],n([1,0,158,42,43,157,114]),function(e,t,n,i,r,s,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var l=function(e){function t(t,n,o){var l=e.call(this,{lazyRender:n.lazyRender,host:o, +scrollbarState:new s.ScrollbarState(n.horizontalHasArrows?n.arrowSize:0,n.horizontal===r.ScrollbarVisibility.Hidden?0:n.horizontalScrollbarSize,n.vertical===r.ScrollbarVisibility.Hidden?0:n.verticalScrollbarSize),visibility:n.horizontal,extraScrollbarClassName:"horizontal",scrollable:t})||this;if(n.horizontalHasArrows){var u=(n.arrowSize-a.ARROW_IMG_SIZE)/2,d=(n.horizontalScrollbarSize-a.ARROW_IMG_SIZE)/2;l._createArrow({className:"left-arrow",top:d,left:u,bottom:void 0,right:void 0,bgWidth:n.arrowSize,bgHeight:n.horizontalScrollbarSize,onActivate:function(){return l._host.onMouseWheel(new i.StandardMouseWheelEvent(null,1,0))}}),l._createArrow({className:"right-arrow",top:d,left:void 0,bottom:void 0,right:u,bgWidth:n.arrowSize,bgHeight:n.horizontalScrollbarSize,onActivate:function(){return l._host.onMouseWheel(new i.StandardMouseWheelEvent(null,-1,0))}})}return l._createSlider(Math.floor((n.horizontalScrollbarSize-n.horizontalSliderSize)/2),0,null,n.horizontalSliderSize),l}return o(t,e), +t.prototype._updateSlider=function(e,t){this.slider.setWidth(e),this.slider.setLeft(t)},t.prototype._renderDomNode=function(e,t){this.domNode.setWidth(e),this.domNode.setHeight(t),this.domNode.setLeft(0),this.domNode.setBottom(0)},t.prototype.onDidScroll=function(e){return this._shouldRender=this._onElementScrollSize(e.scrollWidth)||this._shouldRender,this._shouldRender=this._onElementScrollPosition(e.scrollLeft)||this._shouldRender,this._shouldRender=this._onElementSize(e.width)||this._shouldRender,this._shouldRender},t.prototype._mouseDownRelativePosition=function(e,t){return e},t.prototype._sliderMousePosition=function(e){return e.posx},t.prototype._sliderOrthogonalMousePosition=function(e){return e.posy},t.prototype.writeScrollPosition=function(e,t){e.scrollLeft=t},t}(n.AbstractScrollbar);t.HorizontalScrollbar=l}),define(t[430],n([1,0,158,42,43,157,114]),function(e,t,n,i,r,s,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var l=function(e){function t(t,n,o){var l=e.call(this,{ +lazyRender:n.lazyRender,host:o,scrollbarState:new s.ScrollbarState(n.verticalHasArrows?n.arrowSize:0,n.vertical===r.ScrollbarVisibility.Hidden?0:n.verticalScrollbarSize,0),visibility:n.vertical,extraScrollbarClassName:"vertical",scrollable:t})||this;if(n.verticalHasArrows){var u=(n.arrowSize-a.ARROW_IMG_SIZE)/2,d=(n.verticalScrollbarSize-a.ARROW_IMG_SIZE)/2;l._createArrow({className:"up-arrow",top:u,left:d,bottom:void 0,right:void 0,bgWidth:n.verticalScrollbarSize,bgHeight:n.arrowSize,onActivate:function(){return l._host.onMouseWheel(new i.StandardMouseWheelEvent(null,0,1))}}),l._createArrow({className:"down-arrow",top:void 0,left:d,bottom:u,right:void 0,bgWidth:n.verticalScrollbarSize,bgHeight:n.arrowSize,onActivate:function(){return l._host.onMouseWheel(new i.StandardMouseWheelEvent(null,0,-1))}})}return l._createSlider(0,Math.floor((n.verticalScrollbarSize-n.verticalSliderSize)/2),n.verticalSliderSize,null),l}return o(t,e),t.prototype._updateSlider=function(e,t){this.slider.setHeight(e), +this.slider.setTop(t)},t.prototype._renderDomNode=function(e,t){this.domNode.setWidth(t),this.domNode.setHeight(e),this.domNode.setRight(0),this.domNode.setTop(0)},t.prototype.onDidScroll=function(e){return this._shouldRender=this._onElementScrollSize(e.scrollHeight)||this._shouldRender,this._shouldRender=this._onElementScrollPosition(e.scrollTop)||this._shouldRender,this._shouldRender=this._onElementSize(e.height)||this._shouldRender,this._shouldRender},t.prototype._mouseDownRelativePosition=function(e,t){return t},t.prototype._sliderMousePosition=function(e){return e.posy},t.prototype._sliderOrthogonalMousePosition=function(e){return e.posx},t.prototype.writeScrollPosition=function(e,t){e.scrollTop=t},t}(n.AbstractScrollbar);t.VerticalScrollbar=l}),define(t[437],n([1,0,13,18]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e){n.Promise.is(e)?this._winjsPromise=e:this._winjsPromise=new n.Promise(function(t,n){var o=!0;e(function(e){ +o?i.setImmediate(function(){return t(e)}):t(e)},function(e){o?i.setImmediate(function(){return n(e)}):n(e)}),o=!1})}return e.all=function(t){return new e(n.Promise.join(t).then(null,function(e){for(var t in e)if(e.hasOwnProperty(t))return e[t]}))},e.race=function(t){return new e(n.Promise.any(t).then(function(e){return e.value},function(e){return e.value}))},e.resolve=function(t){return new e(n.Promise.wrap(t))},e.reject=function(t){return new e(n.Promise.wrapError(t))},e.prototype.then=function(t,n){var o=!0,r=new e(this._winjsPromise.then(t&&function(e){o?i.setImmediate(function(){return t(e)}):t(e)},n&&function(e){o?i.setImmediate(function(){return n(e)}):n(e)}));return o=!1,r},e.prototype.catch=function(e){return this.then(null,e)},e}();t.PolyfillPromise=o}),define(t[160],n([1,0,10,2,13,14,18]),function(e,t,n,i,r,s,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var l="$initialize",u=!1;t.logOnceWebWorkerWarning=function(e){a.isWeb&&(u||(u=!0, +console.warn("Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/Microsoft/monaco-editor#faq")),console.warn(e.message))};var d=function(){function e(e){this._workerId=-1,this._handler=e,this._lastSentReq=0,this._pendingReplies=Object.create(null)}return e.prototype.setWorkerId=function(e){this._workerId=e},e.prototype.sendMessage=function(e,t){var n=String(++this._lastSentReq),i={c:null,e:null},o=new r.TPromise(function(e,t){i.c=e,i.e=t},function(){});return this._pendingReplies[n]=i,this._send({vsWorker:this._workerId,req:n,method:e,args:t}),o},e.prototype.handleMessage=function(e){var t;try{t=JSON.parse(e)}catch(e){}t&&t.vsWorker&&(-1!==this._workerId&&t.vsWorker!==this._workerId||this._handleMessage(t))},e.prototype._handleMessage=function(e){var t=this;if(e.seq){var i=e;if(!this._pendingReplies[i.seq])return void console.warn("Got reply to unknown seq");var o=this._pendingReplies[i.seq] +;if(delete this._pendingReplies[i.seq],i.err){var r=i.err;return i.err.$isError&&((r=new Error).name=i.err.name,r.message=i.err.message,r.stack=i.err.stack),void o.e(r)}o.c(i.res)}else{var s=e,a=s.req;this._handler.handleMessage(s.method,s.args).then(function(e){t._send({vsWorker:t._workerId,seq:a,res:e,err:void 0})},function(e){e.detail instanceof Error&&(e.detail=n.transformErrorForSerialization(e.detail)),t._send({vsWorker:t._workerId,seq:a,res:void 0,err:n.transformErrorForSerialization(e)})})}},e.prototype._send=function(e){var t=JSON.stringify(e);this._handler.sendMessage(t)},e}(),c=function(e){function t(t,n){var i=e.call(this)||this,o=null,s=null;i._worker=i._register(t.create("vs/base/common/worker/simpleWorker",function(e){i._protocol.handleMessage(e)},function(e){s(e)})),i._protocol=new d({sendMessage:function(e){i._worker.postMessage(e)},handleMessage:function(e,t){return r.TPromise.as(null)}}),i._protocol.setWorkerId(i._worker.getId());var a=null +;void 0!==self.require&&"function"==typeof self.require.getConfig?a=self.require.getConfig():void 0!==self.requirejs&&(a=self.requirejs.s.contexts._.config),i._lazyProxy=new r.TPromise(function(e,t){o=e,s=t},function(){}),i._onModuleLoaded=i._protocol.sendMessage(l,[i._worker.getId(),n,a]),i._onModuleLoaded.then(function(e){for(var t={},n=0;n0},e.prototype.getChildren=function(e,t){var i=this.modelProvider.getModel();return n.TPromise.as(i===t?i.entries:[])},e.prototype.getParent=function(e,t){return n.TPromise.as(null)},e}();t.DataSource=o;var r=function(){function e(e){ +this.modelProvider=e}return e.prototype.getAriaLabel=function(e,t){var n=this.modelProvider.getModel();return n.accessibilityProvider&&n.accessibilityProvider.getAriaLabel(t)},e.prototype.getPosInSet=function(e,t){var n=this.modelProvider.getModel();return String(n.entries.indexOf(t)+1)},e.prototype.getSetSize=function(){var e=this.modelProvider.getModel();return String(e.entries.length)},e}();t.AccessibilityProvider=r;var s=function(){function e(e){this.modelProvider=e}return e.prototype.isVisible=function(e,t){var n=this.modelProvider.getModel();return!n.filter||n.filter.isVisible(t)},e}();t.Filter=s;var a=function(){function e(e,t){this.modelProvider=e,this.styles=t}return e.prototype.updateStyles=function(e){this.styles=e},e.prototype.getHeight=function(e,t){return this.modelProvider.getModel().renderer.getHeight(t)},e.prototype.getTemplateId=function(e,t){return this.modelProvider.getModel().renderer.getTemplateId(t)},e.prototype.renderTemplate=function(e,t,n){ +return this.modelProvider.getModel().renderer.renderTemplate(t,n,this.styles)},e.prototype.renderElement=function(e,t,n,i){this.modelProvider.getModel().renderer.renderElement(t,n,i,this.styles)},e.prototype.disposeTemplate=function(e,t,n){this.modelProvider.getModel().renderer.disposeTemplate(t,n)},e}();t.Renderer=a}),define(t[93],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});!function(e){e[e.PREVIEW=0]="PREVIEW",e[e.OPEN=1]="OPEN",e[e.OPEN_IN_BACKGROUND=2]="OPEN_IN_BACKGROUND"}(t.Mode||(t.Mode={}))}),define(t[445],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e,t,n){this._posx=e,this._posy=t,this._target=n}return e.prototype.preventDefault=function(){},e.prototype.stopPropagation=function(){},Object.defineProperty(e.prototype,"target",{get:function(){return this._target},enumerable:!0,configurable:!0}),e}();t.ContextMenuEvent=n;var i=function(e){function t(t){ +var n=e.call(this,t.posx,t.posy,t.target)||this;return n.originalEvent=t,n}return o(t,e),t.prototype.preventDefault=function(){this.originalEvent.preventDefault()},t.prototype.stopPropagation=function(){this.originalEvent.stopPropagation()},t}(n);t.MouseContextMenuEvent=i;var r=function(e){function t(t,n,i){var o=e.call(this,t,n,i.target)||this;return o.originalEvent=i,o}return o(t,e),t.prototype.preventDefault=function(){this.originalEvent.preventDefault()},t.prototype.stopPropagation=function(){this.originalEvent.stopPropagation()},t}(n);t.KeyboardContextMenuEvent=r;!function(e){e[e.COPY=0]="COPY",e[e.MOVE=1]="MOVE"}(t.DragOverEffect||(t.DragOverEffect={}));!function(e){e[e.BUBBLE_DOWN=0]="BUBBLE_DOWN",e[e.BUBBLE_UP=1]="BUBBLE_UP"}(t.DragOverBubble||(t.DragOverBubble={}))}),define(t[81],n([1,0,18,10,7,39]),function(e,t,n,i,o,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s;!function(e){e[e.ON_MOUSE_DOWN=0]="ON_MOUSE_DOWN",e[e.ON_MOUSE_UP=1]="ON_MOUSE_UP" +}(s=t.ClickBehavior||(t.ClickBehavior={}));var a;!function(e){e[e.SINGLE_CLICK=0]="SINGLE_CLICK",e[e.DOUBLE_CLICK=1]="DOUBLE_CLICK"}(a=t.OpenMode||(t.OpenMode={}));var l=function(){function e(){this._arr=[]}return e.prototype.set=function(e,t){this._arr.push({keybinding:r.createKeybinding(e,n.OS),callback:t})},e.prototype.dispatch=function(e){for(var t=this._arr.length-1;t>=0;t--){var n=this._arr[t];if(e.equals(n.keybinding))return n.callback}return null},e}();t.KeybindingDispatcher=l;var u=function(){function e(e){void 0===e&&(e={clickBehavior:s.ON_MOUSE_DOWN,keyboardSupport:!0,openMode:a.SINGLE_CLICK});var t=this;this.options=e,this.downKeyBindingDispatcher=new l,this.upKeyBindingDispatcher=new l,("boolean"!=typeof e.keyboardSupport||e.keyboardSupport)&&(this.downKeyBindingDispatcher.set(16,function(e,n){return t.onUp(e,n)}),this.downKeyBindingDispatcher.set(18,function(e,n){return t.onDown(e,n)}),this.downKeyBindingDispatcher.set(15,function(e,n){return t.onLeft(e,n)}), +this.downKeyBindingDispatcher.set(17,function(e,n){return t.onRight(e,n)}),n.isMacintosh&&(this.downKeyBindingDispatcher.set(2064,function(e,n){return t.onLeft(e,n)}),this.downKeyBindingDispatcher.set(300,function(e,n){return t.onDown(e,n)}),this.downKeyBindingDispatcher.set(302,function(e,n){return t.onUp(e,n)})),this.downKeyBindingDispatcher.set(11,function(e,n){return t.onPageUp(e,n)}),this.downKeyBindingDispatcher.set(12,function(e,n){return t.onPageDown(e,n)}),this.downKeyBindingDispatcher.set(14,function(e,n){return t.onHome(e,n)}),this.downKeyBindingDispatcher.set(13,function(e,n){return t.onEnd(e,n)}),this.downKeyBindingDispatcher.set(10,function(e,n){return t.onSpace(e,n)}),this.downKeyBindingDispatcher.set(9,function(e,n){return t.onEscape(e,n)}),this.upKeyBindingDispatcher.set(3,this.onEnter.bind(this)),this.upKeyBindingDispatcher.set(2051,this.onEnter.bind(this)))}return e.prototype.onMouseDown=function(e,t,n,i){if(void 0===i&&(i="mouse"), +this.options.clickBehavior===s.ON_MOUSE_DOWN&&(n.leftButton||n.middleButton)){if(n.target){if(n.target.tagName&&"input"===n.target.tagName.toLowerCase())return!1;if(o.findParentWithClass(n.target,"scrollbar","monaco-tree"))return!1;if(o.findParentWithClass(n.target,"monaco-action-bar","row"))return!1}return this.onLeftClick(e,t,n,i)}return!1},e.prototype.onClick=function(e,t,i){return n.isMacintosh&&i.ctrlKey?(i.preventDefault(),i.stopPropagation(),!1):(!i.target||!i.target.tagName||"input"!==i.target.tagName.toLowerCase())&&((this.options.clickBehavior!==s.ON_MOUSE_DOWN||!i.leftButton&&!i.middleButton)&&this.onLeftClick(e,t,i))},e.prototype.onLeftClick=function(e,t,n,o){void 0===o&&(o="mouse");var r=n,s={origin:o,originalEvent:n,didClickOnTwistie:this.isClickOnTwistie(r)};if(e.getInput()===t)e.clearFocus(s),e.clearSelection(s);else{n&&r.browserEvent&&"mousedown"===r.browserEvent.type&&1===r.browserEvent.detail||n.preventDefault(),n.stopPropagation(),e.domFocus(),e.setSelection([t],s),e.setFocus(t,s), +this.shouldToggleExpansion(t,r,o)&&(e.isExpanded(t)?e.collapse(t).done(null,i.onUnexpectedError):e.expand(t).done(null,i.onUnexpectedError))}return!0},e.prototype.shouldToggleExpansion=function(e,t,n){var i="mouse"===n&&2===t.detail;return this.openOnSingleClick||i||this.isClickOnTwistie(t)},e.prototype.setOpenMode=function(e){this.options.openMode=e},Object.defineProperty(e.prototype,"openOnSingleClick",{get:function(){return this.options.openMode===a.SINGLE_CLICK},enumerable:!0,configurable:!0}),e.prototype.isClickOnTwistie=function(e){var t=e.target;if(!o.hasClass(t,"content"))return!1;var n=window.getComputedStyle(t,":before");if("none"===n.backgroundImage||"none"===n.display)return!1;var i=parseInt(n.width)+parseInt(n.paddingRight);return e.browserEvent.offsetX<=i},e.prototype.onContextMenu=function(e,t,n){return(!n.target||!n.target.tagName||"input"!==n.target.tagName.toLowerCase())&&(n&&(n.preventDefault(),n.stopPropagation()),!1)},e.prototype.onTap=function(e,t,n){var i=n.initialTarget +;return(!i||!i.tagName||"input"!==i.tagName.toLowerCase())&&this.onLeftClick(e,t,n,"touch")},e.prototype.onKeyDown=function(e,t){return this.onKey(this.downKeyBindingDispatcher,e,t)},e.prototype.onKeyUp=function(e,t){return this.onKey(this.upKeyBindingDispatcher,e,t)},e.prototype.onKey=function(e,t,n){var i=e.dispatch(n.toKeybinding());return!(!i||!i(t,n))&&(n.preventDefault(),n.stopPropagation(),!0)},e.prototype.onUp=function(e,t){var n={origin:"keyboard",originalEvent:t};return e.getHighlight()?e.clearHighlight(n):(e.focusPrevious(1,n),e.reveal(e.getFocus()).done(null,i.onUnexpectedError)),!0},e.prototype.onPageUp=function(e,t){var n={origin:"keyboard",originalEvent:t};return e.getHighlight()?e.clearHighlight(n):(e.focusPreviousPage(n),e.reveal(e.getFocus()).done(null,i.onUnexpectedError)),!0},e.prototype.onDown=function(e,t){var n={origin:"keyboard",originalEvent:t};return e.getHighlight()?e.clearHighlight(n):(e.focusNext(1,n),e.reveal(e.getFocus()).done(null,i.onUnexpectedError)),!0}, +e.prototype.onPageDown=function(e,t){var n={origin:"keyboard",originalEvent:t};return e.getHighlight()?e.clearHighlight(n):(e.focusNextPage(n),e.reveal(e.getFocus()).done(null,i.onUnexpectedError)),!0},e.prototype.onHome=function(e,t){var n={origin:"keyboard",originalEvent:t};return e.getHighlight()?e.clearHighlight(n):(e.focusFirst(n),e.reveal(e.getFocus()).done(null,i.onUnexpectedError)),!0},e.prototype.onEnd=function(e,t){var n={origin:"keyboard",originalEvent:t};return e.getHighlight()?e.clearHighlight(n):(e.focusLast(n),e.reveal(e.getFocus()).done(null,i.onUnexpectedError)),!0},e.prototype.onLeft=function(e,t){var n={origin:"keyboard",originalEvent:t};if(e.getHighlight())e.clearHighlight(n);else{var o=e.getFocus();e.collapse(o).then(function(t){if(o&&!t)return e.focusParent(n),e.reveal(e.getFocus())}).done(null,i.onUnexpectedError)}return!0},e.prototype.onRight=function(e,t){var n={origin:"keyboard",originalEvent:t};if(e.getHighlight())e.clearHighlight(n);else{var o=e.getFocus() +;e.expand(o).then(function(t){if(o&&!t)return e.focusFirstChild(n),e.reveal(e.getFocus())}).done(null,i.onUnexpectedError)}return!0},e.prototype.onEnter=function(e,t){var n={origin:"keyboard",originalEvent:t};if(e.getHighlight())return!1;var i=e.getFocus();return i&&e.setSelection([i],n),!0},e.prototype.onSpace=function(e,t){if(e.getHighlight())return!1;var n=e.getFocus();return n&&e.toggleExpansion(n),!0},e.prototype.onEscape=function(e,t){var n={origin:"keyboard",originalEvent:t};return e.getHighlight()?(e.clearHighlight(n),!0):e.getSelection().length?(e.clearSelection(n),!0):!!e.getFocus()&&(e.clearFocus(n),!0)},e}();t.DefaultController=u;var d=function(){function e(){}return e.prototype.getDragURI=function(e,t){return null},e.prototype.onDragStart=function(e,t,n){},e.prototype.onDragOver=function(e,t,n,i){return null},e.prototype.drop=function(e,t,n,i){},e}();t.DefaultDragAndDrop=d;var c=function(){function e(){}return e.prototype.isVisible=function(e,t){return!0},e}();t.DefaultFilter=c;var h=function(){ +function e(){}return e.prototype.getAriaLabel=function(e,t){return null},e}();t.DefaultAccessibilityProvider=h;var p=function(){function e(e,t){this.styleElement=e,this.selectorSuffix=t}return e.prototype.style=function(e){var t=this.selectorSuffix?"."+this.selectorSuffix:"",n=[];e.listFocusBackground&&n.push(".monaco-tree"+t+".focused .monaco-tree-rows > .monaco-tree-row.focused:not(.highlighted) { background-color: "+e.listFocusBackground+"; }"),e.listFocusForeground&&n.push(".monaco-tree"+t+".focused .monaco-tree-rows > .monaco-tree-row.focused:not(.highlighted) { color: "+e.listFocusForeground+"; }"),e.listActiveSelectionBackground&&n.push(".monaco-tree"+t+".focused .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) { background-color: "+e.listActiveSelectionBackground+"; }"),e.listActiveSelectionForeground&&n.push(".monaco-tree"+t+".focused .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) { color: "+e.listActiveSelectionForeground+"; }"), +e.listFocusAndSelectionBackground&&n.push("\n\t\t\t\t.monaco-tree-drag-image,\n\t\t\t\t.monaco-tree"+t+".focused .monaco-tree-rows > .monaco-tree-row.focused.selected:not(.highlighted) { background-color: "+e.listFocusAndSelectionBackground+"; }\n\t\t\t"),e.listFocusAndSelectionForeground&&n.push("\n\t\t\t\t.monaco-tree-drag-image,\n\t\t\t\t.monaco-tree"+t+".focused .monaco-tree-rows > .monaco-tree-row.focused.selected:not(.highlighted) { color: "+e.listFocusAndSelectionForeground+"; }\n\t\t\t"),e.listInactiveSelectionBackground&&n.push(".monaco-tree"+t+" .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) { background-color: "+e.listInactiveSelectionBackground+"; }"),e.listInactiveSelectionForeground&&n.push(".monaco-tree"+t+" .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) { color: "+e.listInactiveSelectionForeground+"; }"), +e.listHoverBackground&&n.push(".monaco-tree"+t+" .monaco-tree-rows > .monaco-tree-row:hover:not(.highlighted):not(.selected):not(.focused) { background-color: "+e.listHoverBackground+"; }"),e.listHoverForeground&&n.push(".monaco-tree"+t+" .monaco-tree-rows > .monaco-tree-row:hover:not(.highlighted):not(.selected):not(.focused) { color: "+e.listHoverForeground+"; }"),e.listDropBackground&&n.push("\n\t\t\t\t.monaco-tree"+t+" .monaco-tree-wrapper.drop-target,\n\t\t\t\t.monaco-tree"+t+" .monaco-tree-rows > .monaco-tree-row.drop-target { background-color: "+e.listDropBackground+" !important; color: inherit !important; }\n\t\t\t"), +e.listFocusOutline&&n.push("\n\t\t\t\t.monaco-tree-drag-image\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ border: 1px solid "+e.listFocusOutline+"; background: #000; }\n\t\t\t\t.monaco-tree"+t+" .monaco-tree-rows > .monaco-tree-row \t\t\t\t\t\t\t\t\t\t\t\t\t\t{ border: 1px solid transparent; }\n\t\t\t\t.monaco-tree"+t+".focused .monaco-tree-rows > .monaco-tree-row.focused:not(.highlighted) \t\t\t\t\t\t{ border: 1px dotted "+e.listFocusOutline+"; }\n\t\t\t\t.monaco-tree"+t+".focused .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) \t\t\t\t\t\t{ border: 1px solid "+e.listFocusOutline+"; }\n\t\t\t\t.monaco-tree"+t+" .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) \t\t\t\t\t\t\t{ border: 1px solid "+e.listFocusOutline+"; }\n\t\t\t\t.monaco-tree"+t+" .monaco-tree-rows > .monaco-tree-row:hover:not(.highlighted):not(.selected):not(.focused) \t{ border: 1px dashed "+e.listFocusOutline+"; }\n\t\t\t\t.monaco-tree"+t+" .monaco-tree-wrapper.drop-target,\n\t\t\t\t.monaco-tree"+t+" .monaco-tree-rows > .monaco-tree-row.drop-target\t\t\t\t\t\t\t\t\t\t\t\t{ border: 1px dashed "+e.listFocusOutline+"; }\n\t\t\t") +;var i=n.join("\n");i!==this.styleElement.innerHTML&&(this.styleElement.innerHTML=i)},e}();t.DefaultTreestyler=p}),define(t[454],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e){this.elements=e}return e.prototype.update=function(e){},e}();t.ElementsDragAndDropData=n;var i=function(){function e(e){this.elements=e}return e.prototype.update=function(e){},e}();t.ExternalElementsDragAndDropData=i;var o=function(){function e(){this.types=[],this.files=[]}return e.prototype.update=function(e){e.dataTransfer.types&&(this.types=[],Array.prototype.push.apply(this.types,e.dataTransfer.types)),e.dataTransfer.files&&(this.files=[],Array.prototype.push.apply(this.files,e.dataTransfer.files),this.files=this.files.filter(function(e){return e.size||e.type}))},e}();t.DesktopDragAndDropData=o}),define(t[463],n([1,0,85,10,2,13,9]),function(e,t,n,i,r,s,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e){ +this._onDispose=new a.Emitter,this.onDispose=this._onDispose.event,this._item=e}return Object.defineProperty(e.prototype,"item",{get:function(){return this._item},enumerable:!0,configurable:!0}),e.prototype.dispose=function(){this._onDispose&&(this._onDispose.fire(),this._onDispose.dispose(),this._onDispose=null)},e}();t.LockData=l;var u=function(){function e(){this.locks=Object.create({})}return e.prototype.isLocked=function(e){return!!this.locks[e.id]},e.prototype.run=function(e,t){var n=this,i=this.getLock(e);if(i){var o;return new s.TPromise(function(r,s){o=a.once(i.onDispose)(function(){return n.run(e,t).then(r,s)})},function(){o.dispose()})}var r;return new s.TPromise(function(i,o){if(e.isDisposed())return o(new Error("Item is disposed."));var s=n.locks[e.id]=new l(e);return r=t().then(function(t){return delete n.locks[e.id],s.dispose(),t}).then(i,o)},function(){return r.cancel()})},e.prototype.getLock=function(e){var t;for(t in this.locks){var n=this.locks[t];if(e.intersects(n.item))return n} +return null},e}();t.Lock=u;var d=function(){function e(){this._isDisposed=!1,this._onDidRevealItem=new a.EventMultiplexer,this.onDidRevealItem=this._onDidRevealItem.event,this._onExpandItem=new a.EventMultiplexer,this.onExpandItem=this._onExpandItem.event,this._onDidExpandItem=new a.EventMultiplexer,this.onDidExpandItem=this._onDidExpandItem.event,this._onCollapseItem=new a.EventMultiplexer,this.onCollapseItem=this._onCollapseItem.event,this._onDidCollapseItem=new a.EventMultiplexer,this.onDidCollapseItem=this._onDidCollapseItem.event,this._onDidAddTraitItem=new a.EventMultiplexer,this.onDidAddTraitItem=this._onDidAddTraitItem.event,this._onDidRemoveTraitItem=new a.EventMultiplexer,this.onDidRemoveTraitItem=this._onDidRemoveTraitItem.event,this._onDidRefreshItem=new a.EventMultiplexer,this.onDidRefreshItem=this._onDidRefreshItem.event,this._onRefreshItemChildren=new a.EventMultiplexer,this.onRefreshItemChildren=this._onRefreshItemChildren.event,this._onDidRefreshItemChildren=new a.EventMultiplexer, +this.onDidRefreshItemChildren=this._onDidRefreshItemChildren.event,this._onDidDisposeItem=new a.EventMultiplexer,this.onDidDisposeItem=this._onDidDisposeItem.event,this.items={}}return e.prototype.register=function(e){n.ok(!this.isRegistered(e.id),"item already registered: "+e.id);var t=r.combinedDisposable([this._onDidRevealItem.add(e.onDidReveal),this._onExpandItem.add(e.onExpand),this._onDidExpandItem.add(e.onDidExpand),this._onCollapseItem.add(e.onCollapse),this._onDidCollapseItem.add(e.onDidCollapse),this._onDidAddTraitItem.add(e.onDidAddTrait),this._onDidRemoveTraitItem.add(e.onDidRemoveTrait),this._onDidRefreshItem.add(e.onDidRefresh),this._onRefreshItemChildren.add(e.onRefreshChildren),this._onDidRefreshItemChildren.add(e.onDidRefreshChildren),this._onDidDisposeItem.add(e.onDidDispose)]);this.items[e.id]={item:e,disposable:t}},e.prototype.deregister=function(e){n.ok(this.isRegistered(e.id),"item not registered: "+e.id),this.items[e.id].disposable.dispose(),delete this.items[e.id]}, +e.prototype.isRegistered=function(e){return this.items.hasOwnProperty(e)},e.prototype.getItem=function(e){var t=this.items[e];return t?t.item:null},e.prototype.dispose=function(){this.items=null,this._onDidRevealItem.dispose(),this._onExpandItem.dispose(),this._onDidExpandItem.dispose(),this._onCollapseItem.dispose(),this._onDidCollapseItem.dispose(),this._onDidAddTraitItem.dispose(),this._onDidRemoveTraitItem.dispose(),this._onDidRefreshItem.dispose(),this._onRefreshItemChildren.dispose(),this._onDidRefreshItemChildren.dispose(),this._isDisposed=!0},e.prototype.isDisposed=function(){return this._isDisposed},e}();t.ItemRegistry=d;var c=function(){function e(e,t,n,i,o){this._onDidCreate=new a.Emitter,this._onDidReveal=new a.Emitter,this.onDidReveal=this._onDidReveal.event,this._onExpand=new a.Emitter,this.onExpand=this._onExpand.event,this._onDidExpand=new a.Emitter,this.onDidExpand=this._onDidExpand.event,this._onCollapse=new a.Emitter,this.onCollapse=this._onCollapse.event,this._onDidCollapse=new a.Emitter, +this.onDidCollapse=this._onDidCollapse.event,this._onDidAddTrait=new a.Emitter,this.onDidAddTrait=this._onDidAddTrait.event,this._onDidRemoveTrait=new a.Emitter,this.onDidRemoveTrait=this._onDidRemoveTrait.event,this._onDidRefresh=new a.Emitter,this.onDidRefresh=this._onDidRefresh.event,this._onRefreshChildren=new a.Emitter,this.onRefreshChildren=this._onRefreshChildren.event,this._onDidRefreshChildren=new a.Emitter,this.onDidRefreshChildren=this._onDidRefreshChildren.event,this._onDidDispose=new a.Emitter,this.onDidDispose=this._onDidDispose.event,this.registry=t,this.context=n,this.lock=i,this.element=o,this.id=e,this.registry.register(this),this.doesHaveChildren=this.context.dataSource.hasChildren(this.context.tree,this.element),this.needsChildrenRefresh=!0,this.parent=null,this.previous=null,this.next=null,this.firstChild=null,this.lastChild=null,this.traits={},this.depth=0,this.expanded=this.context.dataSource.shouldAutoexpand&&this.context.dataSource.shouldAutoexpand(this.context.tree,o), +this._onDidCreate.fire(this),this.visible=this._isVisible(),this.height=this._getHeight(),this._isDisposed=!1}return e.prototype.getElement=function(){return this.element},e.prototype.hasChildren=function(){return this.doesHaveChildren},e.prototype.getDepth=function(){return this.depth},e.prototype.isVisible=function(){return this.visible},e.prototype.setVisible=function(e){this.visible=e},e.prototype.isExpanded=function(){return this.expanded},e.prototype._setExpanded=function(e){this.expanded=e},e.prototype.reveal=function(e){void 0===e&&(e=null);var t={item:this,relativeTop:e};this._onDidReveal.fire(t)},e.prototype.expand=function(){var e=this;if(this.isExpanded()||!this.doesHaveChildren||this.lock.isLocked(this))return s.TPromise.as(!1);return this.lock.run(this,function(){var t={item:e};return e._onExpand.fire(t),(e.needsChildrenRefresh?e.refreshChildren(!1,!0,!0):s.TPromise.as(null)).then(function(){return e._setExpanded(!0),e._onDidExpand.fire(t),!0})}).then(function(t){ +return!e.isDisposed()&&(e.context.options.autoExpandSingleChildren&&t&&null!==e.firstChild&&e.firstChild===e.lastChild&&e.firstChild.isVisible()?e.firstChild.expand().then(function(){return!0}):t)})},e.prototype.collapse=function(e){var t=this;if(void 0===e&&(e=!1),e){var n=s.TPromise.as(null);return this.forEachChild(function(e){n=n.then(function(){return e.collapse(!0)})}),n.then(function(){return t.collapse(!1)})}return!this.isExpanded()||this.lock.isLocked(this)?s.TPromise.as(!1):this.lock.run(this,function(){var e={item:t};return t._onCollapse.fire(e),t._setExpanded(!1),t._onDidCollapse.fire(e),s.TPromise.as(!0)})},e.prototype.addTrait=function(e){var t={item:this,trait:e};this.traits[e]=!0,this._onDidAddTrait.fire(t)},e.prototype.removeTrait=function(e){var t={item:this,trait:e};delete this.traits[e],this._onDidRemoveTrait.fire(t)},e.prototype.hasTrait=function(e){return this.traits[e]||!1},e.prototype.getAllTraits=function(){var e,t=[] +;for(e in this.traits)this.traits.hasOwnProperty(e)&&this.traits[e]&&t.push(e);return t},e.prototype.getHeight=function(){return this.height},e.prototype.refreshChildren=function(t,n,o){var r=this;if(void 0===n&&(n=!1),void 0===o&&(o=!1),!o&&!this.isExpanded())return this.needsChildrenRefresh=!0,s.TPromise.as(this);this.needsChildrenRefresh=!1;var a=function(){var o={item:r,isNested:n};r._onRefreshChildren.fire(o);return(r.doesHaveChildren?r.context.dataSource.getChildren(r.context.tree,r.element):s.TPromise.as([])).then(function(n){if(r.isDisposed()||r.registry.isDisposed())return s.TPromise.as(null);if(!Array.isArray(n))return s.TPromise.wrapError(new Error("Please return an array of children."));n=n?n.slice(0):[],n=r.sort(n);for(var i={};null!==r.firstChild;)i[r.firstChild.id]=r.firstChild,r.removeChild(r.firstChild);for(var o=0,a=n.length;o=0;r--)this.onInsertItem(u[r]);for(r=this.heightMap.length-1;r>=o;r--)this.onRefreshItem(this.heightMap[r]);return a},e.prototype.onInsertItem=function(e){},e.prototype.onRemoveItems=function(e){for(var t,n,i,o=null,r=0;t=e.next();){if(i=this.indexes[t],!(n=this.heightMap[i]))return void console.error("view item doesnt exist");r-=n.height,delete this.indexes[t],this.onRemoveItem(n),null===o&&(o=i)}if(0!==r)for(this.heightMap.splice(o,i-o+1),i=o;i=n.top+n.height))return t;if(i===t)break;i=t}return this.heightMap.length},e.prototype.indexAfter=function(e){return Math.min(this.indexAt(e)+1,this.heightMap.length)}, +e.prototype.itemAtIndex=function(e){return this.heightMap[e]},e.prototype.itemAfter=function(e){return this.heightMap[this.indexes[e.model.id]+1]||null},e.prototype.createViewItem=function(e){throw new Error("not implemented")},e.prototype.dispose=function(){this.heightMap=null,this.indexes=null},e}();t.HeightMap=i}),define(t[470],n([1,0,18,160]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function t(t,i,o,r,s){this.id=i,this.worker=function(t,i){if(n.globals.MonacoEnvironment){if("function"==typeof n.globals.MonacoEnvironment.getWorker)return n.globals.MonacoEnvironment.getWorker(t,i);if("function"==typeof n.globals.MonacoEnvironment.getWorkerUrl)return new Worker(n.globals.MonacoEnvironment.getWorkerUrl(t,i))}if("function"==typeof e)return new Worker(e.toUrl("./"+t)+"#"+i);throw new Error("You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker")}("workerMain.js",o),this.postMessage(t),this.worker.onmessage=function(e){ +r(e.data)},"function"==typeof this.worker.addEventListener&&this.worker.addEventListener("error",s)}return t.prototype.getId=function(){return this.id},t.prototype.postMessage=function(e){this.worker&&this.worker.postMessage(e)},t.prototype.dispose=function(){this.worker.terminate(),this.worker=null},t}(),r=function(){function e(e){this._label=e,this._webWorkerFailedBeforeError=!1}return e.prototype.create=function(t,n,r){var s=this,a=++e.LAST_WORKER_ID;if(this._webWorkerFailedBeforeError)throw this._webWorkerFailedBeforeError;return new o(t,a,this._label||"anonymous"+a,n,function(e){i.logOnceWebWorkerWarning(e),s._webWorkerFailedBeforeError=e,r(e)})},e.LAST_WORKER_ID=0,e}();t.DefaultWorkerFactory=r}),define(t[472],n([8]),{}),define(t[56],n([1,0,33,2,6,85,7,472]),function(e,t,n,i,r,s,a){"use strict";function l(e){return e[f]||(e[f]={}),e[f]}function u(e){return!!e[f]}function d(e,t){return new g(e,t)}function c(){return new g(null,!0)}function h(e,t,n){l(e)[t]=n}function p(e,t,i){if(u(e)){var o=l(e)[t] +;if(!n.isUndefined(o))return o}return i}Object.defineProperty(t,"__esModule",{value:!0});var f="_msDataKey",g=function(){function e(e,t){this.offdom=t,this.container=e,this.currentElement=e,this.createdElements=[],this.toDispose={},this.captureToDispose={}}return e.prototype.clone=function(){var t=new e(this.container,this.offdom);return t.currentElement=this.currentElement,t.createdElements=this.createdElements,t.captureToDispose=this.captureToDispose,t.toDispose=this.toDispose,t},e.prototype.build=function(t,i){s.ok(this.offdom,"This builder was not created off-dom, so build() can not be called."),t?t instanceof e&&(t=t.getHTMLElement()):t=this.container,s.ok(t,"Builder can only be build() with a container provided."),s.ok(a.isHTMLElement(t),"The container must either be a HTMLElement or a Builder.");var o,r,l=t,u=l.childNodes;if(n.isNumber(i)&&i=0){var n=e.split("-");e=n[0];for(var i=1;i=0){var t=e.split("-");e=t[0];for(var n=1;n=this.el.clientHeight-4&&(r=this.orthogonalEndSash):e.offsetX<=4?r=this.orthogonalStartSash:e.offsetX>=this.el.clientWidth-4&&(r=this.orthogonalEndSash),r&&(i=!0,e.__orthogonalSashEvent=!0,r.onMouseDown(e))}if(this.state){for(var s=0,l=u.getElementsByTagName("iframe");s0&&Math.abs(e.deltaY)>0)return 1;var t=.5;-1===this._front&&-1===this._rear||this._memory[this._rear];return(Math.abs(e.deltaX-Math.round(e.deltaX))>0||Math.abs(e.deltaY-Math.round(e.deltaY))>0)&&(t+=.25),Math.min(Math.max(t,0),1)},e.INSTANCE=new e,e}();t.MouseWheelClassifier=m;var v=function(e){function t(t,n,i){var o=e.call(this)||this;o._onScroll=o._register(new p.Emitter),o.onScroll=o._onScroll.event,t.style.overflow="hidden",o._options=f(n),o._scrollable=i,o._register(o._scrollable.onScroll(function(e){o._onDidScroll(e),o._onScroll.fire(e)}));var r={onMouseWheel:function(e){return o._onMouseWheel(e)},onDragStart:function(){return o._onDragStart()},onDragEnd:function(){return o._onDragEnd()}};return o._verticalScrollbar=o._register(new a.VerticalScrollbar(o._scrollable,o._options,r)), +o._horizontalScrollbar=o._register(new s.HorizontalScrollbar(o._scrollable,o._options,r)),o._domNode=document.createElement("div"),o._domNode.className="monaco-scrollable-element "+o._options.className,o._domNode.setAttribute("role","presentation"),o._domNode.style.position="relative",o._domNode.style.overflow="hidden",o._domNode.appendChild(t),o._domNode.appendChild(o._horizontalScrollbar.domNode.domNode),o._domNode.appendChild(o._verticalScrollbar.domNode.domNode),o._options.useShadows&&(o._leftShadowDomNode=h.createFastDomNode(document.createElement("div")),o._leftShadowDomNode.setClassName("shadow"),o._domNode.appendChild(o._leftShadowDomNode.domNode),o._topShadowDomNode=h.createFastDomNode(document.createElement("div")),o._topShadowDomNode.setClassName("shadow"),o._domNode.appendChild(o._topShadowDomNode.domNode),o._topLeftShadowDomNode=h.createFastDomNode(document.createElement("div")),o._topLeftShadowDomNode.setClassName("shadow top-left-corner"), +o._domNode.appendChild(o._topLeftShadowDomNode.domNode)),o._listenOnDomNode=o._options.listenOnDomNode||o._domNode,o._mouseWheelToDispose=[],o._setListeningToMouseWheel(o._options.handleMouseWheel),o.onmouseover(o._listenOnDomNode,function(e){return o._onMouseOver(e)}),o.onnonbubblingmouseout(o._listenOnDomNode,function(e){return o._onMouseOut(e)}),o._hideTimeout=o._register(new c.TimeoutTimer),o._isDragging=!1,o._mouseIsOver=!1,o._shouldRender=!0,o._revealOnScroll=!0,o}return o(t,e),t.prototype.dispose=function(){this._mouseWheelToDispose=l.dispose(this._mouseWheelToDispose),e.prototype.dispose.call(this)},t.prototype.getDomNode=function(){return this._domNode},t.prototype.getOverviewRulerLayoutInfo=function(){return{parent:this._domNode,insertBefore:this._verticalScrollbar.domNode.domNode}},t.prototype.delegateVerticalScrollbarMouseDown=function(e){this._verticalScrollbar.delegateMouseDown(e)},t.prototype.getScrollDimensions=function(){return this._scrollable.getScrollDimensions()}, +t.prototype.setScrollDimensions=function(e){this._scrollable.setScrollDimensions(e)},t.prototype.updateClassName=function(e){this._options.className=e,i.isMacintosh&&(this._options.className+=" mac"),this._domNode.className="monaco-scrollable-element "+this._options.className},t.prototype.updateOptions=function(e){var t=f(e);this._options.handleMouseWheel=t.handleMouseWheel,this._options.mouseWheelScrollSensitivity=t.mouseWheelScrollSensitivity,this._setListeningToMouseWheel(this._options.handleMouseWheel),this._options.lazyRender||this._render()},t.prototype._setListeningToMouseWheel=function(e){var t=this;if(this._mouseWheelToDispose.length>0!==e&&(this._mouseWheelToDispose=l.dispose(this._mouseWheelToDispose),e)){var i=function(e){var n=new r.StandardMouseWheelEvent(e);t._onMouseWheel(n)};this._mouseWheelToDispose.push(n.addDisposableListener(this._listenOnDomNode,"mousewheel",i)),this._mouseWheelToDispose.push(n.addDisposableListener(this._listenOnDomNode,"DOMMouseScroll",i))}}, +t.prototype._onMouseWheel=function(e){var t,n=m.INSTANCE;if(n.accept(Date.now(),e.deltaX,e.deltaY),e.deltaY||e.deltaX){var o=e.deltaY*this._options.mouseWheelScrollSensitivity,r=e.deltaX*this._options.mouseWheelScrollSensitivity;this._options.flipAxes&&(o=(t=[r,o])[0],r=t[1]);var s=!i.isMacintosh&&e.browserEvent&&e.browserEvent.shiftKey;!this._options.scrollYToX&&!s||r||(r=o,o=0);var a=this._scrollable.getFutureScrollPosition(),l={};if(o){var u=a.scrollTop-50*o;this._verticalScrollbar.writeScrollPosition(l,u)}if(r){var d=a.scrollLeft-50*r;this._horizontalScrollbar.writeScrollPosition(l,d)}if(l=this._scrollable.validateScrollPosition(l),a.scrollLeft!==l.scrollLeft||a.scrollTop!==l.scrollTop){this._options.mouseWheelSmoothScroll&&n.isPhysicalMouseWheel()?this._scrollable.setScrollPositionSmooth(l):this._scrollable.setScrollPositionNow(l),this._shouldRender=!0}}(this._options.alwaysConsumeMouseWheel||this._shouldRender)&&(e.preventDefault(),e.stopPropagation())},t.prototype._onDidScroll=function(e){ +this._shouldRender=this._horizontalScrollbar.onDidScroll(e)||this._shouldRender,this._shouldRender=this._verticalScrollbar.onDidScroll(e)||this._shouldRender,this._options.useShadows&&(this._shouldRender=!0),this._revealOnScroll&&this._reveal(),this._options.lazyRender||this._render()},t.prototype.renderNow=function(){if(!this._options.lazyRender)throw new Error("Please use `lazyRender` together with `renderNow`!");this._render()},t.prototype._render=function(){if(this._shouldRender&&(this._shouldRender=!1,this._horizontalScrollbar.render(),this._verticalScrollbar.render(),this._options.useShadows)){var e=this._scrollable.getCurrentScrollPosition(),t=e.scrollTop>0,n=e.scrollLeft>0;this._leftShadowDomNode.setClassName("shadow"+(n?" left":"")),this._topShadowDomNode.setClassName("shadow"+(t?" top":"")),this._topLeftShadowDomNode.setClassName("shadow top-left-corner"+(t?" top":"")+(n?" left":""))}},t.prototype._onDragStart=function(){this._isDragging=!0,this._reveal()},t.prototype._onDragEnd=function(){ +this._isDragging=!1,this._hide()},t.prototype._onMouseOut=function(e){this._mouseIsOver=!1,this._hide()},t.prototype._onMouseOver=function(e){this._mouseIsOver=!0,this._reveal()},t.prototype._reveal=function(){this._verticalScrollbar.beginReveal(),this._horizontalScrollbar.beginReveal(),this._scheduleHide()},t.prototype._hide=function(){this._mouseIsOver||this._isDragging||(this._verticalScrollbar.beginHide(),this._horizontalScrollbar.beginHide())},t.prototype._scheduleHide=function(){var e=this;this._mouseIsOver||this._isDragging||this._hideTimeout.cancelAndSet(function(){return e._hide()},500)},t}(d.Widget);t.AbstractScrollableElement=v;var _=function(e){function t(t,i){var o=this;(i=i||{}).mouseWheelSmoothScroll=!1;var r=new u.Scrollable(0,function(e){return n.scheduleAtNextAnimationFrame(e)});return(o=e.call(this,t,i,r)||this)._register(r),o}return o(t,e),t.prototype.setScrollPosition=function(e){this._scrollable.setScrollPositionNow(e)},t.prototype.getScrollPosition=function(){ +return this._scrollable.getCurrentScrollPosition()},t}(v);t.ScrollableElement=_;var y=function(e){function t(t,n,i){return e.call(this,t,n,i)||this}return o(t,e),t}(v);t.SmoothScrollableElement=y;var C=function(e){function t(t,n){var i=e.call(this,t,n)||this;return i._element=t,i.onScroll(function(e){e.scrollTopChanged&&(i._element.scrollTop=e.scrollTop),e.scrollLeftChanged&&(i._element.scrollLeft=e.scrollLeft)}),i.scanDomNode(),i}return o(t,e),t.prototype.scanDomNode=function(){this.setScrollDimensions({width:this._element.clientWidth,scrollWidth:this._element.scrollWidth,height:this._element.clientHeight,scrollHeight:this._element.scrollHeight}),this.setScrollPosition({scrollLeft:this._element.scrollLeft,scrollTop:this._element.scrollTop})},t}(_);t.DomScrollableElement=C}),define(t[240],n([1,0,28,2,74,7,9,87,55,43,237,253,18,30,111,42]),function(e,t,n,i,o,r,s,l,u,d,c,h,p,f,g,m){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var v={useShadows:!0,verticalScrollMode:d.ScrollbarVisibility.Auto +},_=function(){function e(e,t,i,r){void 0===r&&(r=v),this.virtualDelegate=t,this.renderers=new Map,this.splicing=!1,this.items=[],this.itemId=0,this.rangeMap=new c.RangeMap;for(var a=0,p=i;a=0})},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onMouseDblClick",{get:function(){var e=this;return s.filterEvent(s.mapEvent(l.domEvent(this.domNode,"dblclick"),function(t){return e.toMouseEvent(t)}),function(e){return e.index>=0})},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onMouseDown",{get:function(){var e=this;return s.filterEvent(s.mapEvent(l.domEvent(this.domNode,"mousedown"),function(t){return e.toMouseEvent(t)}),function(e){return e.index>=0})},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onContextMenu",{get:function(){var e=this;return s.filterEvent(s.mapEvent(l.domEvent(this.domNode,"contextmenu"),function(t){return e.toMouseEvent(t)}),function(e){return e.index>=0})},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onTouchStart",{get:function(){var e=this +;return s.filterEvent(s.mapEvent(l.domEvent(this.domNode,"touchstart"),function(t){return e.toTouchEvent(t)}),function(e){return e.index>=0})},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onTap",{get:function(){var e=this;return s.filterEvent(s.mapEvent(l.domEvent(this.rowsContainer,o.EventType.Tap),function(t){return e.toGestureEvent(t)}),function(e){return e.index>=0})},enumerable:!0,configurable:!0}),e.prototype.toMouseEvent=function(e){var t=this.getItemIndexFromEventTarget(e.target),n=t<0?void 0:this.items[t];return{browserEvent:e,index:t,element:n&&n.element}},e.prototype.toTouchEvent=function(e){var t=this.getItemIndexFromEventTarget(e.target),n=t<0?void 0:this.items[t];return{browserEvent:e,index:t,element:n&&n.element}},e.prototype.toGestureEvent=function(e){var t=this.getItemIndexFromEventTarget(e.initialTarget),n=t<0?void 0:this.items[t];return{browserEvent:e,index:t,element:n&&n.element}},e.prototype.onScroll=function(e){try{this.render(e.scrollTop,e.height)}catch(t){ +throw console.log("Got bad scroll event:",e),t}},e.prototype.onTouchChange=function(e){e.preventDefault(),e.stopPropagation(),this.scrollTop-=e.translationY},e.prototype.onDragOver=function(e){this.setupDragAndDropScrollInterval(),this.dragAndDropMouseY=e.posy},e.prototype.setupDragAndDropScrollInterval=function(){var e=this,t=r.getTopLeftOffset(this._domNode).top;this.dragAndDropScrollInterval||(this.dragAndDropScrollInterval=window.setInterval(function(){if(void 0!==e.dragAndDropMouseY){var n=e.dragAndDropMouseY-t,i=0,o=e.renderHeight-35;n<35?i=Math.max(-14,.2*(n-35)):n>o&&(i=Math.min(14,.2*(n-o))),e.scrollTop+=i}},10),this.cancelDragAndDropScrollTimeout(),this.dragAndDropScrollTimeout=window.setTimeout(function(){e.cancelDragAndDropScrollInterval(),e.dragAndDropScrollTimeout=null},1e3))},e.prototype.cancelDragAndDropScrollInterval=function(){this.dragAndDropScrollInterval&&(window.clearInterval(this.dragAndDropScrollInterval),this.dragAndDropScrollInterval=null),this.cancelDragAndDropScrollTimeout()}, +e.prototype.cancelDragAndDropScrollTimeout=function(){this.dragAndDropScrollTimeout&&(window.clearTimeout(this.dragAndDropScrollTimeout),this.dragAndDropScrollTimeout=null)},e.prototype.getItemIndexFromEventTarget=function(e){for(;e instanceof HTMLElement&&e!==this.rowsContainer;){var t=e,n=t.getAttribute("data-index");if(n){var i=Number(n);if(!isNaN(i))return i}e=t.parentElement}return-1},e.prototype.getRenderRange=function(e,t){return{start:this.rangeMap.indexAt(e),end:this.rangeMap.indexAfter(e+t-1)}},e.prototype.getNextToLastElement=function(e){var t=e[e.length-1];if(!t)return null;var n=this.items[t.end];return n&&n.row?n.row.domNode:null},e.prototype.dispose=function(){if(this.items){for(var e=0,t=this.items;e=s;r--)this.insertItemInDOM(this.itemAtIndex(r));for(r=Math.min(this.indexAt(this.lastRenderTop),this.indexAfter(l))-1,s=this.indexAt(a);r>=s;r--)this.insertItemInDOM(this.itemAtIndex(r));for(r=this.indexAt(this.lastRenderTop),s=Math.min(this.indexAt(a),this.indexAfter(u));r1e3,d=void 0,c=void 0;if(!u){c=(d=new l.LcsDiff({getLength:function(){return r.length},getElementAtIndex:function(e){return r[e]}},{getLength:function(){return s.length},getElementAtIndex:function(e){return s[e].id}},null).ComputeDiff(!1)).some(function(e){if(e.modifiedLength>0)for(var n=e.modifiedStart,i=e.modifiedStart+e.modifiedLength;n0&&this.onRemoveItems(new f.ArrayIterator(r,g.originalStart,g.originalStart+g.originalLength)),g.modifiedLength>0){var m=s[g.modifiedStart-1]||n;m=m.getDepth()>0?m:null,this.onInsertItems(new f.ArrayIterator(s,g.modifiedStart,g.modifiedStart+g.modifiedLength),m?m.id:null)}}else(u||d.length)&&(this.onRemoveItems(new f.ArrayIterator(r)),this.onInsertItems(new f.ArrayIterator(s),n.getDepth()>0?n.id:null));(u||d.length)&&this.onRowsChanged()}},t.prototype.onItemRefresh=function(e){ +this.onItemsRefresh([e])},t.prototype.onItemsRefresh=function(e){var t=this;this.onRefreshItemSet(e.filter(function(e){return t.items.hasOwnProperty(e.id)})),this.onRowsChanged()},t.prototype.onItemExpanding=function(e){var t=this.items[e.item.id];t&&(t.expanded=!0)},t.prototype.onItemExpanded=function(e){var t=e.item,n=this.items[t.id];if(n){n.expanded=!0;var i=this.onInsertItems(t.getNavigator(),t.id),o=this.scrollTop;n.top+n.height<=this.scrollTop&&(o+=i),this.onRowsChanged(o)}},t.prototype.onItemCollapsing=function(e){var t=e.item,n=this.items[t.id];n&&(n.expanded=!1,this.onRemoveItems(new f.MappedIterator(t.getNavigator(),function(e){return e&&e.id})),this.onRowsChanged())},t.prototype.onItemReveal=function(e){var t=e.item,n=e.relativeTop,i=this.items[t.id];if(i)if(null!==n){n=(n=n<0?0:n)>1?1:n;var o=i.height-this.viewHeight;this.scrollTop=o*n+i.top}else{var r=i.top+i.height,s=this.scrollTop+this.viewHeight;i.top=s&&(this.scrollTop=r-this.viewHeight)}}, +t.prototype.onItemAddTrait=function(e){var t=e.item,n=e.trait,i=this.items[t.id];i&&i.addClass(n),"highlighted"===n&&(a.addClass(this.domNode,n),i&&(this.highlightedItemWasDraggable=!!i.draggable,i.draggable&&(i.draggable=!1)))},t.prototype.onItemRemoveTrait=function(e){var t=e.item,n=e.trait,i=this.items[t.id];i&&i.removeClass(n),"highlighted"===n&&(a.removeClass(this.domNode,n),this.highlightedItemWasDraggable&&(i.draggable=!0),this.highlightedItemWasDraggable=!1)},t.prototype.onModelFocusChange=function(){var e=this.model&&this.model.getFocus();a.toggleClass(this.domNode,"no-focused-item",!e),e?this.domNode.setAttribute("aria-activedescendant",d.safeBtoa(this.context.dataSource.getId(this.context.tree,e))):this.domNode.removeAttribute("aria-activedescendant")},t.prototype.onInsertItem=function(e){var t=this;e.onDragStart=function(n){t.onDragStart(e,n)},e.needsRender=!0,this.refreshViewItem(e),this.items[e.id]=e},t.prototype.onRefreshItem=function(e,t){void 0===t&&(t=!1),e.needsRender=e.needsRender||t, +this.refreshViewItem(e)},t.prototype.onRemoveItem=function(e){this.removeItemFromDOM(e),e.dispose(),delete this.items[e.id]},t.prototype.refreshViewItem=function(e){e.render(),this.shouldBeRendered(e)?this.insertItemInDOM(e):this.removeItemFromDOM(e)},t.prototype.onClick=function(e){if(!this.lastPointerType||"mouse"===this.lastPointerType){var t=new c.StandardMouseEvent(e),n=this.getItemAround(t.target);n&&(i.isIE&&Date.now()-this.lastClickTimeStamp<300&&(t.detail=2),this.lastClickTimeStamp=Date.now(),this.context.controller.onClick(this.context.tree,n.model.getElement(),t))}},t.prototype.onMouseDown=function(e){if(this.didJustPressContextMenuKey=!1,this.context.controller.onMouseDown&&(!this.lastPointerType||"mouse"===this.lastPointerType)){var t=new c.StandardMouseEvent(e);if(!(t.ctrlKey&&n.isNative&&n.isMacintosh)){var i=this.getItemAround(t.target);i&&this.context.controller.onMouseDown(this.context.tree,i.model.getElement(),t)}}},t.prototype.onMouseUp=function(e){ +if(this.context.controller.onMouseUp&&(!this.lastPointerType||"mouse"===this.lastPointerType)){var t=new c.StandardMouseEvent(e);if(!(t.ctrlKey&&n.isNative&&n.isMacintosh)){var i=this.getItemAround(t.target);i&&this.context.controller.onMouseUp(this.context.tree,i.model.getElement(),t)}}},t.prototype.onTap=function(e){var t=this.getItemAround(e.initialTarget);t&&this.context.controller.onTap(this.context.tree,t.model.getElement(),e)},t.prototype.onTouchChange=function(e){e.preventDefault(),e.stopPropagation(),this.scrollTop-=e.translationY},t.prototype.onContextMenu=function(e){var t,n;if(e instanceof KeyboardEvent||this.didJustPressContextMenuKey){this.didJustPressContextMenuKey=!1;var i,o=new h.StandardKeyboardEvent(e);if(n=this.model.getFocus()){var r=this.context.dataSource.getId(this.context.tree,n),s=this.items[r];i=a.getDomNodePagePosition(s.element)}else n=this.model.getInput(),i=a.getDomNodePagePosition(this.inputItem.element);t=new _.KeyboardContextMenuEvent(i.left+i.width,i.top,o)}else{ +var l=new c.StandardMouseEvent(e),u=this.getItemAround(l.target);if(!u)return;n=u.model.getElement(),t=new _.MouseContextMenuEvent(l)}this.context.controller.onContextMenu(this.context.tree,n,t)},t.prototype.onKeyDown=function(e){var t=new h.StandardKeyboardEvent(e);this.didJustPressContextMenuKey=58===t.keyCode||t.shiftKey&&68===t.keyCode,this.didJustPressContextMenuKey&&(t.preventDefault(),t.stopPropagation()),t.target&&t.target.tagName&&"input"===t.target.tagName.toLowerCase()||this.context.controller.onKeyDown(this.context.tree,t)},t.prototype.onKeyUp=function(e){this.didJustPressContextMenuKey&&this.onContextMenu(e),this.didJustPressContextMenuKey=!1,this.context.controller.onKeyUp(this.context.tree,new h.StandardKeyboardEvent(e))},t.prototype.onDragStart=function(e,n){if(!this.model.getHighlight()){var i,o=e.model.getElement(),r=this.model.getSelection();if(i=r.indexOf(o)>-1?r:[o],n.dataTransfer.effectAllowed="copyMove",n.dataTransfer.setData(C.DataTransfers.RESOURCES,JSON.stringify([e.uri])), +n.dataTransfer.setDragImage){var s=void 0;s=this.context.dnd.getDragLabel?this.context.dnd.getDragLabel(this.context.tree,i):String(i.length);var a=document.createElement("div");a.className="monaco-tree-drag-image",a.textContent=s,document.body.appendChild(a),n.dataTransfer.setDragImage(a,-10,-10),setTimeout(function(){return document.body.removeChild(a)},0)}this.currentDragAndDropData=new p.ElementsDragAndDropData(i),t.currentExternalDragAndDropData=new p.ExternalElementsDragAndDropData(i),this.context.dnd.onDragStart(this.context.tree,this.currentDragAndDropData,new c.DragMouseEvent(n))}},t.prototype.setupDragAndDropScrollInterval=function(){var e=this,t=a.getTopLeftOffset(this.wrapper).top;this.dragAndDropScrollInterval||(this.dragAndDropScrollInterval=window.setInterval(function(){if(void 0!==e.dragAndDropMouseY){var n=e.dragAndDropMouseY-t,i=0,o=e.viewHeight-35;n<35?i=Math.max(-14,.2*(n-35)):n>o&&(i=Math.min(14,.2*(n-o))),e.scrollTop+=i}},10),this.cancelDragAndDropScrollTimeout(), +this.dragAndDropScrollTimeout=window.setTimeout(function(){e.cancelDragAndDropScrollInterval(),e.dragAndDropScrollTimeout=null},1e3))},t.prototype.cancelDragAndDropScrollInterval=function(){this.dragAndDropScrollInterval&&(window.clearInterval(this.dragAndDropScrollInterval),this.dragAndDropScrollInterval=null),this.cancelDragAndDropScrollTimeout()},t.prototype.cancelDragAndDropScrollTimeout=function(){this.dragAndDropScrollTimeout&&(window.clearTimeout(this.dragAndDropScrollTimeout),this.dragAndDropScrollTimeout=null)},t.prototype.onDragOver=function(e){var n=this,i=new c.DragMouseEvent(e),o=this.getItemAround(i.target);if(!o||0===i.posx&&0===i.posy&&i.browserEvent.type===a.EventType.DRAG_LEAVE)return this.currentDropTarget&&(this.currentDropTargets.forEach(function(e){return e.dropTarget=!1}),this.currentDropTargets=[],this.currentDropPromise&&(this.currentDropPromise.cancel(),this.currentDropPromise=null)),this.cancelDragAndDropScrollInterval(),this.currentDropTarget=null,this.currentDropElement=null, +this.dragAndDropMouseY=null,!1;if(this.setupDragAndDropScrollInterval(),this.dragAndDropMouseY=i.posy,!this.currentDragAndDropData)if(t.currentExternalDragAndDropData)this.currentDragAndDropData=t.currentExternalDragAndDropData;else{if(!i.dataTransfer.types)return!1;this.currentDragAndDropData=new p.DesktopDragAndDropData}this.currentDragAndDropData.update(i);var s,l,u=o.model;do{if(s=u?u.getElement():this.model.getInput(),!(l=this.context.dnd.onDragOver(this.context.tree,this.currentDragAndDropData,s,i))||l.bubble!==_.DragOverBubble.BUBBLE_UP)break;u=u&&u.parent}while(u);if(!u)return this.currentDropElement=null,!1;var d=l&&l.accept;d?(this.currentDropElement=u.getElement(),i.preventDefault(),i.dataTransfer.dropEffect=l.effect===_.DragOverEffect.COPY?"copy":"move"):this.currentDropElement=null;var h=u.id===this.inputItem.id?this.inputItem:this.items[u.id];if((this.shouldInvalidateDropReaction||this.currentDropTarget!==h||!function(e,t){ +return!e&&!t||!(!e||!t)&&e.accept===t.accept&&e.bubble===t.bubble&&e.effect===t.effect}(this.currentDropElementReaction,l))&&(this.shouldInvalidateDropReaction=!1,this.currentDropTarget&&(this.currentDropTargets.forEach(function(e){return e.dropTarget=!1}),this.currentDropTargets=[],this.currentDropPromise&&(this.currentDropPromise.cancel(),this.currentDropPromise=null)),this.currentDropTarget=h,this.currentDropElementReaction=l,d)){if(this.currentDropTarget&&(this.currentDropTarget.dropTarget=!0,this.currentDropTargets.push(this.currentDropTarget)),l.bubble===_.DragOverBubble.BUBBLE_DOWN)for(var f,g=u.getNavigator();f=g.next();)(o=this.items[f.id])&&(o.dropTarget=!0,this.currentDropTargets.push(o));l.autoExpand&&(this.currentDropPromise=r.TPromise.timeout(500).then(function(){return n.context.tree.expand(n.currentDropElement)}).then(function(){return n.shouldInvalidateDropReaction=!0}))}return!0},t.prototype.onDrop=function(e){if(this.currentDropElement){var t=new c.DragMouseEvent(e);t.preventDefault(), +this.currentDragAndDropData.update(t),this.context.dnd.drop(this.context.tree,this.currentDragAndDropData,this.currentDropElement,t),this.onDragEnd(e)}this.cancelDragAndDropScrollInterval()},t.prototype.onDragEnd=function(e){this.currentDropTarget&&(this.currentDropTargets.forEach(function(e){return e.dropTarget=!1}),this.currentDropTargets=[]),this.currentDropPromise&&(this.currentDropPromise.cancel(),this.currentDropPromise=null),this.cancelDragAndDropScrollInterval(),this.currentDragAndDropData=null,t.currentExternalDragAndDropData=null,this.currentDropElement=null,this.currentDropTarget=null,this.dragAndDropMouseY=null},t.prototype.onFocus=function(){this.context.options.alwaysFocused||a.addClass(this.domNode,"focused"),this._onDOMFocus.fire()},t.prototype.onBlur=function(){this.context.options.alwaysFocused||a.removeClass(this.domNode,"focused"),this.domNode.removeAttribute("aria-activedescendant"),this._onDOMBlur.fire()},t.prototype.onMsPointerDown=function(e){if(this.msGesture){var t=e.pointerType +;t!==(e.MSPOINTER_TYPE_MOUSE||"mouse")?t===(e.MSPOINTER_TYPE_TOUCH||"touch")&&(this.lastPointerType="touch",e.stopPropagation(),e.preventDefault(),this.msGesture.addPointer(e.pointerId)):this.lastPointerType="mouse"}},t.prototype.onThrottledMsGestureChange=function(e){this.scrollTop-=e.translationY},t.prototype.onMsGestureTap=function(e){e.initialTarget=document.elementFromPoint(e.clientX,e.clientY),this.onTap(e)},t.prototype.insertItemInDOM=function(e){var t=null,n=this.itemAfter(e);n&&n.element&&(t=n.element),e.insertInDOM(this.rowsContainer,t)},t.prototype.removeItemFromDOM=function(e){e&&e.removeFromDOM()},t.prototype.shouldBeRendered=function(e){return e.topthis.lastRenderTop},t.prototype.getItemAround=function(e){var n=this.inputItem;do{if(e[t.BINDING]&&(n=e[t.BINDING]),e===this.wrapper||e===this.domNode)return n;if(e===document.body)return null}while(e=e.parentElement)},t.prototype.releaseModel=function(){ +this.model&&(this.modelListeners=s.dispose(this.modelListeners),this.model=null)},t.prototype.dispose=function(){var t=this;this.scrollableElement.dispose(),this.releaseModel(),this.modelListeners=null,this.viewListeners=s.dispose(this.viewListeners),this._onDOMFocus.dispose(),this._onDOMBlur.dispose(),this.domNode.parentNode&&this.domNode.parentNode.removeChild(this.domNode),this.domNode=null,this.items&&(Object.keys(this.items).forEach(function(e){return t.items[e].removeFromDOM()}),this.items=null),this.context.cache&&(this.context.cache.dispose(),this.context.cache=null),e.prototype.dispose.call(this)},t.BINDING="monaco-tree-row",t.LOADING_DECORATION_DELAY=800,t.counter=0,t.currentExternalDragAndDropData=null,t}(v.HeightMap);t.TreeView=x}),define(t[249],n([8]),{}),define(t[252],n([8]),{}),define(t[155],n([1,0,81,463,246,9,27,28,252]),function(e,t,n,i,o,r,s,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var l=function(){return function(e,t,i){if(void 0===i&&(i={}),this.tree=e, +this.configuration=t,this.options=i,!t.dataSource)throw new Error("You must provide a Data Source to the tree.");this.dataSource=t.dataSource,this.renderer=t.renderer,this.controller=t.controller||new n.DefaultController({clickBehavior:n.ClickBehavior.ON_MOUSE_UP,keyboardSupport:"boolean"!=typeof i.keyboardSupport||i.keyboardSupport}),this.dnd=t.dnd||new n.DefaultDragAndDrop,this.filter=t.filter||new n.DefaultFilter,this.sorter=t.sorter||null,this.accessibilityProvider=t.accessibilityProvider||new n.DefaultAccessibilityProvider,this.styler=t.styler||null}}();t.TreeContext=l;var u={listFocusBackground:s.Color.fromHex("#073655"),listActiveSelectionBackground:s.Color.fromHex("#0E639C"),listActiveSelectionForeground:s.Color.fromHex("#FFFFFF"),listFocusAndSelectionBackground:s.Color.fromHex("#094771"),listFocusAndSelectionForeground:s.Color.fromHex("#FFFFFF"),listInactiveSelectionBackground:s.Color.fromHex("#3F3F46"),listHoverBackground:s.Color.fromHex("#2A2D2E"),listDropBackground:s.Color.fromHex("#383B3D") +},d=function(){function e(e,t,n){void 0===n&&(n={}),this._onDidChangeFocus=new r.Relay,this.onDidChangeFocus=this._onDidChangeFocus.event,this._onDidChangeSelection=new r.Relay,this.onDidChangeSelection=this._onDidChangeSelection.event,this._onHighlightChange=new r.Relay,this._onDidExpandItem=new r.Relay,this._onDidCollapseItem=new r.Relay,this._onDispose=new r.Emitter,this.onDidDispose=this._onDispose.event,this.container=e,a.mixin(n,u,!1),n.twistiePixels="number"==typeof n.twistiePixels?n.twistiePixels:32,n.showTwistie=!1!==n.showTwistie,n.indentPixels="number"==typeof n.indentPixels?n.indentPixels:12,n.alwaysFocused=!0===n.alwaysFocused,n.useShadows=!1!==n.useShadows,n.paddingOnRow=!1!==n.paddingOnRow,n.showLoading=!1!==n.showLoading,this.context=new l(this,t,n),this.model=new i.TreeModel(this.context),this.view=new o.TreeView(this.context,this.container),this.view.setModel(this.model),this._onDidChangeFocus.input=this.model.onDidFocus,this._onDidChangeSelection.input=this.model.onDidSelect, +this._onHighlightChange.input=this.model.onDidHighlight,this._onDidExpandItem.input=this.model.onDidExpandItem,this._onDidCollapseItem.input=this.model.onDidCollapseItem}return e.prototype.style=function(e){this.view.applyStyles(e)},Object.defineProperty(e.prototype,"onDidFocus",{get:function(){return this.view&&this.view.onDOMFocus},enumerable:!0,configurable:!0}),e.prototype.getHTMLElement=function(){return this.view.getHTMLElement()},e.prototype.layout=function(e,t){this.view.layout(e,t)},e.prototype.domFocus=function(){this.view.focus()},e.prototype.isDOMFocused=function(){return this.view.isFocused()},e.prototype.domBlur=function(){this.view.blur()},e.prototype.setInput=function(e){return this.model.setInput(e)},e.prototype.getInput=function(){return this.model.getInput()},e.prototype.refresh=function(e,t){return void 0===e&&(e=null),void 0===t&&(t=!0),this.model.refresh(e,t)},e.prototype.expand=function(e){return this.model.expand(e)},e.prototype.collapse=function(e,t){return void 0===t&&(t=!1), +this.model.collapse(e,t)},e.prototype.toggleExpansion=function(e,t){return void 0===t&&(t=!1),this.model.toggleExpansion(e,t)},e.prototype.isExpanded=function(e){return this.model.isExpanded(e)},e.prototype.reveal=function(e,t){return void 0===t&&(t=null),this.model.reveal(e,t)},e.prototype.getHighlight=function(){return this.model.getHighlight()},e.prototype.clearHighlight=function(e){this.model.setHighlight(null,e)},e.prototype.setSelection=function(e,t){this.model.setSelection(e,t)},e.prototype.getSelection=function(){return this.model.getSelection()},e.prototype.clearSelection=function(e){this.model.setSelection([],e)},e.prototype.setFocus=function(e,t){this.model.setFocus(e,t)},e.prototype.getFocus=function(){return this.model.getFocus()},e.prototype.focusNext=function(e,t){this.model.focusNext(e,t)},e.prototype.focusPrevious=function(e,t){this.model.focusPrevious(e,t)},e.prototype.focusParent=function(e){this.model.focusParent(e)},e.prototype.focusFirstChild=function(e){this.model.focusFirstChild(e)}, +e.prototype.focusFirst=function(e,t){this.model.focusFirst(e,t)},e.prototype.focusNth=function(e,t){this.model.focusNth(e,t)},e.prototype.focusLast=function(e,t){this.model.focusLast(e,t)},e.prototype.focusNextPage=function(e){this.view.focusNextPage(e)},e.prototype.focusPreviousPage=function(e){this.view.focusPreviousPage(e)},e.prototype.clearFocus=function(e){this.model.setFocus(null,e)},e.prototype.dispose=function(){this._onDispose.fire(),null!==this.model&&(this.model.dispose(),this.model=null),null!==this.view&&(this.view.dispose(),this.view=null),this._onDidChangeFocus.dispose(),this._onDidChangeSelection.dispose(),this._onHighlightChange.dispose(),this._onDidExpandItem.dispose(),this._onDidCollapseItem.dispose(),this._onDispose.dispose()},e}();t.Tree=d}),define(t[254],n([8]),{}),define(t[262],n([8]),{}),define(t[263],n([8]),{}),define(t[266],n([8]),{}),define(t[267],n([8]),{}),define(t[268],n([8]),{}),define(t[270],n([8]),{}),define(t[273],n([8]),{}),define(t[275],n([8]),{}),define(t[282],n([8]),{}), +define(t[285],n([8]),{}),define(t[287],n([8]),{}),define(t[296],n([8]),{}),define(t[297],n([8]),{}),define(t[333],n([8]),{}),define(t[360],n([8]),{}),define(t[361],n([8]),{}),define(t[362],n([8]),{}),define(t[363],n([8]),{}),define(t[364],n([8]),{}),define(t[365],n([8]),{}),define(t[367],n([8]),{}),define(t[368],n([8]),{}),define(t[369],n([8]),{}),define(t[371],n([8]),{}),define(t[372],n([8]),{}),define(t[373],n([8]),{}),define(t[375],n([8]),{}),define(t[156],n([8]),{}),define(t[377],n([8]),{}),define(t[378],n([8]),{}),define(t[379],n([8]),{}),define(t[383],n([8]),{}),define(t[384],n([8]),{}),define(t[385],n([8]),{}),define(t[386],n([8]),{}),define(t[388],n([8]),{}),define(t[390],n([8]),{}),define(t[398],n([8]),{}),define(t[401],n([8]),{}),define(t[402],n([8]),{}),define(t[404],n([8]),{}),define(t[406],n([8]),{}),define(t[407],n([8]),{}),define(t[408],n([8]),{}),define(t[410],n([8]),{}),define(t[413],n([8]),{}),define(t[416],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}) +;var n=function(){function e(e,t){this.chr=e,this.type=t,this.width=0}return e.prototype.fulfill=function(e){this.width=e},e}();t.CharWidthRequest=n;var i=function(){function e(e,t){this._bareFontInfo=e,this._requests=t,this._container=null,this._testElements=null}return e.prototype.read=function(){this._createDomElements(),document.body.appendChild(this._container),this._readFromDomElements(),document.body.removeChild(this._container),this._container=null,this._testElements=null},e.prototype._createDomElements=function(){var t=document.createElement("div");t.style.position="absolute",t.style.top="-50000px",t.style.width="50000px";var n=document.createElement("div");n.style.fontFamily=this._bareFontInfo.fontFamily,n.style.fontWeight=this._bareFontInfo.fontWeight,n.style.fontSize=this._bareFontInfo.fontSize+"px",n.style.lineHeight=this._bareFontInfo.lineHeight+"px",n.style.letterSpacing=this._bareFontInfo.letterSpacing+"px",t.appendChild(n);var i=document.createElement("div") +;i.style.fontFamily=this._bareFontInfo.fontFamily,i.style.fontWeight="bold",i.style.fontSize=this._bareFontInfo.fontSize+"px",i.style.lineHeight=this._bareFontInfo.lineHeight+"px",i.style.letterSpacing=this._bareFontInfo.letterSpacing+"px",t.appendChild(i);var o=document.createElement("div");o.style.fontFamily=this._bareFontInfo.fontFamily,o.style.fontWeight=this._bareFontInfo.fontWeight,o.style.fontSize=this._bareFontInfo.fontSize+"px",o.style.lineHeight=this._bareFontInfo.lineHeight+"px",o.style.letterSpacing=this._bareFontInfo.letterSpacing+"px",o.style.fontStyle="italic",t.appendChild(o);for(var r=[],s=0,a=this._requests.length;s0){n=o[0].getStartPosition();var r=t.getTopForPosition(n.lineNumber,n.column);i=t.getScrollTop()-r}}return new e(n,i)},e.prototype.restore=function(e){if(this._visiblePosition){ +var t=e.getTopForPosition(this._visiblePosition.lineNumber,this._visiblePosition.column);e.setScrollTop(t+this._visiblePositionScrollDelta)}},e}();t.StableEditorScrollState=o}),define(t[116],n([1,0,2,42,7,73]),function(e,t,n,i,r,s){"use strict";function a(e){var t=r.getDomNodePagePosition(e);return new d(t.left,t.top,t.width,t.height)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){this.x=e,this.y=t}return e.prototype.toClientCoordinates=function(){return new u(this.x-r.StandardWindow.scrollX,this.y-r.StandardWindow.scrollY)},e}();t.PageCoordinates=l;var u=function(){function e(e,t){this.clientX=e,this.clientY=t}return e.prototype.toPageCoordinates=function(){return new l(this.clientX+r.StandardWindow.scrollX,this.clientY+r.StandardWindow.scrollY)},e}();t.ClientCoordinates=u;var d=function(){return function(e,t,n,i){this.x=e,this.y=t,this.width=n,this.height=i}}();t.EditorPagePosition=d,t.createEditorPagePosition=a;var c=function(e){function t(t,n){var i=e.call(this,t)||this +;return i.pos=new l(i.posx,i.posy),i.editorPos=a(n),i}return o(t,e),t}(i.StandardMouseEvent);t.EditorMouseEvent=c;var h=function(){function e(e){this._editorViewDomNode=e}return e.prototype._create=function(e){return new c(e,this._editorViewDomNode)},e.prototype.onContextMenu=function(e,t){var n=this;return r.addDisposableListener(e,"contextmenu",function(e){t(n._create(e))})},e.prototype.onMouseUp=function(e,t){var n=this;return r.addDisposableListener(e,"mouseup",function(e){t(n._create(e))})},e.prototype.onMouseDown=function(e,t){var n=this;return r.addDisposableListener(e,"mousedown",function(e){t(n._create(e))})},e.prototype.onMouseLeave=function(e,t){var n=this;return r.addDisposableNonBubblingMouseOutListener(e,function(e){t(n._create(e))})},e.prototype.onMouseMoveThrottled=function(e,t,n,i){var o=this;return r.addDisposableThrottledListener(e,"mousemove",t,function(e,t){return n(e,o._create(t))},i)},e}();t.EditorMouseEventFactory=h;var p=function(e){function t(t){var n=e.call(this)||this +;return n._editorViewDomNode=t,n._globalMouseMoveMonitor=n._register(new s.GlobalMouseMoveMonitor),n._keydownListener=null,n}return o(t,e),t.prototype.startMonitoring=function(e,t,n){var i=this;this._keydownListener=r.addStandardDisposableListener(document,"keydown",function(e){e.toKeybinding().isModifierKey()||i._globalMouseMoveMonitor.stopMonitoring(!0)},!0);this._globalMouseMoveMonitor.startMonitoring(function(t,n){return e(t,new c(n,i._editorViewDomNode))},t,function(){i._keydownListener.dispose(),n()})},t}(n.Disposable);t.GlobalEditorMouseMoveMonitor=p}),define(t[423],n([1,0,9]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(){this._codeEditors=Object.create(null),this._diffEditors=Object.create(null),this._onCodeEditorAdd=new n.Emitter,this._onCodeEditorRemove=new n.Emitter,this._onDiffEditorAdd=new n.Emitter,this._onDiffEditorRemove=new n.Emitter}return e.prototype.addCodeEditor=function(e){this._codeEditors[e.getId()]=e, +this._onCodeEditorAdd.fire(e)},Object.defineProperty(e.prototype,"onCodeEditorAdd",{get:function(){return this._onCodeEditorAdd.event},enumerable:!0,configurable:!0}),e.prototype.removeCodeEditor=function(e){delete this._codeEditors[e.getId()]&&this._onCodeEditorRemove.fire(e)},e.prototype.listCodeEditors=function(){var e=this;return Object.keys(this._codeEditors).map(function(t){return e._codeEditors[t]})},e.prototype.addDiffEditor=function(e){this._diffEditors[e.getId()]=e,this._onDiffEditorAdd.fire(e)},e.prototype.removeDiffEditor=function(e){delete this._diffEditors[e.getId()]&&this._onDiffEditorRemove.fire(e)},e.prototype.listDiffEditors=function(){var e=this;return Object.keys(this._diffEditors).map(function(t){return e._diffEditors[t]})},e.prototype.getFocusedCodeEditor=function(){for(var e=null,t=this.listCodeEditors(),n=0;nn||e===n&&t>i?(this.startLineNumber=n,this.startColumn=i,this.endLineNumber=e,this.endColumn=t):(this.startLineNumber=e,this.startColumn=t,this.endLineNumber=n,this.endColumn=i)}return e.prototype.isEmpty=function(){return e.isEmpty(this)},e.isEmpty=function(e){return e.startLineNumber===e.endLineNumber&&e.startColumn===e.endColumn},e.prototype.containsPosition=function(t){return e.containsPosition(this,t)},e.containsPosition=function(e,t){return!(t.lineNumbere.endLineNumber)&&(!(t.lineNumber===e.startLineNumber&&t.columne.endColumn))},e.prototype.containsRange=function(t){return e.containsRange(this,t)},e.containsRange=function(e,t){ +return!(t.startLineNumbere.endLineNumber||t.endLineNumber>e.endLineNumber)&&(!(t.startLineNumber===e.startLineNumber&&t.startColumne.endColumn)))},e.prototype.plusRange=function(t){return e.plusRange(this,t)},e.plusRange=function(t,n){var i,o,r,s;return n.startLineNumbert.endLineNumber?(r=n.endLineNumber,s=n.endColumn):n.endLineNumber===t.endLineNumber?(r=n.endLineNumber,s=Math.max(n.endColumn,t.endColumn)):(r=t.endLineNumber,s=t.endColumn),new e(i,o,r,s)},e.prototype.intersectRanges=function(t){return e.intersectRanges(this,t)},e.intersectRanges=function(t,n){ +var i=t.startLineNumber,o=t.startColumn,r=t.endLineNumber,s=t.endColumn,a=n.startLineNumber,l=n.startColumn,u=n.endLineNumber,d=n.endColumn;return iu?(r=u,s=d):r===u&&(s=Math.min(s,d)),i>r?null:i===r&&o>s?null:new e(i,o,r,s)},e.prototype.equalsRange=function(t){return e.equalsRange(this,t)},e.equalsRange=function(e,t){return!!e&&!!t&&e.startLineNumber===t.startLineNumber&&e.startColumn===t.startColumn&&e.endLineNumber===t.endLineNumber&&e.endColumn===t.endColumn},e.prototype.getEndPosition=function(){return new n.Position(this.endLineNumber,this.endColumn)},e.prototype.getStartPosition=function(){return new n.Position(this.startLineNumber,this.startColumn)},e.prototype.toString=function(){return"["+this.startLineNumber+","+this.startColumn+" -> "+this.endLineNumber+","+this.endColumn+"]"},e.prototype.setEndPosition=function(t,n){return new e(this.startLineNumber,this.startColumn,t,n)},e.prototype.setStartPosition=function(t,n){ +return new e(t,n,this.endLineNumber,this.endColumn)},e.prototype.collapseToStart=function(){return e.collapseToStart(this)},e.collapseToStart=function(t){return new e(t.startLineNumber,t.startColumn,t.startLineNumber,t.startColumn)},e.fromPositions=function(t,n){return void 0===n&&(n=t),new e(t.lineNumber,t.column,n.lineNumber,n.column)},e.lift=function(t){return t?new e(t.startLineNumber,t.startColumn,t.endLineNumber,t.endColumn):null},e.isIRange=function(e){return e&&"number"==typeof e.startLineNumber&&"number"==typeof e.startColumn&&"number"==typeof e.endLineNumber&&"number"==typeof e.endColumn},e.areIntersectingOrTouching=function(e,t){return!(e.endLineNumbere.startLineNumber},e}();t.Range=i}),define(t[185],n([1,0,85,28,3,2,9]),function(e,t,n,i,o,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a={followsCaret:!0,ignoreCharChanges:!0, +alwaysRevealFirst:!0},l=function(){function e(e,t){void 0===t&&(t={});var n=this;this._onDidUpdate=new s.Emitter,this._editor=e,this._options=i.mixin(t,a,!1),this.disposed=!1,this._disposables=[],this.nextIdx=-1,this.ranges=[],this.ignoreSelectionChange=!1,this.revealFirst=this._options.alwaysRevealFirst,this._disposables.push(this._editor.onDidDispose(function(){return n.dispose()})),this._disposables.push(this._editor.onDidUpdateDiff(function(){return n._onDiffUpdated()})),this._options.followsCaret&&this._disposables.push(this._editor.getModifiedEditor().onDidChangeCursorPosition(function(e){n.ignoreSelectionChange||(n.nextIdx=-1)})),this._options.alwaysRevealFirst&&this._disposables.push(this._editor.getModifiedEditor().onDidChangeModel(function(e){n.revealFirst=!0})),this._init()}return e.prototype._init=function(){this._editor.getLineChanges()},e.prototype._onDiffUpdated=function(){this._init(),this._compute(this._editor.getLineChanges()), +this.revealFirst&&null!==this._editor.getLineChanges()&&(this.revealFirst=!1,this.nextIdx=-1,this.next(1))},e.prototype._compute=function(e){var t=this;this.ranges=[],e&&e.forEach(function(e){!t._options.ignoreCharChanges&&e.charChanges?e.charChanges.forEach(function(e){t.ranges.push({rhs:!0,range:new o.Range(e.modifiedStartLineNumber,e.modifiedStartColumn,e.modifiedEndLineNumber,e.modifiedEndColumn)})}):t.ranges.push({rhs:!0,range:new o.Range(e.modifiedStartLineNumber,1,e.modifiedStartLineNumber,1)})}),this.ranges.sort(function(e,t){return e.range.getStartPosition().isBeforeOrEqual(t.range.getStartPosition())?-1:t.range.getStartPosition().isBeforeOrEqual(e.range.getStartPosition())?1:0}),this._onDidUpdate.fire(this)},e.prototype._initIdx=function(e){for(var t=!1,n=this._editor.getPosition(),i=0,o=this.ranges.length;i=this.ranges.length&&(this.nextIdx=0)):(this.nextIdx-=1,this.nextIdx<0&&(this.nextIdx=this.ranges.length-1));var i=this.ranges[this.nextIdx];this.ignoreSelectionChange=!0;try{var o=i.range.getStartPosition();this._editor.setPosition(o),this._editor.revealPositionInCenter(o,t)}finally{this.ignoreSelectionChange=!1}}},e.prototype.canNavigate=function(){return this.ranges&&this.ranges.length>0},e.prototype.next=function(e){void 0===e&&(e=0),this._move(!0,e)},e.prototype.previous=function(e){void 0===e&&(e=0),this._move(!1,e)},e.prototype.dispose=function(){r.dispose(this._disposables),this._disposables.length=0,this._onDidUpdate.dispose(),this.ranges=null,this.disposed=!0},e}();t.DiffNavigator=l}),define(t[53],n([1,0,3]),function(e,t,n){"use strict" +;Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(){}return e.insert=function(e,t){return{range:new n.Range(e.lineNumber,e.column,e.lineNumber,e.column),text:t,forceMoveMarkers:!0}},e.delete=function(e){return{range:e,text:null}},e.replace=function(e,t){return{range:e,text:t}},e.replaceMove=function(e,t){return{range:e,text:t,forceMoveMarkers:!0}},e}();t.EditOperation=i}),define(t[431],n([1,0,6,53,3]),function(e,t,n,i,o){"use strict";function r(e,t){t.sort(function(e,t){return e.lineNumber===t.lineNumber?e.column-t.column:e.lineNumber-t.lineNumber});for(var r=t.length-2;r>=0;r--)t[r].lineNumber===t[r+1].lineNumber&&t.splice(r,1);for(var s=[],a=0,l=0,u=t.length,d=1,c=e.getLineCount();d<=c;d++){var h=e.getLineContent(d),p=h.length+1,f=0;if(!(l255?255:0|e},e}();t.RGBA8=n}),define(t[21],n([1,0,3,12]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r;!function(e){e[e.LTR=0]="LTR",e[e.RTL=1]="RTL"}(r=t.SelectionDirection||(t.SelectionDirection={}));var s=function(e){function t(t,n,i,o){ +var r=e.call(this,t,n,i,o)||this;return r.selectionStartLineNumber=t,r.selectionStartColumn=n,r.positionLineNumber=i,r.positionColumn=o,r}return o(t,e),t.prototype.clone=function(){return new t(this.selectionStartLineNumber,this.selectionStartColumn,this.positionLineNumber,this.positionColumn)},t.prototype.toString=function(){return"["+this.selectionStartLineNumber+","+this.selectionStartColumn+" -> "+this.positionLineNumber+","+this.positionColumn+"]"},t.prototype.equalsSelection=function(e){return t.selectionsEqual(this,e)},t.selectionsEqual=function(e,t){return e.selectionStartLineNumber===t.selectionStartLineNumber&&e.selectionStartColumn===t.selectionStartColumn&&e.positionLineNumber===t.positionLineNumber&&e.positionColumn===t.positionColumn},t.prototype.getDirection=function(){return this.selectionStartLineNumber===this.startLineNumber&&this.selectionStartColumn===this.startColumn?r.LTR:r.RTL},t.prototype.setEndPosition=function(e,n){ +return this.getDirection()===r.LTR?new t(this.startLineNumber,this.startColumn,e,n):new t(e,n,this.startLineNumber,this.startColumn)},t.prototype.getPosition=function(){return new i.Position(this.positionLineNumber,this.positionColumn)},t.prototype.setStartPosition=function(e,n){return this.getDirection()===r.LTR?new t(e,n,this.endLineNumber,this.endColumn):new t(this.endLineNumber,this.endColumn,e,n)},t.fromPositions=function(e,n){return void 0===n&&(n=e),new t(e.lineNumber,e.column,n.lineNumber,n.column)},t.liftSelection=function(e){return new t(e.selectionStartLineNumber,e.selectionStartColumn,e.positionLineNumber,e.positionColumn)},t.selectionsArrEqual=function(e,t){if(e&&!t||!e&&t)return!1;if(!e&&!t)return!0;if(e.length!==t.length)return!1;for(var n=0,i=e.length;n=this._capacity)return this._flushBuffer(),void(this._completedStrings[this._completedStrings.length]=e);for(var n=0;n=this._lines.length)throw new Error("Illegal value for lineNumber");return this._lines[t]},e.prototype.onLinesDeleted=function(e,t){if(0===this.getCount())return null +;var n=this.getStartLineNumber(),i=this.getEndLineNumber();if(ti)return null;for(var r=0,s=0,a=n;a<=i;a++){var l=a-this._rendLineNumberStart;e<=a&&a<=t&&(0===s?(r=l,s=1):s++)}if(e=n&&r<=i&&(this._lines[r-this._rendLineNumberStart].onContentChanged(),o=!0);return o},e.prototype.onLinesInserted=function(e,t){if(0===this.getCount())return null;var n=t-e+1,i=this.getStartLineNumber(),o=this.getEndLineNumber();if(e<=i)return this._rendLineNumberStart+=n,null;if(e>o)return null;if(n+e>o){return this._lines.splice(e-this._rendLineNumberStart,o-e+1)}for(var r=[],s=0;sn))for(var a=Math.max(t,s.fromLineNumber),l=Math.min(n,s.toLineNumber),u=a;u<=l;u++){var d=u-this._rendLineNumberStart;this._lines[d].onTokensChanged(),i=!0}}return i},e}();t.RenderedLinesCollection=o;var r=function(){function e(e){var t=this;this._host=e,this.domNode=this._createDomNode(),this._linesCollection=new o(function(){return t._host.createVisibleLine()})}return e.prototype._createDomNode=function(){var e=n.createFastDomNode(document.createElement("div"));return e.setClassName("view-layer"),e.setPosition("absolute"),e.domNode.setAttribute("role","presentation"), +e.domNode.setAttribute("aria-hidden","true"),e},e.prototype.onConfigurationChanged=function(e){return e.layoutInfo},e.prototype.onFlushed=function(e){return this._linesCollection.flush(),!0},e.prototype.onLinesChanged=function(e){return this._linesCollection.onLinesChanged(e.fromLineNumber,e.toLineNumber)},e.prototype.onLinesDeleted=function(e){var t=this._linesCollection.onLinesDeleted(e.fromLineNumber,e.toLineNumber);if(t)for(var n=0,i=t.length;nt){(s=t)<=(a=Math.min(n,o.rendLineNumberStart-1))&&(this._insertLinesBefore(o,s,a,i,t),o.linesLength+=a-s+1)}else if(o.rendLineNumberStart0&&(this._removeLinesBefore(o,l),o.linesLength-=l)}if(o.rendLineNumberStart=t,o.rendLineNumberStart+o.linesLength-1n){var s=Math.max(0,n-o.rendLineNumberStart+1),a=o.linesLength-1,l=a-s+1;l>0&&(this._removeLinesAfter(o,l),o.linesLength-=l)}return this._finishRendering(o,!1,i),o},e.prototype._renderUntouchedLines=function(e,t,n,i,o){for(var r=e.rendLineNumberStart,s=e.lines,a=t;a<=n;a++){var l=r+a;s[a].layoutLine(l,i[l-o])}},e.prototype._insertLinesBefore=function(e,t,n,i,o){ +for(var r=[],s=0,a=t;a<=n;a++)r[s++]=this.host.createVisibleLine();e.lines=r.concat(e.lines)},e.prototype._removeLinesBefore=function(e,t){for(var n=0;n=0;s--){var a=e.lines[s];i[s]&&(a.setDomNode(r),r=r.previousSibling)}},e.prototype._finishRenderingInvalidLines=function(e,t,n){var i=document.createElement("div");i.innerHTML=t;for(var o=0;o4294967295?4294967295:0|e}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t,n){for(var i=new Uint8Array(e*t),o=0,r=e*t;o255?255:0|e},t.toUint32=n,t.toUint32Array=function(e){for(var t=e.length,i=new Uint32Array(t),o=0;o=0&&e<256?this._asciiMap[e]=i:this._map.set(e,i)},e.prototype.get=function(e){return e>=0&&e<256?this._asciiMap[e]:this._map.get(e)||this._defaultValue},e}();t.CharacterClassifier=i;var o=function(){function e(){this._actual=new i(0)}return e.prototype.add=function(e){this._actual.set(e,1)},e.prototype.has=function(e){return 1===this._actual.get(e)},e}();t.CharacterSet=o}),define(t[89],n([1,0,83]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(e){function t(t){for(var n=e.call(this,0)||this,i=0,o=t.length;i1&&v>1;){if((S=f.charCodeAt(m-2))!==(w=g.charCodeAt(v-2)))break;m--,v--}(m>1||v>1)&&this._pushTrimWhitespaceCharChange(r,s+1,1,m,l+1,1,v);for(var _=a._getLastNonBlankColumn(f,1),y=a._getLastNonBlankColumn(g,1),C=f.length+1,b=g.length+1;_, selectionStart: "+this.selectionStart+", selectionEnd: "+this.selectionEnd+"]"},e.readFromTextArea=function(t){return new e(t.getValue(),t.getSelectionStart(),t.getSelectionEnd(),null,null)},e.prototype.collapseSelection=function(){return new e(this.value,this.value.length,this.value.length,null,null)},e.prototype.writeToTextArea=function(e,t,n){t.setValue(e,this.value),n&&t.setSelectionRange(e,this.selectionStart,this.selectionEnd)},e.prototype.deduceEditorPosition=function(e){if(e<=this.selectionStart){t=this.value.substring(e,this.selectionStart);return this._finishDeduceEditorPosition(this.selectionStartPosition,t,-1)}if(e>=this.selectionEnd){ +var t=this.value.substring(this.selectionEnd,e);return this._finishDeduceEditorPosition(this.selectionEndPosition,t,1)}var n=this.value.substring(this.selectionStart,e);if(-1===n.indexOf(String.fromCharCode(8230)))return this._finishDeduceEditorPosition(this.selectionStartPosition,n,1);var i=this.value.substring(e,this.selectionEnd);return this._finishDeduceEditorPosition(this.selectionEndPosition,i,-1)},e.prototype._finishDeduceEditorPosition=function(e,t,n){for(var i=0,o=-1;-1!==(o=t.indexOf("\n",o+1));)i++;return[e,n*t.length,i]},e.selectedText=function(t){return new e(t,0,t.length,null,null)},e.deduceInput=function(e,t,n,i){if(!e)return{text:"",replaceCharCnt:0};var o=e.value,s=e.selectionStart,a=e.selectionEnd,l=t.value,u=t.selectionStart,d=t.selectionEnd;i&&o.length>0&&s===a&&u===d&&!r.startsWith(l,o)&&r.endsWith(l,o)&&(s=0,a=0);var c=o.substring(a),h=l.substring(d),p=r.commonSuffixLength(c,h);l=l.substring(0,l.length-p) +;var f=(o=o.substring(0,o.length-p)).substring(0,s),g=l.substring(0,u),m=r.commonPrefixLength(f,g);if(l=l.substring(m),o=o.substring(m),u-=m,s-=m,d-=m,a-=m,n&&u===d&&o.length>0){var v=null;if(u===l.length?r.startsWith(l,o)&&(v=l.substring(o.length)):r.endsWith(l,o)&&(v=l.substring(0,l.length-o.length)),null!==v&&v.length>0&&(/\uFE0F/.test(v)||r.containsEmoji(v)))return{text:v,replaceCharCnt:0}}if(u===d){if(o===l&&0===s&&a===o.length&&u===l.length&&-1===l.indexOf("\n")&&r.containsFullWidthCharacter(l))return{text:"",replaceCharCnt:0};return{text:l,replaceCharCnt:f.length-m}}return{text:l,replaceCharCnt:a-s}},e.EMPTY=new e("",0,0,null,null),e}();t.TextAreaState=s;var a=function(){function e(){}return e._getPageOfLine=function(t){return Math.floor((t-1)/e._LINES_PER_PAGE)},e._getRangeForPage=function(t){var i=t*e._LINES_PER_PAGE,o=i+1,r=i+e._LINES_PER_PAGE;return new n.Range(o,1,r+1,1)},e.fromEditorSelection=function(t,r,a,l){ +var u=e._getPageOfLine(a.startLineNumber),d=e._getRangeForPage(u),c=e._getPageOfLine(a.endLineNumber),h=e._getRangeForPage(c),p=d.intersectRanges(new n.Range(1,1,a.startLineNumber,a.startColumn)),f=r.getValueInRange(p,o.EndOfLinePreference.LF),g=r.getLineCount(),m=r.getLineMaxColumn(g),v=h.intersectRanges(new n.Range(a.endLineNumber,a.endColumn,g,m)),_=r.getValueInRange(v,o.EndOfLinePreference.LF),y=null;if(u===c||u+1===c)y=r.getValueInRange(a,o.EndOfLinePreference.LF);else{var C=d.intersectRanges(a),b=h.intersectRanges(a);y=r.getValueInRange(C,o.EndOfLinePreference.LF)+String.fromCharCode(8230)+r.getValueInRange(b,o.EndOfLinePreference.LF)}if(l){f.length>500&&(f=f.substring(f.length-500,f.length)),_.length>500&&(_=_.substring(0,500)),y.length>1e3&&(y=y.substring(0,500)+String.fromCharCode(8230)+y.substring(y.length-500,y.length))}return new s(f+y+_,f.length,f.length+y.length,new i.Position(a.startLineNumber,a.startColumn),new i.Position(a.endLineNumber,a.endColumn))},e._LINES_PER_PAGE=10,e}() +;t.PagedScreenReaderStrategy=a}),define(t[165],n([1,0,14,21,6,9,2,164,30,18,7]),function(e,t,n,i,r,s,a,l,u,d,c){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.CopyOptions={forceCopyWithSyntaxHighlighting:!1};var h=function(e){function a(t,o){var a=e.call(this)||this;a._onFocus=a._register(new s.Emitter),a.onFocus=a._onFocus.event,a._onBlur=a._register(new s.Emitter),a.onBlur=a._onBlur.event,a._onKeyDown=a._register(new s.Emitter),a.onKeyDown=a._onKeyDown.event,a._onKeyUp=a._register(new s.Emitter),a.onKeyUp=a._onKeyUp.event,a._onCut=a._register(new s.Emitter),a.onCut=a._onCut.event,a._onPaste=a._register(new s.Emitter),a.onPaste=a._onPaste.event,a._onType=a._register(new s.Emitter),a.onType=a._onType.event,a._onCompositionStart=a._register(new s.Emitter),a.onCompositionStart=a._onCompositionStart.event,a._onCompositionUpdate=a._register(new s.Emitter),a.onCompositionUpdate=a._onCompositionUpdate.event,a._onCompositionEnd=a._register(new s.Emitter),a.onCompositionEnd=a._onCompositionEnd.event, +a._onSelectionChangeRequest=a._register(new s.Emitter),a.onSelectionChangeRequest=a._onSelectionChangeRequest.event,a._host=t,a._textArea=a._register(new f(o)),a._lastTextAreaEvent=0,a._asyncTriggerCut=a._register(new n.RunOnceScheduler(function(){return a._onCut.fire()},0)),a._textAreaState=l.TextAreaState.EMPTY,a.writeScreenReaderContent("ctor"),a._hasFocus=!1,a._isDoingComposition=!1,a._nextCommand=0,a._register(c.addStandardDisposableListener(o.domNode,"keydown",function(e){!a._isDoingComposition||109!==e.keyCode&&1!==e.keyCode||e.stopPropagation(),e.equals(9)&&e.preventDefault(),a._onKeyDown.fire(e)})),a._register(c.addStandardDisposableListener(o.domNode,"keyup",function(e){a._onKeyUp.fire(e)})),a._register(c.addDisposableListener(o.domNode,"compositionstart",function(e){a._lastTextAreaEvent=1,a._isDoingComposition||(a._isDoingComposition=!0,u.isEdgeOrIE||a._setAndWriteTextAreaState("compositionstart",l.TextAreaState.EMPTY),a._onCompositionStart.fire())}));var h=function(e,t){ +var n=a._textAreaState,i=l.TextAreaState.readFromTextArea(a._textArea);return[i,l.TextAreaState.deduceInput(n,i,e,t)]},g=function(e){var t=a._textAreaState,n=l.TextAreaState.selectedText(e);return[n,{text:n.value,replaceCharCnt:t.selectionEnd-t.selectionStart}]},m=function(e){return!(!u.isEdgeOrIE||"ja"!==e)||!(!u.isIE||0!==e.indexOf("zh-Han"))};a._register(c.addDisposableListener(o.domNode,"compositionupdate",function(e){if(a._lastTextAreaEvent=2,m(e.locale)){var t=h(!1,!1),n=t[0],i=t[1];return a._textAreaState=n,a._onType.fire(i),void a._onCompositionUpdate.fire(e)}var o=g(e.data),r=o[0],s=o[1];a._textAreaState=r,a._onType.fire(s),a._onCompositionUpdate.fire(e)})),a._register(c.addDisposableListener(o.domNode,"compositionend",function(e){if(a._lastTextAreaEvent=3,m(e.locale)){var t=h(!1,!1),n=t[0],i=t[1];a._textAreaState=n,a._onType.fire(i)}else{var o=g(e.data),n=o[0],i=o[1];a._textAreaState=n,a._onType.fire(i)}(u.isEdgeOrIE||u.isChrome)&&(a._textAreaState=l.TextAreaState.readFromTextArea(a._textArea)), +a._isDoingComposition&&(a._isDoingComposition=!1,a._onCompositionEnd.fire())})),a._register(c.addDisposableListener(o.domNode,"input",function(){var e=8===a._lastTextAreaEvent;if(a._lastTextAreaEvent=4,a._textArea.setIgnoreSelectionChangeTime("received input event"),!a._isDoingComposition){var t=h(d.isMacintosh,e&&d.isMacintosh),n=t[0],i=t[1];0===i.replaceCharCnt&&1===i.text.length&&r.isHighSurrogate(i.text.charCodeAt(0))||(a._textAreaState=n,0===a._nextCommand?""!==i.text&&a._onType.fire(i):(""!==i.text&&a._onPaste.fire({text:i.text}),a._nextCommand=0))}})),a._register(c.addDisposableListener(o.domNode,"cut",function(e){a._lastTextAreaEvent=5,a._textArea.setIgnoreSelectionChangeTime("received cut event"),a._ensureClipboardGetsEditorSelection(e),a._asyncTriggerCut.schedule()})),a._register(c.addDisposableListener(o.domNode,"copy",function(e){a._lastTextAreaEvent=6,a._ensureClipboardGetsEditorSelection(e)})),a._register(c.addDisposableListener(o.domNode,"paste",function(e){if(a._lastTextAreaEvent=7, +a._textArea.setIgnoreSelectionChangeTime("received paste event"),p.canUseTextData(e)){var t=p.getTextData(e);""!==t&&a._onPaste.fire({text:t})}else a._textArea.getSelectionStart()!==a._textArea.getSelectionEnd()&&a._setAndWriteTextAreaState("paste",l.TextAreaState.EMPTY),a._nextCommand=1})),a._register(c.addDisposableListener(o.domNode,"focus",function(){a._lastTextAreaEvent=8,a._setHasFocus(!0)})),a._register(c.addDisposableListener(o.domNode,"blur",function(){a._lastTextAreaEvent=9,a._setHasFocus(!1)}));var v=0;return a._register(c.addDisposableListener(document,"selectionchange",function(e){if(a._hasFocus&&!a._isDoingComposition&&u.isChrome&&d.isWindows){var t=Date.now(),n=t-v;if(v=t,!(n<5)){var o=t-a._textArea.getIgnoreSelectionChangeTime();if(a._textArea.resetSelectionChangeTime(),!(o<100)&&a._textAreaState.selectionStartPosition&&a._textAreaState.selectionEndPosition){var r=a._textArea.getValue();if(a._textAreaState.value===r){var s=a._textArea.getSelectionStart(),l=a._textArea.getSelectionEnd() +;if(a._textAreaState.selectionStart!==s||a._textAreaState.selectionEnd!==l){var c=a._textAreaState.deduceEditorPosition(s),h=a._host.deduceModelPosition(c[0],c[1],c[2]),p=a._textAreaState.deduceEditorPosition(l),f=a._host.deduceModelPosition(p[0],p[1],p[2]),g=new i.Selection(h.lineNumber,h.column,f.lineNumber,f.column);a._onSelectionChangeRequest.fire(g)}}}}}})),a}return o(a,e),a.prototype.dispose=function(){e.prototype.dispose.call(this)},a.prototype.focusTextArea=function(){this._setHasFocus(!0)},a.prototype.isFocused=function(){return this._hasFocus},a.prototype._setHasFocus=function(e){this._hasFocus!==e&&(this._hasFocus=e,this._hasFocus&&(u.isEdge?this._setAndWriteTextAreaState("focusgain",l.TextAreaState.EMPTY):this.writeScreenReaderContent("focusgain")),this._hasFocus?this._onFocus.fire():this._onBlur.fire())},a.prototype._setAndWriteTextAreaState=function(e,t){this._hasFocus||(t=t.collapseSelection()),t.writeToTextArea(e,this._textArea,this._hasFocus),this._textAreaState=t}, +a.prototype.writeScreenReaderContent=function(e){this._isDoingComposition||this._setAndWriteTextAreaState(e,this._host.getScreenReaderContent(this._textAreaState))},a.prototype._ensureClipboardGetsEditorSelection=function(e){var n=this._host.getPlainTextToCopy();if(p.canUseTextData(e)){var i=null;u.hasClipboardSupport()&&(n.length<65536||t.CopyOptions.forceCopyWithSyntaxHighlighting)&&(i=this._host.getHTMLToCopy()),p.setTextData(e,n,i)}else this._setAndWriteTextAreaState("copy or cut",l.TextAreaState.selectedText(n))},a}(a.Disposable);t.TextAreaInput=h;var p=function(){function e(){}return e.canUseTextData=function(e){return!!e.clipboardData||!!window.clipboardData},e.getTextData=function(e){if(e.clipboardData)return e.preventDefault(),e.clipboardData.getData("text/plain");if(window.clipboardData)return e.preventDefault(),window.clipboardData.getData("Text");throw new Error("ClipboardEventUtils.getTextData: Cannot use text data!")},e.setTextData=function(e,t,n){ +if(e.clipboardData)return e.clipboardData.setData("text/plain",t),null!==n&&e.clipboardData.setData("text/html",n),void e.preventDefault();if(window.clipboardData)return window.clipboardData.setData("Text",t),void e.preventDefault();throw new Error("ClipboardEventUtils.setTextData: Cannot use text data!")},e}(),f=function(e){function t(t){var n=e.call(this)||this;return n._actual=t,n._ignoreSelectionChangeTime=0,n}return o(t,e),t.prototype.setIgnoreSelectionChangeTime=function(e){this._ignoreSelectionChangeTime=Date.now()},t.prototype.getIgnoreSelectionChangeTime=function(){return this._ignoreSelectionChangeTime},t.prototype.resetSelectionChangeTime=function(){this._ignoreSelectionChangeTime=0},t.prototype.getValue=function(){return this._actual.domNode.value},t.prototype.setValue=function(e,t){var n=this._actual.domNode;n.value!==t&&(this.setIgnoreSelectionChangeTime("setValue"),n.value=t)},t.prototype.getSelectionStart=function(){return this._actual.domNode.selectionStart}, +t.prototype.getSelectionEnd=function(){return this._actual.domNode.selectionEnd},t.prototype.setSelectionRange=function(e,t,n){var i=this._actual.domNode,o=document.activeElement===i,r=i.selectionStart,s=i.selectionEnd;if(o&&r===t&&s===n)u.isFirefox&&window.parent!==window&&i.focus();else{if(o)return this.setIgnoreSelectionChangeTime("setSelectionRange"),i.setSelectionRange(t,n),void(u.isFirefox&&window.parent!==window&&i.focus());try{var a=c.saveParentsScrollTop(i);this.setIgnoreSelectionChangeTime("setSelectionRange"),i.focus(),i.setSelectionRange(t,n),c.restoreParentsScrollTop(i,a)}catch(e){}}},t}(a.Disposable)}),define(t[483],n([1,0,10,24]),function(e,t,n,i){"use strict";function o(e){return"\n"===e.getEOL()?i.EndOfLineSequence.LF:i.EndOfLineSequence.CRLF}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){this.beforeVersionId=e,this.beforeCursorState=t,this.afterCursorState=null,this.afterVersionId=-1,this.editOperations=[]}return e.prototype.undo=function(e){ +for(var t=this.editOperations.length-1;t>=0;t--)this.editOperations[t]={operations:e.applyEdits(this.editOperations[t].operations)}},e.prototype.redo=function(e){for(var t=0;t0){var e=this.past.pop();try{e.undo(this.model)}catch(e){return n.onUnexpectedError(e), +this.clear(),null}return this.future.push(e),{selections:e.beforeCursorState,recordedVersionId:e.beforeVersionId}}return null},e.prototype.canUndo=function(){return this.past.length>0},e.prototype.redo=function(){if(this.future.length>0){var e=this.future.pop();try{e.redo(this.model)}catch(e){return n.onUnexpectedError(e),this.clear(),null}return this.past.push(e),{selections:e.afterCursorState,recordedVersionId:e.afterVersionId}}return null},e.prototype.canRedo=function(){return this.future.length>0},e}();t.EditStack=a}),define(t[486],n([1,0]),function(e,t){"use strict";function n(e,t,n,i){var o;for(o=0;o0&&s>0)return 0;if(u>0&&d>0)return 0;var h=Math.abs(s-d),p=Math.abs(r-u);return 0===h?p:p%h==0?p/h:0}Object.defineProperty(t,"__esModule",{value:!0}),t.guessIndentation=function(e,t,i){ +for(var o=Math.min(e.getLineCount(),1e4),r=0,s=0,a="",l=0,u=[0,0,0,0,0,0,0,0,0],d=1;d<=o;d++){for(var c=e.getLineLength(d),h=e.getLineContent(d),p=c<=65536,f=!1,g=0,m=0,v=0,_=0,y=c;_0?r++:m>1&&s++;var b=n(a,l,h,g);b<=8&&u[b]++,a=h,l=g}}var S=i;r!==s&&(S=rE&&(E=t,w=e)}),{insertSpaces:S,tabSize:w}}}),define(t[487],n([1,0]),function(e,t){"use strict";function n(e){return(1&e.metadata)>>>0}function i(e,t){e.metadata=254&e.metadata|t<<0}function o(e){return(2&e.metadata)>>>1==1}function r(e,t){e.metadata=253&e.metadata|(t?1:0)<<1}function s(e){return(4&e.metadata)>>>2==1}function a(e,t){e.metadata=251&e.metadata|(t?1:0)<<2}function l(e,t){e.metadata=247&e.metadata|(t?1:0)<<3}function u(e,t){e.metadata=207&e.metadata|t<<4}function d(e,t,n,i){return en)&&(1!==i&&(2===i||t))}function c(e,t,n,i,o){var r=function(e){ +return(48&e.metadata)>>>4}(e),s=0===r||2===r,a=1===r||2===r,l=n-t,u=i,c=Math.min(l,u),h=e.start,p=!1,f=e.end,g=!1,m=o?1:l>0?2:0;if(!p&&d(h,s,t,m)&&(p=!0),!g&&d(f,a,t,m)&&(g=!0),c>0&&!o){m=l>u?2:0;!p&&d(h,s,t+c,m)&&(p=!0),!g&&d(f,a,t+c,m)&&(g=!0)}m=o?1:0;!p&&d(h,s,n,m)&&(e.start=t+u,p=!0),!g&&d(f,a,n,m)&&(e.end=t+u,g=!0);var v=u-l;p||(e.start=Math.max(0,h+v),p=!0),g||(e.end=Math.max(0,f+v),g=!0),e.start>e.end&&(e.end=e.start)}function h(e,o){if(e.root===t.SENTINEL)return o.parent=t.SENTINEL,o.left=t.SENTINEL,o.right=t.SENTINEL,i(o,0),e.root=o,e.root;!function(e,n){var o=0,r=e.root,s=n.start,a=n.end;for(;;){if(C(s,a,r.start+o,r.end+o)<0){if(r.left===t.SENTINEL){n.start-=o,n.end-=o,n.maxEnd-=o,r.left=n;break}r=r.left}else{if(r.right===t.SENTINEL){n.start-=o+r.delta,n.end-=o+r.delta,n.maxEnd-=o+r.delta,r.right=n;break}o+=r.delta,r=r.right}}n.parent=r,n.left=t.SENTINEL,n.right=t.SENTINEL,i(n,1)}(e,o),y(o.parent);for(var r=o;r!==e.root&&1===n(r.parent);)if(r.parent===r.parent.parent.left){ +1===n(s=r.parent.parent.right)?(i(r.parent,0),i(s,0),i(r.parent.parent,1),r=r.parent.parent):(r===r.parent.right&&g(e,r=r.parent),i(r.parent,0),i(r.parent.parent,1),m(e,r.parent.parent))}else{var s=r.parent.parent.left;1===n(s)?(i(r.parent,0),i(s,0),i(r.parent.parent,1),r=r.parent.parent):(r===r.parent.left&&m(e,r=r.parent),i(r.parent,0),i(r.parent.parent,1),g(e,r.parent.parent))}return i(e.root,0),o}function p(e,o){var r,s;if(o.left===t.SENTINEL?(s=o,(r=o.right).delta+=o.delta,(r.delta<-1073741824||r.delta>1073741824)&&(e.requestNormalizeDelta=!0),r.start+=o.delta,r.end+=o.delta):o.right===t.SENTINEL?(r=o.left,s=o):((r=(s=function(e){for(;e.left!==t.SENTINEL;)e=e.left;return e}(o.right)).right).start+=s.delta,r.end+=s.delta,r.delta+=s.delta,(r.delta<-1073741824||r.delta>1073741824)&&(e.requestNormalizeDelta=!0),s.start+=o.delta,s.end+=o.delta,s.delta=o.delta,(s.delta<-1073741824||s.delta>1073741824)&&(e.requestNormalizeDelta=!0)),s===e.root)return e.root=r,i(r,0),o.detach(),f(),_(r), +void(e.root.parent=t.SENTINEL);var a=1===n(s);if(s===s.parent.left?s.parent.left=r:s.parent.right=r,s===o?r.parent=s.parent:(s.parent===o?r.parent=s:r.parent=s.parent,s.left=o.left,s.right=o.right,s.parent=o.parent,i(s,n(o)),o===e.root?e.root=s:o===o.parent.left?o.parent.left=s:o.parent.right=s,s.left!==t.SENTINEL&&(s.left.parent=s),s.right!==t.SENTINEL&&(s.right.parent=s)),o.detach(),a)return y(r.parent),s!==o&&(y(s),y(s.parent)),void f();y(r),y(r.parent),s!==o&&(y(s),y(s.parent));for(var l;r!==e.root&&0===n(r);)r===r.parent.left?(1===n(l=r.parent.right)&&(i(l,0),i(r.parent,1),g(e,r.parent),l=r.parent.right),0===n(l.left)&&0===n(l.right)?(i(l,1),r=r.parent):(0===n(l.right)&&(i(l.left,0),i(l,1),m(e,l),l=r.parent.right),i(l,n(r.parent)),i(r.parent,0),i(l.right,0),g(e,r.parent),r=e.root)):(1===n(l=r.parent.left)&&(i(l,0),i(r.parent,1),m(e,r.parent),l=r.parent.left),0===n(l.left)&&0===n(l.right)?(i(l,1),r=r.parent):(0===n(l.left)&&(i(l.right,0),i(l,1),g(e,l),l=r.parent.left),i(l,n(r.parent)),i(r.parent,0), +i(l.left,0),m(e,r.parent),r=e.root));i(r,0),f()}function f(){t.SENTINEL.parent=t.SENTINEL,t.SENTINEL.delta=0,t.SENTINEL.start=0,t.SENTINEL.end=0}function g(e,n){var i=n.right;i.delta+=n.delta,(i.delta<-1073741824||i.delta>1073741824)&&(e.requestNormalizeDelta=!0),i.start+=n.delta,i.end+=n.delta,n.right=i.left,i.left!==t.SENTINEL&&(i.left.parent=n),i.parent=n.parent,n.parent===t.SENTINEL?e.root=i:n===n.parent.left?n.parent.left=i:n.parent.right=i,i.left=n,n.parent=i,_(n),_(i)}function m(e,n){var i=n.left;n.delta-=i.delta,(n.delta<-1073741824||n.delta>1073741824)&&(e.requestNormalizeDelta=!0),n.start-=i.delta,n.end-=i.delta,n.left=i.right,i.right!==t.SENTINEL&&(i.right.parent=n),i.parent=n.parent,n.parent===t.SENTINEL?e.root=i:n===n.parent.right?n.parent.right=i:n.parent.left=i,i.right=n,n.parent=i,_(n),_(i)}function v(e){var n=e.end;if(e.left!==t.SENTINEL){var i=e.left.maxEnd;i>n&&(n=i)}if(e.right!==t.SENTINEL){var o=e.right.maxEnd+e.delta;o>n&&(n=o)}return n}function _(e){e.maxEnd=v(e)}function y(e){ +for(;e!==t.SENTINEL;){var n=v(e);if(e.maxEnd===n)return;e.maxEnd=n,e=e.parent}}function C(e,t,n,i){return e===n?t-i:e-n}Object.defineProperty(t,"__esModule",{value:!0}),t.getNodeColor=n,t.getNodeIsInOverviewRuler=function(e){return(8&e.metadata)>>>3==1};var b=function(){function e(e,t,n){this.metadata=0,this.parent=null,this.left=null,this.right=null,i(this,1),this.start=t,this.end=n,this.delta=0,this.maxEnd=n,this.id=e,this.ownerId=0,this.options=null,a(this,!1),u(this,1),l(this,!1),this.cachedVersionId=0,this.cachedAbsoluteStart=t,this.cachedAbsoluteEnd=n,this.range=null,r(this,!1)}return e.prototype.reset=function(e,t,n,i){this.start=t,this.end=n,this.maxEnd=n,this.cachedVersionId=e,this.cachedAbsoluteStart=t,this.cachedAbsoluteEnd=n,this.range=i},e.prototype.setOptions=function(e){this.options=e;var t=this.options.className;a(this,"squiggly-error"===t||"squiggly-warning"===t||"squiggly-info"===t),u(this,this.options.stickiness),l(this,!!this.options.overviewRuler.color)}, +e.prototype.setCachedOffsets=function(e,t,n){this.cachedVersionId!==n&&(this.range=null),this.cachedVersionId=n,this.cachedAbsoluteStart=e,this.cachedAbsoluteEnd=t},e.prototype.detach=function(){this.parent=null,this.left=null,this.right=null},e}();t.IntervalNode=b,t.SENTINEL=new b(null,0,0),t.SENTINEL.parent=t.SENTINEL,t.SENTINEL.left=t.SENTINEL,t.SENTINEL.right=t.SENTINEL,i(t.SENTINEL,0);var S=function(){function e(){this.root=t.SENTINEL,this.requestNormalizeDelta=!1}return e.prototype.intervalSearch=function(e,n,i,a,l){return this.root===t.SENTINEL?[]:function(e,n,i,a,l,u){for(var d=e.root,c=0,h=0,p=0,f=[],g=0;d!==t.SENTINEL;)if(o(d))r(d.left,!1),r(d.right,!1),d===d.parent.right&&(c-=d.parent.delta),d=d.parent;else{if(!o(d.left)){if(c+d.maxEndi)r(d,!0);else{if((p=c+d.end)>=n){d.setCachedOffsets(h,p,u);var m=!0;a&&d.ownerId&&d.ownerId!==a&&(m=!1),l&&s(d)&&(m=!1),m&&(f[g++]=d)}r(d,!0), +d.right===t.SENTINEL||o(d.right)||(c+=d.delta,d=d.right)}}return r(e.root,!1),f}(this,e,n,i,a,l)},e.prototype.search=function(e,n,i){return this.root===t.SENTINEL?[]:function(e,n,i,a){for(var l=e.root,u=0,d=0,c=0,h=[],p=0;l!==t.SENTINEL;)if(o(l))r(l.left,!1),r(l.right,!1),l===l.parent.right&&(u-=l.parent.delta),l=l.parent;else if(l.left===t.SENTINEL||o(l.left)){d=u+l.start,c=u+l.end,l.setCachedOffsets(d,c,a);var f=!0;n&&l.ownerId&&l.ownerId!==n&&(f=!1),i&&s(l)&&(f=!1),f&&(h[p++]=l),r(l,!0),l.right===t.SENTINEL||o(l.right)||(u+=l.delta,l=l.right)}else l=l.left;return r(e.root,!1),h}(this,e,n,i)},e.prototype.collectNodesFromOwner=function(e){return function(e,n){for(var i=e.root,s=[],a=0;i!==t.SENTINEL;)o(i)?(r(i.left,!1),r(i.right,!1),i=i.parent):i.left===t.SENTINEL||o(i.left)?(i.ownerId===n&&(s[a++]=i),r(i,!0),i.right===t.SENTINEL||o(i.right)||(i=i.right)):i=i.left;return r(e.root,!1),s}(this,e)},e.prototype.collectNodesPostOrder=function(){return function(e){ +for(var n=e.root,i=[],s=0;n!==t.SENTINEL;)o(n)?(r(n.left,!1),r(n.right,!1),n=n.parent):n.left===t.SENTINEL||o(n.left)?n.right===t.SENTINEL||o(n.right)?(i[s++]=n,r(n,!0)):n=n.right:n=n.left;return r(e.root,!1),i}(this)},e.prototype.insert=function(e){h(this,e),this._normalizeDeltaIfNecessary()},e.prototype.delete=function(e){p(this,e),this._normalizeDeltaIfNecessary()},e.prototype.resolveNode=function(e,t){for(var n=e,i=0;e!==this.root;)e===e.parent.right&&(i+=e.parent.delta),e=e.parent;var o=n.start+i,r=n.end+i;n.setCachedOffsets(o,r,t)},e.prototype.acceptReplace=function(e,n,i,s){for(var a=function(e,n,i){for(var s=e.root,a=0,l=0,u=0,d=[],c=0;s!==t.SENTINEL;)if(o(s))r(s.left,!1),r(s.right,!1),s===s.parent.right&&(a-=s.parent.delta),s=s.parent;else{if(!o(s.left)){if(a+s.maxEndi?r(s,!0):((u=a+s.end)>=n&&(s.setCachedOffsets(l,u,0),d[c++]=s),r(s,!0),s.right===t.SENTINEL||o(s.right)||(a+=s.delta,s=s.right))}return r(e.root,!1),d +}(this,e,e+n),l=0,u=a.length;li?(a.start+=u,a.end+=u,a.delta+=u,(a.delta<-1073741824||a.delta>1073741824)&&(e.requestNormalizeDelta=!0),r(a,!0)):(r(a,!0),a.right===t.SENTINEL||o(a.right)||(l+=a.delta,a=a.right))}r(e.root,!1)}(this,e,e+n,i),this._normalizeDeltaIfNecessary();for(var l=0,u=a.length;l0){var s=t.charCodeAt(i);if(0!==e.get(s))return!0}return!1}(e,t,0,i,o)&&function(e,t,n,i,o){if(i+o===n)return!0;var r=t.charCodeAt(i+o);if(0!==e.get(r))return!0;if(13===r||10===r)return!0;if(o>0){var s=t.charCodeAt(i+o-1);if(0!==e.get(s))return!0}return!1}(e,t,n,i,o)}Object.defineProperty(t,"__esModule",{value:!0});var u=function(){function e(e,t,n,i){this.searchString=e,this.isRegex=t,this.matchCase=n, +this.wordSeparators=i}return e._isMultilineRegexSource=function(e){if(!e||0===e.length)return!1;for(var t=0,n=e.length;t=n)break;var i=e.charCodeAt(t);if(110===i||114===i)return!0}}return!1},e.prototype.parseSearchRequest=function(){if(""===this.searchString)return null;var t;t=this.isRegex?e._isMultilineRegexSource(this.searchString):this.searchString.indexOf("\n")>=0;var i=null;try{i=n.createRegExp(this.searchString,this.isRegex,{matchCase:this.matchCase,wholeWord:!1,multiline:t,global:!0})}catch(e){return null}if(!i)return null;var o=!this.isRegex&&!t;return o&&this.searchString.toLowerCase()!==this.searchString.toUpperCase()&&(o=this.matchCase),new d(i,this.wordSeparators?s.getMapForWordSeparators(this.wordSeparators):null,o?this.searchString:null)},e}();t.SearchParams=u;var d=function(){return function(e,t,n){this.regex=e,this.wordSeparators=t,this.simpleSearch=n}}();t.SearchData=d,t.createFindMatch=a;var c=function(){function e(e){ +for(var t=[],n=0,i=0,o=e.length;i>0);t[o]>=e?i=o-1:t[o+1]>=e?(n=o,i=o):n=o+1}return n+1},e}(),h=function(){function e(){}return e.findMatches=function(e,t,n,i,o){var r=t.parseSearchRequest();return r?r.regex.multiline?this._doFindMatchesMultiline(e,n,new p(r.wordSeparators,r.regex),i,o):this._doFindMatchesLineByLine(e,n,r,i,o):[]},e._getMultilineMatchRange=function(e,t,n,i,r,s){var a,l=0;a="\r\n"===e.getEOL()?t+r+(l=i.findLineFeedCountBeforeOffset(r)):t+r;var u;if("\r\n"===e.getEOL()){var d=i.findLineFeedCountBeforeOffset(r+s.length)-l;u=a+s.length+d}else u=a+s.length;var c=e.getPositionAt(a),h=e.getPositionAt(u);return new o.Range(c.lineNumber,c.column,h.lineNumber,h.column)},e._doFindMatchesMultiline=function(e,t,n,i,o){ +var s,l=e.getOffsetAt(t.getStartPosition()),u=e.getValueInRange(t,r.EndOfLinePreference.LF),d="\r\n"===e.getEOL()?new c(u):null,h=[],p=0;for(n.reset(0);s=n.next(u);)if(h[p++]=a(this._getMultilineMatchRange(e,l,u,d,s.index,s[0]),s,i),p>=o)return h;return h},e._doFindMatchesLineByLine=function(e,t,n,i,o){var r=[],s=0;if(t.startLineNumber===t.endLineNumber){var a=e.getLineContent(t.startLineNumber).substring(t.startColumn-1,t.endColumn-1);return s=this._findMatchesInLine(n,a,t.startLineNumber,t.startColumn-1,s,r,i,o),r}var l=e.getLineContent(t.startLineNumber).substring(t.startColumn-1);s=this._findMatchesInLine(n,l,t.startLineNumber,t.startColumn-1,s,r,i,o);for(var u=t.startLineNumber+1;u=c))return s;return s}var _,y=new p(e.wordSeparators,e.regex);y.reset(0);do{if((_=y.next(t))&&(u[s++]=a(new o.Range(n,_.index+1+i,n,_.index+1+_[0].length+i),_,d),s>=c))return s}while(_);return s},e.findNextMatch=function(e,t,n,i){var o=t.parseSearchRequest();if(!o)return null;var r=new p(o.wordSeparators,o.regex);return o.regex.multiline?this._doFindNextMatchMultiline(e,n,r,i):this._doFindNextMatchLineByLine(e,n,r,i)},e._doFindNextMatchMultiline=function(e,t,n,s){var l=new i.Position(t.lineNumber,1),u=e.getOffsetAt(l),d=e.getLineCount(),h=e.getValueInRange(new o.Range(l.lineNumber,l.column,d,e.getLineMaxColumn(d)),r.EndOfLinePreference.LF),p="\r\n"===e.getEOL()?new c(h):null;n.reset(t.column-1);var f=n.next(h) +;return f?a(this._getMultilineMatchRange(e,u,h,p,f.index,f[0]),f,s):1!==t.lineNumber||1!==t.column?this._doFindNextMatchMultiline(e,new i.Position(1,1),n,s):null},e._doFindNextMatchLineByLine=function(e,t,n,i){var o=e.getLineCount(),r=t.lineNumber,s=e.getLineContent(r),a=this._findFirstMatchInLine(n,s,r,t.column,i);if(a)return a;for(var l=1;l<=o;l++){var u=(r+l-1)%o,d=e.getLineContent(u+1),c=this._findFirstMatchInLine(n,d,u+1,1,i);if(c)return c}return null},e._findFirstMatchInLine=function(e,t,n,i,r){e.reset(i-1);var s=e.next(t);return s?a(new o.Range(n,s.index+1,n,s.index+1+s[0].length),s,r):null},e.findPreviousMatch=function(e,t,n,i){var o=t.parseSearchRequest();if(!o)return null;var r=new p(o.wordSeparators,o.regex);return o.regex.multiline?this._doFindPreviousMatchMultiline(e,n,r,i):this._doFindPreviousMatchLineByLine(e,n,r,i)},e._doFindPreviousMatchMultiline=function(e,t,n,r){var s=this._doFindMatchesMultiline(e,new o.Range(1,1,t.lineNumber,t.column),n,r,9990);if(s.length>0)return s[s.length-1] +;var a=e.getLineCount();return t.lineNumber!==a||t.column!==e.getLineMaxColumn(a)?this._doFindPreviousMatchMultiline(e,new i.Position(a,e.getLineMaxColumn(a)),n,r):null},e._doFindPreviousMatchLineByLine=function(e,t,n,i){var o=e.getLineCount(),r=t.lineNumber,s=e.getLineContent(r).substring(0,t.column-1),a=this._findLastMatchInLine(n,s,r,i);if(a)return a;for(var l=1;l<=o;l++){var u=(o+r-l-1)%o,d=e.getLineContent(u+1),c=this._findLastMatchInLine(n,d,u+1,i);if(c)return c}return null},e._findLastMatchInLine=function(e,t,n,i){var r,s=null;for(e.reset(0);r=e.next(t);)s=a(new o.Range(n,r.index+1,n,r.index+1+r[0].length),r,i);return s},e}();t.TextModelSearch=h,t.isValidMatch=l;var p=function(){function e(e,t){this._wordSeparators=e,this._searchRegex=t,this._prevMatchStartIndex=-1,this._prevMatchLength=0}return e.prototype.reset=function(e){this._searchRegex.lastIndex=e,this._prevMatchStartIndex=-1,this._prevMatchLength=0},e.prototype.next=function(e){var t,n=e.length;do{ +if(this._prevMatchStartIndex+this._prevMatchLength===n)return null;if(!(t=this._searchRegex.exec(e)))return null;var i=t.index,o=t[0].length;if(i===this._prevMatchStartIndex&&o===this._prevMatchLength)return null;if(this._prevMatchStartIndex=i,this._prevMatchLength=o,!this._wordSeparators||l(this._wordSeparators,e,n,i,o))return t}while(t);return null},e}();t.Searcher=p}),define(t[167],n([1,0,12,3,495,136,24]),function(e,t,n,i,o,r,s){"use strict";function a(e){var t;return(t=e[e.length-1]<65536?new Uint16Array(e.length):new Uint32Array(e.length)).set(e,0),t}function l(e,t){void 0===t&&(t=!0);for(var n=[0],i=1,o=0,r=e.length;o126)&&(s=!1)}var h=new u(a(e),i,o,r,s);return e.length=0,h};var d=function(){return function(e,t,n,i,o){this.bufferIndex=e,this.start=t,this.end=n,this.lineFeedCnt=i,this.length=o}}();t.Piece=d;var c=function(){return function(e,t){this.buffer=e,this.lineStarts=t}}();t.StringBuffer=c;var h=function(){function e(e){this._limit=e,this._cache=[]}return e.prototype.get=function(e){for(var t=this._cache.length-1;t>=0;t--){var n=this._cache[t];if(n.nodeStartOffset<=e&&n.nodeStartOffset+n.node.piece.length>=e)return n}return null},e.prototype.get2=function(e){for(var t=this._cache.length-1;t>=0;t--){var n=this._cache[t];if(n.nodeStartLineNumber&&n.nodeStartLineNumber=e)return n}return null},e.prototype.set=function(e){ +this._cache.length>=this._limit&&this._cache.shift(),this._cache.push(e)},e.prototype.valdiate=function(e){for(var t=!1,n=0;n=e)&&(this._cache[n]=null,t=!0)}if(t){for(var o=[],n=0;n0){e[r].lineStarts||(e[r].lineStarts=l(e[r].buffer));var a=new d(r+1,{line:0,column:0},{line:e[r].lineStarts.length-1,column:e[r].buffer.length-e[r].lineStarts[e[r].lineStarts.length-1]},e[r].lineStarts.length-1,e[r].buffer.length);this._buffers.push(e[r]),i=this.rbInsertRight(i,a)}this._searchCache=new h(1), +this._lastVisitedLine={lineNumber:0,value:null},this.computeBufferMetadata()},e.prototype.normalizeEOL=function(e){var n=this,i=t.AverageBufferSize,o=i-Math.floor(i/3),r=2*o,s="",a=0,u=[];if(this.iterate(this.root,function(t){var i=n.getNodeContent(t),d=i.length;if(a<=o||a+d0){var d=s.replace(/\r\n|\r|\n/g,e);u.push(new c(d,l(d)))}this.create(u,e,!0)},e.prototype.getEOL=function(){return this._EOL},e.prototype.setEOL=function(e){this._EOL=e,this._EOLLength=this._EOL.length,this.normalizeEOL(e)},e.prototype.getOffsetAt=function(e,t){for(var n=0,i=this.root;i!==o.SENTINEL;)if(i.left!==o.SENTINEL&&i.lf_left+1>=e)i=i.left;else{if(i.lf_left+i.piece.lineFeedCnt+1>=e){n+=i.size_left;return n+=this.getAccumulatedValue(i,e-i.lf_left-2)+t-1}e-=i.lf_left+i.piece.lineFeedCnt,n+=i.size_left+i.piece.length,i=i.right}return n},e.prototype.getPositionAt=function(e){e=Math.floor(e),e=Math.max(0,e) +;for(var t=this.root,i=0,r=e;t!==o.SENTINEL;)if(0!==t.size_left&&t.size_left>=e)t=t.left;else{if(t.size_left+t.piece.length>=e){var s=this.getIndexOf(t,e-t.size_left);if(i+=t.lf_left+s.index,0===s.index){l=r-(a=this.getOffsetAt(i+1,1));return new n.Position(i+1,l+1)}return new n.Position(i+1,s.remainder+1)}if(e-=t.size_left+t.piece.length,i+=t.lf_left+t.piece.lineFeedCnt,t.right===o.SENTINEL){var a=this.getOffsetAt(i+1,1),l=r-e-a;return new n.Position(i+1,l+1)}t=t.right}return new n.Position(1,1)},e.prototype.getValueInRange=function(e,t){if(e.startLineNumber===e.endLineNumber&&e.startColumn===e.endColumn)return"";var n=this.nodeAt2(e.startLineNumber,e.startColumn),i=this.nodeAt2(e.endLineNumber,e.endColumn),o=this.getValueInRange2(n,i);return t?t===this._EOL&&this._EOLNormalized&&t===this.getEOL()&&this._EOLNormalized?o:o.replace(/\r\n|\r|\n/g,t):o},e.prototype.getValueInRange2=function(e,t){if(e.node===t.node){ +var n=e.node,i=this._buffers[n.piece.bufferIndex].buffer,r=this.offsetInBuffer(n.piece.bufferIndex,n.piece.start);return i.substring(r+e.remainder,r+t.remainder)}var s=e.node,a=this._buffers[s.piece.bufferIndex].buffer,l=this.offsetInBuffer(s.piece.bufferIndex,s.piece.start),u=a.substring(l+e.remainder,l+s.piece.length);for(s=s.next();s!==o.SENTINEL;){var d=this._buffers[s.piece.bufferIndex].buffer,c=this.offsetInBuffer(s.piece.bufferIndex,s.piece.start);if(s===t.node){u+=d.substring(c,c+t.remainder);break}u+=d.substr(c,s.piece.length),s=s.next()}return u},e.prototype.getLinesContent=function(){return this.getContentOfSubTree(this.root).split(/\r\n|\r|\n/)},e.prototype.getLength=function(){return this._length},e.prototype.getLineCount=function(){return this._lineCnt},e.prototype.getLineContent=function(e){return this._lastVisitedLine.lineNumber===e?this._lastVisitedLine.value:(this._lastVisitedLine.lineNumber=e, +e===this._lineCnt?this._lastVisitedLine.value=this.getLineRawContent(e):this._EOLNormalized?this._lastVisitedLine.value=this.getLineRawContent(e,this._EOLLength):this._lastVisitedLine.value=this.getLineRawContent(e).replace(/(\r\n|\r|\n)$/,""),this._lastVisitedLine.value)},e.prototype.getLineCharCode=function(e,t){var n=this.nodeAt2(e,t+1);if(n.remainder===n.node.piece.length){var i=n.node.next();if(!i)return 0;var o=this._buffers[i.piece.bufferIndex],r=this.offsetInBuffer(i.piece.bufferIndex,i.piece.start);return o.buffer.charCodeAt(r)}var o=this._buffers[n.node.piece.bufferIndex],s=(r=this.offsetInBuffer(n.node.piece.bufferIndex,n.node.piece.start))+n.remainder;return o.buffer.charCodeAt(s)},e.prototype.getLineLength=function(e){if(e===this.getLineCount()){var t=this.getOffsetAt(e,1);return this.getLength()-t}return this.getOffsetAt(e+1,1)-this.getOffsetAt(e,1)-this._EOLLength},e.prototype.findMatchesInNode=function(e,t,n,o,s,a,l,u,d,c,h){ +var p,f=this._buffers[e.piece.bufferIndex],g=this.offsetInBuffer(e.piece.bufferIndex,e.piece.start),m=this.offsetInBuffer(e.piece.bufferIndex,s),v=this.offsetInBuffer(e.piece.bufferIndex,a);t.reset(m);var _={line:0,column:0};do{if(p=t.next(f.buffer)){if(p.index>=v)return c;this.positionInBuffer(e,p.index-g,_);var y=this.getLineFeedCnt(e.piece.bufferIndex,s,_),C=_.line===s.line?_.column-s.column+o:_.column+1,b=C+p[0].length;if(h[c++]=r.createFindMatch(new i.Range(n+y,C,n+y,b),p,u),p.index+p[0].length>=v)return c;if(c>=d)return c}}while(p);return c},e.prototype.findMatchesLineByLine=function(e,t,n,i){var o=[],s=0,a=new r.Searcher(t.wordSeparators,t.regex),l=this.nodeAt2(e.startLineNumber,e.startColumn);if(null===l)return[];var u=this.nodeAt2(e.endLineNumber,e.endColumn);if(null===u)return[];var d=this.positionInBuffer(l.node,l.remainder),c=this.positionInBuffer(u.node,u.remainder);if(l.node===u.node)return this.findMatchesInNode(l.node,a,e.startLineNumber,e.startColumn,d,c,t,n,i,s,o),o +;for(var h=e.startLineNumber,p=l.node;p!==u.node;){var f=this.getLineFeedCnt(p.piece.bufferIndex,d,p.piece.end);if(f>=1){var g=this._buffers[p.piece.bufferIndex].lineStarts,m=this.offsetInBuffer(p.piece.bufferIndex,p.piece.start),v=g[d.line+f],_=h===e.startLineNumber?e.startColumn:1;if((s=this.findMatchesInNode(p,a,h,_,d,this.positionInBuffer(p,v-m),t,n,i,s,o))>=i)return o;h+=f}var y=h===e.startLineNumber?e.startColumn-1:0;if(h===e.endLineNumber){b=this.getLineContent(h).substring(y,e.endColumn-1);return s=this._findMatchesInLine(t,a,b,e.endLineNumber,y,s,o,n,i),o}if((s=this._findMatchesInLine(t,a,this.getLineContent(h).substr(y),h,y,s,o,n,i))>=i)return o;h++,p=(l=this.nodeAt2(h,1)).node,d=this.positionInBuffer(l.node,l.remainder)}if(h===e.endLineNumber){var C=h===e.startLineNumber?e.startColumn-1:0,b=this.getLineContent(h).substring(C,e.endColumn-1);return s=this._findMatchesInLine(t,a,b,e.endLineNumber,C,s,o,n,i),o}var S=h===e.startLineNumber?e.startColumn:1 +;return s=this.findMatchesInNode(u.node,a,h,S,d,c,t,n,i,s,o),o},e.prototype._findMatchesInLine=function(e,t,n,o,a,l,u,d,c){var h=e.wordSeparators;if(!d&&e.simpleSearch){for(var p=e.simpleSearch,f=p.length,g=n.length,m=-f;-1!==(m=n.indexOf(p,m+f));)if((!h||r.isValidMatch(h,n,g,m,f))&&(u[l++]=new s.FindMatch(new i.Range(o,m+1+a,o,m+1+f+a),null),l>=c))return l;return l}var v;t.reset(0);do{if((v=t.next(n))&&(u[l++]=r.createFindMatch(new i.Range(o,v.index+1+a,o,v.index+1+v[0].length+a),v,d),l>=c))return l}while(v);return l},e.prototype.insert=function(e,n,i){if(void 0===i&&(i=!1),this._EOLNormalized=this._EOLNormalized&&i,this._lastVisitedLine.lineNumber=0,this._lastVisitedLine.value=null,this.root!==o.SENTINEL){var r=this.nodeAt(e),s=r.node,a=r.remainder,l=r.nodeStartOffset,u=s.piece,c=u.bufferIndex,h=this.positionInBuffer(s,a) +;if(0===s.piece.bufferIndex&&u.end.line===this._lastChangeBufferPos.line&&u.end.column===this._lastChangeBufferPos.column&&l+u.length===e&&n.lengthe){var p=[],f=new d(u.bufferIndex,h,u.end,this.getLineFeedCnt(u.bufferIndex,h,u.end),this.offsetInBuffer(c,u.end)-this.offsetInBuffer(c,h));if(this.shouldCheckCRLF()&&this.endWithCR(n)){if(10===this.nodeCharCodeAt(s,a)){var g={line:f.start.line+1,column:0};f=new d(f.bufferIndex,g,f.end,this.getLineFeedCnt(f.bufferIndex,g,f.end),f.length-1),n+="\n"}}if(this.shouldCheckCRLF()&&this.startWithLF(n)){if(13===this.nodeCharCodeAt(s,a-1)){var m=this.positionInBuffer(s,a-1);this.deleteNodeTail(s,m),n="\r"+n,0===s.piece.length&&p.push(s)}else this.deleteNodeTail(s,h)}else this.deleteNodeTail(s,h);var v=this.createNewPieces(n);f.length>0&&this.rbInsertRight(s,f) +;for(var _=s,y=0;y=0;u--)l=this.rbInsertLeft(l,a[u]);this.validateCRLFWithPrevNode(l),this.deleteNodes(n)},e.prototype.insertContentToNodeRight=function(e,t){ +this.adjustCarriageReturnFromNext(e,t)&&(e+="\n");for(var n=this.createNewPieces(e),i=this.rbInsertRight(t,n[0]),o=i,r=1;r=o))break;d=i+1}return n?(n.line=i,n.column=u-r,null):{line:i,column:u-r}},e.prototype.getLineFeedCnt=function(e,t,n){if(0===n.column)return n.line-t.line;var i=this._buffers[e].lineStarts;if(n.line===i.length-1)return n.line-t.line;var o=i[n.line+1],r=i[n.line]+n.column;if(o>r+1)return n.line-t.line;var s=r-1;return 13===this._buffers[e].buffer.charCodeAt(s)?n.line-t.line+1:n.line-t.line},e.prototype.offsetInBuffer=function(e,t){return this._buffers[e].lineStarts[t.line]+t.column},e.prototype.deleteNodes=function(e){for(var t=0;tt.AverageBufferSize){for(var n=[];e.length>t.AverageBufferSize;){var i=e.charCodeAt(t.AverageBufferSize-1),o=void 0;13===i||i>=55296&&i<=56319?(o=e.substring(0,t.AverageBufferSize-1),e=e.substring(t.AverageBufferSize-1)):(o=e.substring(0,t.AverageBufferSize),e=e.substring(t.AverageBufferSize));var r=l(o);n.push(new d(this._buffers.length,{line:0,column:0},{line:r.length-1,column:o.length-r[r.length-1]},r.length-1,o.length)),this._buffers.push(new c(o,r))}var s=l(e);return n.push(new d(this._buffers.length,{line:0,column:0},{line:s.length-1,column:e.length-s[s.length-1]},s.length-1,e.length)),this._buffers.push(new c(e,s)),n}var a=this._buffers[0].buffer.length,u=l(e,!1),h=this._lastChangeBufferPos;if(this._buffers[0].lineStarts[this._buffers[0].lineStarts.length-1]===a&&0!==a&&this.startWithLF(e)&&this.endWithCR(this._buffers[0].buffer)){this._lastChangeBufferPos={line:this._lastChangeBufferPos.line,column:this._lastChangeBufferPos.column+1}, +h=this._lastChangeBufferPos;for(p=0;p=e-1)n=n.left;else{if(n.lf_left+n.piece.lineFeedCnt>e-1){var s=this.getAccumulatedValue(n,e-n.lf_left-2),c=this.getAccumulatedValue(n,e-n.lf_left-1),a=this._buffers[n.piece.bufferIndex].buffer,l=this.offsetInBuffer(n.piece.bufferIndex,n.piece.start);return u+=n.size_left,this._searchCache.set({node:n,nodeStartOffset:u,nodeStartLineNumber:d-(e-1-n.lf_left)}),a.substring(l+s,l+c-t)}if(n.lf_left+n.piece.lineFeedCnt===e-1){var s=this.getAccumulatedValue(n,e-n.lf_left-2),a=this._buffers[n.piece.bufferIndex].buffer,l=this.offsetInBuffer(n.piece.bufferIndex,n.piece.start);i=a.substring(l+s,l+n.piece.length);break}e-=n.lf_left+n.piece.lineFeedCnt,u+=n.size_left+n.piece.length,n=n.right}for(n=n.next();n!==o.SENTINEL;){a=this._buffers[n.piece.bufferIndex].buffer;if(n.piece.lineFeedCnt>0){var c=this.getAccumulatedValue(n,0),l=this.offsetInBuffer(n.piece.bufferIndex,n.piece.start);return i+=a.substring(l,l+c-t)} +l=this.offsetInBuffer(n.piece.bufferIndex,n.piece.start);i+=a.substr(l,n.piece.length),n=n.next()}return i},e.prototype.computeBufferMetadata=function(){for(var e=this.root,t=1,n=0;e!==o.SENTINEL;)t+=e.lf_left+e.piece.lineFeedCnt,n+=e.size_left+e.piece.length,e=e.right;this._lineCnt=t,this._length=n,this._searchCache.valdiate(this._length)},e.prototype.getIndexOf=function(e,t){var n=e.piece,i=this.positionInBuffer(e,t),o=i.line-n.start.line;if(this.offsetInBuffer(n.bufferIndex,n.end)-this.offsetInBuffer(n.bufferIndex,n.start)===t){var r=this.getLineFeedCnt(e.piece.bufferIndex,n.start,i);if(r!==o)return{index:r,remainder:0}}return{index:o,remainder:i.column}},e.prototype.getAccumulatedValue=function(e,t){if(t<0)return 0;var n=e.piece,i=this._buffers[n.bufferIndex].lineStarts,o=n.start.line+t+1;return o>n.end.line?i[n.end.line]+n.end.column-i[n.start.line]-n.start.column:i[o]-i[n.start.line]-n.start.column},e.prototype.deleteNodeTail=function(e,t){ +var n=e.piece,i=n.lineFeedCnt,r=this.offsetInBuffer(n.bufferIndex,n.end),s=t,a=this.offsetInBuffer(n.bufferIndex,s),l=this.getLineFeedCnt(n.bufferIndex,n.start,s),u=l-i,c=a-r,h=n.length+c;e.piece=new d(n.bufferIndex,n.start,s,l,h),o.updateTreeMetadata(this,e,c,u)},e.prototype.deleteNodeHead=function(e,t){var n=e.piece,i=n.lineFeedCnt,r=this.offsetInBuffer(n.bufferIndex,n.start),s=t,a=this.getLineFeedCnt(n.bufferIndex,s,n.end),l=a-i,u=r-this.offsetInBuffer(n.bufferIndex,s),c=n.length+u;e.piece=new d(n.bufferIndex,s,n.end,a,c),o.updateTreeMetadata(this,e,u,l)},e.prototype.shrinkNode=function(e,t,n){var i=e.piece,r=i.start,s=i.end,a=i.length,l=i.lineFeedCnt,u=t,c=this.getLineFeedCnt(i.bufferIndex,i.start,u),h=this.offsetInBuffer(i.bufferIndex,t)-this.offsetInBuffer(i.bufferIndex,r);e.piece=new d(i.bufferIndex,i.start,u,c,h),o.updateTreeMetadata(this,e,h-a,c-l) +;var p=new d(i.bufferIndex,n,s,this.getLineFeedCnt(i.bufferIndex,n,s),this.offsetInBuffer(i.bufferIndex,s)-this.offsetInBuffer(i.bufferIndex,n)),f=this.rbInsertRight(e,p);this.validateCRLFWithPrevNode(f)},e.prototype.appendToNode=function(e,t){this.adjustCarriageReturnFromNext(t,e)&&(t+="\n");var n=this.shouldCheckCRLF()&&this.startWithLF(t)&&this.endWithCR(e),i=this._buffers[0].buffer.length;this._buffers[0].buffer+=t;for(var r=l(t,!1),s=0;se)t=t.left;else{if(t.size_left+t.piece.length>=e){i+=t.size_left;var r={node:t,remainder:e-t.size_left,nodeStartOffset:i};return this._searchCache.set(r),r}e-=t.size_left+t.piece.length,i+=t.size_left+t.piece.length,t=t.right}return null},e.prototype.nodeAt2=function(e,t){for(var n=this.root,i=0;n!==o.SENTINEL;)if(n.left!==o.SENTINEL&&n.lf_left>=e-1)n=n.left;else{if(n.lf_left+n.piece.lineFeedCnt>e-1){var r=this.getAccumulatedValue(n,e-n.lf_left-2),s=this.getAccumulatedValue(n,e-n.lf_left-1);return i+=n.size_left,{node:n,remainder:Math.min(r+t-1,s),nodeStartOffset:i}}if(n.lf_left+n.piece.lineFeedCnt===e-1){if((r=this.getAccumulatedValue(n,e-n.lf_left-2))+t-1<=n.piece.length)return{node:n,remainder:r+t-1,nodeStartOffset:i} +;t-=n.piece.length-r;break}e-=n.lf_left+n.piece.lineFeedCnt,i+=n.size_left+n.piece.length,n=n.right}for(n=n.next();n!==o.SENTINEL;){if(n.piece.lineFeedCnt>0){var s=this.getAccumulatedValue(n,0),a=this.offsetOfNode(n);return{node:n,remainder:Math.min(t-1,s),nodeStartOffset:a}}if(n.piece.length>=t-1){return{node:n,remainder:t-1,nodeStartOffset:this.offsetOfNode(n)}}t-=n.piece.length,n=n.next()}return null},e.prototype.nodeCharCodeAt=function(e,t){if(e.piece.lineFeedCnt<1)return-1;var n=this._buffers[e.piece.bufferIndex],i=this.offsetInBuffer(e.piece.bufferIndex,e.piece.start)+t;return n.buffer.charCodeAt(i)},e.prototype.offsetOfNode=function(e){if(!e)return 0;for(var t=e.size_left;e!==this.root;)e.parent.right===e&&(t+=e.parent.size_left+e.parent.piece.length),e=e.parent;return t},e.prototype.shouldCheckCRLF=function(){return!(this._EOLNormalized&&"\n"===this._EOL)},e.prototype.startWithLF=function(e){if("string"==typeof e)return 10===e.charCodeAt(0);if(e===o.SENTINEL||0===e.piece.lineFeedCnt)return!1 +;var t=e.piece,n=this._buffers[t.bufferIndex].lineStarts,i=t.start.line,r=n[i]+t.start.column;if(i===n.length-1)return!1;return!(n[i+1]>r+1)&&10===this._buffers[t.bufferIndex].buffer.charCodeAt(r)},e.prototype.endWithCR=function(e){return"string"==typeof e?13===e.charCodeAt(e.length-1):e!==o.SENTINEL&&0!==e.piece.lineFeedCnt&&13===this.nodeCharCodeAt(e,e.piece.length-1)},e.prototype.validateCRLFWithPrevNode=function(e){if(this.shouldCheckCRLF()&&this.startWithLF(e)){var t=e.prev();this.endWithCR(t)&&this.fixCRLF(t,e)}},e.prototype.validateCRLFWithNextNode=function(e){if(this.shouldCheckCRLF()&&this.endWithCR(e)){var t=e.next();this.startWithLF(t)&&this.fixCRLF(e,t)}},e.prototype.fixCRLF=function(e,t){var n,i=[],r=this._buffers[e.piece.bufferIndex].lineStarts;n=0===e.piece.end.column?{line:e.piece.end.line-1,column:r[e.piece.end.line]-r[e.piece.end.line-1]-1}:{line:e.piece.end.line,column:e.piece.end.column-1};var s=e.piece.length-1,a=e.piece.lineFeedCnt-1 +;e.piece=new d(e.piece.bufferIndex,e.piece.start,n,a,s),o.updateTreeMetadata(this,e,-1,-1),0===e.piece.length&&i.push(e);var l={line:t.piece.start.line+1,column:0},u=t.piece.length-1,c=this.getLineFeedCnt(t.piece.bufferIndex,l,t.piece.end);t.piece=new d(t.piece.bufferIndex,l,t.piece.end,c,u),o.updateTreeMetadata(this,t,-1,-1),0===t.piece.length&&i.push(t);var h=this.createNewPieces("\r\n");this.rbInsertRight(e,h[0]);for(var p=0;p0){m.sort(function(e,t){return t.lineNumber-e.lineNumber}),S=[];for(var u=0,w=m.length;u0&&m[u-1].lineNumber===E)){var L=m[u].oldContent,x=this.getLineContent(E);0!==x.length&&x!==L&&-1===i.firstNonWhitespaceIndex(x)&&S.push(E)}}}return new r.ApplyEditsResult(C,b,S)},e.prototype._reduceOperations=function(e){return e.length<1e3?e:[this._toSingleEditOperation(e)]},e.prototype._toSingleEditOperation=function(e){for(var t=!1,i=e[0].range,o=e[e.length-1].range,s=new n.Range(i.startLineNumber,i.startColumn,o.endLineNumber,o.endColumn),a=i.startLineNumber,l=i.startColumn,u=[],d=0,c=e.length;d0){var h=l.lines.length,p=l.lines[0],f=l.lines[h-1];c=1===h?new n.Range(u,d,u,d+p.length):new n.Range(u,d,u+h-1,f.length+1)}else c=new n.Range(u,d,u,d);t=c.endLineNumber,i=c.endColumn,o.push(c),r=l}return o},e._sortOpsAscending=function(e,t){var i=n.Range.compareRangesUsingEnds(e.range,t.range);return 0===i?e.sortIndex-t.sortIndex:i},e._sortOpsDescending=function(e,t){var i=n.Range.compareRangesUsingEnds(e.range,t.range);return 0===i?t.sortIndex-e.sortIndex:-i},e}();t.PieceTreeTextBuffer=s}), +define(t[515],n([1,0,6,24,508,167]),function(e,t,n,i,o,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e,t,n,i,o,r,s,a){this._chunks=e,this._bom=t,this._cr=n,this._lf=i,this._crlf=o,this._containsRTL=r,this._isBasicASCII=s,this._normalizeEOL=a}return e.prototype._getEOL=function(e){var t=this._cr+this._lf+this._crlf,n=this._cr+this._crlf;return 0===t?e===i.DefaultEndOfLine.LF?"\n":"\r\n":n>t/2?"\r\n":"\n"},e.prototype.create=function(e){var t=this._getEOL(e),n=this._chunks;if(this._normalizeEOL&&("\r\n"===t&&(this._cr>0||this._lf>0)||"\n"===t&&(this._cr>0||this._crlf>0)))for(var i=0,s=n.length;i=55296&&t<=56319?(this._acceptChunk1(e.substr(0,e.length-1),!1),this._hasPreviousChar=!0,this._previousChar=t):(this._acceptChunk1(e,!1),this._hasPreviousChar=!1,this._previousChar=t)}},e.prototype._acceptChunk1=function(e,t){(t||0!==e.length)&&(this._hasPreviousChar?this._acceptChunk2(String.fromCharCode(this._previousChar)+e):this._acceptChunk2(e))},e.prototype._acceptChunk2=function(e){var t=r.createLineStarts(this._tmpLineStarts,e);this.chunks.push(new r.StringBuffer(e,t.lineStarts)),this.cr+=t.cr,this.lf+=t.lf,this.crlf+=t.crlf,this.isBasicASCII&&(this.isBasicASCII=t.isBasicASCII),this.isBasicASCII||this.containsRTL||(this.containsRTL=n.containsRTL(e))},e.prototype.finish=function(e){return void 0===e&&(e=!0),this._finish(), +new s(this.chunks,this.BOM,this.cr,this.lf,this.crlf,this.containsRTL,this.isBasicASCII,e)},e.prototype._finish=function(){if(0===this.chunks.length&&this._acceptChunk1("",!0),this._hasPreviousChar){this._hasPreviousChar=!1;var e=this.chunks[this.chunks.length-1];e.buffer+=String.fromCharCode(this._previousChar);var t=r.createLineStartsFast(e.buffer);e.lineStarts=t,13===this._previousChar&&this.cr++}},e}();t.PieceTreeTextBufferBuilder=a}),define(t[100],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.USUAL_WORD_SEPARATORS="`~!@#$%^&*()-=+[{]}\\|;:'\",.<>/?",t.DEFAULT_WORD_REGEXP=function(e){void 0===e&&(e="");for(var n="(-?\\d*\\.\\d\\w*)|([^",i=0;i=0||(n+="\\"+t.USUAL_WORD_SEPARATORS[i]);return n+="\\s]+)",new RegExp(n,"g")}(),t.ensureValidWordDefinition=function(e){var n=t.DEFAULT_WORD_REGEXP;if(e&&e instanceof RegExp)if(e.global)n=e;else{var i="g";e.ignoreCase&&(i+="i"),e.multiline&&(i+="m"), +n=new RegExp(e.source,i)}return n.lastIndex=0,n},t.getWordAtText=function(e,t,n,i){t.lastIndex=0;var o=t.exec(n);if(!o)return null;var r=o[0].indexOf(" ")>=0?function(e,t,n,i){var o=e-1-i;t.lastIndex=0;for(var r;r=t.exec(n);){if(r.index>o)return null;if(t.lastIndex>=o)return{word:r[0],startColumn:i+1+r.index,endColumn:i+1+t.lastIndex}}return null}(e,t,n,i):function(e,t,n,i){var o=e-1-i,r=n.lastIndexOf(" ",o-1)+1,s=n.indexOf(" ",o);-1===s&&(s=n.length),t.lastIndex=r;for(var a;a=t.exec(n);)if(a.index<=o&&t.lastIndex>=o)return{word:a[0],startColumn:i+1+a.index,endColumn:i+1+t.lastIndex};return null}(e,t,n,i);return t.lastIndex=0,r}}),define(t[528],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e){this._languageIdentifier=e}return e.prototype.getId=function(){return this._languageIdentifier.language},e.prototype.getLanguageIdentifier=function(){return this._languageIdentifier},e}();t.FrankensteinMode=n}),define(t[58],n([1,0]),function(e,t){ +"use strict";Object.defineProperty(t,"__esModule",{value:!0});!function(e){e[e.None=0]="None",e[e.Indent=1]="Indent",e[e.IndentOutdent=2]="IndentOutdent",e[e.Outdent=3]="Outdent"}(t.IndentAction||(t.IndentAction={}));var n=function(){function e(e){if(this.open=e.open,this.close=e.close,this._standardTokenMask=0,Array.isArray(e.notIn))for(var t=0,n=e.notIn.length;ts&&(s=u)}return s}if("string"==typeof e)return r?"*"===e?5:e===o?10:0:0;if(e){var d=e.language,c=e.pattern,h=e.scheme,p=e.hasAccessToAllModels;if(!r&&!p)return 0;s=0;if(h)if(h===t.scheme)s=10;else{ +if("*"!==h)return 0;s=5}if(d)if(d===o)s=10;else{if("*"!==d)return 0;s=Math.max(s,5)}if(c){if(c!==t.fsPath&&!n.match(c,t.fsPath))return 0;s=10}return s}return 0}Object.defineProperty(t,"__esModule",{value:!0}),t.score=i}),define(t[544],n([1,0,83,94]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e){for(var t=0,n=0,o=0,r=e.length;ot&&(t=l),a>n&&(n=a),u>n&&(n=u)}t++,n++;for(var d=new i.Uint8Matrix(n,t,0),o=0,r=e.length;o=this._maxCharCode?0:this._states.get(e,t)},e}(),r=null,s=null,a=function(){function e(){}return e._createLink=function(e,t,n,i,o){var r=o-1;do{var s=t.charCodeAt(r);if(2!==e.get(s))break;r--}while(r>i);if(i>0){var a=t.charCodeAt(i-1),l=t.charCodeAt(r);(40===a&&41===l||91===a&&93===l||123===a&&125===l)&&r--}return{range:{startLineNumber:n, +startColumn:i+1,endLineNumber:n,endColumn:r+2},url:t.substring(i,r+1)}},e.computeLinks=function(t){for(var i=(null===r&&(r=new o([[1,104,2],[1,72,2],[1,102,6],[1,70,6],[2,116,3],[2,84,3],[3,116,4],[3,84,4],[4,112,5],[4,80,5],[5,115,9],[5,83,9],[5,58,10],[6,105,7],[6,73,7],[7,108,8],[7,76,8],[8,101,9],[8,69,9],[9,58,10],[10,47,11],[11,47,12]])),r),a=function(){if(null===s){for(s=new n.CharacterClassifier(0),e=0;e<" \t<>'\"、。。、,.:;?!@#$%&*‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…".length;e++)s.set(" \t<>'\"、。。、,.:;?!@#$%&*‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…".charCodeAt(e),1);for(var e=0;e<".,;".length;e++)s.set(".,;".charCodeAt(e),2)}return s}(),l=[],u=1,d=t.getLineCount();u<=d;u++){for(var c=t.getLineContent(u),h=c.length,p=0,f=0,g=0,m=1,v=!1,_=!1,y=!1;p0&&e.getLanguageId(a-1)===r;)a--;return new n(e,r,a,s+1,e.getStartOffset(a),e.getEndOffset(s))};var n=function(){function e(e,t,n,i,o,r){this._actual=e,this.languageId=t,this._firstTokenIndex=n,this._lastTokenIndex=i,this.firstCharOffset=o,this._lastCharOffset=r}return e.prototype.getLineContent=function(){ +return this._actual.getLineContent().substring(this.firstCharOffset,this._lastCharOffset)},e.prototype.getTokenCount=function(){return this._lastTokenIndex-this._firstTokenIndex},e.prototype.findTokenIndexAtOffset=function(e){return this._actual.findTokenIndexAtOffset(e+this.firstCharOffset)-this._firstTokenIndex},e.prototype.getStandardTokenType=function(e){return this._actual.getStandardTokenType(e+this._firstTokenIndex)},e}();t.ScopedLineTokens=n,t.ignoreBracketsInToken=function(e){return 0!=(7&e)}}),define(t[550],n([1,0,58]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e){e.autoClosingPairs?this._autoClosingPairs=e.autoClosingPairs.map(function(e){return new n.StandardAutoClosingPairConditional(e)}):e.brackets?this._autoClosingPairs=e.brackets.map(function(e){return new n.StandardAutoClosingPairConditional({open:e[0],close:e[1]})}):this._autoClosingPairs=[],this._surroundingPairs=e.surroundingPairs||this._autoClosingPairs} +return e.prototype.getAutoClosingPairs=function(){return this._autoClosingPairs},e.prototype.shouldAutoClosePair=function(e,t,n){if(0===t.getTokenCount())return!0;for(var i=t.findTokenIndexAtOffset(n-2),o=t.getStandardTokenType(i),r=0;r=0?((i+=n?1:-1)<0?i=e.length-1:i%=e.length,e[i]):null},e.INSTANCE=new e,e}();t.BasicInplaceReplace=n}),define(t[553],n([1,0,10,6,58]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(t){(t=t||{}).brackets=t.brackets||[["(",")"],["{","}"],["[","]"]],this._brackets=t.brackets.map(function(t){return{open:t[0], +openRegExp:e._createOpenBracketRegExp(t[0]),close:t[1],closeRegExp:e._createCloseBracketRegExp(t[1])}}),this._regExpRules=t.regExpRules||[]}return e.prototype.onEnter=function(e,t,n){for(var i=0,r=this._regExpRules.length;i0&&n.length>0)for(var i=0,r=this._brackets.length;i0)for(var i=0,r=this._brackets.length;i=0;n--)t+=e.charAt(n);return t}(e=n)),t}}(),f=function(){function e(){}return e._findPrevBracketInText=function(e,t,n,o){var r=n.match(e) +;if(!r)return null;var s=n.length-r.index,a=r[0].length,l=o+s;return new i.Range(t,l-a+1,t,l+1)},e.findPrevBracketInToken=function(e,t,n,i,o){var r=p(n).substring(n.length-o,n.length-i);return this._findPrevBracketInText(e,t,r,i)},e.findNextBracketInText=function(e,t,n,o){var r=n.match(e);if(!r)return null;var s=r.index,a=r[0].length;if(0===a)return null;var l=o+s;return new i.Range(t,l+1,t,l+1+a)},e.findNextBracketInToken=function(e,t,n,i,o){var r=n.substring(i,o);return this.findNextBracketInText(e,t,r,i)},e}();t.BracketsUtils=f}),define(t[560],n([1,0,91,105,58]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t,n){n=n||{},this._richEditBrackets=e,this._complexAutoClosePairs=t.filter(function(e){return e.open.length>1&&!!e.close}).map(function(e){return new o.StandardAutoClosingPairConditional(e)}),n.docComment&&this._complexAutoClosePairs.push(new o.StandardAutoClosingPairConditional({open:n.docComment.open,close:n.docComment.close}))} +return e.prototype.getElectricCharacters=function(){var e=[];if(this._richEditBrackets)for(var t=0,n=this._richEditBrackets.brackets.length;t=0))return{appendText:s.close}}}}return null},e}();t.BracketElectricCharacterSupport=r}),define(t[41],n([1,0,550,560,553,551,105,9,10,6,2,100,91,3,58]),function(e,t,n,i,o,r,s,a,l,u,d,c,h,p,f){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var g=function(){function e(t,i,o){this._languageIdentifier=t,this._brackets=null,this._electricCharacter=null;var s=null;i&&(s=i._conf),this._conf=e._mergeConf(s,o),this.onEnter=e._handleOnEnter(this._conf), +this.comments=e._handleComments(this._conf),this.characterPair=new n.CharacterPairSupport(this._conf),this.wordDefinition=this._conf.wordPattern||c.DEFAULT_WORD_REGEXP,this.indentationRules=this._conf.indentationRules,this._conf.indentationRules&&(this.indentRulesSupport=new r.IndentRulesSupport(this._conf.indentationRules)),this.foldingRules=this._conf.folding||{}}return Object.defineProperty(e.prototype,"brackets",{get:function(){return!this._brackets&&this._conf.brackets&&(this._brackets=new s.RichEditBrackets(this._languageIdentifier,this._conf.brackets)),this._brackets},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"electricCharacter",{get:function(){if(!this._electricCharacter){var e=[];this._conf.autoClosingPairs?e=this._conf.autoClosingPairs:this._conf.brackets&&(e=this._conf.brackets.map(function(e){return{open:e[0],close:e[1]}})),this._electricCharacter=new i.BracketElectricCharacterSupport(this.brackets,e,this._conf.__electricCharacterSupport)}return this._electricCharacter}, +enumerable:!0,configurable:!0}),e._mergeConf=function(e,t){return{comments:e?t.comments||e.comments:t.comments,brackets:e?t.brackets||e.brackets:t.brackets,wordPattern:e?t.wordPattern||e.wordPattern:t.wordPattern,indentationRules:e?t.indentationRules||e.indentationRules:t.indentationRules,onEnterRules:e?t.onEnterRules||e.onEnterRules:t.onEnterRules,autoClosingPairs:e?t.autoClosingPairs||e.autoClosingPairs:t.autoClosingPairs,surroundingPairs:e?t.surroundingPairs||e.surroundingPairs:t.surroundingPairs,folding:e?t.folding||e.folding:t.folding,__electricCharacterSupport:e?t.__electricCharacterSupport||e.__electricCharacterSupport:t.__electricCharacterSupport}},e._handleOnEnter=function(e){var t={},n=!0;return e.brackets&&(n=!1,t.brackets=e.brackets),e.indentationRules&&(n=!1),e.onEnterRules&&(n=!1,t.regExpRules=e.onEnterRules),n?null:new o.OnEnterSupport(t)},e._handleComments=function(e){var t=e.comments;if(!t)return null;var n={};if(t.lineComment&&(n.lineCommentToken=t.lineComment),t.blockComment){ +var i=t.blockComment,o=i[0],r=i[1];n.blockCommentStartToken=o,n.blockCommentEndToken=r}return n},e}();t.RichEditSupport=g;var m=function(){return function(){}}();t.LanguageConfigurationChangeEvent=m;var v=function(){function e(){this._onDidChange=new a.Emitter,this.onDidChange=this._onDidChange.event,this._entries=[]}return e.prototype.register=function(e,t){var n=this,i=this._getRichEditSupport(e.id),o=new g(e,i,t);return this._entries[e.id]=o,this._onDidChange.fire({languageIdentifier:e}),d.toDisposable(function(){n._entries[e.id]===o&&(n._entries[e.id]=i,n._onDidChange.fire({languageIdentifier:e}))})},e.prototype._getRichEditSupport=function(e){return this._entries[e]||null},e.prototype._getElectricCharacterSupport=function(e){var t=this._getRichEditSupport(e);return t?t.electricCharacter||null:null},e.prototype.getElectricCharacters=function(e){var t=this._getElectricCharacterSupport(e);return t?t.getElectricCharacters():[]},e.prototype.onElectricCharacter=function(e,t,n){ +var i=h.createScopedLineTokens(t,n-1),o=this._getElectricCharacterSupport(i.languageId);return o?o.onElectricCharacter(e,i,n-i.firstCharOffset):null},e.prototype.getComments=function(e){var t=this._getRichEditSupport(e);return t?t.comments||null:null},e.prototype._getCharacterPairSupport=function(e){var t=this._getRichEditSupport(e);return t?t.characterPair||null:null},e.prototype.getAutoClosingPairs=function(e){var t=this._getCharacterPairSupport(e);return t?t.getAutoClosingPairs():[]},e.prototype.getSurroundingPairs=function(e){var t=this._getCharacterPairSupport(e);return t?t.getSurroundingPairs():[]},e.prototype.shouldAutoClosePair=function(e,t,n){var i=h.createScopedLineTokens(t,n-1),o=this._getCharacterPairSupport(i.languageId);return!!o&&o.shouldAutoClosePair(e,i,n-i.firstCharOffset)},e.prototype.getWordDefinition=function(e){var t=this._getRichEditSupport(e);return t?c.ensureValidWordDefinition(t.wordDefinition||null):c.ensureValidWordDefinition(null)},e.prototype.getFoldingRules=function(e){ +var t=this._getRichEditSupport(e);return t?t.foldingRules:{}},e.prototype.getIndentRulesSupport=function(e){var t=this._getRichEditSupport(e);return t?t.indentRulesSupport||null:null},e.prototype.getPrecedingValidLine=function(e,t,n){var i=e.getLanguageIdAtPosition(t,0);if(t>1){var o=t-1,r=-1;for(o=t-1;o>=1;o--){if(e.getLanguageIdAtPosition(o,0)!==i)return r;var s=e.getLineContent(o);if(!n.shouldIgnore(s)&&!/^\s+$/.test(s)&&""!==s)return o;r=o}}return-1},e.prototype.getInheritIndentForLine=function(e,t,n){void 0===n&&(n=!0);var i=this.getIndentRulesSupport(e.getLanguageIdentifier().id);if(!i)return null;if(t<=1)return{indentation:"",action:null};var o=this.getPrecedingValidLine(e,t,i);if(o<0)return null;if(o<1)return{indentation:"",action:null};var r=e.getLineContent(o);if(i.shouldIncrease(r)||i.shouldIndentNextLine(r))return{indentation:u.getLeadingWhitespace(r),action:f.IndentAction.Indent,line:o};if(i.shouldDecrease(r))return{indentation:u.getLeadingWhitespace(r),action:null,line:o};if(1===o)return{ +indentation:u.getLeadingWhitespace(e.getLineContent(o)),action:null,line:o};var s=o-1,a=i.getIndentMetadata(e.getLineContent(s));if(!(3&a)&&4&a){for(var l=0,d=s-1;d>0;d--)if(!i.shouldIndentNextLine(e.getLineContent(d))){l=d;break}return{indentation:u.getLeadingWhitespace(e.getLineContent(l+1)),action:null,line:l+1}}if(n)return{indentation:u.getLeadingWhitespace(e.getLineContent(o)),action:null,line:o};for(d=o;d>0;d--){var c=e.getLineContent(d);if(i.shouldIncrease(c))return{indentation:u.getLeadingWhitespace(c),action:f.IndentAction.Indent,line:d};if(i.shouldIndentNextLine(c)){for(var l=0,h=d-1;h>0;h--)if(!i.shouldIndentNextLine(e.getLineContent(d))){l=h;break}return{indentation:u.getLeadingWhitespace(e.getLineContent(l+1)),action:null,line:l+1}}if(i.shouldDecrease(c))return{indentation:u.getLeadingWhitespace(c),action:null,line:d}}return{indentation:u.getLeadingWhitespace(e.getLineContent(1)),action:null,line:1}},e.prototype.getGoodIndentForLine=function(e,t,n,i){var o=this.getIndentRulesSupport(t) +;if(!o)return null;var r=this.getInheritIndentForLine(e,n),s=e.getLineContent(n);if(r){var a=r.line;if(void 0!==a){var d=this._getOnEnterSupport(t),c=null;try{c=d.onEnter("",e.getLineContent(a),"")}catch(e){l.onUnexpectedError(e)}if(c){var h=u.getLeadingWhitespace(e.getLineContent(a));return c.removeText&&(h=h.substring(0,h.length-c.removeText)),c.indentAction===f.IndentAction.Indent||c.indentAction===f.IndentAction.IndentOutdent?h=i.shiftIndent(h):c.indentAction===f.IndentAction.Outdent&&(h=i.unshiftIndent(h)),o.shouldDecrease(s)&&(h=i.unshiftIndent(h)),c.appendText&&(h+=c.appendText),u.getLeadingWhitespace(h)}}return o.shouldDecrease(s)?r.action===f.IndentAction.Indent?r.indentation:i.unshiftIndent(r.indentation):r.action===f.IndentAction.Indent?i.shiftIndent(r.indentation):r.indentation}return null},e.prototype.getIndentForEnter=function(e,t,n,i){e.forceTokenization(t.startLineNumber);var o,r,s=e.getLineTokens(t.startLineNumber),a=h.createScopedLineTokens(s,t.startColumn-1),l=a.getLineContent(),d=!1 +;if(a.firstCharOffset>0&&s.getLanguageId(0)!==a.languageId?(d=!0,o=l.substr(0,t.startColumn-1-a.firstCharOffset)):o=s.getLineContent().substring(0,t.startColumn-1),t.isEmpty())r=l.substr(t.startColumn-1-a.firstCharOffset);else{r=this.getScopedLineTokens(e,t.endLineNumber,t.endColumn).getLineContent().substr(t.endColumn-1-a.firstCharOffset)}var c=this.getIndentRulesSupport(a.languageId);if(!c)return null;var p=o,g=u.getLeadingWhitespace(o);if(!i&&!d){var m=this.getInheritIndentForLine(e,t.startLineNumber);c.shouldDecrease(o)&&m&&(g=m.indentation,m.action!==f.IndentAction.Indent&&(g=n.unshiftIndent(g))),p=g+u.ltrim(u.ltrim(o," "),"\t")}var v={getLineTokens:function(t){return e.getLineTokens(t)},getLanguageIdentifier:function(){return e.getLanguageIdentifier()},getLanguageIdAtPosition:function(t,n){return e.getLanguageIdAtPosition(t,n)},getLineContent:function(n){return n===t.startLineNumber?p:e.getLineContent(n)}},_=u.getLeadingWhitespace(s.getLineContent()),y=this.getInheritIndentForLine(v,t.startLineNumber+1) +;if(!y){var C=d?_:g;return{beforeEnter:C,afterEnter:C}}var b=d?_:y.indentation;return y.action===f.IndentAction.Indent&&(b=n.shiftIndent(b)),c.shouldDecrease(r)&&(b=n.unshiftIndent(b)),{beforeEnter:d?_:g,afterEnter:b}},e.prototype.getIndentActionForType=function(e,t,n,i){var o=this.getScopedLineTokens(e,t.startLineNumber,t.startColumn),r=this.getIndentRulesSupport(o.languageId);if(!r)return null;var s,a=o.getLineContent(),l=a.substr(0,t.startColumn-1-o.firstCharOffset);if(t.isEmpty())s=a.substr(t.startColumn-1-o.firstCharOffset);else{s=this.getScopedLineTokens(e,t.endLineNumber,t.endColumn).getLineContent().substr(t.endColumn-1-o.firstCharOffset)}if(!r.shouldDecrease(l+s)&&r.shouldDecrease(l+n+s)){var u=this.getInheritIndentForLine(e,t.startLineNumber,!1);if(!u)return null;var d=u.indentation;return u.action!==f.IndentAction.Indent&&(d=i.unshiftIndent(d)),d}return null},e.prototype.getIndentMetadata=function(e,t){var n=this.getIndentRulesSupport(e.getLanguageIdentifier().id) +;return n?t<1||t>e.getLineCount()?null:n.getIndentMetadata(e.getLineContent(t)):null},e.prototype._getOnEnterSupport=function(e){var t=this._getRichEditSupport(e);return t?t.onEnter||null:null},e.prototype.getRawEnterActionAtPosition=function(e,t,n){var i=this.getEnterAction(e,new p.Range(t,n,t,n));return i?i.enterAction:null},e.prototype.getEnterAction=function(e,t){var n=this.getIndentationAtPosition(e,t.startLineNumber,t.startColumn),i=this.getScopedLineTokens(e,t.startLineNumber,t.startColumn),o=this._getOnEnterSupport(i.languageId);if(!o)return null;var r,s=i.getLineContent(),a=s.substr(0,t.startColumn-1-i.firstCharOffset);if(t.isEmpty())r=s.substr(t.startColumn-1-i.firstCharOffset);else{r=this.getScopedLineTokens(e,t.endLineNumber,t.endColumn).getLineContent().substr(t.endColumn-1-i.firstCharOffset)}var u=t.startLineNumber,d="";if(u>1&&0===i.firstCharOffset){var c=this.getScopedLineTokens(e,u-1);c.languageId===i.languageId&&(d=c.getLineContent())}var h=null;try{h=o.onEnter(d,a,r)}catch(e){ +l.onUnexpectedError(e)}return h?(h.appendText||(h.indentAction===f.IndentAction.Indent||h.indentAction===f.IndentAction.IndentOutdent?h.appendText="\t":h.appendText=""),h.removeText&&(n=n.substring(0,n.length-h.removeText)),{enterAction:h,indentation:n}):null},e.prototype.getIndentationAtPosition=function(e,t,n){var i=e.getLineContent(t),o=u.getLeadingWhitespace(i);return o.length>n-1&&(o=o.substring(0,n-1)),o},e.prototype.getScopedLineTokens=function(e,t,n){e.forceTokenization(t);var i=e.getLineTokens(t),o=isNaN(n)?e.getLineMaxColumn(t)-1:n-1;return h.createScopedLineTokens(i,o)},e.prototype.getBracketsSupport=function(e){var t=this._getRichEditSupport(e);return t?t.brackets||null:null},e}();t.LanguageConfigurationRegistryImpl=v,t.LanguageConfigurationRegistry=new v}),define(t[204],n([1,0,27]),function(e,t,n){"use strict";function i(e){if(!e||!Array.isArray(e))return[];for(var t=[],n=0,i=0,o=e.length;i=1&&""===e[0].token;){var r=e.shift();-1!==r.fontStyle&&(n=r.fontStyle),null!==r.foreground&&(i=r.foreground),null!==r.background&&(o=r.background)}for(var a=new u,l=0,c=t;lt?1:0}Object.defineProperty(t,"__esModule",{value:!0});var a=function(){return function(e,t,n,i,o){this.token=e,this.index=t,this.fontStyle=n,this.foreground=i,this.background=o}}();t.ParsedTokenThemeRule=a,t.parseTokenTheme=i;var l=/^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/,u=function(){function e(){this._lastColorId=0,this._id2color=[],this._color2id=new Map}return e.prototype.getId=function(e){if(null===e)return 0;var t=e.match(l);if(!t)throw new Error("Illegal value for token color: "+e);e=t[1].toUpperCase();var i=this._color2id.get(e);return i||(i=++this._lastColorId,this._color2id.set(e,i),this._id2color[i]=n.Color.fromHex("#"+e),i)},e.prototype.getColorMap=function(){return this._id2color.slice(0)},e}();t.ColorMap=u;var d=function(){function e(e,t){this._colorMap=e,this._root=t,this._cache=new Map}return e.createFromRawTokenTheme=function(e,t){return this.createFromParsedTokenTheme(i(e),t)},e.createFromParsedTokenTheme=function(e,t){return o(e,t)}, +e.prototype.getColorMap=function(){return this._colorMap.getColorMap()},e.prototype._match=function(e){return this._root.match(e)},e.prototype.match=function(e,t){var n=this._cache.get(t);if(void 0===n){var i=this._match(t),o=r(t);n=(i.metadata|o<<8)>>>0,this._cache.set(t,n)}return(n|e<<0)>>>0},e}();t.TokenTheme=d;var c=/\b(comment|string|regex)\b/;t.toStandardTokenType=r,t.strcmp=s;var h=function(){function e(e,t,n){this._fontStyle=e,this._foreground=t,this._background=n,this.metadata=(this._fontStyle<<11|this._foreground<<14|this._background<<23)>>>0}return e.prototype.clone=function(){return new e(this._fontStyle,this._foreground,this._background)},e.prototype.acceptOverwrite=function(e,t,n){-1!==e&&(this._fontStyle=e),0!==t&&(this._foreground=t),0!==n&&(this._background=n),this.metadata=(this._fontStyle<<11|this._foreground<<14|this._background<<23)>>>0},e}();t.ThemeTrieElementRule=h;var p=function(){function e(e){this._mainRule=e,this._children=new Map}return e.prototype.match=function(e){ +if(""===e)return this._mainRule;var t,n,i=e.indexOf(".");-1===i?(t=e,n=""):(t=e.substring(0,i),n=e.substring(i+1));var o=this._children.get(t);return void 0!==o?o.match(n):this._mainRule},e.prototype.insert=function(t,n,i,o){if(""!==t){var r,s,a=t.indexOf(".");-1===a?(r=t,s=""):(r=t.substring(0,a),s=t.substring(a+1));var l=this._children.get(r);void 0===l&&(l=new e(this._mainRule.clone()),this._children.set(r,l)),l.insert(s,n,i,o)}else this._mainRule.acceptOverwrite(n,i,o)},e}();t.ThemeTrieElement=p,t.generateTokensCSSForColorMap=function(e){for(var t=[],n=1,i=e.length;ni&&(p=i-f);var g=u.color,m=this._color2Id[g] +;m||(m=++this._lastAssignedId,this._color2Id[g]=m,this._id2Color[m]=g);var v=new n(p-f,p+f,m);u.setColorZone(v),s.push(v)}return this._colorZonesInvalid=!1,s.sort(n.compare),s},e}();t.OverviewZoneManager=o}),define(t[88],n([1,0,3]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){this._viewLayout=e,this.viewportData=t,this.scrollWidth=this._viewLayout.getScrollWidth(),this.scrollHeight=this._viewLayout.getScrollHeight(),this.visibleRange=this.viewportData.visibleRange,this.bigNumbersDelta=this.viewportData.bigNumbersDelta;var n=this._viewLayout.getCurrentViewport();this.scrollTop=n.top,this.scrollLeft=n.left,this.viewportWidth=n.width,this.viewportHeight=n.height}return e.prototype.getScrolledTopFromAbsoluteTop=function(e){return e-this.scrollTop},e.prototype.getVerticalOffsetForLineNumber=function(e){return this._viewLayout.getVerticalOffsetForLineNumber(e)},e.prototype.getDecorationsInViewport=function(){ +return this.viewportData.getDecorationsInViewport()},e}();t.RestrictedRenderingContext=i;var r=function(e){function t(t,n,i){var o=e.call(this,t,n)||this;return o._viewLines=i,o}return o(t,e),t.prototype.linesVisibleRangesForRange=function(e,t){return this._viewLines.linesVisibleRangesForRange(e,t)},t.prototype.visibleRangeForPosition=function(e){var t=this._viewLines.visibleRangesForRange2(new n.Range(e.lineNumber,e.column,e.lineNumber,e.column));return t?t[0]:null},t}(i);t.RenderingContext=r;var s=function(){return function(e,t){this.lineNumber=e,this.ranges=t}}();t.LineVisibleRanges=s;var a=function(){function e(e,t){this.left=Math.round(e),this.width=Math.round(t)}return e.prototype.toString=function(){return"["+this.left+","+this.width+"]"},e}();t.HorizontalRange=a}),define(t[209],n([1,0,88]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){this.left=e,this.width=t}return e.prototype.toString=function(){return"["+this.left+","+this.width+"]"}, +e.compare=function(e,t){return e.left-t.left},e}(),o=function(){function e(){}return e._createRange=function(){return this._handyReadyRange||(this._handyReadyRange=document.createRange()),this._handyReadyRange},e._detachRange=function(e,t){e.selectNodeContents(t)},e._readClientRects=function(e,t,n,i,o){var r=this._createRange();try{return r.setStart(e,t),r.setEnd(n,i),r.getClientRects()}catch(e){return null}finally{this._detachRange(r,o)}},e._mergeAdjacentRanges=function(e){if(1===e.length)return[new n.HorizontalRange(e[0].left,e[0].width)];e.sort(i.compare);for(var t=[],o=0,r=e[0].left,s=e[0].width,a=1,l=e.length;a=d?s=Math.max(s,d+c-r):(t[o++]=new n.HorizontalRange(r,s),r=d,s=c)}return t[o++]=new n.HorizontalRange(r,s),t},e._createHorizontalRangesFromClientRects=function(e,t){if(!e||0===e.length)return null;for(var n=[],o=0,r=e.length;oa)return null;(t=Math.min(a,Math.max(0,t)))!==(i=Math.min(a,Math.max(0,i)))&&i>0&&0===o&&(i--,o=Number.MAX_VALUE);var l=e.children[t].firstChild,u=e.children[i].firstChild;if(l&&u||(!l&&0===n&&t>0&&(l=e.children[t-1].firstChild,n=1073741824),!u&&0===o&&i>0&&(u=e.children[i-1].firstChild,o=1073741824)),!l||!u)return null;n=Math.min(l.textContent.length,Math.max(0,n)),o=Math.min(u.textContent.length,Math.max(0,o));var d=this._readClientRects(l,n,u,o,s);return this._createHorizontalRangesFromClientRects(d,r)},e}();t.RangeUtil=o}),define(t[210],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e,t,n,i){this.configuration=e,this.theme=t,this.model=n,this.viewLayout=n.viewLayout,this.privateViewEventBus=i}return e.prototype.addEventHandler=function(e){this.privateViewEventBus.addEventHandler(e)},e.prototype.removeEventHandler=function(e){ +this.privateViewEventBus.removeEventHandler(e)},e}();t.ViewContext=n}),define(t[211],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e){this._eventHandlerGateKeeper=e,this._eventHandlers=[],this._eventQueue=null,this._isConsumingQueue=!1}return e.prototype.addEventHandler=function(e){for(var t=0,n=this._eventHandlers.length;t0&&this._emit(e)}},t.prototype._emit=function(e){for(var t=this._listeners.slice(0),i=0,o=t.length;in)&&(!d.isEmpty()||0!==u.type&&3!==u.type)){var c=d.startLineNumber===n?d.startColumn:i,h=d.endLineNumber===n?d.endColumn:o;r[s++]=new e(c,h,u.inlineClassName,u.type)}}return r},e.compare=function(e,t){return e.startColumn===t.startColumn?e.endColumn===t.endColumn?e.classNamet.className?1:0:e.endColumn-t.endColumn:e.startColumn-t.startColumn},e}();t.LineDecoration=i;var o=function(){return function(e,t,n){this.startOffset=e,this.endOffset=t,this.className=n}}();t.DecorationSegment=o;var r=function(){function e(){this.stopOffsets=[],this.classNames=[], +this.count=0}return e.prototype.consumeLowerThan=function(e,t,n){for(;this.count>0&&this.stopOffsets[0]0&&t=e){this.stopOffsets.splice(n,0,e),this.classNames.splice(n,0,t);break}this.count++},e}(),s=function(){function e(){}return e.normalize=function(e,t){if(0===t.length)return[];for(var i=[],o=new r,s=0,a=0,l=t.length;a1){p=e.charCodeAt(d-2);n.isHighSurrogate(p)&&d--}if(c>1){var p=e.charCodeAt(c-2);n.isHighSurrogate(p)&&c--} +var f=d-1,g=c-2;s=o.consumeLowerThan(f,s,i),0===o.count&&(s=f),o.insert(g,h)}return o.consumeLowerThan(1073741824,s,i),i},e}();t.LineDecorationsNormalizer=s}),define(t[96],n([1,0,125,6,112]),function(e,t,n,i,o){"use strict";function r(e,t){if(0===e.lineContent.length){var o=0,r=" ";if(e.lineDecorations.length>0){for(var a=[],d=0,h=e.lineDecorations.length;d')}return t.appendASCIIString(r),new u(new l(0,0),!1,o)}return function(e,t){var n=e.fontIsMonospace,o=e.containsForeignElements,r=e.lineContent,s=e.len,a=e.isOverflowing,d=e.parts,c=e.tabSize,h=e.containsRTL,p=e.spaceWidth,f=e.renderWhitespace,g=e.renderControlCharacters,m=new l(s+1,d.length),v=0,_=0,y=0,C=0,b=0;t.appendASCIIString("");for(var S=0,w=d.length;S=0;if(y=0,t.appendASCIIString('0&&(k>1?t.write1(8594):t.write1(65515),k--);k>0;)t.write1(160),k--}else t.write1(183);y++}C=I}else{I=0;for(h&&t.appendASCIIString(' dir="ltr"'),t.appendASCII(62);v0;)t.write1(160),I++,k--;break;case 32:t.write1(160),I++;break;case 60:t.appendASCIIString("<"),I++;break;case 62:t.appendASCIIString(">"),I++;break;case 38:t.appendASCIIString("&"),I++;break;case 0:t.appendASCIIString("�"),I++;break +;case 65279:case 8232:t.write1(65533),I++;break;default:i.isFullWidthCharacter(T)&&_++,g&&T<32?(t.write1(9216+T),I++):(t.write1(T),I++)}y++}C=I}t.appendASCIIString("")}m.setPartData(s,d.length-1,y,b),a&&t.appendASCIIString("");return t.appendASCIIString(""),new u(m,h,o)}(function(e){var t,o,r=e.useMonospaceOptimizations,a=e.lineContent;-1!==e.stopRenderingLineAfter&&e.stopRenderingLineAfter0&&(i[o++]=new s(t,""));for(var r=0,a=e.getCount();r=n){i[o++]=new s(n,u);break}i[o++]=new s(l,u)}}return i}(e.lineTokens,e.fauxIndentLength,o);2!==e.renderWhitespace&&1!==e.renderWhitespace||(l=function(e,t,n,o,r,a,l,u){var d,c=[],h=0,p=0,f=o[p].type,g=o[p].endIndex,m=i.firstNonWhitespaceIndex(e);-1===m?(m=t,d=t):d=i.lastNonWhitespaceIndex(e);for(var v=0,_=0;_d)b=!0;else if(9===C)b=!0;else if(32===C)if(u)if(y)b=!0;else{var S=_+1=a)&&(c[h++]=new s(_,"vs-whitespace"),v%=a):(_===g||b&&_>r)&&(c[h++]=new s(_,f),v%=a),9===C?v=a:i.isFullWidthCharacter(C)?v+=2:v++,y=b,_===g&&(f=o[++p].type,g=o[p].endIndex)}var w=!1;if(y)if(n&&u){var E=t>0?e.charCodeAt(t-1):0,L=t>1?e.charCodeAt(t-2):0;32===E&&32!==L&&9!==L||(w=!0)}else w=!0;return c[h++]=new s(t,w?"vs-whitespace":f),c}(a,o,e.continuesWithWrappedLine,l,e.fauxIndentLength,e.tabSize,r,1===e.renderWhitespace));var u=0;if(e.lineDecorations.length>0){for(var d=0,h=e.lineDecorations.length;dc&&(c=v.startOffset,u[d++]=new s(c,m)),!(v.endOffset+1<=g)){c=g,u[d++]=new s(c,m+" "+v.className);break}c=v.endOffset+1,u[d++]=new s(c,m+" "+v.className),l++}g>c&&(c=g,u[d++]=new s(c,m))}var _=i[i.length-1].endIndex;if(l50){for(var c=l.type,h=Math.ceil(d/50),p=1;p>>16},e.getCharIndex=function(e){return(65535&e)>>>0},e.prototype.setPartData=function(e,t,n,i){var o=(t<<16|n<<0)>>>0;this._data[e]=o,this._absoluteOffsets[e]=i+n}, +e.prototype.getAbsoluteOffsets=function(){return this._absoluteOffsets},e.prototype.charOffsetToPartData=function(e){return 0===this.length?0:e<0?this._data[0]:e>=this.length?this._data[this.length-1]:this._data[e]},e.prototype.partDataToCharOffset=function(t,n,i){if(0===this.length)return 0;for(var o=(t<<16|i<<0)>>>0,r=0,s=this.length-1;r+1>>1,l=this._data[a];if(l===o)return a;l>o?s=a:r=a}if(r===s)return r;var u=this._data[r],d=this._data[s];if(u===o)return r;if(d===o)return s;var c=e.getPartIndex(u);return i-e.getCharIndex(u)<=(c!==e.getPartIndex(d)?n:e.getCharIndex(d))-i?r:s},e}();t.CharacterMapping=l;var u=function(){return function(e,t,n){this.characterMapping=e,this.containsRTL=t,this.containsForeignElements=n}}();t.RenderLineOutput=u,t.renderViewLine=r;var d=function(){return function(e,t,n,i){this.characterMapping=e,this.html=t,this.containsRTL=n,this.containsForeignElements=i}}();t.RenderLineOutput2=d,t.renderViewLine2=function(e){var t=o.createStringBuilder(1e4),n=r(e,t) +;return new d(n.characterMapping,t.build(),n.containsRTL,n.containsForeignElements)};var c=function(){return function(e,t,n,i,o,r,s,a,l,u,d){this.fontIsMonospace=e,this.lineContent=t,this.len=n,this.isOverflowing=i,this.parts=o,this.containsForeignElements=r,this.tabSize=s,this.containsRTL=a,this.spaceWidth=l,this.renderWhitespace=u,this.renderControlCharacters=d}}()}),define(t[215],n([1,0,3]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t,i,o){this.selections=e,this.startLineNumber=0|t.startLineNumber,this.endLineNumber=0|t.endLineNumber,this.relativeVerticalOffset=t.relativeVerticalOffset,this.bigNumbersDelta=0|t.bigNumbersDelta,this.whitespaceViewportData=i,this._model=o,this.visibleRange=new n.Range(t.startLineNumber,this._model.getLineMinColumn(t.startLineNumber),t.endLineNumber,this._model.getLineMaxColumn(t.endLineNumber))}return e.prototype.getViewLineRenderingData=function(e){ +return this._model.getViewLineRenderingData(this.visibleRange,e)},e.prototype.getDecorationsInViewport=function(){return this._model.getDecorationsInViewport(this.visibleRange)},e}();t.ViewportData=i}),define(t[216],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(){this._heights=[],this._minWidths=[],this._ids=[],this._afterLineNumbers=[],this._ordinals=[],this._prefixSum=[],this._prefixSumValidIndex=-1,this._whitespaceId2Index={},this._lastWhitespaceId=0,this._minWidth=-1}return e.findInsertionIndex=function(e,t,n,i){for(var o=0,r=e.length;o>>1;t===e[s]?i=t&&(this._whitespaceId2Index[u]=d+1)}this._whitespaceId2Index[e.toString()]=t,this._prefixSumValidIndex=Math.min(this._prefixSumValidIndex,t-1)},e.prototype.changeWhitespace=function(e,t,n){e|=0,t|=0,n|=0;var i=!1;return i=this.changeWhitespaceHeight(e,n)||i,i=this.changeWhitespaceAfterLineNumber(e,t)||i},e.prototype.changeWhitespaceHeight=function(e,t){t|=0;var n=(e|=0).toString();if(this._whitespaceId2Index.hasOwnProperty(n)){var i=this._whitespaceId2Index[n];if(this._heights[i]!==t)return this._heights[i]=t,this._prefixSumValidIndex=Math.min(this._prefixSumValidIndex,i-1),!0}return!1},e.prototype.changeWhitespaceAfterLineNumber=function(t,n){n|=0;var i=(t|=0).toString();if(this._whitespaceId2Index.hasOwnProperty(i)){ +var o=this._whitespaceId2Index[i];if(this._afterLineNumbers[o]!==n){var r=this._ordinals[o],s=this._heights[o],a=this._minWidths[o];this.removeWhitespace(t);var l=e.findInsertionIndex(this._afterLineNumbers,n,this._ordinals,r);return this._insertWhitespaceAtIndex(t,l,n,r,s,a),!0}}return!1},e.prototype.removeWhitespace=function(e){var t=(e|=0).toString();if(this._whitespaceId2Index.hasOwnProperty(t)){var n=this._whitespaceId2Index[t];return delete this._whitespaceId2Index[t],this._removeWhitespaceAtIndex(n),this._minWidth=-1,!0}return!1},e.prototype._removeWhitespaceAtIndex=function(e){e|=0,this._heights.splice(e,1),this._minWidths.splice(e,1),this._ids.splice(e,1),this._afterLineNumbers.splice(e,1),this._ordinals.splice(e,1),this._prefixSum.splice(e,1),this._prefixSumValidIndex=Math.min(this._prefixSumValidIndex,e-1);for(var t=Object.keys(this._whitespaceId2Index),n=0,i=t.length;n=e&&(this._whitespaceId2Index[o]=r-1)}}, +e.prototype.onLinesDeleted=function(e,t){e|=0,t|=0;for(var n=0,i=this._afterLineNumbers.length;nt&&(this._afterLineNumbers[n]-=t-e+1)}},e.prototype.onLinesInserted=function(e,t){e|=0,t|=0;for(var n=0,i=this._afterLineNumbers.length;n=t.length||t[o+1]>=e)return o;n=o+1|0}else i=o-1|0}return-1},e.prototype._findFirstWhitespaceAfterLineNumber=function(e){e|=0;var t=this._findLastWhitespaceBeforeLineNumber(e)+1;return t1?this._lineHeight*(e-1):0)+this._whitespaces.getAccumulatedHeightBeforeLineNumber(e)},e.prototype.getWhitespaceAccumulatedHeightBeforeLineNumber=function(e){return this._whitespaces.getAccumulatedHeightBeforeLineNumber(e)},e.prototype.getWhitespaceMinWidth=function(){return this._whitespaces.getMinWidth()},e.prototype.isAfterLines=function(e){return e>this.getLinesTotalHeight()},e.prototype.getLineNumberAtOrAfterVerticalOffset=function(e){if((e|=0)<0)return 1;for(var t=0|this._lineCount,n=this._lineHeight,i=1,o=t;i=s+n)i=r+1;else{if(e>=s)return r;o=r}}return i>t?t:i},e.prototype.getLinesViewportData=function(e,t){e|=0,t|=0 +;var n,i,o=this._lineHeight,r=0|this.getLineNumberAtOrAfterVerticalOffset(e),s=0|this.getVerticalOffsetForLineNumber(r),a=0|this._lineCount,l=0|this._whitespaces.getFirstWhitespaceIndexAfterLineNumber(r),u=0|this._whitespaces.getCount();-1===l?(l=u,i=a+1,n=0):(i=0|this._whitespaces.getAfterLineNumberForWhitespaceIndex(l),n=0|this._whitespaces.getHeightForWhitespaceIndex(l));var d=s,c=d,h=0;s>=5e5&&(h=5e5*Math.floor(s/5e5),c-=h=Math.floor(h/o)*o);for(var p=[],f=e+(t-e)/2,g=-1,m=r;m<=a;m++){if(-1===g){var v=d;(v<=f&&ff)&&(g=m)}for(d+=o,p[m-r]=c,c+=o;i===m;)c+=n,d+=n,++l>=u?i=a+1:(i=0|this._whitespaces.getAfterLineNumberForWhitespaceIndex(l),n=0|this._whitespaces.getHeightForWhitespaceIndex(l));if(d>=t){a=m;break}}-1===g&&(g=a);var _=0|this.getVerticalOffsetForLineNumber(a),y=r,C=a;return yt&&C--,{bigNumbersDelta:h,startLineNumber:r,endLineNumber:a,relativeVerticalOffset:p,centeredLineNumber:g,completelyVisibleStartLineNumber:y,completelyVisibleEndLineNumber:C}}, +e.prototype.getVerticalOffsetForWhitespaceIndex=function(e){e|=0;var t,n=this._whitespaces.getAfterLineNumberForWhitespaceIndex(e);t=n>=1?this._lineHeight*n:0;var i;return i=e>0?this._whitespaces.getAccumulatedHeight(e-1):0,t+i},e.prototype.getWhitespaceIndexAtOrAfterVerticallOffset=function(e){e|=0;var t,n,i,o=0,r=this._whitespaces.getCount()-1;if(r<0)return-1;if(e>=this.getVerticalOffsetForWhitespaceIndex(r)+this._whitespaces.getHeightForWhitespaceIndex(r))return-1;for(;o=n+i)o=t+1;else{if(e>=n)return t;r=t}return o},e.prototype.getWhitespaceAtVerticalOffset=function(e){e|=0;var t=this.getWhitespaceIndexAtOrAfterVerticallOffset(e);if(t<0)return null;if(t>=this._whitespaces.getCount())return null;var n=this.getVerticalOffsetForWhitespaceIndex(t);if(n>e)return null;var i=this._whitespaces.getHeightForWhitespaceIndex(t);return{id:this._whitespaces.getIdForWhitespaceIndex(t), +afterLineNumber:this._whitespaces.getAfterLineNumberForWhitespaceIndex(t),verticalOffset:n,height:i}},e.prototype.getWhitespaceViewportData=function(e,t){e|=0,t|=0;var n=this.getWhitespaceIndexAtOrAfterVerticallOffset(e),i=this._whitespaces.getCount()-1;if(n<0)return[];for(var o=[],r=n;r<=i;r++){var s=this.getVerticalOffsetForWhitespaceIndex(r),a=this._whitespaces.getHeightForWhitespaceIndex(r);if(s>=t)break;o.push({id:this._whitespaces.getIdForWhitespaceIndex(r),afterLineNumber:this._whitespaces.getAfterLineNumberForWhitespaceIndex(r),verticalOffset:s,height:a})}return o},e.prototype.getWhitespaces=function(){return this._whitespaces.getWhitespaces(this._lineHeight)},e}();t.LinesLayout=i}),define(t[129],n([1,0,94]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){return function(e,t){this.index=e,this.remainder=t}}();t.PrefixSumIndexOfResult=i;var o=function(){function e(e){this.values=e,this.prefixSum=new Uint32Array(e.length), +this.prefixSumValidIndex=new Int32Array(1),this.prefixSumValidIndex[0]=-1}return e.prototype.getCount=function(){return this.values.length},e.prototype.insertValues=function(e,t){e=n.toUint32(e);var i=this.values,o=this.prefixSum,r=t.length;return 0!==r&&(this.values=new Uint32Array(i.length+r),this.values.set(i.subarray(0,e),0),this.values.set(i.subarray(e),e+r),this.values.set(t,e),e-1=0&&this.prefixSum.set(o.subarray(0,this.prefixSumValidIndex[0]+1)),!0)},e.prototype.changeValue=function(e,t){return e=n.toUint32(e),t=n.toUint32(t),this.values[e]!==t&&(this.values[e]=t,e-1=i.length)return!1;var r=i.length-e;return t>=r&&(t=r),0!==t&&(this.values=new Uint32Array(i.length-t), +this.values.set(i.subarray(0,e),0),this.values.set(i.subarray(e+t),e),this.prefixSum=new Uint32Array(this.values.length),e-1=0&&this.prefixSum.set(o.subarray(0,this.prefixSumValidIndex[0]+1)),!0)},e.prototype.getTotalValue=function(){return 0===this.values.length?0:this._getAccumulatedValue(this.values.length-1)},e.prototype.getAccumulatedValue=function(e){return e<0?0:(e=n.toUint32(e),this._getAccumulatedValue(e))},e.prototype._getAccumulatedValue=function(e){if(e<=this.prefixSumValidIndex[0])return this.prefixSum[e];var t=this.prefixSumValidIndex[0]+1;0===t&&(this.prefixSum[0]=this.values[0],t++),e>=this.values.length&&(e=this.values.length-1);for(var n=t;n<=e;n++)this.prefixSum[n]=this.prefixSum[n-1]+this.values[n];return this.prefixSumValidIndex[0]=Math.max(this.prefixSumValidIndex[0],e),this.prefixSum[e]},e.prototype.getIndexOf=function(e){e=Math.floor(e),this.getTotalValue() +;for(var t,n,o,r=0,s=this.values.length-1;r<=s;)if(t=r+(s-r)/2|0,n=this.prefixSum[t],o=n-this.values[t],e=n))break;r=t+1}return new i(t,e-o)},e}();t.PrefixSumComputer=o;var r=function(){function e(e){this._cacheAccumulatedValueStart=0,this._cache=null,this._actual=new o(e),this._bustCache()}return e.prototype._bustCache=function(){this._cacheAccumulatedValueStart=0,this._cache=null},e.prototype.insertValues=function(e,t){this._actual.insertValues(e,t)&&this._bustCache()},e.prototype.changeValue=function(e,t){this._actual.changeValue(e,t)&&this._bustCache()},e.prototype.removeValues=function(e,t){this._actual.removeValues(e,t)&&this._bustCache()},e.prototype.getTotalValue=function(){return this._actual.getTotalValue()},e.prototype.getAccumulatedValue=function(e){return this._actual.getAccumulatedValue(e)},e.prototype.getIndexOf=function(e){if(e=Math.floor(e),null!==this._cache){var t=e-this._cacheAccumulatedValueStart;if(t>=0&&t=n._lines.length))return t=n._lines[o],s=n._wordenize(t,e),r=0,o+=1,a() +;i.done=!0,i.value=void 0}return i};return{next:a}},t.prototype._wordenize=function(e,t){var n,i=[];for(t.lastIndex=0;(n=t.exec(e))&&0!==n[0].length;)i.push({start:n.index,end:n.index+n[0].length});return i},t.prototype.getValueInRange=function(e){if((e=this._validateRange(e)).startLineNumber===e.endLineNumber)return this._lines[e.startLineNumber-1].substring(e.startColumn-1,e.endColumn-1);var t=this._eol,n=e.startLineNumber-1,i=e.endLineNumber-1,o=[];o.push(this._lines[n].substring(e.startColumn-1));for(var r=n+1;rthis._lines.length)t=this._lines.length,n=this._lines[t-1].length+1,i=!0;else{var o=this._lines[t-1].length+1;n<1?(n=1,i=!0):n>o&&(n=o,i=!0)}return i?{lineNumber:t,column:n}:e},t}(u.MirrorTextModel),m=function(){function t(e){this._foreignModuleFactory=e,this._foreignModule=null}return t.prototype.computeDiff=function(e,t,n){var o=this._getModel(e),r=this._getModel(t);if(!o||!r)return null +;var a=o.getLinesContent(),l=r.getLinesContent(),u=new s.DiffComputer(a,l,{shouldComputeCharChanges:!0,shouldPostProcessCharChanges:!0,shouldIgnoreTrimWhitespace:n,shouldMakePrettyDiff:!0});return i.TPromise.as(u.computeDiff())},t.prototype.computeMoreMinimalEdits=function(e,n){var o=this._getModel(e);if(!o)return i.TPromise.as(n);for(var s,l=[],u=0,d=n;ut._diffLimit)l.push({range:h,text:p});else for(var m=a.stringDiff(g,p,!1),v=o.offsetAt(r.Range.lift(h).getStartPosition()),_=0,y=m;_=n,u=s,d=i.viewportHeight-s>=n,c=e.left;return c+t>i.scrollLeft+i.viewportWidth&&(c=i.scrollLeft+i.viewportWidth-t),cthis._contentWidth)return null;var s=e.top-i,a=e.top+this._lineHeight,l=r+this._contentLeft,u=n.getDomNodePagePosition(this._viewDomNode.domNode),d=u.top+s-n.StandardWindow.scrollY,c=u.top+a-n.StandardWindow.scrollY,h=u.left+l-n.StandardWindow.scrollX,p=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,f=d>=22,g=c+i<=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)-22;if(h+t+20>p){h-=m=h-(p-t-20),l-=m}if(h<0){var m=h;h-=m,l-=m}return this._fixedOverflowWidgets&&(s=d,a=c,l=h),{aboveTop:s,fitsAbove:f,belowTop:a,fitsBelow:g,left:l}},e.prototype._prepareRenderWidgetAtExactPositionOverflowing=function(e){return new a(e.top,e.left+this._contentLeft)},e.prototype._getTopLeft=function(e){if(!this._viewPosition)return null;var t=e.visibleRangeForPosition(this._viewPosition);if(!t)return null +;var n=e.getVerticalOffsetForLineNumber(this._viewPosition.lineNumber)-e.scrollTop;return new a(n,t.left)},e.prototype._prepareRenderWidget=function(e,t){var n=this;if(!e)return null;for(var i=null,o=function(){if(!i){if(-1===n._cachedDomNodeClientWidth||-1===n._cachedDomNodeClientHeight){var o=n.domNode.domNode;n._cachedDomNodeClientWidth=o.clientWidth,n._cachedDomNodeClientHeight=o.clientHeight}i=n.allowEditorOverflow?n._layoutBoxInPage(e,n._cachedDomNodeClientWidth,n._cachedDomNodeClientHeight,t):n._layoutBoxInViewport(e,n._cachedDomNodeClientWidth,n._cachedDomNodeClientHeight,t)}},s=1;s<=2;s++)for(var l=0;le.endLineNumber||this.domNode.setMaxWidth(this._maxWidth))},e.prototype.prepareRender=function(e){var t=this._getTopLeft(e);this._renderData=this._prepareRenderWidget(t,e)},e.prototype.render=function(e){this._renderData?(this.allowEditorOverflow?(this.domNode.setTop(this._renderData.top),this.domNode.setLeft(this._renderData.left)):(this.domNode.setTop(this._renderData.top+e.scrollTop-e.bigNumbersDelta),this.domNode.setLeft(this._renderData.left)),this._isVisible||(this.domNode.setVisibility("inherit"),this.domNode.setAttribute("monaco-visible-content-widget","true"),this._isVisible=!0)):this._isVisible&&(this.domNode.removeAttribute("monaco-visible-content-widget"),this._isVisible=!1,this.domNode.setVisibility("hidden"))},e}()}),define(t[225],n([1,0,59,3,88,266]),function(e,t,n,i,r){"use strict";Object.defineProperty(t,"__esModule",{ +value:!0});var s=function(e){function t(t){var n=e.call(this)||this;return n._context=t,n._lineHeight=n._context.configuration.editor.lineHeight,n._typicalHalfwidthCharacterWidth=n._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth,n._renderResult=null,n._context.addEventHandler(n),n}return o(t,e),t.prototype.dispose=function(){this._context.removeEventHandler(this),this._context=null,this._renderResult=null,e.prototype.dispose.call(this)},t.prototype.onConfigurationChanged=function(e){return e.lineHeight&&(this._lineHeight=this._context.configuration.editor.lineHeight),e.fontInfo&&(this._typicalHalfwidthCharacterWidth=this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth),!0},t.prototype.onDecorationsChanged=function(e){return!0},t.prototype.onFlushed=function(e){return!0},t.prototype.onLinesChanged=function(e){return!0},t.prototype.onLinesDeleted=function(e){return!0},t.prototype.onLinesInserted=function(e){return!0},t.prototype.onScrollChanged=function(e){ +return e.scrollTopChanged||e.scrollWidthChanged},t.prototype.onZonesChanged=function(e){return!0},t.prototype.prepareRender=function(e){for(var t=e.getDecorationsInViewport(),n=[],o=0,r=0,s=t.length;rt.options.zIndex)return 1;var n=e.options.className,o=t.options.className;return no?1:i.Range.compareRangesUsingStarts(e.range,t.range)});for(var l=e.visibleRange.startLineNumber,u=e.visibleRange.endLineNumber,d=[],c=l;c<=u;c++){d[c-l]=""}this._renderWholeLineDecorations(e,n,d),this._renderNormalDecorations(e,n,d),this._renderResult=d},t.prototype._renderWholeLineDecorations=function(e,t,n){for(var i=String(this._lineHeight),o=e.visibleRange.startLineNumber,r=e.visibleRange.endLineNumber,s=0,a=t.length;s',d=Math.max(l.range.startLineNumber,o),c=Math.min(l.range.endLineNumber,r),h=d;h<=c;h++){n[h-o]+=u}}},t.prototype._renderNormalDecorations=function(e,t,n){for(var o=String(this._lineHeight),r=e.visibleRange.startLineNumber,s=null,a=!1,l=null,u=0,d=t.length;u';a[h]+=v}}},t.prototype.render=function(e,t){if(!this._renderResult)return"";var n=t-e;return n<0||n>=this._renderResult.length?"":this._renderResult[n]},t}(n.DynamicViewOverlay);t.DecorationsOverlay=s}),define(t[134],n([1,0,59,267]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){return function(e,t,n){this.startLineNumber=+e,this.endLineNumber=+t,this.className=String(n)}}();t.DecorationToRender=i;var r=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype._render=function(e,t,n){for(var i=[],o=e;o<=t;o++){i[o-e]=[]}if(0===n.length)return i +;n.sort(function(e,t){return e.className===t.className?e.startLineNumber===t.startLineNumber?e.endLineNumber-t.endLineNumber:e.startLineNumber-t.startLineNumber:e.className',s=[],a=t;a<=n;a++){var l=a-t,u=i[l];0===u.length?s[l]="":s[l]='
                                      =this._renderResult.length?"":this._renderResult[n]},t}(r);t.GlyphMarginOverlay=s}),define(t[227],n([1,0,134,275]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(e){function t(t){var n=e.call(this)||this;return n._context=t,n._decorationsLeft=n._context.configuration.editor.layoutInfo.decorationsLeft, +n._decorationsWidth=n._context.configuration.editor.layoutInfo.decorationsWidth,n._renderResult=null,n._context.addEventHandler(n),n}return o(t,e),t.prototype.dispose=function(){this._context.removeEventHandler(this),this._context=null,this._renderResult=null,e.prototype.dispose.call(this)},t.prototype.onConfigurationChanged=function(e){return e.layoutInfo&&(this._decorationsLeft=this._context.configuration.editor.layoutInfo.decorationsLeft,this._decorationsWidth=this._context.configuration.editor.layoutInfo.decorationsWidth),!0},t.prototype.onDecorationsChanged=function(e){return!0},t.prototype.onFlushed=function(e){return!0},t.prototype.onLinesChanged=function(e){return!0},t.prototype.onLinesDeleted=function(e){return!0},t.prototype.onLinesInserted=function(e){return!0},t.prototype.onScrollChanged=function(e){return e.scrollTopChanged},t.prototype.onZonesChanged=function(e){return!0},t.prototype._getDecorations=function(e){for(var t=e.getDecorationsInViewport(),i=[],o=0,r=0,s=t.length;r
                                      ',r=[],s=t;s<=n;s++){for(var a=s-t,l=i[a],u="",d=0,c=l.length;d';o[s]=l}this._renderResult=o},t.prototype.render=function(e,t){return this._renderResult?this._renderResult[t-e]:""},t}(n.DedupOverlay);t.MarginViewLineDecorationsOverlay=i}),define(t[230],n([1,0,26,23,36,287]),function(e,t,n,i,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=function(e){function t(t){var i=e.call(this,t)||this;return i._widgets={},i._verticalScrollbarWidth=i._context.configuration.editor.layoutInfo.verticalScrollbarWidth,i._minimapWidth=i._context.configuration.editor.layoutInfo.minimapWidth,i._horizontalScrollbarHeight=i._context.configuration.editor.layoutInfo.horizontalScrollbarHeight,i._editorHeight=i._context.configuration.editor.layoutInfo.height,i._editorWidth=i._context.configuration.editor.layoutInfo.width, +i._domNode=n.createFastDomNode(document.createElement("div")),r.PartFingerprints.write(i._domNode,4),i._domNode.setClassName("overlayWidgets"),i}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this),this._widgets=null},t.prototype.getDomNode=function(){return this._domNode},t.prototype.onConfigurationChanged=function(e){return!!e.layoutInfo&&(this._verticalScrollbarWidth=this._context.configuration.editor.layoutInfo.verticalScrollbarWidth,this._minimapWidth=this._context.configuration.editor.layoutInfo.minimapWidth,this._horizontalScrollbarHeight=this._context.configuration.editor.layoutInfo.horizontalScrollbarHeight,this._editorHeight=this._context.configuration.editor.layoutInfo.height,this._editorWidth=this._context.configuration.editor.layoutInfo.width,!0)},t.prototype.addWidget=function(e){var t=n.createFastDomNode(e.getDomNode());this._widgets[e.getId()]={widget:e,preference:null,domNode:t},t.setPosition("absolute"),t.setAttribute("widgetId",e.getId()),this._domNode.appendChild(t), +this.setShouldRender()},t.prototype.setWidgetPosition=function(e,t){var n=this._widgets[e.getId()];return n.preference!==t&&(n.preference=t,this.setShouldRender(),!0)},t.prototype.removeWidget=function(e){var t=e.getId();if(this._widgets.hasOwnProperty(t)){var n=this._widgets[t].domNode.domNode;delete this._widgets[t],n.parentNode.removeChild(n),this.setShouldRender()}},t.prototype._renderWidget=function(e){var t=e.domNode;if(null!==e.preference)if(e.preference===i.OverlayWidgetPositionPreference.TOP_RIGHT_CORNER)t.setTop(0),t.setRight(2*this._verticalScrollbarWidth+this._minimapWidth);else if(e.preference===i.OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER){var n=t.domNode.clientHeight;t.setTop(this._editorHeight-n-2*this._horizontalScrollbarHeight),t.setRight(2*this._verticalScrollbarWidth+this._minimapWidth)}else e.preference===i.OverlayWidgetPositionPreference.TOP_CENTER&&(t.setTop(0),t.domNode.style.right="50%");else t.unsetTop()},t.prototype.prepareRender=function(e){}, +t.prototype.render=function(e){this._domNode.setWidth(this._editorWidth);for(var t=Object.keys(this._widgets),n=0,i=t.length;n0&&this._renderOneLane(o,n,i,e),!0},t.prototype._renderOneLane=function(e,t,n,i){for(var o=0,r=0,s=0,a=0,l=t.length;a=c?s=Math.max(s,h):(e.fillRect(0,r,i,s-r),r=c,s=h)}e.fillRect(0,r,i,s-r)},t}(n.ViewEventHandler);t.OverviewRuler=s}),define(t[232],n([1,0,10,26,36,12]),function(e,t,n,i,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(e){function t(t){var n=e.call(this,t)||this;return n._lineHeight=n._context.configuration.editor.lineHeight,n._contentWidth=n._context.configuration.editor.layoutInfo.contentWidth,n._contentLeft=n._context.configuration.editor.layoutInfo.contentLeft,n.domNode=i.createFastDomNode(document.createElement("div")),n.domNode.setClassName("view-zones"),n.domNode.setPosition("absolute"),n.domNode.setAttribute("role","presentation"),n.domNode.setAttribute("aria-hidden","true"),n.marginDomNode=i.createFastDomNode(document.createElement("div")),n.marginDomNode.setClassName("margin-view-zones"),n.marginDomNode.setPosition("absolute"),n.marginDomNode.setAttribute("role","presentation"),n.marginDomNode.setAttribute("aria-hidden","true"),n._zones={}, +n}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this),this._zones={}},t.prototype._recomputeWhitespacesProps=function(){for(var e=!1,t=Object.keys(this._zones),n=0,i=t.length;n=e.scrollWidth?0:this._configuration.editor.viewInfo.scrollbar.horizontalScrollbarSize},t.prototype._getTotalHeight=function(){var e=this.scrollable.getScrollDimensions(),t=this._linesLayout.getLinesTotalHeight();return this._configuration.editor.viewInfo.scrollBeyondLastLine?t+=e.height-this._configuration.editor.lineHeight:t+=this._getHorizontalScrollbarHeight(e),Math.max(e.height,t)}, +t.prototype._updateHeight=function(){this.scrollable.setScrollDimensions({scrollHeight:this._getTotalHeight()})},t.prototype.getCurrentViewport=function(){var e=this.scrollable.getScrollDimensions(),t=this.scrollable.getCurrentScrollPosition();return new s.Viewport(t.scrollTop,t.scrollLeft,e.width,e.height)},t.prototype.getFutureViewport=function(){var e=this.scrollable.getScrollDimensions(),t=this.scrollable.getFutureScrollPosition();return new s.Viewport(t.scrollTop,t.scrollLeft,e.width,e.height)},t.prototype._computeScrollWidth=function(e,t){if(!this._configuration.editor.wrappingInfo.isViewportWrapping){var n=this._configuration.editor.viewInfo.scrollBeyondLastColumn*this._configuration.editor.fontInfo.typicalHalfwidthCharacterWidth,i=this._linesLayout.getWhitespaceMinWidth();return Math.max(e+n,t,i)}return Math.max(e,t)},t.prototype.onMaxLineWidthChanged=function(e){var t=this._computeScrollWidth(e,this.getCurrentViewport().width);this.scrollable.setScrollDimensions({scrollWidth:t}),this._updateHeight() +},t.prototype.saveState=function(){var e=this.scrollable.getFutureScrollPosition(),t=e.scrollTop,n=this._linesLayout.getLineNumberAtOrAfterVerticalOffset(t);return{scrollTop:t,scrollTopWithoutViewZones:t-this._linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(n),scrollLeft:e.scrollLeft}},t.prototype.addWhitespace=function(e,t,n,i){return this._linesLayout.insertWhitespace(e,t,n,i)},t.prototype.changeWhitespace=function(e,t,n){return this._linesLayout.changeWhitespace(e,t,n)},t.prototype.removeWhitespace=function(e){return this._linesLayout.removeWhitespace(e)},t.prototype.getVerticalOffsetForLineNumber=function(e){return this._linesLayout.getVerticalOffsetForLineNumber(e)},t.prototype.isAfterLines=function(e){return this._linesLayout.isAfterLines(e)},t.prototype.getLineNumberAtVerticalOffset=function(e){return this._linesLayout.getLineNumberAtOrAfterVerticalOffset(e)},t.prototype.getWhitespaceAtVerticalOffset=function(e){return this._linesLayout.getWhitespaceAtVerticalOffset(e)}, +t.prototype.getLinesViewportData=function(){var e=this.getCurrentViewport();return this._linesLayout.getLinesViewportData(e.top,e.top+e.height)},t.prototype.getLinesViewportDataAtScrollTop=function(e){var t=this.scrollable.getScrollDimensions();return e+t.height>t.scrollHeight&&(e=t.scrollHeight-t.height),e<0&&(e=0),this._linesLayout.getLinesViewportData(e,e+t.height)},t.prototype.getWhitespaceViewportData=function(){var e=this.getCurrentViewport();return this._linesLayout.getWhitespaceViewportData(e.top,e.top+e.height)},t.prototype.getWhitespaces=function(){return this._linesLayout.getWhitespaces()},t.prototype.getScrollWidth=function(){return this.scrollable.getScrollDimensions().scrollWidth},t.prototype.getScrollHeight=function(){return this.scrollable.getScrollDimensions().scrollHeight},t.prototype.getCurrentScrollLeft=function(){return this.scrollable.getCurrentScrollPosition().scrollLeft},t.prototype.getCurrentScrollTop=function(){return this.scrollable.getCurrentScrollPosition().scrollTop}, +t.prototype.validateScrollPosition=function(e){return this.scrollable.validateScrollPosition(e)},t.prototype.setScrollPositionNow=function(e){this.scrollable.setScrollPositionNow(e)},t.prototype.setScrollPositionSmooth=function(e){this.scrollable.setScrollPositionSmooth(e)},t.prototype.deltaScrollNow=function(e,t){var n=this.scrollable.getCurrentScrollPosition();this.scrollable.setScrollPositionNow({scrollLeft:n.scrollLeft+e,scrollTop:n.scrollTop+t})},t}(n.Disposable);t.ViewLayout=a}),define(t[235],n([1,0,3,12,63]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t,n,i,o){this.editorId=e,this.model=t,this.configuration=n,this._linesCollection=i,this._coordinatesConverter=o,this._decorationsCache=Object.create(null),this._clearCachedModelDecorationsResolver()}return e.prototype._clearCachedModelDecorationsResolver=function(){this._cachedModelDecorationsResolver=null,this._cachedModelDecorationsResolverViewRange=null},e.prototype.dispose=function(){ +this._decorationsCache=null,this._clearCachedModelDecorationsResolver()},e.prototype.reset=function(){this._decorationsCache=Object.create(null),this._clearCachedModelDecorationsResolver()},e.prototype.onModelDecorationsChanged=function(){this._decorationsCache=Object.create(null),this._clearCachedModelDecorationsResolver()},e.prototype.onLineMappingChanged=function(){this._decorationsCache=Object.create(null),this._clearCachedModelDecorationsResolver()},e.prototype._getOrCreateViewModelDecoration=function(e){var t=e.id,r=this._decorationsCache[t];if(!r){var s=e.range,a=e.options,l=void 0;if(a.isWholeLine){var u=this._coordinatesConverter.convertModelPositionToViewPosition(new i.Position(s.startLineNumber,1)),d=this._coordinatesConverter.convertModelPositionToViewPosition(new i.Position(s.endLineNumber,this.model.getLineMaxColumn(s.endLineNumber)));l=new n.Range(u.lineNumber,u.column,d.lineNumber,d.column)}else l=this._coordinatesConverter.convertModelRangeToViewRange(s);r=new o.ViewModelDecoration(l,a), +this._decorationsCache[t]=r}return r},e.prototype.getDecorationsViewportData=function(e){var t=!0;return t=t&&null!==this._cachedModelDecorationsResolver,(t=t&&e.equalsRange(this._cachedModelDecorationsResolverViewRange))||(this._cachedModelDecorationsResolver=this._getDecorationsViewportData(e),this._cachedModelDecorationsResolverViewRange=e),this._cachedModelDecorationsResolver},e.prototype._getDecorationsViewportData=function(e){for(var t=this._linesCollection.getDecorationsInRange(e,this.editorId,this.configuration.editor.readOnly),i=e.startLineNumber,r=e.endLineNumber,s=[],a=0,l=[],u=i;u<=r;u++)l[u-i]=[];for(var d=0,c=t.length;de.length-1&&(this.presentationIndex=0),this._onDidChangePresentation.fire(this.presentation)},enumerable:!0,configurable:!0}),e.prototype.selectNextColorPresentation=function(){this.presentationIndex=(this.presentationIndex+1)%this.colorPresentations.length, +this.flushColor(),this._onDidChangePresentation.fire(this.presentation)},e.prototype.guessColorPresentation=function(e,t){for(var n=0;ne.length)return!1;for(var o=0;o=65&&r<=90&&r+32===s||s>=65&&s<=90&&s+32===r))return!1}return!0},e.prototype._createOperationsForBlockComment=function(t,n,i,r){ +var s=t.startLineNumber,a=t.startColumn,l=t.endLineNumber,u=t.endColumn,d=i.getLineContent(s),c=i.getLineContent(l),h=n.blockCommentStartToken,p=n.blockCommentEndToken,f=d.lastIndexOf(h,a-1+h.length),g=c.indexOf(p,u-1-p.length);if(-1!==f&&-1!==g)if(s===l){d.substring(f+h.length,g).indexOf(p)>=0&&(f=-1,g=-1)}else{var m=d.substring(f+h.length),v=c.substring(0,g);(m.indexOf(p)>=0||v.indexOf(p)>=0)&&(f=-1,g=-1)}var _;-1!==f&&-1!==g?(f+h.length0&&32===c.charCodeAt(g-1)&&(p=" "+p,g-=1),_=e._createRemoveBlockCommentOperations(new o.Range(s,f+h.length+1,l,g+1),h,p)):(_=e._createAddBlockCommentOperations(t,h,p),this._usedEndToken=1===_.length?p:null);for(var y=0;y<_.length;y++)r.addTrackedEditOperation(_[y].range,_[y].text)},e._createRemoveBlockCommentOperations=function(e,t,i){var r=[] +;return o.Range.isEmpty(e)?r.push(n.EditOperation.delete(new o.Range(e.startLineNumber,e.startColumn-t.length,e.endLineNumber,e.endColumn+i.length))):(r.push(n.EditOperation.delete(new o.Range(e.startLineNumber,e.startColumn-t.length,e.startLineNumber,e.startColumn))),r.push(n.EditOperation.delete(new o.Range(e.endLineNumber,e.endColumn,e.endLineNumber,e.endColumn+i.length)))),r},e._createAddBlockCommentOperations=function(e,t,r){var s=[];return o.Range.isEmpty(e)?s.push(n.EditOperation.replace(new o.Range(e.startLineNumber,e.startColumn,e.endLineNumber,e.endColumn),t+" "+r)):(s.push(n.EditOperation.insert(new i.Position(e.startLineNumber,e.startColumn),t+" ")),s.push(n.EditOperation.insert(new i.Position(e.endLineNumber,e.endColumn)," "+r))),s},e.prototype.getEditOperations=function(e,t){var n=this._selection.startLineNumber,i=this._selection.startColumn;e.tokenizeIfCheap(n);var o=e.getLanguageIdAtPosition(n,i),r=s.LanguageConfigurationRegistry.getComments(o) +;r&&r.blockCommentStartToken&&r.blockCommentEndToken&&this._createOperationsForBlockComment(this._selection,r,e,t)},e.prototype.computeCursorState=function(e,t){var n=t.getInverseEditOperations();if(2===n.length){var i=n[0],o=n[1];return new r.Selection(i.range.endLineNumber,i.range.endColumn,o.range.startLineNumber,o.range.startColumn)}var s=n[0].range,a=this._usedEndToken?-this._usedEndToken.length-1:0;return new r.Selection(s.endLineNumber,s.endColumn+a,s.endLineNumber,s.endColumn+a)},e}();t.BlockCommentCommand=a}),define(t[241],n([1,0,6,53,12,3,21,149,41]),function(e,t,n,i,o,r,s,a,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=function(){function e(e,t,n){this._selection=e,this._tabSize=t,this._type=n,this._deltaColumn=0}return e._gatherPreflightCommentStrings=function(e,t,n){e.tokenizeIfCheap(t);var i=e.getLanguageIdAtPosition(t,1),o=l.LanguageConfigurationRegistry.getComments(i),r=o?o.lineCommentToken:null;if(!r)return null;for(var s=[],a=0,u=n-t+1;aa?r-1:r}},e}();t.LineCommentCommand=u}),define(t[242],n([1,0,21,3]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t,n){this.selection=e,this.targetPosition=t,this.copy=n}return e.prototype.getEditOperations=function(e,t){var o=e.getValueInRange(this.selection);this.copy||t.addEditOperation(this.selection,null),t.addEditOperation(new i.Range(this.targetPosition.lineNumber,this.targetPosition.column,this.targetPosition.lineNumber,this.targetPosition.column),o), +!this.selection.containsPosition(this.targetPosition)||this.copy&&(this.selection.getEndPosition().equals(this.targetPosition)||this.selection.getStartPosition().equals(this.targetPosition))?this.copy?this.targetSelection=new n.Selection(this.targetPosition.lineNumber,this.targetPosition.column,this.selection.endLineNumber-this.selection.startLineNumber+this.targetPosition.lineNumber,this.selection.startLineNumber===this.selection.endLineNumber?this.targetPosition.column+this.selection.endColumn-this.selection.startColumn:this.selection.endColumn):this.targetPosition.lineNumber>this.selection.endLineNumber?this.targetSelection=new n.Selection(this.targetPosition.lineNumber-this.selection.endLineNumber+this.selection.startLineNumber,this.targetPosition.column,this.targetPosition.lineNumber,this.selection.startLineNumber===this.selection.endLineNumber?this.targetPosition.column+this.selection.endColumn-this.selection.startColumn:this.selection.endColumn):this.targetPosition.lineNumbert&&(e=t),this._matchesPosition!==e&&(this._matchesPosition=e,o.matchesPosition=!0,r=!0),this._matchesCount!==t&&(this._matchesCount=t,o.matchesCount=!0,r=!0),void 0!==n&&(i.Range.equalsRange(this._currentMatch,n)||(this._currentMatch=n,o.currentMatch=!0,r=!0)),r&&this._onFindReplaceStateChange.fire(o)},e.prototype.change=function(e,t,n){void 0===n&&(n=!0);var o={moveCursor:t,updateHistory:n,searchString:!1,replaceString:!1,isRevealed:!1,isReplaceRevealed:!1,isRegex:!1,wholeWord:!1,matchCase:!1,searchScope:!1,matchesPosition:!1,matchesCount:!1, +currentMatch:!1},r=!1,s=this.isRegex,a=this.wholeWord,l=this.matchCase;void 0!==e.searchString&&this._searchString!==e.searchString&&(this._searchString=e.searchString,o.searchString=!0,r=!0),void 0!==e.replaceString&&this._replaceString!==e.replaceString&&(this._replaceString=e.replaceString,o.replaceString=!0,r=!0),void 0!==e.isRevealed&&this._isRevealed!==e.isRevealed&&(this._isRevealed=e.isRevealed,o.isRevealed=!0,r=!0),void 0!==e.isReplaceRevealed&&this._isReplaceRevealed!==e.isReplaceRevealed&&(this._isReplaceRevealed=e.isReplaceRevealed,o.isReplaceRevealed=!0,r=!0),void 0!==e.isRegex&&(this._isRegex=e.isRegex),void 0!==e.wholeWord&&(this._wholeWord=e.wholeWord),void 0!==e.matchCase&&(this._matchCase=e.matchCase),void 0!==e.searchScope&&(i.Range.equalsRange(this._searchScope,e.searchScope)||(this._searchScope=e.searchScope,o.searchScope=!0,r=!0)),this._isRegexOverride=void 0!==e.isRegexOverride?e.isRegexOverride:0,this._wholeWordOverride=void 0!==e.wholeWordOverride?e.wholeWordOverride:0, +this._matchCaseOverride=void 0!==e.matchCaseOverride?e.matchCaseOverride:0,s!==this.isRegex&&(r=!0,o.isRegex=!0),a!==this.wholeWord&&(r=!0,o.wholeWord=!0),l!==this.matchCase&&(r=!0,o.matchCase=!0),r&&this._onFindReplaceStateChange.fire(o)},e}();t.FindReplaceState=r}),define(t[244],n([1,0,3]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t,n){this._editorSelection=e,this._ranges=t,this._replaceStrings=n}return e.prototype.getEditOperations=function(e,t){if(this._ranges.length>0){for(var i=[],o=0;o0;){if(e=r)break;if(36===(u=e.charCodeAt(i))){t.emitUnchanged(i-1),t.emitStatic("$",i+1);continue}if(48===u||38===u){t.emitUnchanged(i-1),t.emitMatchIndex(0,i+1);continue}if(49<=u&&u<=57){var a=u-48;if(i+1=r)break;var u;switch(u=e.charCodeAt(i)){case 92:t.emitUnchanged(i-1),t.emitStatic("\\",i+1);break;case 110:t.emitUnchanged(i-1),t.emitStatic("\n",i+1);break;case 116:t.emitUnchanged(i-1),t.emitStatic("\t",i+1)}}} +return t.finalize()}}),define(t[109],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.MAX_FOLDING_REGIONS=65535,t.MAX_LINE_NUMBER=16777215;var n=function(){function e(e,n,i){if(e.length!==n.length||e.length>t.MAX_FOLDING_REGIONS)throw new Error("invalid startIndexes or endIndexes size");this._startIndexes=e,this._endIndexes=n,this._collapseStates=new Uint32Array(Math.ceil(e.length/32)),this._types=i}return e.prototype.ensureParentIndices=function(){var e=this;if(!this._parentsComputed){this._parentsComputed=!0;for(var n=[],i=function(t,i){var o=n[n.length-1];return e.getStartLineNumber(o)<=t&&e.getEndLineNumber(o)>=i},o=0,r=this._startIndexes.length;ot.MAX_LINE_NUMBER||a>t.MAX_LINE_NUMBER)throw new Error("startLineNumber or endLineNumber must not exceed "+t.MAX_LINE_NUMBER);for(;n.length>0&&!i(s,a);)n.pop();var l=n.length>0?n[n.length-1]:-1;n.push(o),this._startIndexes[o]=s+((255&l)<<24), +this._endIndexes[o]=a+((65280&l)<<16)}}},Object.defineProperty(e.prototype,"length",{get:function(){return this._startIndexes.length},enumerable:!0,configurable:!0}),e.prototype.getStartLineNumber=function(e){return this._startIndexes[e]&t.MAX_LINE_NUMBER},e.prototype.getEndLineNumber=function(e){return this._endIndexes[e]&t.MAX_LINE_NUMBER},e.prototype.getType=function(e){return this._types?this._types[e]:void 0},e.prototype.hasTypes=function(){return!!this._types},e.prototype.isCollapsed=function(e){var t=e/32|0,n=e%32;return 0!=(this._collapseStates[t]&1<>>24)+((4278190080&this._endIndexes[e])>>>16);return n===t.MAX_FOLDING_REGIONS?-1:n},e.prototype.contains=function(e,t){ +return this.getStartLineNumber(e)<=t&&this.getEndLineNumber(e)>=t},e.prototype.findIndex=function(e){var t=0,n=this._startIndexes.length;if(0===n)return-1;for(;t=0){if(this.getEndLineNumber(t)>=e)return t;for(t=this.getParentIndex(t);-1!==t;){if(this.contains(t,e))return t;t=this.getParentIndex(t)}}return-1},e.prototype.toString=function(){for(var e=[],t=0;t=this.endLineNumber},e.prototype.containsLine=function(e){return this.startLineNumber<=e&&e<=this.endLineNumber},e}();t.FoldingRegion=i}),define(t[247],n([1,0,9,109]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){this._updateEventEmitter=new n.Emitter,this._textModel=e,this._decorationProvider=t,this._regions=new i.FoldingRegions(new Uint32Array(0),new Uint32Array(0)),this._editorDecorationIds=[],this._isInitialized=!1} +return Object.defineProperty(e.prototype,"regions",{get:function(){return this._regions},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onDidChange",{get:function(){return this._updateEventEmitter.event},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"textModel",{get:function(){return this._textModel},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"isInitialized",{get:function(){return this._isInitialized},enumerable:!0,configurable:!0}),e.prototype.toggleCollapseState=function(e){var t=this;if(e.length){var n={};this._decorationProvider.changeDecorations(function(i){for(var o=0,r=e;o=c))break;o(a,d===c),a++}}l=s()}for(;a0?e:null},e.prototype.applyMemento=function(e){if(Array.isArray(e)){for(var t=[],n=0,i=e;n=0;){var r=this._regions.toRegion(i);t&&!t(r,o)||n.push(r),o++,i=r.parentIndex}return n},e.prototype.getRegionAtLine=function(e){if(this._regions){var t=this._regions.findRange(e);if(t>=0)return this._regions.toRegion(t)}return null}, +e.prototype.getRegionsInside=function(e,t){for(var n=[],i=t&&2===t.length,o=i?[]:null,r=e?e.regionIndex+1:0,s=e?e.endLineNumber:Number.MAX_VALUE,a=r,l=this._regions.length;a0&&!u.containedBy(o[o.length-1]);)o.pop();o.push(u),t(u,o.length)&&n.push(u)}else t&&!t(u)||n.push(u)}return n},e}();t.FoldingModel=o,t.setCollapseStateLevelsDown=function(e,t,n,i){void 0===n&&(n=Number.MAX_VALUE);var o=[];if(i&&i.length>0)for(var r=0,s=i;r1)&&(u=e.getRegionsInside(l,function(e,i){return e.isCollapsed!==t&&i=0;s--)if(n!==o.isCollapsed(s)){var a=o.getStartLineNumber(s);t.test(i.getLineContent(a))&&r.push(o.toRegion(s))}e.toggleCollapseState(r)},t.setCollapseStateForType=function(e,t,n){for(var i=e.regions,o=[],r=i.length-1;r>=0;r--)n!==i.isCollapsed(r)&&t===i.getType(r)&&o.push(i.toRegion(r));e.toggleCollapseState(o)}}),define(t[248],n([1,0,9,3,25]),function(e,t,n,i,o){"use strict";function r(e,t){var n=o.findFirstInSorted(e,function(e){return t=0&&e[n].endLineNumber>=t?e[n]:null}Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e){var t=this;this._updateEventEmitter=new n.Emitter,this._foldingModel=e, +this._foldingModelListener=e.onDidChange(function(e){return t.updateHiddenRanges()}),this._hiddenRanges=[],e.regions.length&&this.updateHiddenRanges()}return Object.defineProperty(e.prototype,"onDidChange",{get:function(){return this._updateEventEmitter.event},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"hiddenRanges",{get:function(){return this._hiddenRanges},enumerable:!0,configurable:!0}),e.prototype.updateHiddenRanges=function(){for(var e=!1,t=[],n=0,o=0,r=Number.MAX_VALUE,s=-1,a=this._foldingModel.regions;n0},e.prototype.isHidden=function(e){return null!==r(this._hiddenRanges,e)},e.prototype.adjustSelections=function(e){for(var t=this,n=!1,i=this._foldingModel.textModel,o=null,s=function(e){return o&&function(e,t){return e>=t.startLineNumber&&e<=t.endLineNumber}(e,o)||(o=r(t._hiddenRanges,e)),o?o.startLineNumber-1:null},a=0,l=e.length;a0&&(this._hiddenRanges=[],this._updateEventEmitter.fire(this._hiddenRanges)),this._foldingModelListener&&(this._foldingModelListener.dispose(),this._foldingModelListener=null)},e}();t.HiddenRangeModel=s}),define(t[168],n([1,0,10,14,13,109]),function(e,t,n,i,o,r){"use strict";function s(e,t){for(var n=e.sort(function(e,t){var n=e.start-t.start;return 0===n&&(n=e.rank-t.rank),n}),i=new d(t),o=null,r=[],s=0,a=n;so.start)if(l.end<=o.end)r.push(o),o=l,i.add(l.start,l.end,l.kind&&l.kind.value,r.length);else{if(l.start>o.end){do{o=r.pop()}while(o&&l.start>o.end);o&&r.push(o),o=l}i.add(l.start,l.end,l.kind&&l.kind.value,r.length)}}else o=l,i.add(l.start,l.end,l.kind&&l.kind.value,r.length)}return i.toIndentRanges()}Object.defineProperty(t,"__esModule",{value:!0});var a=5e3,l={};t.ID_SYNTAX_PROVIDER="syntax";var u=function(){function e(e,n,i){void 0===i&&(i=a),this.editorModel=e,this.providers=n,this.limit=i, +this.id=t.ID_SYNTAX_PROVIDER}return e.prototype.compute=function(e){var t=this;return function(e,t,r){var s=null,a=e.map(function(e,o){return i.toThenable(e.provideFoldingRanges(t,l,r)).then(function(e){if(!r.isCancellationRequested&&Array.isArray(e)){Array.isArray(s)||(s=[]);for(var n=t.getLineCount(),i=0,a=e;i0&&l.end>l.start&&l.end<=n&&s.push({start:l.start,end:l.end,rank:o,kind:l.kind})}}},n.onUnexpectedExternalError)});return o.TPromise.join(a).then(function(e){return s})}(this.providers,this.editorModel,e).then(function(e){if(e){return s(e,t.limit)}return null})},e.prototype.dispose=function(){},e}();t.SyntaxRangeProvider=u;var d=function(){function e(e){this._startIndexes=[],this._endIndexes=[],this._nestingLevels=[],this._nestingLevelCounts=[],this._types=[],this._length=0,this._foldingRangesLimit=e}return e.prototype.add=function(e,t,n,i){if(!(e>r.MAX_LINE_NUMBER||t>r.MAX_LINE_NUMBER)){var o=this._length;this._startIndexes[o]=e,this._endIndexes[o]=t, +this._nestingLevels[o]=i,this._types[o]=n,this._length++,i<30&&(this._nestingLevelCounts[i]=(this._nestingLevelCounts[i]||0)+1)}},e.prototype.toIndentRanges=function(){if(this._length<=this._foldingRangesLimit){for(var e=new Uint32Array(this._length),t=new Uint32Array(this._length),n=0;nthis._foldingRangesLimit){o=n;break}i+=s}}for(var e=new Uint32Array(this._foldingRangesLimit),t=new Uint32Array(this._foldingRangesLimit),a=[],n=0,l=0;n0?this._renderMessages(this._lastLineNumber,this._messages):this.hide()},t.prototype._renderMessages=function(e,t){var n=this;a.dispose(this._renderDisposeables),this._renderDisposeables=[];var i=document.createDocumentFragment();t.forEach(function(e){var t=n._markdownRenderer.render(e.value);n._renderDisposeables.push(t),i.appendChild(r.$("div.hover-row",null,t.element))}),this.updateContents(i),this.showAt(e)},t.ID="editor.contrib.modesGlyphHoverWidget",t}(i.GlyphHoverWidget);t.ModesGlyphHoverWidget=u}),define(t[256],n([1,0,21]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t,n){this._editRange=e,this._originalSelection=t,this._text=n}return e.prototype.getEditOperations=function(e,t){t.addTrackedEditOperation(this._editRange,this._text)}, +e.prototype.computeCursorState=function(e,t){var i=t.getInverseEditOperations()[0].range;return this._originalSelection.isEmpty()?new n.Selection(i.endLineNumber,Math.min(this._originalSelection.positionColumn,i.endColumn),i.endLineNumber,Math.min(this._originalSelection.positionColumn,i.endColumn)):new n.Selection(i.endLineNumber,i.endColumn-this._text.length,i.endLineNumber,i.endColumn)},e}();t.InPlaceReplaceCommand=i}),define(t[257],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getSpaceCnt=function(e,t){for(var n=0,i=0;i1&&(i-=1,r=e.getLineMaxColumn(i)),t.addTrackedEditOperation(new n.Range(i,r,o,s),null)}},e.prototype.computeCursorState=function(e,t){var n=t.getInverseEditOperations()[0].range;return new i.Selection(n.endLineNumber,this.restoreCursorToColumn,n.endLineNumber,this.restoreCursorToColumn)},e}();t.DeleteLinesCommand=o}), +define(t[260],n([1,0,53,3]),function(e,t,n,i){"use strict";function o(e,t,n){var i=t.startLineNumber,o=t.endLineNumber;if(1===t.endColumn&&o--,i>=o)return null;for(var r=[],s=i;s<=o;s++)r.push(e.getLineContent(s));var a=r.slice(0);return a.sort(function(e,t){return e.toLowerCase().localeCompare(t.toLowerCase())}),!0===n&&(a=a.reverse()),{startLineNumber:i,endLineNumber:o,before:r,after:a}}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){this.selection=e,this.descending=t}return e.prototype.getEditOperations=function(e,t){var r=function(e,t,r){var s=o(e,t,r);return s?n.EditOperation.replace(new i.Range(s.startLineNumber,1,s.endLineNumber,e.getLineMaxColumn(s.endLineNumber)),s.after.join("\n")):null}(e,this.selection,this.descending);r&&t.addEditOperation(r.range,r.text),this.selectionId=t.trackSelection(this.selection)},e.prototype.computeCursorState=function(e,t){return t.getTrackedSelection(this.selectionId)},e.canRun=function(e,t,n){var i=o(e,t,n);if(!i)return!1 +;for(var r=0,s=i.before.length;r0},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"isEmpty",{get:function(){return!this.hasChildren&&!this.parent},enumerable:!0,configurable:!0}),t.prototype.append=function(e){return!!e&&(e.parent=this,this.children||(this.children=[]),e instanceof t?e.children&&this.children.push.apply(this.children,e.children):this.children.push(e),!0)},t}(u);t.NodeList=d;var c=function(e){function t(){var t=e.call(this)||this;return t.elements=new d,t.elements.parent=t,t}return o(t,e),t}(u);t.Block=c;var h=function(){return function(e,t,n){this.range=e,this.bracket=t,this.bracketType=n}}(),p=function(){return function(e,t,n){this.lineNumber=n,this.lineText=e.getLineContent(),this.startOffset=e.getStartOffset(t),this.endOffset=e.getEndOffset(t),this.type=e.getStandardTokenType(t),this.languageId=e.getLanguageId(t)}}(),f=function(){function e(e){this._model=e,this._lineCount=this._model.getLineCount(),this._versionId=this._model.getVersionId(), +this._lineNumber=0,this._tokenIndex=0,this._lineTokens=null,this._advance()}return e.prototype._advance=function(){for(this._lineTokens&&(this._tokenIndex++,this._tokenIndex>=this._lineTokens.getCount()&&(this._lineTokens=null));this._lineNumber0)return this._nextBuff.shift();var e=this._rawTokenScanner.next();if(!e)return null +;var t=e.lineNumber,o=e.lineText,a=e.type,l=e.startOffset,u=e.endOffset;this._cachedLanguageId!==e.languageId&&(this._cachedLanguageId=e.languageId,this._cachedLanguageBrackets=s.LanguageConfigurationRegistry.getBracketsSupport(this._cachedLanguageId));var d=this._cachedLanguageBrackets;if(!d||i.ignoreBracketsInToken(a))return new h(new n.Range(t,l+1,t,u+1),0,null);var c;do{if(c=r.BracketsUtils.findNextBracketInToken(d.forwardRegex,t,o,l,u)){var p=c.startColumn-1,f=c.endColumn-1;l0;){var i=n.shift();if(!t(i))break;n.unshift.apply(n,i.children)}}Object.defineProperty(t,"__esModule",{value:!0});var i,r=function(){function e(){this.text("")}return e.isDigitCharacter=function(e){return e>=48&&e<=57},e.isVariableCharacter=function(e){return 95===e||e>=97&&e<=122||e>=65&&e<=90},e.prototype.text=function(e){this.value=e,this.pos=0},e.prototype.tokenText=function(e){return this.value.substr(e.pos,e.len)},e.prototype.next=function(){if(this.pos>=this.value.length)return{type:14,pos:this.pos,len:0};var t,n=this.pos,i=0,o=this.value.charCodeAt(n);if("number"==typeof(t=e._table[o]))return this.pos+=1,{type:t,pos:n,len:1};if(e.isDigitCharacter(o)){t=8;do{i+=1,o=this.value.charCodeAt(n+i) +}while(e.isDigitCharacter(o));return this.pos+=i,{type:t,pos:n,len:i}}if(e.isVariableCharacter(o)){t=9;do{o=this.value.charCodeAt(n+ ++i)}while(e.isVariableCharacter(o)||e.isDigitCharacter(o));return this.pos+=i,{type:t,pos:n,len:i}}t=10;do{i+=1,o=this.value.charCodeAt(n+i)}while(!isNaN(o)&&void 0===e._table[o]&&!e.isDigitCharacter(o)&&!e.isVariableCharacter(o));return this.pos+=i,{type:t,pos:n,len:i}},e._table=(i={},i[36]=0,i[58]=1,i[44]=2,i[123]=3,i[125]=4,i[92]=5,i[47]=6,i[124]=7,i[43]=11,i[45]=12,i[63]=13,i),e}();t.Scanner=r;var s=function(){function e(){this._children=[]}return e.prototype.appendChild=function(e){return e instanceof a&&this._children[this._children.length-1]instanceof a?this._children[this._children.length-1].value+=e.value:(e.parent=this,this._children.push(e)),this},e.prototype.replace=function(e,t){var n=e.parent,i=n.children.indexOf(e),o=n.children.slice(0);o.splice.apply(o,[i,1].concat(t)),n._children=o,t.forEach(function(e){return e.parent=n})}, +Object.defineProperty(e.prototype,"children",{get:function(){return this._children},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"snippet",{get:function(){for(var e=this;;){if(!e)return;if(e instanceof f)return e;e=e.parent}},enumerable:!0,configurable:!0}),e.prototype.toString=function(){return this.children.reduce(function(e,t){return e+t.toString()},"")},e.prototype.len=function(){return 0},e}();t.Marker=s;var a=function(e){function t(t){var n=e.call(this)||this;return n.value=t,n}return o(t,e),t.prototype.toString=function(){return this.value},t.prototype.len=function(){return this.value.length},t.prototype.clone=function(){return new t(this.value)},t}(s);t.Text=a;var l=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t}(s);t.TransformableMarker=l;var u=function(e){function t(t){var n=e.call(this)||this;return n.index=t,n}return o(t,e),t.compareByIndex=function(e,t){ +return e.index===t.index?0:e.isFinalTabstop?1:t.isFinalTabstop?-1:e.indext.index?1:0},Object.defineProperty(t.prototype,"isFinalTabstop",{get:function(){return 0===this.index},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"choice",{get:function(){return 1===this._children.length&&this._children[0]instanceof d?this._children[0]:void 0},enumerable:!0,configurable:!0}),t.prototype.clone=function(){var e=new t(this.index);return this.transform&&(e.transform=this.transform.clone()),e._children=this.children.map(function(e){return e.clone()}),e},t}(l);t.Placeholder=u;var d=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.options=[],t}return o(t,e),t.prototype.appendChild=function(e){return e instanceof a&&(e.parent=this,this.options.push(e)),this},t.prototype.toString=function(){return this.options[0].value},t.prototype.len=function(){return this.options[0].len()},t.prototype.clone=function(){var e=new t +;return this.options.forEach(e.appendChild,e),e},t}(s);t.Choice=d;var c=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype.resolve=function(e){var t=this;return e.replace(this.regexp,function(){for(var e="",n=0,i=t._children;no.index?arguments[o.index]:"";e+=r=o.resolve(r)}else e+=o.toString()}return e})},t.prototype.toString=function(){return""},t.prototype.clone=function(){var e=new t;return e.regexp=new RegExp(this.regexp.source,(this.regexp.ignoreCase?"i":"")+(this.regexp.global?"g":"")),e._children=this.children.map(function(e){return e.clone()}),e},t}(s);t.Transform=c;var h=function(e){function t(t,n,i,o){var r=e.call(this)||this;return r.index=t,r.shorthandName=n,r.ifValue=i,r.elseValue=o,r}return o(t,e),t.prototype.resolve=function(e){ +return"upcase"===this.shorthandName?e?e.toLocaleUpperCase():"":"downcase"===this.shorthandName?e?e.toLocaleLowerCase():"":"capitalize"===this.shorthandName?e?e[0].toLocaleUpperCase()+e.substr(1):"":Boolean(e)&&"string"==typeof this.ifValue?this.ifValue:Boolean(e)||"string"!=typeof this.elseValue?e||"":this.elseValue},t.prototype.clone=function(){return new t(this.index,this.shorthandName,this.ifValue,this.elseValue)},t}(s);t.FormatString=h;var p=function(e){function t(t){var n=e.call(this)||this;return n.name=t,n}return o(t,e),t.prototype.resolve=function(e){var t=e.resolve(this);return this.transform&&(t=this.transform.resolve(t||"")),void 0!==t&&(this._children=[new a(t)],!0)},t.prototype.clone=function(){var e=new t(this.name);return this.transform&&(e.transform=this.transform.clone()),e._children=this.children.map(function(e){return e.clone()}),e},t}(l);t.Variable=p;var f=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e), +Object.defineProperty(t.prototype,"placeholderInfo",{get:function(){if(!this._placeholders){var e,t=[];this.walk(function(n){return n instanceof u&&(t.push(n),e=!e||e.index0?o.set(e.index,e.children):r.push(e)),!0});for(var a=0,l=r;a0&&t),!o.has(0)&&n&&i.appendChild(new u(0)),i},e.prototype._accept=function(e,t){ +if(void 0===e||this._token.type===e){var n=!t||this._scanner.tokenText(this._token);return this._token=this._scanner.next(),n}return!1},e.prototype._backTo=function(e){return this._scanner.pos=e.pos+e.len,this._token=e,!1},e.prototype._until=function(e){if(14===this._token.type)return!1;for(var t=this._token;this._token.type!==e;)if(this._token=this._scanner.next(),14===this._token.type)return!1;var n=this._scanner.value.substring(t.pos,this._token.pos);return this._token=this._scanner.next(),n},e.prototype._parse=function(e){return this._parseEscaped(e)||this._parseTabstopOrVariableName(e)||this._parseComplexPlaceholder(e)||this._parseComplexVariable(e)||this._parseAnything(e)},e.prototype._parseEscaped=function(e){var t;return!!(t=this._accept(5,!0))&&(t=this._accept(0,!0)||this._accept(4,!0)||this._accept(5,!0)||t,e.appendChild(new a(t)),!0)},e.prototype._parseTabstopOrVariableName=function(e){var t,n=this._token +;return this._accept(0)&&(t=this._accept(9,!0)||this._accept(8,!0))?(e.appendChild(/^\d+$/.test(t)?new u(Number(t)):new p(t)),!0):this._backTo(n)},e.prototype._parseComplexPlaceholder=function(e){var t,n=this._token;if(!(this._accept(0)&&this._accept(3)&&(t=this._accept(8,!0))))return this._backTo(n);var i=new u(Number(t));if(this._accept(1))for(;;){if(this._accept(4))return e.appendChild(i),!0;if(!this._parse(i))return e.appendChild(new a("${"+t+":")),i.children.forEach(e.appendChild,e),!0}else{if(!(i.index>0&&this._accept(7)))return this._accept(6)?this._parseTransform(i)?(e.appendChild(i),!0):(this._backTo(n),!1):this._accept(4)?(e.appendChild(i),!0):this._backTo(n);for(var o=new d;;){if(this._parseChoiceElement(o)){if(this._accept(2))continue;if(this._accept(7)&&(i.appendChild(o),this._accept(4)))return e.appendChild(i),!0}return this._backTo(n),!1}}},e.prototype._parseChoiceElement=function(e){for(var t=this._token,n=[];;){if(2===this._token.type||7===this._token.type)break;var i=void 0 +;if(!(i=(i=this._accept(5,!0))?this._accept(2,!0)||this._accept(7,!0)||i:this._accept(void 0,!0)))return this._backTo(t),!1;n.push(i)}return 0===n.length?(this._backTo(t),!1):(e.appendChild(new a(n.join(""))),!0)},e.prototype._parseComplexVariable=function(e){var t,n=this._token;if(!(this._accept(0)&&this._accept(3)&&(t=this._accept(9,!0))))return this._backTo(n);var i=new p(t);if(!this._accept(1))return this._accept(6)?this._parseTransform(i)?(e.appendChild(i),!0):(this._backTo(n),!1):this._accept(4)?(e.appendChild(i),!0):this._backTo(n);for(;;){if(this._accept(4))return e.appendChild(i),!0;if(!this._parse(i))return e.appendChild(new a("${"+t+":")),i.children.forEach(e.appendChild,e),!0}},e.prototype._parseTransform=function(e){for(var t=new c,n="",i="";;){if(this._accept(6))break;o=void 0;if(o=this._accept(5,!0))n+=o=this._accept(6,!0)||o;else{if(14===this._token.type)return!1;n+=this._accept(void 0,!0)}}for(;;){if(this._accept(6))break;var o=void 0;if(o=this._accept(5,!0))o=this._accept(6,!0)||o, +t.appendChild(new a(o));else if(!this._parseFormatString(t)&&!this._parseAnything(t))return!1}for(;;){if(this._accept(4))break;if(14===this._token.type)return!1;i+=this._accept(void 0,!0)}try{t.regexp=new RegExp(n,i)}catch(e){return!1}return e.transform=t,!0},e.prototype._parseFormatString=function(e){var t=this._token;if(!this._accept(0))return!1;var n=!1;this._accept(3)&&(n=!0);var i=this._accept(8,!0);if(!i)return this._backTo(t),!1;if(!n)return e.appendChild(new h(Number(i))),!0;if(this._accept(4))return e.appendChild(new h(Number(i))),!0;if(!this._accept(1))return this._backTo(t),!1;if(this._accept(6)){var o=this._accept(9,!0);return o&&this._accept(4)?(e.appendChild(new h(Number(i),o)),!0):(this._backTo(t),!1)}if(this._accept(11)){if(r=this._until(4))return e.appendChild(new h(Number(i),void 0,r,void 0)),!0}else if(this._accept(12)){if(s=this._until(4))return e.appendChild(new h(Number(i),void 0,void 0,s)),!0}else if(this._accept(13)){var r=this._until(1);if(r){ +if(s=this._until(4))return e.appendChild(new h(Number(i),void 0,r,s)),!0}}else{var s=this._until(4);if(s)return e.appendChild(new h(Number(i),void 0,void 0,s)),!0}return this._backTo(t),!1},e.prototype._parseAnything=function(e){return 14!==this._token.type&&(e.appendChild(new a(this._scanner.tokenText(this._token))),this._accept(void 0),!0)},e}();t.SnippetParser=g}),define(t[190],n([1,0]),function(e,t){"use strict";function n(e){return Array.isArray(e)}function i(e){return"string"==typeof e}function o(e){return!e}function r(e,t){return e.ignoreCase&&t?t.toLowerCase():t}Object.defineProperty(t,"__esModule",{value:!0}),t.isFuzzyActionArr=n,t.isFuzzyAction=function(e){return!n(e)},t.isString=i,t.isIAction=function(e){return!i(e)},t.empty=o,t.fixCase=r,t.sanitize=function(e){return e.replace(/[&<>'"_]/g,"-")},t.log=function(e,t){console.log(e.languageId+": "+t)},t.throwError=function(e,t){throw new Error(e.languageId+": "+t)},t.substituteMatches=function(e,t,n,i,s){var a=null +;return t.replace(/\$((\$)|(#)|(\d\d?)|[sS](\d\d?)|@(\w+))/g,function(t,l,u,d,c,h,p,f,g){return o(u)?o(d)?!o(c)&&c0;){var n=e.tokenizer[t];if(n)return n;var i=t.lastIndexOf(".");t=i<0?null:t.substr(0,i)}return null},t.stateExists=function(e,t){for(;t&&t.length>0;){if(e.stateNames[t])return!0;var n=t.lastIndexOf(".");t=n<0?null:t.substr(0,n)}return!1}}),define(t[264],n([1,0,28,190]),function(e,t,n,i){"use strict";function o(e,t,n){return"boolean"==typeof e?e:(n&&(e||void 0===t)&&n(),void 0===t?null:t)}function r(e,t,n){return"string"==typeof e?e:(n&&(e||void 0===t)&&n(),void 0===t?null:t)}function s(e,t){if("string"!=typeof t)return null;for(var n=0;t.indexOf("@")>=0&&n<5;)n++,t=t.replace(/@(\w+)/g,function(n,o){var r="" +;return"string"==typeof e[o]?r=e[o]:e[o]&&e[o]instanceof RegExp?r=e[o].source:void 0===e[o]?i.throwError(e,"language definition does not contain attribute '"+o+"', used at: "+t):i.throwError(e,"attribute reference '"+o+"' must be a string, used at: "+t),i.empty(r)?"":"(?:"+r+")"});return new RegExp(t,e.ignoreCase?"i":"")}function a(e,t,o,r){var a=-1,l=o,u=o.match(/^\$(([sS]?)(\d\d?)|#)(.*)$/);u&&(u[3]&&(a=parseInt(u[3]),u[2]&&(a+=100)),l=u[4]);var d="~",c=l;l&&0!==l.length?/^\w*$/.test(c)?d="==":(u=l.match(/^(@|!@|~|!~|==|!=)(.*)$/))&&(d=u[1],c=u[2]):(d="!=",c="");var h;if("~"!==d&&"!~"!==d||!/^(\w|\|)*$/.test(c))if("@"===d||"!@"===d){var p=e[c];p||i.throwError(e,"the @ match target '"+c+"' is not defined, in rule: "+t),function(e,t){if(!t)return!1;if(!Array.isArray(t))return!1;for(var n in t)if(t.hasOwnProperty(n)&&!e(t[n]))return!1;return!0}(function(e){return"string"==typeof e},p)||i.throwError(e,"the @ match target '"+c+"' must be an array of strings, in rule: "+t) +;var f=n.createKeywordMatcher(p,e.ignoreCase);h=function(e){return"@"===d?f(e):!f(e)}}else if("~"===d||"!~"===d)if(c.indexOf("$")<0){var g=s(e,"^"+c+"$");h=function(e){return"~"===d?g.test(e):!g.test(e)}}else h=function(t,n,o,r){return s(e,"^"+i.substituteMatches(e,c,n,o,r)+"$").test(t)};else if(c.indexOf("$")<0){var m=i.fixCase(e,c);h=function(e){return"=="===d?e===m:e!==m}}else{var v=i.fixCase(e,c);h=function(t,n,o,r,s){var a=i.substituteMatches(e,v,n,o,r);return"=="===d?t===a:t!==a}}else{var _=n.createKeywordMatcher(c.split("|"),e.ignoreCase);h=function(e){return"~"===d?_(e):!_(e)}}return-1===a?{name:o,value:r,test:function(e,t,n,i){return h(e,e,t,n,i)}}:{name:o,value:r,test:function(e,t,n,i){var o=function(e,t,n,i){if(i<0)return e;if(i=100){i-=100;var o=n.split(".");if(o.unshift(n),i=0&&(o.tokenSubst=!0),"string"==typeof n.bracket&&("@open"===n.bracket?o.bracket=1:"@close"===n.bracket?o.bracket=-1:i.throwError(e,"a 'bracket' attribute must be either '@open' or '@close', in rule: "+t)),n.next)if("string"!=typeof n.next)i.throwError(e,"the next state must be a string value in rule: "+t);else{var r=n.next;/^(@pop|@push|@popall)$/.test(r)||("@"===r[0]&&(r=r.substr(1)),r.indexOf("$")<0&&(i.stateExists(e,i.substituteMatches(e,r,"",[],""))||i.throwError(e,"the next state '"+n.next+"' is not defined in rule: "+t))),o.next=r}return"number"==typeof n.goBack&&(o.goBack=n.goBack),"string"==typeof n.switchTo&&(o.switchTo=n.switchTo),"string"==typeof n.log&&(o.log=n.log),"string"==typeof n.nextEmbedded&&(o.nextEmbedded=n.nextEmbedded,e.usesEmbedded=!0),o}if(Array.isArray(n)){var s=[];for(var u in n)n.hasOwnProperty(u)&&(s[u]=l(e,t,n[u])) +;return{group:s}}if(n.cases){var d=[];for(var c in n.cases)if(n.cases.hasOwnProperty(c)){var h=l(e,t,n.cases[c]);"@default"===c||"@"===c||""===c?d.push({test:null,value:h,name:c}):"@eos"===c?d.push({test:function(e,t,n,i){return i},value:h,name:c}):d.push(a(e,t,c,h))}var p=e.defaultToken;return{test:function(e,t,n,i){for(var o in d)if(d.hasOwnProperty(o)){if(!d[o].test||d[o].test(e,t,n,i))return d[o].value}return p}}}return i.throwError(e,"an action must be a string, an object with a 'token' or 'cases' attribute, or an array of actions; in rule: "+t),""}return{token:""}}Object.defineProperty(t,"__esModule",{value:!0});var u=function(){function e(e){this.regex=new RegExp(""),this.action={token:""},this.matchOnlyAtLineStart=!1,this.name="",this.name=e}return e.prototype.setRegex=function(e,t){var n;"string"==typeof t?n=t:t instanceof RegExp?n=t.source:i.throwError(e,"rules must start with a match string or regular expression: "+this.name),this.matchOnlyAtLineStart=n.length>0&&"^"===n[0], +this.name=this.name+": "+n,this.regex=s(e,"^(?:"+(this.matchOnlyAtLineStart?n.substr(1):n)+")")},e.prototype.setAction=function(e,t){this.action=l(e,this.name,t)},e}();t.compile=function(e,t){function n(e,l,d){for(var c in d)if(d.hasOwnProperty(c)){var h=d[c],p=h.include;if(p)"string"!=typeof p&&i.throwError(s,"an 'include' attribute must be a string at: "+e),"@"===p[0]&&(p=p.substr(1)),t.tokenizer[p]||i.throwError(s,"include target '"+p+"' is not defined at: "+e),n(e+"."+p,l,t.tokenizer[p]);else{var f=new u(e);if(Array.isArray(h)&&h.length>=1&&h.length<=3)if(f.setRegex(a,h[0]),h.length>=3)if("string"==typeof h[1])f.setAction(a,{token:h[1],next:h[2]});else if("object"==typeof h[1]){var g=h[1];g.next=h[2],f.setAction(a,g)}else i.throwError(s,"a next state as the last element of a rule can only be given if the action is either an object or a string, at: "+e);else f.setAction(a,h[1]);else h.regex||i.throwError(s,"a rule must either be an array, or an object with a 'regex' or 'include' field at: "+e), +h.name&&(f.name=r(h.name)),h.matchOnlyAtStart&&(f.matchOnlyAtLineStart=o(h.matchOnlyAtLineStart)),f.setRegex(a,h.regex),f.setAction(a,h.action);l.push(f)}}}if(!t||"object"!=typeof t)throw new Error("Monarch: expecting a language definition object");var s={};s.languageId=e,s.noThrow=!1,s.maxStack=100,s.start=r(t.start),s.ignoreCase=o(t.ignoreCase,!1),s.tokenPostfix=r(t.tokenPostfix,"."+s.languageId),s.defaultToken=r(t.defaultToken,"source",function(){i.throwError(s,"the 'defaultToken' must be a string")}),s.usesEmbedded=!1;var a=t;a.languageId=e,a.ignoreCase=s.ignoreCase,a.noThrow=s.noThrow,a.usesEmbedded=s.usesEmbedded,a.stateNames=t.tokenizer,a.defaultToken=s.defaultToken,t.tokenizer&&"object"==typeof t.tokenizer||i.throwError(s,"a language definition must define the 'tokenizer' attribute as an object"),s.tokenizer=[];for(var l in t.tokenizer)if(t.tokenizer.hasOwnProperty(l)){s.start||(s.start=l);var d=t.tokenizer[l];s.tokenizer[l]=new Array,n("tokenizer."+l,s.tokenizer[l],d)}s.usesEmbedded=a.usesEmbedded, +t.brackets?Array.isArray(t.brackets)||i.throwError(s,"the 'brackets' attribute must be defined as an array"):t.brackets=[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}];var c=[];for(var h in t.brackets)if(t.brackets.hasOwnProperty(h)){var p=t.brackets[h];p&&Array.isArray(p)&&3===p.length&&(p={token:p[2],open:p[0],close:p[1]}),p.open===p.close&&i.throwError(s,"open and close brackets in a 'brackets' attribute must be different: "+p.open+"\n hint: use the 'bracket' attribute if matching on equal brackets is required."),"string"==typeof p.open&&"string"==typeof p.token?c.push({token:r(p.token)+s.tokenPostfix,open:i.fixCase(s,r(p.open)),close:i.fixCase(s,r(p.close))}):i.throwError(s,"every element in the 'brackets' array must be a '{open,close,token}' object or array")}return s.brackets=c,s.noThrow=!0,s}}),define(t[265],n([5,4]),function(e,t){ +return e.create("vs/base/browser/ui/actionbar/actionbar",t)}),define(t[69],n([1,0,18,265,2,56,67,7,33,74,57,9,481]),function(e,t,n,i,r,s,a,l,u,d,c,h){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var p=function(){function e(e,t,n){var i=this;this.options=n,this._callOnDispose=[],this._context=e||this,this._action=t,t instanceof a.Action&&this._callOnDispose.push(t.onDidChange(function(e){i.builder&&i._handleActionChangeEvent(e)}))}return e.prototype._handleActionChangeEvent=function(e){void 0!==e.enabled&&this._updateEnabled(),void 0!==e.checked&&this._updateChecked(),void 0!==e.class&&this._updateClass(),void 0!==e.label&&(this._updateLabel(),this._updateTooltip()),void 0!==e.tooltip&&this._updateTooltip()},Object.defineProperty(e.prototype,"actionRunner",{get:function(){return this._actionRunner},set:function(e){this._actionRunner=e},enumerable:!0,configurable:!0}),e.prototype.getAction=function(){return this._action},e.prototype.isEnabled=function(){return this._action.enabled}, +e.prototype.setActionContext=function(e){this._context=e},e.prototype.render=function(e){var t=this;this.builder=s.$(e),d.Gesture.addTarget(e);var i=this.options&&this.options.draggable;i&&(e.draggable=!0),this.builder.on(d.EventType.Tap,function(e){return t.onClick(e)}),this.builder.on(l.EventType.MOUSE_DOWN,function(e){i||l.EventHelper.stop(e,!0);var n=e;t._action.enabled&&0===n.button&&t.builder.addClass("active")}),this.builder.on(l.EventType.CLICK,function(e){l.EventHelper.stop(e,!0),t.options&&t.options.isMenu?t.onClick(e):n.setImmediate(function(){return t.onClick(e)})}),this.builder.on([l.EventType.MOUSE_UP,l.EventType.MOUSE_OUT],function(e){l.EventHelper.stop(e),t.builder.removeClass("active")})},e.prototype.onClick=function(e){l.EventHelper.stop(e,!0);var t;u.isUndefinedOrNull(this._context)||!u.isObject(this._context)?t=e:(t=this._context).event=e,this._actionRunner.run(this._action,t)},e.prototype._updateEnabled=function(){},e.prototype._updateLabel=function(){}, +e.prototype._updateTooltip=function(){},e.prototype._updateClass=function(){},e.prototype._updateChecked=function(){},e.prototype.dispose=function(){this.builder&&(this.builder.destroy(),this.builder=null),this._callOnDispose=r.dispose(this._callOnDispose)},e}();t.BaseActionItem=p;var f=function(e){function t(n,i){var o=e.call(this,t.ID,n,n?"separator text":"separator")||this;return o.checked=!1,o.radio=!1,o.enabled=!1,o.order=i,o}return o(t,e),t.ID="vs.actions.separator",t}(a.Action);t.Separator=f;var g=function(e){function t(t,n,i){void 0===i&&(i={});var o=e.call(this,t,n,i)||this;return o.options=i,o.options.icon=void 0!==i.icon&&i.icon,o.options.label=void 0===i.label||i.label,o.cssClass="",o}return o(t,e),t.prototype.render=function(t){e.prototype.render.call(this,t),this.$e=s.$("a.action-label").appendTo(this.builder),this._action.id===f.ID?this.$e.attr({role:"presentation"}):this.options.isMenu?this.$e.attr({role:"menuitem"}):this.$e.attr({role:"button"}), +this.options.label&&this.options.keybinding&&s.$("span.keybinding").text(this.options.keybinding).appendTo(this.builder),this._updateClass(),this._updateLabel(),this._updateTooltip(),this._updateEnabled(),this._updateChecked()},t.prototype._updateLabel=function(){this.options.label&&this.$e.text(this.getAction().label)},t.prototype._updateTooltip=function(){var e=null;this.getAction().tooltip?e=this.getAction().tooltip:!this.options.label&&this.getAction().label&&this.options.icon&&(e=this.getAction().label,this.options.keybinding&&(e=i.localize(0,null,e,this.options.keybinding))),e&&this.$e.attr({title:e})},t.prototype._updateClass=function(){this.cssClass&&this.$e.removeClass(this.cssClass),this.options.icon?(this.cssClass=this.getAction().class,this.$e.addClass("icon"),this.cssClass&&this.$e.addClass(this.cssClass),this._updateEnabled()):this.$e.removeClass("icon")},t.prototype._updateEnabled=function(){this.getAction().enabled?(this.builder.removeClass("disabled"),this.$e.removeClass("disabled"), +this.$e.attr({tabindex:0})):(this.builder.addClass("disabled"),this.$e.addClass("disabled"),l.removeTabIndexAndUpdateFocus(this.$e.getHTMLElement()))},t.prototype._updateChecked=function(){this.getAction().checked?this.$e.addClass("checked"):this.$e.removeClass("checked")},t}(p);t.ActionItem=g;var m;!function(e){e[e.HORIZONTAL=0]="HORIZONTAL",e[e.HORIZONTAL_REVERSE=1]="HORIZONTAL_REVERSE",e[e.VERTICAL=2]="VERTICAL",e[e.VERTICAL_REVERSE=3]="VERTICAL_REVERSE"}(m=t.ActionsOrientation||(t.ActionsOrientation={}));var v={orientation:m.HORIZONTAL,context:null},_=function(){function e(e,t){void 0===t&&(t=v);var n=this;this._onDidBlur=new h.Emitter,this._onDidCancel=new h.Emitter,this._onDidRun=new h.Emitter,this._onDidBeforeRun=new h.Emitter,this.options=t,this._context=t.context,this.toDispose=[],this._actionRunner=this.options.actionRunner,this._actionRunner||(this._actionRunner=new a.ActionRunner,this.toDispose.push(this._actionRunner)),this.toDispose.push(this._actionRunner.onDidRun(function(e){ +return n._onDidRun.fire(e)})),this.toDispose.push(this._actionRunner.onDidBeforeRun(function(e){return n._onDidBeforeRun.fire(e)})),this.items=[],this.focusedItem=void 0,this.domNode=document.createElement("div"),this.domNode.className="monaco-action-bar",!1!==t.animated&&l.addClass(this.domNode,"animated");var i,o;switch(this.options.orientation){case m.HORIZONTAL:i=15,o=17;break;case m.HORIZONTAL_REVERSE:i=17,o=15,this.domNode.className+=" reverse";break;case m.VERTICAL:i=16,o=18,this.domNode.className+=" vertical";break;case m.VERTICAL_REVERSE:i=18,o=16,this.domNode.className+=" vertical reverse"}s.$(this.domNode).on(l.EventType.KEY_DOWN,function(e){var t=new c.StandardKeyboardEvent(e),r=!0;t.equals(i)?n.focusPrevious():t.equals(o)?n.focusNext():t.equals(9)?n.cancel():t.equals(3)||t.equals(10)||(r=!1),r&&(t.preventDefault(),t.stopPropagation())}),s.$(this.domNode).on(l.EventType.KEY_UP,function(e){var t=new c.StandardKeyboardEvent(e);t.equals(3)||t.equals(10)?(n.doTrigger(t),t.preventDefault(), +t.stopPropagation()):(t.equals(2)||t.equals(1026))&&n.updateFocusedItem()}),this.focusTracker=l.trackFocus(this.domNode),this.toDispose.push(this.focusTracker.onDidBlur(function(){document.activeElement!==n.domNode&&l.isAncestor(document.activeElement,n.domNode)||(n._onDidBlur.fire(),n.focusedItem=void 0)})),this.toDispose.push(this.focusTracker.onDidFocus(function(){return n.updateFocusedItem()})),this.actionsList=document.createElement("ul"),this.actionsList.className="actions-container",this.options.isMenu?this.actionsList.setAttribute("role","menu"):this.actionsList.setAttribute("role","toolbar"),this.options.ariaLabel&&this.actionsList.setAttribute("aria-label",this.options.ariaLabel),this.options.isMenu&&(this.domNode.tabIndex=0,s.$(this.domNode).on(l.EventType.MOUSE_OUT,function(e){var t=e.relatedTarget;l.isAncestor(t,n.domNode)||(n.focusedItem=void 0,n.updateFocus(),e.stopPropagation())}),s.$(this.actionsList).on(l.EventType.MOUSE_OVER,function(e){var t=e.target +;if(t&&l.isAncestor(t,n.actionsList)&&t!==n.actionsList){for(;t.parentElement!==n.actionsList;)t=t.parentElement;if(l.hasClass(t,"action-item")){var i=n.focusedItem;n.setFocusedItem(t),i!==n.focusedItem&&n.updateFocus()}}})),this.domNode.appendChild(this.actionsList),e.appendChild(this.domNode)}return Object.defineProperty(e.prototype,"onDidBlur",{get:function(){return this._onDidBlur.event},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onDidCancel",{get:function(){return this._onDidCancel.event},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onDidRun",{get:function(){return this._onDidRun.event},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onDidBeforeRun",{get:function(){return this._onDidBeforeRun.event},enumerable:!0,configurable:!0}),e.prototype.setFocusedItem=function(e){for(var t=0;t=n.actionsList.children.length?(n.actionsList.appendChild(i), +n.items.push(r)):(n.actionsList.insertBefore(i,n.actionsList.children[o]),n.items.splice(o,0,r),o++)})},e.prototype.clear=function(){this.items=r.dispose(this.items),s.$(this.actionsList).empty()},e.prototype.isEmpty=function(){return 0===this.items.length},e.prototype.focus=function(e){e&&void 0===this.focusedItem?(this.focusedItem=this.items.length-1,this.focusNext()):this.updateFocus()},e.prototype.focusNext=function(){void 0===this.focusedItem&&(this.focusedItem=this.items.length-1);var e,t=this.focusedItem;do{this.focusedItem=(this.focusedItem+1)%this.items.length,e=this.items[this.focusedItem]}while(this.focusedItem!==t&&!e.isEnabled());this.focusedItem!==t||e.isEnabled()||(this.focusedItem=void 0),this.updateFocus()},e.prototype.focusPrevious=function(){void 0===this.focusedItem&&(this.focusedItem=0);var e,t=this.focusedItem;do{this.focusedItem=this.focusedItem-1,this.focusedItem<0&&(this.focusedItem=this.items.length-1),e=this.items[this.focusedItem]}while(this.focusedItem!==t&&!e.isEnabled()) +;this.focusedItem!==t||e.isEnabled()||(this.focusedItem=void 0),this.updateFocus(!0)},e.prototype.updateFocus=function(e){void 0===this.focusedItem&&this.domNode.focus();for(var t=0;t=0){var n=void 0;e.equals(17)?n=(t+1)%a.length:e.equals(15)&&(n=0===t?a.length-1:t-1),e.equals(9)?a[t].blur():n>=0&&a[n].focus(),i.EventHelper.stop(e,!0)}}}),this.setInputWidth();var u=document.createElement("div");u.className="controls",u.appendChild(this.caseSensitive.domNode), +u.appendChild(this.wholeWords.domNode),u.appendChild(this.regex.domNode),this.domNode.appendChild(u)},t.prototype.validate=function(){this.inputBox.validate()},t.prototype.dispose=function(){e.prototype.dispose.call(this)},t}(s.Widget);t.FindInput=d}),define(t[277],n([5,4]),function(e,t){return e.create("vs/base/browser/ui/list/listWidget",t)}),define(t[278],n([1,0,277,2,33,25,111,7,18,74,57,9,87,240,27,28,425,473,218]),function(e,t,n,i,r,s,l,u,d,c,h,p,f,g,m,v,_,y){"use strict";function C(e){return"INPUT"===e.tagName||"TEXTAREA"===e.tagName}function b(e){return d.isMacintosh?e.browserEvent.metaKey:e.browserEvent.ctrlKey}function S(e){return e.browserEvent.shiftKey}function w(e){return e instanceof MouseEvent&&2===e.button}function E(e,t){for(var n=[],i=0,o=0;i=e.length)n.push(t[o++]);else if(o>=t.length)n.push(e[i++]);else{if(e[i]===t[o]){n.push(e[i]),i++,o++;continue}e[i]=0){o=this.renderedElements[i];this.trait.unrender(n),o.index=t}else{var o={index:t,templateData:n};this.renderedElements.push(o)}this.trait.renderIndex(t,n)},e.prototype.disposeElement=function(){},e.prototype.splice=function(e,t,n){for(var i=[],o=0;o=e+t&&i.push({index:r.index+n-t,templateData:r.templateData})}this.renderedElements=i},e.prototype.renderIndexes=function(e){for(var t=0,n=this.renderedElements;t-1&&this.trait.renderIndex(o,r)}},e.prototype.disposeTemplate=function(e){ +var t=s.firstIndex(this.renderedElements,function(t){return t.templateData===e});t<0||this.renderedElements.splice(t,1)},e}(),x=function(){function e(e){this._trait=e,this._onChange=new p.Emitter,this.indexes=[]}return Object.defineProperty(e.prototype,"onChange",{get:function(){return this._onChange.event},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"trait",{get:function(){return this._trait},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"renderer",{get:function(){return new L(this)},enumerable:!0,configurable:!0}),e.prototype.splice=function(e,t,n){var i=n.length-t,o=e+t,r=this.indexes.filter(function(t){return t=o}).map(function(e){return e+i}));this.renderer.splice(e,t,n.length),this.set(r)},e.prototype.renderIndex=function(e,t){u.toggleClass(t,this._trait,this.contains(e))},e.prototype.unrender=function(e){u.removeClass(e,this._trait)}, +e.prototype.set=function(e){var t=this.indexes;this.indexes=e;var n=E(t,e);return this.renderer.renderIndexes(n),this._onChange.fire({indexes:e}),t},e.prototype.get=function(){return this.indexes},e.prototype.contains=function(e){return this.indexes.some(function(t){return t===e})},e.prototype.dispose=function(){this.indexes=null,this._onChange=i.dispose(this._onChange)},a([l.memoize],e.prototype,"renderer",null),e}(),N=function(e){function t(t){var n=e.call(this,"focused")||this;return n.getDomId=t,n}return o(t,e),t.prototype.renderIndex=function(t,n){e.prototype.renderIndex.call(this,t,n),n.setAttribute("role","treeitem"),n.setAttribute("id",this.getDomId(t))},t}(x),I=function(){function e(e,t,n){this.trait=e,this.view=t,this.getId=n}return e.prototype.splice=function(e,t,n){var i=this;if(!this.getId)return this.trait.splice(e,t,n.map(function(e){return!1}));var o=this.trait.get().map(function(e){return i.getId(i.view.element(e))}),r=n.map(function(e){return o.indexOf(i.getId(e))>-1}) +;this.trait.splice(e,t,r)},e}(),M=function(){function e(e,t,n){this.list=e,this.view=t;var i=!(!1===n.multipleSelectionSupport);this.disposables=[],this.openController=n.openController||k;var o=p.chain(f.domEvent(t.domNode,"keydown")).filter(function(e){return!C(e.target)}).map(function(e){return new h.StandardKeyboardEvent(e)});o.filter(function(e){return 3===e.keyCode}).on(this.onEnter,this,this.disposables),o.filter(function(e){return 16===e.keyCode}).on(this.onUpArrow,this,this.disposables),o.filter(function(e){return 18===e.keyCode}).on(this.onDownArrow,this,this.disposables),o.filter(function(e){return 11===e.keyCode}).on(this.onPageUpArrow,this,this.disposables),o.filter(function(e){return 12===e.keyCode}).on(this.onPageDownArrow,this,this.disposables),o.filter(function(e){return 9===e.keyCode}).on(this.onEscape,this,this.disposables),i&&o.filter(function(e){return(d.isMacintosh?e.metaKey:e.ctrlKey)&&31===e.keyCode}).on(this.onCtrlA,this,this.disposables)}return e.prototype.onEnter=function(e){ +e.preventDefault(),e.stopPropagation(),this.list.setSelection(this.list.getFocus()),this.openController.shouldOpen(e.browserEvent)&&this.list.open(this.list.getFocus(),e.browserEvent)},e.prototype.onUpArrow=function(e){e.preventDefault(),e.stopPropagation(),this.list.focusPrevious(),this.list.reveal(this.list.getFocus()[0]),this.view.domNode.focus()},e.prototype.onDownArrow=function(e){e.preventDefault(),e.stopPropagation(),this.list.focusNext(),this.list.reveal(this.list.getFocus()[0]),this.view.domNode.focus()},e.prototype.onPageUpArrow=function(e){e.preventDefault(),e.stopPropagation(),this.list.focusPreviousPage(),this.list.reveal(this.list.getFocus()[0]),this.view.domNode.focus()},e.prototype.onPageDownArrow=function(e){e.preventDefault(),e.stopPropagation(),this.list.focusNextPage(),this.list.reveal(this.list.getFocus()[0]),this.view.domNode.focus()},e.prototype.onCtrlA=function(e){e.preventDefault(),e.stopPropagation(),this.list.setSelection(s.range(this.list.length)),this.view.domNode.focus()}, +e.prototype.onEscape=function(e){e.preventDefault(),e.stopPropagation(),this.list.setSelection([]),this.view.domNode.focus()},e.prototype.dispose=function(){this.disposables=i.dispose(this.disposables)},e}(),D=function(){function e(e,t){this.list=e,this.view=t,this.disposables=[],this.disposables=[];p.chain(f.domEvent(t.domNode,"keydown")).filter(function(e){return!C(e.target)}).map(function(e){return new h.StandardKeyboardEvent(e)}).filter(function(e){return!(2!==e.keyCode||e.ctrlKey||e.metaKey||e.shiftKey||e.altKey)}).on(this.onTab,this,this.disposables)}return e.prototype.onTab=function(e){if(e.target===this.view.domNode){var t=this.list.getFocus();if(0!==t.length){var n=this.view.domElement(t[0]).querySelector("[tabIndex]");if(n&&n instanceof HTMLElement){var i=window.getComputedStyle(n);"hidden"!==i.visibility&&"none"!==i.display&&(e.preventDefault(),e.stopPropagation(),n.focus())}}}},e.prototype.dispose=function(){this.disposables=i.dispose(this.disposables)},e}();t.isSelectionSingleChangeEvent=b, +t.isSelectionRangeChangeEvent=S;var T={isSelectionSingleChangeEvent:b,isSelectionRangeChangeEvent:S},k={shouldOpen:function(e){return!(e instanceof MouseEvent)||!w(e)}},R=function(){function e(e,t,n){void 0===n&&(n={}),this.list=e,this.view=t,this.options=n,this.didJustPressContextMenuKey=!1,this.disposables=[],this.multipleSelectionSupport=!(!1===n.multipleSelectionSupport),this.multipleSelectionSupport&&(this.multipleSelectionController=n.multipleSelectionController||T),this.openController=n.openController||k,t.onMouseDown(this.onMouseDown,this,this.disposables),t.onMouseClick(this.onPointer,this,this.disposables),t.onMouseDblClick(this.onDoubleClick,this,this.disposables),t.onTouchStart(this.onMouseDown,this,this.disposables),t.onTap(this.onPointer,this,this.disposables),c.Gesture.addTarget(t.domNode)}return Object.defineProperty(e.prototype,"onContextMenu",{get:function(){var e=this,t=p.chain(f.domEvent(this.view.domNode,"keydown")).map(function(e){return new h.StandardKeyboardEvent(e) +}).filter(function(t){return e.didJustPressContextMenuKey=58===t.keyCode||t.shiftKey&&68===t.keyCode}).filter(function(e){return e.preventDefault(),e.stopPropagation(),!1}).event,n=p.chain(f.domEvent(this.view.domNode,"keyup")).filter(function(){var t=e.didJustPressContextMenuKey;return e.didJustPressContextMenuKey=!1,t}).filter(function(){return e.list.getFocus().length>0}).map(function(){var t=e.list.getFocus()[0];return{index:t,element:e.view.element(t),anchor:e.view.domElement(t)}}).filter(function(e){return!!e.anchor}).event,i=p.chain(this.view.onContextMenu).filter(function(){return!e.didJustPressContextMenuKey}).map(function(e){var t=e.element,n=e.index,i=e.browserEvent;return{element:t,index:n,anchor:{x:i.clientX+1,y:i.clientY}}}).event;return p.anyEvent(t,n,i)},enumerable:!0,configurable:!0}),e.prototype.isSelectionSingleChangeEvent=function(e){ +return this.multipleSelectionController?this.multipleSelectionController.isSelectionSingleChangeEvent(e):d.isMacintosh?e.browserEvent.metaKey:e.browserEvent.ctrlKey},e.prototype.isSelectionRangeChangeEvent=function(e){return this.multipleSelectionController?this.multipleSelectionController.isSelectionRangeChangeEvent(e):e.browserEvent.shiftKey},e.prototype.isSelectionChangeEvent=function(e){return this.isSelectionSingleChangeEvent(e)||this.isSelectionRangeChangeEvent(e)},e.prototype.onMouseDown=function(e){!1===this.options.focusOnMouseDown?(e.browserEvent.preventDefault(),e.browserEvent.stopPropagation()):document.activeElement!==e.browserEvent.target&&this.view.domNode.focus();var t=this.list.getFocus()[0],n=this.list.getSelection();if(t=void 0===t?n[0]:t,this.multipleSelectionSupport&&this.isSelectionRangeChangeEvent(e))return this.changeSelection(e,t);var i=e.index;if(n.every(function(e){return e!==i})&&this.list.setFocus([i]), +this.multipleSelectionSupport&&this.isSelectionChangeEvent(e))return this.changeSelection(e,t);this.options.selectOnMouseDown&&!w(e.browserEvent)&&(this.list.setSelection([i]),this.openController.shouldOpen(e.browserEvent)&&this.list.open([i],e.browserEvent))},e.prototype.onPointer=function(e){if(!(this.multipleSelectionSupport&&this.isSelectionChangeEvent(e)||this.options.selectOnMouseDown)){var t=this.list.getFocus();this.list.setSelection(t),this.openController.shouldOpen(e.browserEvent)&&this.list.open(t,e.browserEvent)}},e.prototype.onDoubleClick=function(e){if(!this.multipleSelectionSupport||!this.isSelectionChangeEvent(e)){var t=this.list.getFocus();this.list.setSelection(t),this.list.pin(t)}},e.prototype.changeSelection=function(e,t){var n=e.index;if(this.isSelectionRangeChangeEvent(e)&&void 0!==t){var i=Math.min(t,n),o=Math.max(t,n),r=s.range(i,o+1),a=function(e,t){var n=e.indexOf(t);if(-1===n)return[];for(var i=[],o=n-1;o>=0&&e[o]===t-(n-o);)i.push(e[o--]);for(i.reverse(), +o=n;o=e.length)n.push(t[o++]);else if(o>=t.length)n.push(e[i++]);else{if(e[i]===t[o]){i++,o++;continue}e[i]this.view.length)throw new Error("Invalid start index: "+e);if(t<0)throw new Error("Invalid delete count: "+t);0===t&&0===n.length||this.eventBufferer.bufferEvents(function(){return i.spliceable.splice(e,t,n)})},Object.defineProperty(e.prototype,"length",{get:function(){return this.view.length},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"contentHeight",{get:function(){return this.view.getContentHeight()},enumerable:!0,configurable:!0}),e.prototype.layout=function(e){this.view.layout(e)},e.prototype.setSelection=function(e){for(var t=0,n=e;t=this.length)throw new Error("Invalid index "+i)}e=e.sort(F),this.selection.set(e)},e.prototype.getSelection=function(){return this.selection.get()},e.prototype.setFocus=function(e){for(var t=0,n=e;t=this.length)throw new Error("Invalid index "+i)}e=e.sort(F),this.focus.set(e)},e.prototype.focusNext=function(e,t){if(void 0===e&&(e=1),void 0===t&&(t=!1),0!==this.length){var n=this.focus.get(),i=n.length>0?n[0]+e:0;this.setFocus(t?[i%this.length]:[Math.min(i,this.length-1)])}},e.prototype.focusPrevious=function(e,t){if(void 0===e&&(e=1),void 0===t&&(t=!1),0!==this.length){var n=this.focus.get(),i=n.length>0?n[0]-e:0;t&&i<0&&(i=(this.length+i%this.length)%this.length),this.setFocus([Math.max(i,0)])}},e.prototype.focusNextPage=function(){var e=this,t=this.view.indexAt(this.view.getScrollTop()+this.view.renderHeight);t=0===t?0:t-1;var n=this.view.element(t);if(this.getFocusedElements()[0]!==n)this.setFocus([t]);else{var i=this.view.getScrollTop() +;this.view.setScrollTop(i+this.view.renderHeight-this.view.elementHeight(t)),this.view.getScrollTop()!==i&&setTimeout(function(){return e.focusNextPage()},0)}},e.prototype.focusPreviousPage=function(){var e,t=this,n=this.view.getScrollTop();e=0===n?this.view.indexAt(n):this.view.indexAfter(n-1);var i=this.view.element(e);if(this.getFocusedElements()[0]!==i)this.setFocus([e]);else{var o=n;this.view.setScrollTop(n-this.view.renderHeight),this.view.getScrollTop()!==o&&setTimeout(function(){return t.focusPreviousPage()},0)}},e.prototype.focusLast=function(){0!==this.length&&this.setFocus([this.length-1])},e.prototype.focusFirst=function(){0!==this.length&&this.setFocus([0])},e.prototype.getFocus=function(){return this.focus.get()},e.prototype.getFocusedElements=function(){var e=this;return this.getFocus().map(function(t){return e.view.element(t)})},e.prototype.reveal=function(e,t){if(e<0||e>=this.length)throw new Error("Invalid index "+e) +;var n=this.view.getScrollTop(),i=this.view.elementTop(e),o=this.view.elementHeight(e);if(r.isNumber(t)){var s=o-this.view.renderHeight;this.view.setScrollTop(s*y.clamp(t,0,1)+i)}else{var a=i+o,l=n+this.view.renderHeight;i=l&&this.view.setScrollTop(a-this.view.renderHeight)}},e.prototype.getElementDomId=function(e){return this.idPrefix+"_"+e},e.prototype.isDOMFocused=function(){return this.view.domNode===document.activeElement},e.prototype.getHTMLElement=function(){return this.view.domNode},e.prototype.open=function(e,t){for(var n=this,i=0,o=e;i=this.length)throw new Error("Invalid index "+r)}this._onOpen.fire({indexes:e,elements:e.map(function(e){return n.view.element(e)}),browserEvent:t})},e.prototype.pin=function(e){for(var t=0,n=e;t=this.length)throw new Error("Invalid index "+i)}this._onPin.fire(e)},e.prototype.style=function(e){this.styleController.style(e)},e.prototype.toListEvent=function(e){ +var t=this,n=e.indexes;return{indexes:n,elements:n.map(function(e){return t.view.element(e)})}},e.prototype._onFocusChange=function(){var e=this.focus.get();e.length>0?this.view.domNode.setAttribute("aria-activedescendant",this.getElementDomId(e[0])):this.view.domNode.removeAttribute("aria-activedescendant"),this.view.domNode.setAttribute("role","tree"),u.toggleClass(this.view.domNode,"element-focused",e.length>0)},e.prototype._onSelectionChange=function(){var e=this.selection.get();u.toggleClass(this.view.domNode,"selection-none",0===e.length),u.toggleClass(this.view.domNode,"selection-single",1===e.length),u.toggleClass(this.view.domNode,"selection-multiple",e.length>1)},e.prototype.dispose=function(){this._onDidDispose.fire(),this.disposables=i.dispose(this.disposables)},e.InstanceCount=0,a([l.memoize],e.prototype,"onFocusChange",null),a([l.memoize],e.prototype,"onSelectionChange",null),e}();t.List=V}),define(t[279],n([5,4]),function(e,t){return e.create("vs/base/browser/ui/menu/menu",t)}), +define(t[280],n([1,0,279,67,69,7,57,56,14,221]),function(e,t,n,i,r,s,a,l,u){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var d=function(e){function t(t,n,i){var o=e.call(this,i||"submenu",t,"",!0)||this;return o.entries=n,o}return o(t,e),t}(i.Action);t.SubmenuAction=d;var c=function(){function e(e,t,n){void 0===n&&(n={});var i=this;s.addClass(e,"monaco-menu-container"),e.setAttribute("role","presentation");var o=document.createElement("div");s.addClass(o,"monaco-menu"),o.setAttribute("role","presentation"),e.appendChild(o);var a={parent:this};this.actionBar=new r.ActionBar(o,{orientation:r.ActionsOrientation.VERTICAL,actionItemProvider:function(e){return i.doGetActionItem(e,n,a)},context:n.context,actionRunner:n.actionRunner,isMenu:!0,ariaLabel:n.ariaLabel}),this.actionBar.push(t,{icon:!0,label:!0,isMenu:!0})}return e.prototype.doGetActionItem=function(e,t,n){if(e instanceof r.Separator)return new r.ActionItem(t.context,e,{icon:!0});if(e instanceof d)return new p(e,e.entries,n,t);var i={} +;if(t.getKeyBinding){var o=t.getKeyBinding(e);o&&(i.keybinding=o.getLabel())}return new h(t.context,e,i)},Object.defineProperty(e.prototype,"onDidCancel",{get:function(){return this.actionBar.onDidCancel},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"onDidBlur",{get:function(){return this.actionBar.onDidBlur},enumerable:!0,configurable:!0}),e.prototype.focus=function(e){void 0===e&&(e=!0),this.actionBar&&this.actionBar.focus(e)},e.prototype.dispose=function(){this.actionBar&&(this.actionBar.dispose(),this.actionBar=null),this.listener&&(this.listener.dispose(),this.listener=null)},e}();t.Menu=c;var h=function(e){function t(t,n,i){void 0===i&&(i={});var o=this;return i.isMenu=!0,o=e.call(this,n,n,i)||this,o.options=i,o.options.icon=void 0!==i.icon&&i.icon,o.options.label=void 0===i.label||i.label,o.cssClass="",o}return o(t,e),t.prototype.render=function(t){e.prototype.render.call(this,t),this.$e=l.$("a.action-menu-item").appendTo(this.builder), +this._action.id===r.Separator.ID?this.$e.attr({role:"presentation"}):this.$e.attr({role:"menuitem"}),this.$label=l.$("span.action-label").appendTo(this.$e),this.options.label&&this.options.keybinding&&l.$("span.keybinding").text(this.options.keybinding).appendTo(this.$e),this._updateClass(),this._updateLabel(),this._updateTooltip(),this._updateEnabled(),this._updateChecked()},t.prototype._updateLabel=function(){if(this.options.label){var e=this.getAction().label;if(e){var n=t.MNEMONIC_REGEX.exec(e);if(n&&2===n.length){var i=n[1],o=e.replace(t.MNEMONIC_REGEX,i);this.$e.getHTMLElement().accessKey=i.toLocaleLowerCase(),this.$label.attr("aria-label",o)}else this.$label.attr("aria-label",e);e=e.replace(t.MNEMONIC_REGEX,"$1̲")}this.$label.text(e)}},t.prototype._updateTooltip=function(){var e=null;this.getAction().tooltip?e=this.getAction().tooltip:!this.options.label&&this.getAction().label&&this.options.icon&&(e=this.getAction().label,this.options.keybinding&&(e=n.localize(0,null,e,this.options.keybinding))), +e&&this.$e.attr({title:e})},t.prototype._updateClass=function(){this.cssClass&&this.$e.removeClass(this.cssClass),this.options.icon?(this.cssClass=this.getAction().class,this.$label.addClass("icon"),this.cssClass&&this.$label.addClass(this.cssClass),this._updateEnabled()):this.$label.removeClass("icon")},t.prototype._updateEnabled=function(){this.getAction().enabled?(this.builder.removeClass("disabled"),this.$e.removeClass("disabled"),this.$e.attr({tabindex:0})):(this.builder.addClass("disabled"),this.$e.addClass("disabled"),s.removeTabIndexAndUpdateFocus(this.$e.getHTMLElement()))},t.prototype._updateChecked=function(){this.getAction().checked?this.$label.addClass("checked"):this.$label.removeClass("checked")},t.MNEMONIC_REGEX=/&&(.)/g,t}(r.BaseActionItem),p=function(e){function t(t,n,i,o){var r=e.call(this,t,t,{label:!0,isMenu:!0})||this;return r.submenuActions=n,r.parentData=i,r.submenuOptions=o,r.showScheduler=new u.RunOnceScheduler(function(){r.mouseOver&&(r.cleanupExistingSubmenu(!1), +r.createSubmenu(!1))},250),r.hideScheduler=new u.RunOnceScheduler(function(){s.isAncestor(document.activeElement,r.builder.getHTMLElement())||r.parentData.submenu!==r.mysubmenu||(r.parentData.parent.focus(!1),r.cleanupExistingSubmenu(!0))},750),r}return o(t,e),t.prototype.render=function(t){var n=this;e.prototype.render.call(this,t),this.$e.addClass("monaco-submenu-item"),this.$e.attr("aria-haspopup","true"),l.$("span.submenu-indicator").text("▶").appendTo(this.$e),l.$(this.builder).on(s.EventType.KEY_UP,function(e){new a.StandardKeyboardEvent(e).equals(17)&&(s.EventHelper.stop(e,!0),n.createSubmenu(!0))}),l.$(this.builder).on(s.EventType.KEY_DOWN,function(e){new a.StandardKeyboardEvent(e).equals(17)&&s.EventHelper.stop(e,!0)}),l.$(this.builder).on(s.EventType.MOUSE_OVER,function(e){n.mouseOver||(n.mouseOver=!0,n.showScheduler.schedule())}),l.$(this.builder).on(s.EventType.MOUSE_LEAVE,function(e){n.mouseOver=!1}),l.$(this.builder).on(s.EventType.FOCUS_OUT,function(e){ +s.isAncestor(document.activeElement,n.builder.getHTMLElement())||n.hideScheduler.schedule()})},t.prototype.onClick=function(e){s.EventHelper.stop(e,!0),this.createSubmenu(!1)},t.prototype.cleanupExistingSubmenu=function(e){this.parentData.submenu&&(e||this.parentData.submenu!==this.mysubmenu)&&(this.parentData.submenu.dispose(),this.parentData.submenu=null,this.submenuContainer&&(this.submenuContainer.dispose(),this.submenuContainer=null))},t.prototype.createSubmenu=function(e){var t=this;void 0===e&&(e=!0),this.parentData.submenu?this.parentData.submenu.focus(!1):(this.submenuContainer=l.$(this.builder).div({class:"monaco-submenu menubar-menu-items-holder context-view"}),l.$(this.submenuContainer).style({left:l.$(this.builder).getClientArea().width+"px"}),l.$(this.submenuContainer).on(s.EventType.KEY_UP,function(e){new a.StandardKeyboardEvent(e).equals(15)&&(s.EventHelper.stop(e,!0),t.parentData.parent.focus(),t.parentData.submenu.dispose(),t.parentData.submenu=null,t.submenuContainer.dispose(), +t.submenuContainer=null)}),l.$(this.submenuContainer).on(s.EventType.KEY_DOWN,function(e){new a.StandardKeyboardEvent(e).equals(15)&&s.EventHelper.stop(e,!0)}),this.parentData.submenu=new c(this.submenuContainer.getHTMLElement(),this.submenuActions,this.submenuOptions),this.parentData.submenu.focus(e),this.mysubmenu=this.parentData.submenu)},t.prototype.dispose=function(){e.prototype.dispose.call(this),this.hideScheduler.dispose(),this.mysubmenu&&(this.mysubmenu.dispose(),this.mysubmenu=null),this.submenuContainer&&(this.submenuContainer.dispose(),this.submenuContainer=null)},t}(h)}),define(t[281],n([5,4]),function(e,t){return e.create("vs/base/common/keybindingLabels",t)}),define(t[162],n([1,0,281]),function(e,t,n){"use strict";function i(e,t,n){if(null===t)return"";var i=[];return e.ctrlKey&&i.push(n.ctrlKey),e.shiftKey&&i.push(n.shiftKey),e.altKey&&i.push(n.altKey),e.metaKey&&i.push(n.metaKey),i.push(t),i.join(n.separator)}Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t,n){ +void 0===n&&(n=t),this.modifierLabels=[null],this.modifierLabels[2]=e,this.modifierLabels[1]=t,this.modifierLabels[3]=n}return e.prototype.toLabel=function(e,t,n,o,r){return null===t&&null===o?null:function(e,t,n,o,r){var s=i(e,t,r);return null!==o&&(s+=" ",s+=i(n,o,r)),s}(e,t,n,o,this.modifierLabels[r])},e}();t.ModifierLabelProvider=o,t.UILabelProvider=new o({ctrlKey:"⌃",shiftKey:"⇧",altKey:"⌥",metaKey:"⌘",separator:""},{ctrlKey:n.localize(0,null),shiftKey:n.localize(1,null),altKey:n.localize(2,null),metaKey:n.localize(3,null),separator:"+"},{ctrlKey:n.localize(4,null),shiftKey:n.localize(5,null),altKey:n.localize(6,null),metaKey:n.localize(7,null),separator:"+"}),t.AriaLabelProvider=new o({ctrlKey:n.localize(8,null),shiftKey:n.localize(9,null),altKey:n.localize(10,null),metaKey:n.localize(11,null),separator:"+"},{ctrlKey:n.localize(12,null),shiftKey:n.localize(13,null),altKey:n.localize(14,null),metaKey:n.localize(15,null),separator:"+"},{ctrlKey:n.localize(16,null),shiftKey:n.localize(17,null), +altKey:n.localize(18,null),metaKey:n.localize(19,null),separator:"+"})}),define(t[283],n([1,0,28,162,7,214]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=o.$,s=function(){function e(e,t){this.os=t,this.domNode=o.append(e,r(".monaco-keybinding")),this.didEverRender=!1,e.appendChild(this.domNode)}return e.prototype.set=function(t,n){this.didEverRender&&this.keybinding===t&&e.areSame(this.matches,n)||(this.keybinding=t,this.matches=n,this.render())},e.prototype.render=function(){if(o.clearNode(this.domNode),this.keybinding){var e=this.keybinding.getParts(),t=e[0],n=e[1];t&&this.renderPart(this.domNode,t,this.matches?this.matches.firstPart:null),n&&(o.append(this.domNode,r("span.monaco-keybinding-key-chord-separator",null," ")),this.renderPart(this.domNode,n,this.matches?this.matches.chordPart:null)),this.domNode.title=this.keybinding.getAriaLabel()}this.didEverRender=!0},e.prototype.renderPart=function(e,t,n){var o=i.UILabelProvider.modifierLabels[this.os] +;t.ctrlKey&&this.renderKey(e,o.ctrlKey,n&&n.ctrlKey,o.separator),t.shiftKey&&this.renderKey(e,o.shiftKey,n&&n.shiftKey,o.separator),t.altKey&&this.renderKey(e,o.altKey,n&&n.altKey,o.separator),t.metaKey&&this.renderKey(e,o.metaKey,n&&n.metaKey,o.separator);var r=t.keyLabel;r&&this.renderKey(e,r,n&&n.keyCode,"")},e.prototype.renderKey=function(e,t,n,i){o.append(e,r("span.monaco-keybinding-key"+(n?".highlight":""),null,t)),i&&o.append(e,r("span.monaco-keybinding-key-separator",null,i))},e.prototype.dispose=function(){this.keybinding=null},e.areSame=function(e,t){return e===t||!e&&!t||!!e&&!!t&&n.equals(e.firstPart,t.firstPart)&&n.equals(e.chordPart,t.chordPart)},e}();t.KeybindingLabel=s}),define(t[284],n([5,4]),function(e,t){return e.create("vs/base/common/severity",t)}),define(t[118],n([1,0,284,6]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o;!function(e){e[e.Ignore=0]="Ignore",e[e.Info=1]="Info",e[e.Warning=2]="Warning",e[e.Error=3]="Error"}(o||(o={})),function(e){ +var t="error",o="warning",r="warn",s="info",a=Object.create(null);a[e.Error]=n.localize(0,null),a[e.Warning]=n.localize(1,null),a[e.Info]=n.localize(2,null),e.fromValue=function(n){return n?i.equalsIgnoreCase(t,n)?e.Error:i.equalsIgnoreCase(o,n)||i.equalsIgnoreCase(r,n)?e.Warning:i.equalsIgnoreCase(s,n)?e.Info:e.Ignore:e.Ignore}}(o||(o={})),t.default=o}),define(t[286],n([5,4]),function(e,t){return e.create("vs/base/parts/quickopen/browser/quickOpenModel",t)}),define(t[119],n([1,0,286,13,199,69,138,7,283,18]),function(e,t,n,i,r,s,a,l,u,d){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var c=0,h=function(){function e(e){void 0===e&&(e=[]),this.id=(c++).toString(),this.labelHighlights=e,this.descriptionHighlights=[]}return e.prototype.getId=function(){return this.id},e.prototype.getLabel=function(){return null},e.prototype.getLabelOptions=function(){return null},e.prototype.getAriaLabel=function(){return[this.getLabel(),this.getDescription(),this.getDetail()].filter(function(e){return!!e +}).join(", ")},e.prototype.getDetail=function(){return null},e.prototype.getIcon=function(){return null},e.prototype.getDescription=function(){return null},e.prototype.getTooltip=function(){return null},e.prototype.getDescriptionTooltip=function(){return null},e.prototype.getKeybinding=function(){return null},e.prototype.isHidden=function(){return this.hidden},e.prototype.setHighlights=function(e,t,n){this.labelHighlights=e,this.descriptionHighlights=t,this.detailHighlights=n},e.prototype.getHighlights=function(){return[this.labelHighlights,this.descriptionHighlights,this.detailHighlights]},e.prototype.run=function(e,t){return!1},e}();t.QuickOpenEntry=h;var p=function(e){function t(t,n,i){var o=e.call(this)||this;return o.entry=t,o.groupLabel=n,o.withBorder=i,o}return o(t,e),t.prototype.getGroupLabel=function(){return this.groupLabel},t.prototype.setGroupLabel=function(e){this.groupLabel=e},t.prototype.showBorder=function(){return this.withBorder},t.prototype.setShowBorder=function(e){this.withBorder=e}, +t.prototype.getLabel=function(){return this.entry?this.entry.getLabel():e.prototype.getLabel.call(this)},t.prototype.getLabelOptions=function(){return this.entry?this.entry.getLabelOptions():e.prototype.getLabelOptions.call(this)},t.prototype.getAriaLabel=function(){return this.entry?this.entry.getAriaLabel():e.prototype.getAriaLabel.call(this)},t.prototype.getDetail=function(){return this.entry?this.entry.getDetail():e.prototype.getDetail.call(this)},t.prototype.getIcon=function(){return this.entry?this.entry.getIcon():e.prototype.getIcon.call(this)},t.prototype.getDescription=function(){return this.entry?this.entry.getDescription():e.prototype.getDescription.call(this)},t.prototype.getHighlights=function(){return this.entry?this.entry.getHighlights():e.prototype.getHighlights.call(this)},t.prototype.isHidden=function(){return this.entry?this.entry.isHidden():e.prototype.isHidden.call(this)},t.prototype.setHighlights=function(t,n,i){ +this.entry?this.entry.setHighlights(t,n,i):e.prototype.setHighlights.call(this,t,n,i)},t.prototype.run=function(t,n){return this.entry?this.entry.run(t,n):e.prototype.run.call(this,t,n)},t}(h);t.QuickOpenEntryGroup=p;var f=function(){function e(){}return e.prototype.hasActions=function(e,t){return!1},e.prototype.getActions=function(e,t){return i.TPromise.as(null)},e}(),g=function(){function e(e,t){void 0===e&&(e=new f),void 0===t&&(t=null),this.actionProvider=e,this.actionRunner=t}return e.prototype.getHeight=function(e){return e.getDetail()?44:22},e.prototype.getTemplateId=function(e){return e instanceof p?"quickOpenEntryGroup":"quickOpenEntry"},e.prototype.renderTemplate=function(e,t,n){var i=document.createElement("div");l.addClass(i,"sub-content"),t.appendChild(i);var o=l.$(".quick-open-row"),c=l.$(".quick-open-row"),h=l.$(".quick-open-entry",null,o,c);i.appendChild(h);var p=document.createElement("span");o.appendChild(p);var f=new r.IconLabel(o,{supportHighlights:!0,supportDescriptionHighlights:!0 +}),g=document.createElement("span");o.appendChild(g),l.addClass(g,"quick-open-entry-keybinding");var m=new u.KeybindingLabel(g,d.OS),v=document.createElement("div");c.appendChild(v),l.addClass(v,"quick-open-entry-meta");var _,y=new a.HighlightedLabel(v);"quickOpenEntryGroup"===e&&(_=document.createElement("div"),l.addClass(_,"results-group"),t.appendChild(_)),l.addClass(t,"actions");var C=document.createElement("div");l.addClass(C,"primary-action-bar"),t.appendChild(C);return{container:t,entry:h,icon:p,label:f,detail:y,keybinding:m,group:_,actionBar:new s.ActionBar(C,{actionRunner:this.actionRunner})}},e.prototype.renderElement=function(e,t,n,i){if(this.actionProvider.hasActions(null,e)?l.addClass(n.container,"has-actions"):l.removeClass(n.container,"has-actions"),n.actionBar.context=e,this.actionProvider.getActions(null,e).then(function(e){n.actionBar.isEmpty()&&e&&e.length>0?n.actionBar.push(e,{icon:!0,label:!1}):n.actionBar.isEmpty()||e&&0!==e.length||n.actionBar.clear()}), +e instanceof p&&e.getGroupLabel()?l.addClass(n.container,"has-group-label"):l.removeClass(n.container,"has-group-label"),e instanceof p){var o=e,r=n;o.showBorder()?(l.addClass(r.container,"results-group-separator"),r.container.style.borderTopColor=i.pickerGroupBorder.toString()):(l.removeClass(r.container,"results-group-separator"),r.container.style.borderTopColor=null);var s=o.getGroupLabel()||"";r.group.textContent=s,r.group.style.color=i.pickerGroupForeground.toString()}if(e instanceof h){var a=e.getHighlights(),u=a[0],d=a[1],c=a[2],f=e.getIcon()?"quick-open-entry-icon "+e.getIcon():"";n.icon.className=f;var g=e.getLabelOptions()||Object.create(null);g.matches=u||[],g.title=e.getTooltip(),g.descriptionTitle=e.getDescriptionTooltip()||e.getDescription(),g.descriptionMatches=d||[],n.label.setValue(e.getLabel(),e.getDescription(),g),n.detail.set(e.getDetail(),c),n.keybinding.set(e.getKeybinding(),null)}},e.prototype.disposeTemplate=function(e,t){var n=t;n.actionBar.dispose(),n.actionBar=null,n.container=null, +n.entry=null,n.keybinding.dispose(),n.keybinding=null,n.detail.dispose(),n.detail=null,n.group=null,n.icon=null,n.label.dispose(),n.label=null},e}(),m=function(){function e(e,t){void 0===e&&(e=[]),void 0===t&&(t=new f),this._entries=e,this._dataSource=this,this._renderer=new g(t),this._filter=this,this._runner=this,this._accessibilityProvider=this}return Object.defineProperty(e.prototype,"entries",{get:function(){return this._entries},set:function(e){this._entries=e},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"dataSource",{get:function(){return this._dataSource},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"renderer",{get:function(){return this._renderer},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"filter",{get:function(){return this._filter},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"runner",{get:function(){return this._runner},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"accessibilityProvider",{ +get:function(){return this._accessibilityProvider},enumerable:!0,configurable:!0}),e.prototype.getId=function(e){return e.getId()},e.prototype.getLabel=function(e){return e.getLabel()},e.prototype.getAriaLabel=function(e){return e.getAriaLabel()?n.localize(0,null,e.getAriaLabel()):n.localize(1,null)},e.prototype.isVisible=function(e){return!e.isHidden()},e.prototype.run=function(e,t,n){return e.run(t,n)},e}();t.QuickOpenModel=m}),define(t[288],n([5,4]),function(e,t){return e.create("vs/base/parts/quickopen/browser/quickOpenWidget",t)}),define(t[289],n([1,0,288,13,18,33,10,93,443,56,115,155,223,57,81,7,2,43,27,28,42,249]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m,v,_,y,C,b){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var S=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype.onContextMenu=function(t,n,i){return r.isMacintosh?this.onLeftClick(t,n,i):e.prototype.onContextMenu.call(this,t,n,i)},t}(g.DefaultController);t.QuickOpenController=S;var w +;!function(e){e[e.ELEMENT_SELECTED=0]="ELEMENT_SELECTED",e[e.FOCUS_LOST=1]="FOCUS_LOST",e[e.CANCELED=2]="CANCELED"}(w=t.HideReason||(t.HideReason={}));var E={background:y.Color.fromHex("#1E1E1E"),foreground:y.Color.fromHex("#CCCCCC"),pickerGroupForeground:y.Color.fromHex("#0097FB"),pickerGroupBorder:y.Color.fromHex("#3F3F46"),widgetShadow:y.Color.fromHex("#000000"),progressBarBackground:y.Color.fromHex("#0E70C0")},L=n.localize(0,null),x=function(e){function t(t,n,i){var o=e.call(this)||this;return o.isDisposed=!1,o.container=t,o.callbacks=n,o.options=i,o.styles=i||Object.create(null),C.mixin(o.styles,E,!1),o.model=null,o}return o(t,e),t.prototype.getModel=function(){return this.model},t.prototype.create=function(){var e=this;return this.builder=d.$().div(function(t){t.on(m.EventType.KEY_DOWN,function(t){var n=new f.StandardKeyboardEvent(t);if(9===n.keyCode)m.EventHelper.stop(t,!0),e.hide(w.CANCELED);else if(2===n.keyCode&&!n.altKey&&!n.ctrlKey&&!n.metaKey){ +var i=t.currentTarget.querySelectorAll("input, .monaco-tree, .monaco-tree-row.focused .action-label.icon");n.shiftKey&&n.target===i[0]?(m.EventHelper.stop(t,!0),i[i.length-1].focus()):n.shiftKey||n.target!==i[i.length-1]||(m.EventHelper.stop(t,!0),i[0].focus())}}).on(m.EventType.CONTEXT_MENU,function(e){return m.EventHelper.stop(e,!0)}).on(m.EventType.FOCUS,function(t){return e.gainingFocus()},null,!0).on(m.EventType.BLUR,function(t){return e.loosingFocus(t)},null,!0),e.progressBar=e._register(new p.ProgressBar(t.clone(),{progressBarBackground:e.styles.progressBarBackground})),e.progressBar.hide(),t.div({class:"quick-open-input"},function(t){e.inputContainer=t,e.inputBox=e._register(new c.InputBox(t.getHTMLElement(),null,{placeholder:e.options.inputPlaceHolder||"",ariaLabel:L,inputBackground:e.styles.inputBackground,inputForeground:e.styles.inputForeground,inputBorder:e.styles.inputBorder,inputValidationInfoBackground:e.styles.inputValidationInfoBackground, +inputValidationInfoBorder:e.styles.inputValidationInfoBorder,inputValidationWarningBackground:e.styles.inputValidationWarningBackground,inputValidationWarningBorder:e.styles.inputValidationWarningBorder,inputValidationErrorBackground:e.styles.inputValidationErrorBackground,inputValidationErrorBorder:e.styles.inputValidationErrorBorder})),e.inputElement=e.inputBox.inputElement,e.inputElement.setAttribute("role","combobox"),e.inputElement.setAttribute("aria-haspopup","false"),e.inputElement.setAttribute("aria-autocomplete","list"),m.addDisposableListener(e.inputBox.inputElement,m.EventType.KEY_DOWN,function(t){var n=new f.StandardKeyboardEvent(t),i=e.shouldOpenInBackground(n);if(2!==n.keyCode)if(18===n.keyCode||16===n.keyCode||12===n.keyCode||11===n.keyCode)m.EventHelper.stop(t,!0),e.navigateInTree(n.keyCode,n.shiftKey),e.inputBox.inputElement.selectionStart===e.inputBox.inputElement.selectionEnd&&(e.inputBox.inputElement.selectionStart=e.inputBox.value.length);else if(3===n.keyCode||i){m.EventHelper.stop(t,!0) +;var o=e.tree.getFocus();o&&e.elementSelected(o,t,i?l.Mode.OPEN_IN_BACKGROUND:l.Mode.OPEN)}}),m.addDisposableListener(e.inputBox.inputElement,m.EventType.INPUT,function(t){e.onType()})}),e.resultCount=t.div({class:"quick-open-result-count","aria-live":"polite"}).clone(),e.treeContainer=t.div({class:"quick-open-tree"},function(t){var i=e.options.treeCreator||function(e,t,n){return new h.Tree(e,t,n)};e.tree=e._register(i(t.getHTMLElement(),{dataSource:new u.DataSource(e),controller:new S({clickBehavior:g.ClickBehavior.ON_MOUSE_UP,keyboardSupport:e.options.keyboardSupport}),renderer:e.renderer=new u.Renderer(e,e.styles),filter:new u.Filter(e),accessibilityProvider:new u.AccessibilityProvider(e)},{twistiePixels:11,indentPixels:0,alwaysFocused:!0,verticalScrollMode:_.ScrollbarVisibility.Visible,horizontalScrollMode:_.ScrollbarVisibility.Hidden,ariaLabel:n.localize(1,null),keyboardSupport:e.options.keyboardSupport,preventRootFocus:!1})),e.treeElement=e.tree.getHTMLElement(), +e._register(e.tree.onDidChangeFocus(function(t){e.elementFocused(t.focus,t)})),e._register(e.tree.onDidChangeSelection(function(t){if(t.selection&&t.selection.length>0){var n=t.payload&&t.payload.originalEvent instanceof b.StandardMouseEvent?t.payload.originalEvent:void 0,i=!!n&&e.shouldOpenInBackground(n);e.elementSelected(t.selection[0],t,i?l.Mode.OPEN_IN_BACKGROUND:l.Mode.OPEN)}}))}).on(m.EventType.KEY_DOWN,function(t){var n=new f.StandardKeyboardEvent(t);e.quickNavigateConfiguration&&(18!==n.keyCode&&16!==n.keyCode&&12!==n.keyCode&&11!==n.keyCode||(m.EventHelper.stop(t,!0),e.navigateInTree(n.keyCode)))}).on(m.EventType.KEY_UP,function(t){var n=new f.StandardKeyboardEvent(t),i=n.keyCode;if(e.quickNavigateConfiguration){var o=e.quickNavigateConfiguration.keybindings;if(3===i||o.some(function(e){var t=e.getParts(),o=t[0];return!t[1]&&(o.shiftKey&&4===i?!(n.ctrlKey||n.altKey||n.metaKey):!(!o.altKey||6!==i)||(!(!o.ctrlKey||5!==i)||!(!o.metaKey||57!==i)))})){var r=e.tree.getFocus();r&&e.elementSelected(r,t)}} +}).clone()}).addClass("monaco-quick-open-widget").build(this.container),this.layoutDimensions&&this.layout(this.layoutDimensions),this.applyStyles(),m.addDisposableListener(this.treeContainer.getHTMLElement(),m.EventType.KEY_DOWN,function(t){var n=new f.StandardKeyboardEvent(t);e.quickNavigateConfiguration||18!==n.keyCode&&16!==n.keyCode&&12!==n.keyCode&&11!==n.keyCode||(m.EventHelper.stop(t,!0),e.navigateInTree(n.keyCode,n.shiftKey),e.treeElement.focus())}),this.builder.getHTMLElement()},t.prototype.style=function(e){this.styles=e,this.applyStyles()},t.prototype.applyStyles=function(){if(this.builder){var e=this.styles.foreground?this.styles.foreground.toString():null,t=this.styles.background?this.styles.background.toString():null,n=this.styles.borderColor?this.styles.borderColor.toString():null,i=this.styles.widgetShadow?this.styles.widgetShadow.toString():null;this.builder.style("color",e),this.builder.style("background-color",t),this.builder.style("border-color",n), +this.builder.style("border-width",n?"1px":null),this.builder.style("border-style",n?"solid":null),this.builder.style("box-shadow",i?"0 5px 8px "+i:null)}this.progressBar&&this.progressBar.style({progressBarBackground:this.styles.progressBarBackground}),this.inputBox&&this.inputBox.style({inputBackground:this.styles.inputBackground,inputForeground:this.styles.inputForeground,inputBorder:this.styles.inputBorder,inputValidationInfoBackground:this.styles.inputValidationInfoBackground,inputValidationInfoBorder:this.styles.inputValidationInfoBorder,inputValidationWarningBackground:this.styles.inputValidationWarningBackground,inputValidationWarningBorder:this.styles.inputValidationWarningBorder,inputValidationErrorBackground:this.styles.inputValidationErrorBackground,inputValidationErrorBorder:this.styles.inputValidationErrorBorder}),this.tree&&!this.options.treeCreator&&this.tree.style(this.styles),this.renderer&&this.renderer.updateStyles(this.styles)},t.prototype.shouldOpenInBackground=function(e){ +if(e instanceof f.StandardKeyboardEvent){if(17!==e.keyCode)return!1;if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return!1;var t=this.inputBox.inputElement;return t.selectionEnd===this.inputBox.value.length&&t.selectionStart===t.selectionEnd}return e.middleButton},t.prototype.onType=function(){var e=this.inputBox.value;this.helpText&&(e?this.helpText.hide():this.helpText.show()),this.callbacks.onType(e)},t.prototype.navigateInTree=function(e,t){var n=this.tree.getInput(),i=n?n.entries:[],o=this.tree.getFocus();switch(e){case 18:this.tree.focusNext();break;case 16:this.tree.focusPrevious();break;case 12:this.tree.focusNextPage();break;case 11:this.tree.focusPreviousPage();break;case 2:t?this.tree.focusPrevious():this.tree.focusNext()}var r=this.tree.getFocus();i.length>1&&o===r&&(16===e||2===e&&t?this.tree.focusLast():(18===e||2===e&&!t)&&this.tree.focusFirst()),(r=this.tree.getFocus())&&this.tree.reveal(r).done(null,a.onUnexpectedError)},t.prototype.elementFocused=function(e,t){if(e&&this.isVisible()){ +this.inputElement.setAttribute("aria-activedescendant",this.treeElement.getAttribute("aria-activedescendant"));var n={event:t,keymods:this.extractKeyMods(t),quickNavigateConfiguration:this.quickNavigateConfiguration};this.model.runner.run(e,l.Mode.PREVIEW,n)}},t.prototype.elementSelected=function(e,t,n){var i=!0;if(this.isVisible()){var o=n||l.Mode.OPEN,r={event:t,keymods:this.extractKeyMods(t),quickNavigateConfiguration:this.quickNavigateConfiguration};i=this.model.runner.run(e,o,r)}i&&this.hide(w.ELEMENT_SELECTED)},t.prototype.extractKeyMods=function(e){return{ctrlCmd:e&&(e.ctrlKey||e.metaKey||e.payload&&e.payload.originalEvent&&(e.payload.originalEvent.ctrlKey||e.payload.originalEvent.metaKey)),alt:e&&(e.altKey||e.payload&&e.payload.originalEvent&&e.payload.originalEvent.altKey)}},t.prototype.show=function(e,t){this.visible=!0,this.isLoosingFocus=!1,this.quickNavigateConfiguration=t?t.quickNavigateConfiguration:void 0,this.quickNavigateConfiguration?(this.inputContainer.hide(),this.builder.show(), +this.tree.domFocus()):(this.inputContainer.show(),this.builder.show(),this.inputBox.focus()),this.helpText&&(this.quickNavigateConfiguration||s.isString(e)?this.helpText.hide():this.helpText.show()),s.isString(e)?this.doShowWithPrefix(e):this.doShowWithInput(e,t&&t.autoFocus?t.autoFocus:{}),t&&t.inputSelection&&!this.quickNavigateConfiguration&&this.inputBox.select(t.inputSelection),this.callbacks.onShow&&this.callbacks.onShow()},t.prototype.doShowWithPrefix=function(e){this.inputBox.value=e,this.callbacks.onType(e)},t.prototype.doShowWithInput=function(e,t){this.setInput(e,t)},t.prototype.setInputAndLayout=function(e,t){var n=this;this.treeContainer.style({height:this.getHeight(e)+"px"}),this.tree.setInput(null).then(function(){return n.model=e,n.inputElement.setAttribute("aria-haspopup",String(e&&e.entries&&e.entries.length>0)),n.tree.setInput(e)}).done(function(){n.tree.layout();var i=e?e.entries.filter(function(t){return n.isElementVisible(e,t)}):[];n.updateResultCount(i.length), +i.length&&n.autoFocus(e,i,t)},a.onUnexpectedError)},t.prototype.isElementVisible=function(e,t){return!e.filter||e.filter.isVisible(t)},t.prototype.autoFocus=function(e,t,n){if(void 0===n&&(n={}),n.autoFocusPrefixMatch){for(var i=void 0,o=void 0,r=n.autoFocusPrefixMatch,s=r.toLowerCase(),l=0;ln.autoFocusIndex&&(this.tree.focusNth(n.autoFocusIndex),this.tree.reveal(this.tree.getFocus()).done(null,a.onUnexpectedError)):n.autoFocusSecondEntry?t.length>1&&this.tree.focusNth(1):n.autoFocusLastEntry&&t.length>1&&this.tree.focusLast()},t.prototype.getHeight=function(e){var n=this,i=e.renderer;if(!e){var o=i.getHeight(null) +;return this.options.minItemsToShow?this.options.minItemsToShow*o:0}var r,s=0;this.layoutDimensions&&this.layoutDimensions.height&&(r=.4*(this.layoutDimensions.height-50)),(!r||r>t.MAX_ITEMS_HEIGHT)&&(r=t.MAX_ITEMS_HEIGHT);for(var a=e.entries.filter(function(t){return n.isElementVisible(e,t)}),l=this.options.maxItemsToShow||a.length,u=0;u=2?(E=_?f.Large:f.LargeBlocks,R=2/C):(E=_?f.Small:f.SmallBlocks,R=1/C);(x=Math.max(0,Math.floor((k-c-2)*R/(u+R))))/R>y&&(x=Math.floor(y*R)),N=k-x,"left"===v?(L=0,I+=x,M+=x,D+=x,T+=x):L=t-x-c}else L=0,x=0,E=f.None,N=k;var O=Math.max(1,Math.floor((N-c-2)/u)),P=h?p:0;return{width:t, +height:n,glyphMarginLeft:I,glyphMarginWidth:w,glyphMarginHeight:n,lineNumbersLeft:M,lineNumbersWidth:b,lineNumbersHeight:n,decorationsLeft:D,decorationsWidth:l,decorationsHeight:n,contentLeft:T,contentWidth:N,contentHeight:n,renderMinimap:E,minimapLeft:L,minimapWidth:x,viewportColumn:O,verticalScrollbarWidth:c,horizontalScrollbarHeight:g,overviewRuler:{top:P,width:c,height:n-2*P,right:0}}},e}();t.EditorLayoutProvider=b;t.EDITOR_FONT_DEFAULTS={fontFamily:i.isMacintosh?"Menlo, Monaco, 'Courier New', monospace":i.isLinux?"'Droid Sans Mono', 'monospace', monospace, 'Droid Sans Fallback'":"Consolas, 'Courier New', monospace",fontWeight:"normal",fontSize:i.isMacintosh?12:14,lineHeight:0,letterSpacing:0},t.EDITOR_MODEL_DEFAULTS={tabSize:4,insertSpaces:!0,detectIndentation:!0,trimAutoWhitespace:!0,largeFileOptimizations:!0},t.EDITOR_DEFAULTS={inDiffEditor:!1,wordSeparators:r.USUAL_WORD_SEPARATORS,lineNumbersMinChars:5,lineDecorationsWidth:10,readOnly:!1,mouseStyle:"text",disableLayerHinting:!1,automaticLayout:!1, +wordWrap:"off",wordWrapColumn:80,wordWrapMinified:!0,wrappingIndent:g.Same,wordWrapBreakBeforeCharacters:"([{‘“〈《「『【〔([{「£¥$£¥++",wordWrapBreakAfterCharacters:" \t})]?|&,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」",wordWrapBreakObtrusiveCharacters:".",autoClosingBrackets:!0,autoIndent:!0,dragAndDrop:!0,emptySelectionClipboard:!0,useTabStops:!0,multiCursorModifier:"altKey",multiCursorMergeOverlapping:!0,accessibilitySupport:"auto",showUnused:!0,viewInfo:{extraEditorClassName:"",disableMonospaceOptimizations:!1,rulers:[],ariaLabel:n.localize(1,null),renderLineNumbers:1,renderCustomLineNumbers:null,selectOnLineNumbers:!0,glyphMargin:!0,revealHorizontalRightPadding:30,roundedSelection:!0,overviewRulerLanes:2,overviewRulerBorder:!0,cursorBlinking:m.Blink,mouseWheelZoom:!1,cursorStyle:v.Line,cursorWidth:0,hideCursorInOverviewRuler:!1,scrollBeyondLastLine:!0,scrollBeyondLastColumn:5,smoothScrolling:!1,stopRenderingLineAfter:1e4,renderWhitespace:"none", +renderControlCharacters:!1,fontLigatures:!1,renderIndentGuides:!0,highlightActiveIndentGuide:!0,renderLineHighlight:"line",scrollbar:{vertical:o.ScrollbarVisibility.Auto,horizontal:o.ScrollbarVisibility.Auto,arrowSize:11,useShadows:!0,verticalHasArrows:!1,horizontalHasArrows:!1,horizontalScrollbarSize:10,horizontalSliderSize:10,verticalScrollbarSize:14,verticalSliderSize:14,handleMouseWheel:!0,mouseWheelScrollSensitivity:1},minimap:{enabled:!0,side:"right",showSlider:"mouseover",renderCharacters:!0,maxColumn:120},fixedOverflowWidgets:!1},contribInfo:{selectionClipboard:!0,hover:{enabled:!0,delay:300,sticky:!0},links:!0,contextmenu:!0,quickSuggestions:{other:!0,comments:!1,strings:!1},quickSuggestionsDelay:10,parameterHints:!0,iconsInSuggestions:!0,formatOnType:!1,formatOnPaste:!1,suggestOnTriggerCharacters:!0,acceptSuggestionOnEnter:"on",acceptSuggestionOnCommitCharacter:!0,wordBasedSuggestions:!0,suggestSelection:"recentlyUsed",suggestFontSize:0,suggestLineHeight:0,suggest:{filterGraceful:!0, +snippets:"inline",snippetsPreventQuickSuggestions:!0},selectionHighlight:!0,occurrencesHighlight:!0,codeLens:!0,folding:!0,foldingStrategy:"auto",showFoldingControls:"mouseover",matchBrackets:!0,find:{seedSearchStringFromSelection:!0,autoFindInSelection:!1,globalFindClipboard:!1},colorDecorators:!0,lightbulbEnabled:!0,codeActionsOnSave:{},codeActionsOnSaveTimeout:750}}}),define(t[122],n([1,0,18,98,47]),function(e,t,n,i,r){"use strict";function s(e,t){if("number"==typeof e)return e;var n=parseFloat(e);return isNaN(n)?t:n}function a(e,t,n){return en?n:e}function l(e,t){return"string"!=typeof e?t:e}Object.defineProperty(t,"__esModule",{value:!0});var u=n.isMacintosh?1.5:1.35,d=function(){function e(e){this.zoomLevel=e.zoomLevel,this.fontFamily=String(e.fontFamily),this.fontWeight=String(e.fontWeight),this.fontSize=e.fontSize,this.lineHeight=0|e.lineHeight,this.letterSpacing=e.letterSpacing}return e.createFromRawSettings=function(t,n){ +var o=l(t.fontFamily,r.EDITOR_FONT_DEFAULTS.fontFamily),d=l(t.fontWeight,r.EDITOR_FONT_DEFAULTS.fontWeight),c=s(t.fontSize,r.EDITOR_FONT_DEFAULTS.fontSize);0===(c=a(c,0,100))?c=r.EDITOR_FONT_DEFAULTS.fontSize:c<8&&(c=8);var h=function(e,t){if("number"==typeof e)return Math.round(e);var n=parseInt(e);return isNaN(n)?t:n}(t.lineHeight,0);0===(h=a(h,0,150))?h=Math.round(u*c):h<8&&(h=8);var p=s(t.letterSpacing,0);p=a(p,-5,20);var f=1+.1*i.EditorZoom.getZoomLevel();return c*=f,h*=f,new e({zoomLevel:n,fontFamily:o,fontWeight:d,fontSize:c,lineHeight:h,letterSpacing:p})},e.prototype.getId=function(){return this.zoomLevel+"-"+this.fontFamily+"-"+this.fontWeight+"-"+this.fontSize+"-"+this.lineHeight+"-"+this.letterSpacing},e}();t.BareFontInfo=d;var c=function(e){function t(t,n){var i=e.call(this,t)||this;return i.isTrusted=n,i.isMonospace=t.isMonospace,i.typicalHalfwidthCharacterWidth=t.typicalHalfwidthCharacterWidth,i.typicalFullwidthCharacterWidth=t.typicalFullwidthCharacterWidth,i.spaceWidth=t.spaceWidth, +i.maxDigitWidth=t.maxDigitWidth,i}return o(t,e),t.prototype.equals=function(e){return this.fontFamily===e.fontFamily&&this.fontWeight===e.fontWeight&&this.fontSize===e.fontSize&&this.lineHeight===e.lineHeight&&this.letterSpacing===e.letterSpacing&&this.typicalHalfwidthCharacterWidth===e.typicalHalfwidthCharacterWidth&&this.typicalFullwidthCharacterWidth===e.typicalFullwidthCharacterWidth&&this.spaceWidth===e.spaceWidth&&this.maxDigitWidth===e.maxDigitWidth},t}(d);t.FontInfo=c}),define(t[298],n([1,0,102,2,47]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){return function(){}}();t.LineContext=r;var s=function(){function e(t,n,i,r){void 0===r&&(r=o.EDITOR_DEFAULTS.contribInfo.suggest),this._snippetCompareFn=e._compareCompletionItems,this._items=t,this._column=n,this._options=r,this._refilterKind=1,this._lineContext=i, +"top"===r.snippets?this._snippetCompareFn=e._compareCompletionItemsSnippetsUp:"bottom"===r.snippets&&(this._snippetCompareFn=e._compareCompletionItemsSnippetsDown)}return e.prototype.dispose=function(){for(var e=new Set,t=0,n=this._items;t2e3?n.fuzzyScore:n.fuzzyScoreGracefulAggressive,l=0;lt.score?-1:e.scoret.idx?1:0},e._compareCompletionItemsSnippetsDown=function(t,n){if(t.suggestion.type!==n.suggestion.type){if("snippet"===t.suggestion.type)return 1;if("snippet"===n.suggestion.type)return-1}return e._compareCompletionItems(t,n)},e._compareCompletionItemsSnippetsUp=function(t,n){if(t.suggestion.type!==n.suggestion.type){ +if("snippet"===t.suggestion.type)return-1;if("snippet"===n.suggestion.type)return 1}return e._compareCompletionItems(t,n)},e}();t.CompletionModel=s}),define(t[299],n([5,4]),function(e,t){return e.create("vs/editor/common/controller/cursor",t)}),define(t[300],n([5,4]),function(e,t){return e.create("vs/editor/common/modes/modesRegistry",t)}),define(t[301],n([5,4]),function(e,t){return e.create("vs/editor/common/services/modelServiceImpl",t)}),define(t[302],n([5,4]),function(e,t){return e.create("vs/editor/common/view/editorColorRegistry",t)}),define(t[303],n([5,4]),function(e,t){return e.create("vs/editor/contrib/bracketMatching/bracketMatching",t)}),define(t[304],n([5,4]),function(e,t){return e.create("vs/editor/contrib/caretOperations/caretOperations",t)}),define(t[305],n([5,4]),function(e,t){return e.create("vs/editor/contrib/caretOperations/transpose",t)}),define(t[306],n([5,4]),function(e,t){return e.create("vs/editor/contrib/clipboard/clipboard",t)}),define(t[307],n([5,4]),function(e,t){ +return e.create("vs/editor/contrib/codeAction/codeActionCommands",t)}),define(t[308],n([5,4]),function(e,t){return e.create("vs/editor/contrib/comment/comment",t)}),define(t[309],n([5,4]),function(e,t){return e.create("vs/editor/contrib/contextmenu/contextmenu",t)}),define(t[310],n([5,4]),function(e,t){return e.create("vs/editor/contrib/cursorUndo/cursorUndo",t)}),define(t[311],n([5,4]),function(e,t){return e.create("vs/editor/contrib/find/findController",t)}),define(t[312],n([5,4]),function(e,t){return e.create("vs/editor/contrib/find/findWidget",t)}),define(t[313],n([5,4]),function(e,t){return e.create("vs/editor/contrib/folding/folding",t)}),define(t[314],n([5,4]),function(e,t){return e.create("vs/editor/contrib/fontZoom/fontZoom",t)}),define(t[315],n([5,4]),function(e,t){return e.create("vs/editor/contrib/format/formatActions",t)}),define(t[316],n([5,4]),function(e,t){return e.create("vs/editor/contrib/goToDefinition/goToDefinitionCommands",t)}),define(t[317],n([5,4]),function(e,t){ +return e.create("vs/editor/contrib/goToDefinition/goToDefinitionMouse",t)}),define(t[318],n([5,4]),function(e,t){return e.create("vs/editor/contrib/gotoError/gotoError",t)}),define(t[319],n([5,4]),function(e,t){return e.create("vs/editor/contrib/gotoError/gotoErrorWidget",t)}),define(t[320],n([5,4]),function(e,t){return e.create("vs/editor/contrib/hover/hover",t)}),define(t[321],n([5,4]),function(e,t){return e.create("vs/editor/contrib/hover/modesContentHover",t)}),define(t[322],n([5,4]),function(e,t){return e.create("vs/editor/contrib/inPlaceReplace/inPlaceReplace",t)}),define(t[323],n([5,4]),function(e,t){return e.create("vs/editor/contrib/linesOperations/linesOperations",t)}),define(t[324],n([5,4]),function(e,t){return e.create("vs/editor/contrib/links/links",t)}),define(t[325],n([5,4]),function(e,t){return e.create("vs/editor/contrib/message/messageController",t)}),define(t[326],n([5,4]),function(e,t){return e.create("vs/editor/contrib/multicursor/multicursor",t)}),define(t[327],n([5,4]),function(e,t){ +return e.create("vs/editor/contrib/parameterHints/parameterHints",t)}),define(t[328],n([5,4]),function(e,t){return e.create("vs/editor/contrib/parameterHints/parameterHintsWidget",t)}),define(t[329],n([5,4]),function(e,t){return e.create("vs/editor/contrib/referenceSearch/peekViewWidget",t)}),define(t[330],n([5,4]),function(e,t){return e.create("vs/editor/contrib/referenceSearch/referenceSearch",t)}),define(t[331],n([5,4]),function(e,t){return e.create("vs/editor/contrib/referenceSearch/referencesController",t)}),define(t[332],n([5,4]),function(e,t){return e.create("vs/editor/contrib/referenceSearch/referencesModel",t)}),define(t[123],n([1,0,332,9,50,2,6,130,13,3]),function(e,t,n,i,o,r,s,a,l,u){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var d=function(){function e(e,t){this._parent=e,this._range=t,this._onRefChanged=new i.Emitter,this.onRefChanged=this._onRefChanged.event,this._id=a.defaultGenerator.nextId()}return Object.defineProperty(e.prototype,"id",{get:function(){return this._id}, +enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"parent",{get:function(){return this._parent},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"uri",{get:function(){return this._parent.uri},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"range",{get:function(){return this._range},set:function(e){this._range=e,this._onRefChanged.fire(this)},enumerable:!0,configurable:!0}),e.prototype.getAriaMessage=function(){return n.localize(0,null,o.basename(this.uri.fsPath),this.range.startLineNumber,this.range.startColumn)},e}();t.OneReference=d;var c=function(){function e(e){this._modelReference=e}return Object.defineProperty(e.prototype,"_model",{get:function(){return this._modelReference.object.textEditorModel},enumerable:!0,configurable:!0}),e.prototype.preview=function(e,t){void 0===t&&(t=8);var n=this._model;if(n){var i=e.startLineNumber,o=e.startColumn,r=e.endLineNumber,a=e.endColumn,l=n.getWordUntilPosition({lineNumber:i,column:o-t +}),d=new u.Range(i,l.startColumn,i,o),c=new u.Range(r,a,r,Number.MAX_VALUE);return{before:n.getValueInRange(d).replace(/^\s+/,s.empty),inside:n.getValueInRange(e),after:n.getValueInRange(c).replace(/\s+$/,s.empty)}}},e.prototype.dispose=function(){this._modelReference&&(this._modelReference.dispose(),this._modelReference=null)},e}();t.FilePreview=c;var h=function(){function e(e,t){this._parent=e,this._uri=t,this._children=[]}return Object.defineProperty(e.prototype,"id",{get:function(){return this._uri.toString()},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"parent",{get:function(){return this._parent},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"children",{get:function(){return this._children},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"uri",{get:function(){return this._uri},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"preview",{get:function(){return this._preview},enumerable:!0,configurable:!0}), +Object.defineProperty(e.prototype,"failure",{get:function(){return this._loadFailure},enumerable:!0,configurable:!0}),e.prototype.getAriaMessage=function(){var e=this.children.length;return 1===e?n.localize(1,null,o.basename(this.uri.fsPath),this.uri.fsPath):n.localize(2,null,e,o.basename(this.uri.fsPath),this.uri.fsPath)},e.prototype.resolve=function(e){var t=this;return this._resolved?l.TPromise.as(this):e.createModelReference(this._uri).then(function(e){if(!e.object)throw e.dispose(),new Error;return t._preview=new c(e),t._resolved=!0,t},function(e){return t._children=[],t._resolved=!0,t._loadFailure=e,t})},e.prototype.dispose=function(){this._preview&&(this._preview.dispose(),this._preview=null)},e}();t.FileReferences=h;var p=function(){function e(t){var n=this;this._groups=[],this._references=[],this._onDidChangeReferenceRange=new i.Emitter,this.onDidChangeReferenceRange=this._onDidChangeReferenceRange.event,this._disposables=[],t.sort(e._compareReferences);for(var o,r=0,s=t;r0?(i=t?(i+1)%o:(i+o-1)%o,n.children[i]):(i=n.parent.groups.indexOf(n),t?(i=(i+1)%r,n.parent.groups[i].children[0]):(i=(i+r-1)%r,n.parent.groups[i].children[n.parent.groups[i].children.length-1]))},e.prototype.nearestReference=function(e,t){var n=this._references.map(function(n,i){return{idx:i,prefixLen:s.commonPrefixLength(n.uri.toString(),e.toString()),offsetDist:100*Math.abs(n.range.startLineNumber-t.lineNumber)+Math.abs(n.range.startColumn-t.column)}}).sort(function(e,t){return e.prefixLen>t.prefixLen?-1:e.prefixLent.offsetDist?1:0})[0];if(n)return this._references[n.idx]},e.prototype.dispose=function(){this._groups=r.dispose(this._groups),r.dispose(this._disposables),this._disposables.length=0},e._compareReferences=function(e,t){var n=e.uri.toString(),i=t.uri.toString() +;return ni?1:u.Range.compareRangesUsingStarts(e.range,t.range)},e}();t.ReferencesModel=p}),define(t[334],n([5,4]),function(e,t){return e.create("vs/editor/contrib/referenceSearch/referencesWidget",t)}),define(t[335],n([5,4]),function(e,t){return e.create("vs/editor/contrib/rename/rename",t)}),define(t[336],n([5,4]),function(e,t){return e.create("vs/editor/contrib/rename/renameInputField",t)}),define(t[337],n([5,4]),function(e,t){return e.create("vs/editor/contrib/smartSelect/smartSelect",t)}),define(t[338],n([5,4]),function(e,t){return e.create("vs/editor/contrib/snippet/snippetVariables",t)}),define(t[339],n([1,0,338,50,110,6]),function(e,t,n,i,o,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e){this._delegates=e}return e.prototype.resolve=function(e){for(var t=0,n=this._delegates;t=0&&(n._entries.splice(e,1),n._lastCandidate=void 0,n._onDidChange.fire(n._entries.length),o=void 0)}})},e.prototype.has=function(e){return this.all(e).length>0},e.prototype.all=function(e){if(!e)return[];this._updateScores(e) +;for(var t=[],n=0,i=this._entries;n0&&t.push(o.provider)}return t},e.prototype.ordered=function(e){var t=[];return this._orderedForEach(e,function(e){return t.push(e.provider)}),t},e.prototype.orderedGroups=function(e){var t,n,i=[];return this._orderedForEach(e,function(e){t&&n===e._score?t.push(e.provider):(n=e._score,t=[e.provider],i.push(t))}),i},e.prototype._orderedForEach=function(e,t){if(e){this._updateScores(e);for(var n=0;n0&&t(i)}}},e.prototype._updateScores=function(t){var n={uri:t.uri.toString(),language:t.getLanguageIdentifier().language};if(!this._lastCandidate||this._lastCandidate.language!==n.language||this._lastCandidate.uri!==n.uri){this._lastCandidate=n;for(var i=0,a=this._entries;i0){for(var u=0,d=this._entries;ut._score?-1:e._timet._time?-1:0},e}();t.default=a}),define(t[17],n([1,0,366,205,33]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){return function(e,t){this.language=e,this.id=t}}();t.LanguageIdentifier=r;var s=function(){function e(){}return e.getLanguageId=function(e){return(255&e)>>>0},e.getTokenType=function(e){return(1792&e)>>>8},e.getFontStyle=function(e){return(14336&e)>>>11},e.getForeground=function(e){return(8372224&e)>>>14},e.getBackground=function(e){return(4286578688&e)>>>23},e.getClassNameFromMetadata=function(e){var t="mtk"+this.getForeground(e),n=this.getFontStyle(e);return 1&n&&(t+=" mtki"),2&n&&(t+=" mtkb"),4&n&&(t+=" mtku"),t},e.getInlineStyleFromMetadata=function(e,t){var n=this.getForeground(e),i=this.getFontStyle(e),o="color: "+t[n]+";";return 1&i&&(o+="font-style: italic;"), +2&i&&(o+="font-weight: bold;"),4&i&&(o+="text-decoration: underline;"),o},e}();t.TokenMetadata=s;!function(e){e[e.Invoke=0]="Invoke",e[e.TriggerCharacter=1]="TriggerCharacter",e[e.TriggerForIncompleteCompletions=2]="TriggerForIncompleteCompletions"}(t.SuggestTriggerKind||(t.SuggestTriggerKind={}));!function(e){e[e.Automatic=1]="Automatic",e[e.Manual=2]="Manual"}(t.CodeActionTrigger||(t.CodeActionTrigger={}));!function(e){e[e.Text=0]="Text",e[e.Read=1]="Read",e[e.Write=2]="Write"}(t.DocumentHighlightKind||(t.DocumentHighlightKind={}));var a;!function(e){e[e.File=0]="File",e[e.Module=1]="Module",e[e.Namespace=2]="Namespace",e[e.Package=3]="Package",e[e.Class=4]="Class",e[e.Method=5]="Method",e[e.Property=6]="Property",e[e.Field=7]="Field",e[e.Constructor=8]="Constructor",e[e.Enum=9]="Enum",e[e.Interface=10]="Interface",e[e.Function=11]="Function",e[e.Variable=12]="Variable",e[e.Constant=13]="Constant",e[e.String=14]="String",e[e.Number=15]="Number",e[e.Boolean=16]="Boolean",e[e.Array=17]="Array", +e[e.Object=18]="Object",e[e.Key=19]="Key",e[e.Null=20]="Null",e[e.EnumMember=21]="EnumMember",e[e.Struct=22]="Struct",e[e.Event=23]="Event",e[e.Operator=24]="Operator",e[e.TypeParameter=25]="TypeParameter"}(a=t.SymbolKind||(t.SymbolKind={})),t.symbolKindToCssClass=function(){var e=Object.create(null);return e[a.File]="file",e[a.Module]="module",e[a.Namespace]="namespace",e[a.Package]="package",e[a.Class]="class",e[a.Method]="method",e[a.Property]="property",e[a.Field]="field",e[a.Constructor]="constructor",e[a.Enum]="enum",e[a.Interface]="interface",e[a.Function]="function",e[a.Variable]="variable",e[a.Constant]="constant",e[a.String]="string",e[a.Number]="number",e[a.Boolean]="boolean",e[a.Array]="array",e[a.Object]="object",e[a.Key]="key",e[a.Null]="null",e[a.EnumMember]="enum-member",e[a.Struct]="struct",e[a.Event]="event",e[a.Operator]="operator",e[a.TypeParameter]="type-parameter",function(t){return"symbol-icon "+(e[t]||"property")}}();var l=function(){function e(e){this.value=e} +return e.Comment=new e("comment"),e.Imports=new e("imports"),e.Region=new e("region"),e}();t.FoldingRangeKind=l,t.isResourceTextEdit=function(e){return o.isObject(e)&&e.resource&&Array.isArray(e.edits)},t.ReferenceProviderRegistry=new n.default,t.RenameProviderRegistry=new n.default,t.SuggestRegistry=new n.default,t.SignatureHelpProviderRegistry=new n.default,t.HoverProviderRegistry=new n.default,t.DocumentSymbolProviderRegistry=new n.default,t.DocumentHighlightProviderRegistry=new n.default,t.DefinitionProviderRegistry=new n.default,t.ImplementationProviderRegistry=new n.default,t.TypeDefinitionProviderRegistry=new n.default,t.CodeLensProviderRegistry=new n.default,t.CodeActionProviderRegistry=new n.default,t.DocumentFormattingEditProviderRegistry=new n.default,t.DocumentRangeFormattingEditProviderRegistry=new n.default,t.OnTypeFormattingEditProviderRegistry=new n.default,t.LinkProviderRegistry=new n.default,t.ColorProviderRegistry=new n.default,t.FoldingRangeProviderRegistry=new n.default, +t.TokenizationRegistry=new i.TokenizationRegistryImpl}),define(t[99],n([1,0,17]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){this._tokens=e,this._tokensCount=this._tokens.length>>>1,this._text=t}return e.prototype.equals=function(t){return t instanceof e&&this.slicedEquals(t,0,this._tokensCount)},e.prototype.slicedEquals=function(e,t,n){if(this._text!==e._text)return!1;if(this._tokensCount!==e._tokensCount)return!1;for(var i=t<<1,o=i+(n<<1),r=i;r0?this._tokens[e-1<<1]:0},e.prototype.getLanguageId=function(e){var t=this._tokens[1+(e<<1)];return n.TokenMetadata.getLanguageId(t)},e.prototype.getStandardTokenType=function(e){var t=this._tokens[1+(e<<1)];return n.TokenMetadata.getTokenType(t)}, +e.prototype.getForeground=function(e){var t=this._tokens[1+(e<<1)];return n.TokenMetadata.getForeground(t)},e.prototype.getClassName=function(e){var t=this._tokens[1+(e<<1)];return n.TokenMetadata.getClassNameFromMetadata(t)},e.prototype.getInlineStyle=function(e,t){var i=this._tokens[1+(e<<1)];return n.TokenMetadata.getInlineStyleFromMetadata(i,t)},e.prototype.getEndOffset=function(e){return this._tokens[e<<1]},e.prototype.findTokenIndexAtOffset=function(t){return e.findIndexInTokensArray(this._tokens,t)},e.prototype.inflate=function(){return this},e.prototype.sliceAndInflate=function(e,t,n){return new o(this,e,t,n)},e.convertToEndOffset=function(e,t){for(var n=(e.length>>>1)-1,i=0;i>>1)-1;nt&&(i=o)}return n},e}();t.LineTokens=i;var o=function(){function e(e,t,n,i){this._source=e,this._startOffset=t, +this._endOffset=n,this._deltaOffset=i,this._firstTokenIndex=e.findTokenIndexAtOffset(t),this._tokensCount=0;for(var o=this._firstTokenIndex,r=e.getCount();o=n)break;this._tokensCount++}}return e.prototype.equals=function(t){return t instanceof e&&(this._startOffset===t._startOffset&&this._endOffset===t._endOffset&&this._deltaOffset===t._deltaOffset&&this._source.slicedEquals(t._source,this._firstTokenIndex,this._tokensCount))},e.prototype.getCount=function(){return this._tokensCount},e.prototype.getForeground=function(e){return this._source.getForeground(this._firstTokenIndex+e)},e.prototype.getEndOffset=function(e){var t=this._source.getEndOffset(this._firstTokenIndex+e);return Math.min(this._endOffset,t)-this._startOffset+this._deltaOffset},e.prototype.getClassName=function(e){return this._source.getClassName(this._firstTokenIndex+e)},e.prototype.getInlineStyle=function(e,t){return this._source.getInlineStyle(this._firstTokenIndex+e,t)}, +e.prototype.findTokenIndexAtOffset=function(e){return this._source.findTokenIndexAtOffset(e+this._startOffset-this._deltaOffset)-this._firstTokenIndex},e}();t.SlicedLineTokens=o}),define(t[60],n([1,0,17,95]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(){}return e.prototype.clone=function(){return this},e.prototype.equals=function(e){return this===e},e}();t.NULL_STATE=new o,t.NULL_MODE_ID="vs.editor.nullMode",t.NULL_LANGUAGE_IDENTIFIER=new n.LanguageIdentifier(t.NULL_MODE_ID,0),t.nullTokenize=function(e,t,n,o){return new i.TokenizationResult([new i.Token(o,"",e)],n)},t.nullTokenize2=function(e,t,n,o){var r=new Uint32Array(2);return r[0]=o,r[1]=(16384|e<<0|2<<23)>>>0,new i.TokenizationResult2(r,n)}}),define(t[370],n([1,0,99,25,12,10,60]),function(e,t,n,i,o,r,s){"use strict";function a(e){return(16384|e<<0|2<<23)>>>0}Object.defineProperty(t,"__esModule",{value:!0});var l=new Uint32Array(0).buffer,u=function(){function e(e){this._state=e, +this._lineTokens=null,this._invalid=!0}return e.prototype.deleteBeginning=function(e){null!==this._lineTokens&&this._lineTokens!==l&&this.delete(0,e)},e.prototype.deleteEnding=function(e){if(null!==this._lineTokens&&this._lineTokens!==l){var t=new Uint32Array(this._lineTokens),n=t[t.length-2];this.delete(e,n)}},e.prototype.delete=function(e,t){if(null!==this._lineTokens&&this._lineTokens!==l&&e!==t){var i=new Uint32Array(this._lineTokens),o=i.length>>>1;if(0!==e||i[i.length-2]!==t){var r=n.LineTokens.findIndexInTokensArray(i,e),s=r>0?i[r-1<<1]:0;if(tc&&(i[d++]=f,i[d++]=i[1+(p<<1)],c=f)}if(d!==i.length){var g=new Uint32Array(d);g.set(i.subarray(0,d),0),this._lineTokens=g.buffer}}}else this._lineTokens=l}},e.prototype.append=function(e){if(e!==l)if(this._lineTokens!==l){if(null!==this._lineTokens)if(null!==e){ +var t=new Uint32Array(this._lineTokens),n=new Uint32Array(e),i=n.length>>>1,o=new Uint32Array(t.length+n.length);o.set(t,0);for(var r=t.length,s=t[t.length-2],a=0;a>>1,r=n.LineTokens.findIndexInTokensArray(i,e);if(r>0){(r>0?i[r-1<<1]:0)===e&&r--}for(var s=r;s=e},e.prototype.hasLinesToTokenize=function(e){return this._invalidLineStartIndex=0;s--)this.invalidateLine(e.startLineNumber+s-1);this._acceptDeleteRange(e),this._acceptInsertText(new o.Position(e.startLineNumber,e.startColumn),t,n)},e.prototype._acceptDeleteRange=function(e){var t=e.startLineNumber-1;if(!(t>=this._tokens.length))if(e.startLineNumber!==e.endLineNumber){var n=this._tokens[t];n.deleteEnding(e.startColumn-1);var i=e.endLineNumber-1,o=null;if(i=this._tokens.length))if(0!==t){var r=this._tokens[o];r.deleteEnding(e.column-1),r.insert(e.column-1,n);for(var s=new Array(t),a=t-1;a>=0;a--)s[a]=new u(null);this._tokens=i.arrayInsert(this._tokens,e.lineNumber,s)}else this._tokens[o].insert(e.column-1,n)}},e.prototype._tokenizeOneLine=function(e,t){if(!this.hasLinesToTokenize(e))return e.getLineCount()+1;var n=this._invalidLineStartIndex+1;return this._updateTokensUntilLine(e,t,n),n},e.prototype._tokenizeText=function(e,t,n){var i=null;try{i=this.tokenizationSupport.tokenize2(t,n,0)}catch(e){r.onUnexpectedError(e)}return i||(i=s.nullTokenize2(this.languageIdentifier.id,t,n,0)),i},e.prototype._updateTokensUntilLine=function(e,t,n){if(this.tokenizationSupport){ +for(var i=e.getLineCount(),o=n-1,a=this._invalidLineStartIndex;a<=o;a++){var l=a+1,u=null,d=e.getLineContent(a+1);try{var c=this._getState(a).clone();u=this.tokenizationSupport.tokenize2(d,c,0)}catch(e){r.onUnexpectedError(e)}if(u||(u=s.nullTokenize2(this.languageIdentifier.id,d,this._getState(a),0)),this._setTokens(this.languageIdentifier.id,a,d.length,u.tokens),t.registerChangedTokens(a+1),this._setIsInvalid(a,!1),l0?t[n-1]:null;i&&i.toLineNumber===e-1?i.toLineNumber++:t[n]={fromLineNumber:e,toLineNumber:e}},e.prototype.build=function(){return 0===this._ranges.length?null:{ranges:this._ranges}},e}();t.ModelTokensChangedEventBuilder=c}),define(t[29],n([1,0,31,9,24,17,483,3,21,499,10,6,487,2,228,60,91,105,12,41,100,370,486,47,136,515]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m,v,_,y,C,b,S,w,E,L,x){"use strict";function N(e){var t=new x.PieceTreeTextBufferBuilder;return t.acceptChunk(e),t.finish()}function I(e,t){return("string"==typeof e?N(e):e).create(t)}function M(e){return e.replace(/[^a-z0-9\-_]/gi," ")}function D(e){return e instanceof P?e:P.createDynamic(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.createTextBufferFactory=N,t.createTextBuffer=I;var T=0;t.LONG_LINE_BOUNDARY=1e4;var k=function(e){function f(t,o,u,d){void 0===d&&(d=null);var c=e.call(this)||this;c._onWillDispose=c._register(new i.Emitter),c.onWillDispose=c._onWillDispose.event, +c._onDidChangeDecorations=c._register(new F),c.onDidChangeDecorations=c._onDidChangeDecorations.event,c._onDidChangeLanguage=c._register(new i.Emitter),c.onDidChangeLanguage=c._onDidChangeLanguage.event,c._onDidChangeLanguageConfiguration=c._register(new i.Emitter),c.onDidChangeLanguageConfiguration=c._onDidChangeLanguageConfiguration.event,c._onDidChangeTokens=c._register(new i.Emitter),c.onDidChangeTokens=c._onDidChangeTokens.event,c._onDidChangeOptions=c._register(new i.Emitter),c.onDidChangeOptions=c._onDidChangeOptions.event,c._eventEmitter=c._register(new W),T++,c.id="$model"+T,c.isForSimpleWidget=o.isForSimpleWidget,c._associatedResource=void 0===d||null===d?n.default.parse("inmemory://model/"+T):d,c._attachedEditorCount=0,c._buffer=I(t,o.defaultEOL),c._options=f.resolveOptions(c._buffer,o);var h=c._buffer.getLineCount(),p=c._buffer.getValueLengthInRange(new l.Range(1,1,h,c._buffer.getLineLength(h)+1),r.EndOfLinePreference.TextDefined) +;return o.largeFileOptimizations?c._isTooLargeForTokenization=p>f.LARGE_FILE_SIZE_THRESHOLD||h>f.LARGE_FILE_LINE_COUNT_THRESHOLD:c._isTooLargeForTokenization=!1,c._isTooLargeForSyncing=p>f.MODEL_SYNC_LIMIT,c._setVersionId(1),c._isDisposed=!1,c._isDisposing=!1,c._languageIdentifier=u||m.NULL_LANGUAGE_IDENTIFIER,c._tokenizationListener=s.TokenizationRegistry.onDidChange(function(e){-1!==e.changedLanguages.indexOf(c._languageIdentifier.language)&&(c._resetTokenizationState(),c.emitModelTokensChangedEvent({ranges:[{fromLineNumber:1,toLineNumber:c.getLineCount()}]}),c._shouldAutoTokenize()&&c._warmUpTokens())}),c._revalidateTokensTimeout=-1,c._languageRegistryListener=C.LanguageConfigurationRegistry.onDidChange(function(e){e.languageIdentifier.id===c._languageIdentifier.id&&c._onDidChangeLanguageConfiguration.fire({})}),c._resetTokenizationState(),c._instanceId=function(e){return(e%=52)<26?String.fromCharCode(97+e):String.fromCharCode(65+e-26)}(T),c._lastDecorationId=0,c._decorations=Object.create(null), +c._decorationsTree=new R,c._commandManager=new a.EditStack(c),c._isUndoing=!1,c._isRedoing=!1,c._trimAutoWhitespaceLines=null,c}return o(f,e),f.createFromString=function(e,t,n,i){return void 0===t&&(t=f.DEFAULT_CREATION_OPTIONS),void 0===n&&(n=null),void 0===i&&(i=null),new f(e,t,n,i)},f.resolveOptions=function(e,t){if(t.detectIndentation){var n=w.guessIndentation(e,t.tabSize,t.insertSpaces);return new r.TextModelResolvedOptions({tabSize:n.tabSize,insertSpaces:n.insertSpaces,trimAutoWhitespace:t.trimAutoWhitespace,defaultEOL:t.defaultEOL})}return new r.TextModelResolvedOptions({tabSize:t.tabSize,insertSpaces:t.insertSpaces,trimAutoWhitespace:t.trimAutoWhitespace,defaultEOL:t.defaultEOL})},f.prototype.onDidChangeRawContentFast=function(e){return this._eventEmitter.fastEvent(function(t){return e(t.rawContentChangedEvent)})},f.prototype.onDidChangeRawContent=function(e){return this._eventEmitter.slowEvent(function(t){return e(t.rawContentChangedEvent)})},f.prototype.onDidChangeContent=function(e){ +return this._eventEmitter.slowEvent(function(t){return e(t.contentChangedEvent)})},f.prototype.dispose=function(){this._isDisposing=!0,this._onWillDispose.fire(),this._commandManager=null,this._decorations=null,this._decorationsTree=null,this._tokenizationListener.dispose(),this._languageRegistryListener.dispose(),this._clearTimers(),this._tokens=null,this._isDisposed=!0,this._buffer=null,e.prototype.dispose.call(this),this._isDisposing=!1},f.prototype._assertNotDisposed=function(){if(this._isDisposed)throw new Error("Model is disposed!")},f.prototype._emitContentChangedEvent=function(e,t){this._isDisposing||this._eventEmitter.fire(new d.InternalModelContentChangeEvent(e,t))},f.prototype.setValue=function(e){if(this._assertNotDisposed(),null!==e){var t=I(e,this._options.defaultEOL);this.setValueFromTextBuffer(t)}},f.prototype._createContentChanged2=function(e,t,n,i,o,r,s){return{changes:[{range:e,rangeOffset:t,rangeLength:n,text:i}],eol:this._buffer.getEOL(),versionId:this.getVersionId(),isUndoing:o, +isRedoing:r,isFlush:s}},f.prototype.setValueFromTextBuffer=function(e){if(this._assertNotDisposed(),null!==e){var t=this.getFullModelRange(),n=this.getValueLengthInRange(t),i=this.getLineCount(),o=this.getLineMaxColumn(i);this._buffer=e,this._increaseVersionId(),this._resetTokenizationState(),this._decorations=Object.create(null),this._decorationsTree=new R,this._commandManager=new a.EditStack(this),this._trimAutoWhitespaceLines=null,this._emitContentChangedEvent(new d.ModelRawContentChangedEvent([new d.ModelRawFlush],this._versionId,!1,!1),this._createContentChanged2(new l.Range(1,1,i,o),0,n,this.getValue(),!1,!1,!0))}},f.prototype.setEOL=function(e){this._assertNotDisposed();var t=e===r.EndOfLineSequence.CRLF?"\r\n":"\n";if(this._buffer.getEOL()!==t){var n=this.getFullModelRange(),i=this.getValueLengthInRange(n),o=this.getLineCount(),s=this.getLineMaxColumn(o);this._onBeforeEOLChange(),this._buffer.setEOL(t),this._increaseVersionId(),this._onAfterEOLChange(), +this._emitContentChangedEvent(new d.ModelRawContentChangedEvent([new d.ModelRawEOLChanged],this._versionId,!1,!1),this._createContentChanged2(new l.Range(1,1,o,s),0,i,this.getValue(),!1,!1,!1))}},f.prototype._onBeforeEOLChange=function(){var e=this.getVersionId(),t=this._decorationsTree.search(0,!1,!1,e);this._ensureNodesHaveRanges(t)},f.prototype._onAfterEOLChange=function(){for(var e=this.getVersionId(),t=this._decorationsTree.collectNodesPostOrder(),n=0,i=t.length;n0},f.prototype.getAttachedEditorCount=function(){return this._attachedEditorCount},f.prototype.isTooLargeForSyncing=function(){return this._isTooLargeForSyncing},f.prototype.isTooLargeForTokenization=function(){return this._isTooLargeForTokenization},f.prototype.isDisposed=function(){return this._isDisposed},f.prototype.isDominatedByLongLines=function(){if(this._assertNotDisposed(),this.isTooLargeForTokenization())return!1;for(var e=0,n=0,i=this._buffer.getLineCount(),o=1;o<=i;o++){var r=this._buffer.getLineLength(o) +;r>=t.LONG_LINE_BOUNDARY?n+=r:e+=r}return n>e},Object.defineProperty(f.prototype,"uri",{get:function(){return this._associatedResource},enumerable:!0,configurable:!0}),f.prototype.getOptions=function(){return this._assertNotDisposed(),this._options},f.prototype.updateOptions=function(e){this._assertNotDisposed();var t=void 0!==e.tabSize?e.tabSize:this._options.tabSize,n=void 0!==e.insertSpaces?e.insertSpaces:this._options.insertSpaces,i=void 0!==e.trimAutoWhitespace?e.trimAutoWhitespace:this._options.trimAutoWhitespace,o=new r.TextModelResolvedOptions({tabSize:t,insertSpaces:n,defaultEOL:this._options.defaultEOL,trimAutoWhitespace:i});if(!this._options.equals(o)){var s=this._options.createChangeEvent(o);this._options=o,this._onDidChangeOptions.fire(s)}},f.prototype.detectIndentation=function(e,t){this._assertNotDisposed();var n=w.guessIndentation(this._buffer,t,e);this.updateOptions({insertSpaces:n.insertSpaces,tabSize:n.tabSize})},f._normalizeIndentationFromWhitespace=function(e,t,n){ +for(var i=0,o=0;othis.getLineCount())throw new Error("Illegal value for lineNumber");return this._buffer.getLineContent(e)},f.prototype.getLineLength=function(e){if(this._assertNotDisposed(),e<1||e>this.getLineCount())throw new Error("Illegal value for lineNumber");return this._buffer.getLineLength(e)},f.prototype.getLinesContent=function(){return this._assertNotDisposed(),this._buffer.getLinesContent()},f.prototype.getEOL=function(){return this._assertNotDisposed(),this._buffer.getEOL()}, +f.prototype.getLineMinColumn=function(e){return this._assertNotDisposed(),1},f.prototype.getLineMaxColumn=function(e){if(this._assertNotDisposed(),e<1||e>this.getLineCount())throw new Error("Illegal value for lineNumber");return this._buffer.getLineLength(e)+1},f.prototype.getLineFirstNonWhitespaceColumn=function(e){if(this._assertNotDisposed(),e<1||e>this.getLineCount())throw new Error("Illegal value for lineNumber");return this._buffer.getLineFirstNonWhitespaceColumn(e)},f.prototype.getLineLastNonWhitespaceColumn=function(e){if(this._assertNotDisposed(),e<1||e>this.getLineCount())throw new Error("Illegal value for lineNumber");return this._buffer.getLineLastNonWhitespaceColumn(e)},f.prototype._validateRangeRelaxedNoAllocations=function(e){var t,n,i=this._buffer.getLineCount(),o=e.startLineNumber,r=e.startColumn;if(o<1)t=1,n=1;else if(o>i)t=i,n=this.getLineMaxColumn(t);else if(t=0|o,r<=1)n=1;else{n=r>=(h=this.getLineMaxColumn(t))?h:0|r}var s,a,d=e.endLineNumber,c=e.endColumn;if(d<1)s=1,a=1;else if(d>i)s=i, +a=this.getLineMaxColumn(s);else if(s=0|d,c<=1)a=1;else{var h=this.getLineMaxColumn(s);a=c>=h?h:0|c}return o===t&&r===n&&d===s&&c===a&&e instanceof l.Range&&!(e instanceof u.Selection)?e:new l.Range(t,n,s,a)},f.prototype._isValidPosition=function(e,t,n){if(isNaN(e))return!1;if(e<1)return!1;if(e>this._buffer.getLineCount())return!1;if(isNaN(t))return!1;if(t<1)return!1;if(t>this.getLineMaxColumn(e))return!1;if(n&&t>1){var i=this._buffer.getLineCharCode(e,t-2);if(h.isHighSurrogate(i))return!1}return!0},f.prototype._validatePosition=function(e,t,n){var i=Math.floor("number"!=typeof e||isNaN(e)?1:e),o=Math.floor("number"!=typeof t||isNaN(t)?1:t),r=this._buffer.getLineCount();if(i<1)return new y.Position(1,1);if(i>r)return new y.Position(r,this.getLineMaxColumn(r));if(o<=1)return new y.Position(i,1);var s=this.getLineMaxColumn(i);if(o>=s)return new y.Position(i,s);if(n){var a=this._buffer.getLineCharCode(i,o-2);if(h.isHighSurrogate(a))return new y.Position(i,o-1)}return new y.Position(i,o)}, +f.prototype.validatePosition=function(e){return this._assertNotDisposed(),e instanceof y.Position&&this._isValidPosition(e.lineNumber,e.column,!0)?e:this._validatePosition(e.lineNumber,e.column,!0)},f.prototype._isValidRange=function(e,t){var n=e.startLineNumber,i=e.startColumn,o=e.endLineNumber,r=e.endColumn;if(!this._isValidPosition(n,i,!1))return!1;if(!this._isValidPosition(o,r,!1))return!1;if(t){var s=i>1?this._buffer.getLineCharCode(n,i-2):0,a=r>1&&r<=this._buffer.getLineLength(o)?this._buffer.getLineCharCode(o,r-2):0,l=h.isHighSurrogate(s),u=h.isHighSurrogate(a);return!l&&!u}return!0},f.prototype.validateRange=function(e){if(this._assertNotDisposed(),e instanceof l.Range&&!(e instanceof u.Selection)&&this._isValidRange(e,!0))return e +;var t=this._validatePosition(e.startLineNumber,e.startColumn,!1),n=this._validatePosition(e.endLineNumber,e.endColumn,!1),i=t.lineNumber,o=t.column,r=n.lineNumber,s=n.column,a=o>1?this._buffer.getLineCharCode(i,o-2):0,d=s>1&&s<=this._buffer.getLineLength(r)?this._buffer.getLineCharCode(r,s-2):0,c=h.isHighSurrogate(a),p=h.isHighSurrogate(d);return c||p?i===r&&o===s?new l.Range(i,o-1,r,s-1):c&&p?new l.Range(i,o-1,r,s+1):c?new l.Range(i,o-1,r,s):new l.Range(i,o,r,s+1):new l.Range(i,o,r,s)},f.prototype.modifyPosition=function(e,t){this._assertNotDisposed();var n=this.getOffsetAt(e)+t;return this.getPositionAt(Math.min(this._buffer.getLength(),Math.max(0,n)))},f.prototype.getFullModelRange=function(){this._assertNotDisposed();var e=this.getLineCount();return new l.Range(1,1,e,this.getLineMaxColumn(e))},f.prototype.findMatchesLineByLine=function(e,t,n,i){return this._buffer.findMatchesLineByLine(e,t,n,i)},f.prototype.findMatches=function(e,t,n,i,o,r,s){void 0===s&&(s=999),this._assertNotDisposed();var a +;if(a=l.Range.isIRange(t)?this.validateRange(t):this.getFullModelRange(),!n&&e.indexOf("\n")<0){var u=new L.SearchParams(e,n,i,o).parseSearchRequest();return u?this.findMatchesLineByLine(a,u,r,s):[]}return L.TextModelSearch.findMatches(this,new L.SearchParams(e,n,i,o),a,r,s)},f.prototype.findNextMatch=function(e,t,n,i,o,r){this._assertNotDisposed();var s=this.validatePosition(t);if(!n&&e.indexOf("\n")<0){var a=new L.SearchParams(e,n,i,o).parseSearchRequest(),u=this.getLineCount(),d=new l.Range(s.lineNumber,s.column,u,this.getLineMaxColumn(u)),c=this.findMatchesLineByLine(d,a,r,1);return L.TextModelSearch.findNextMatch(this,new L.SearchParams(e,n,i,o),s,r),c.length>0?c[0]:(d=new l.Range(1,1,s.lineNumber,this.getLineMaxColumn(s.lineNumber)),(c=this.findMatchesLineByLine(d,a,r,1)).length>0?c[0]:null)}return L.TextModelSearch.findNextMatch(this,new L.SearchParams(e,n,i,o),s,r)},f.prototype.findPreviousMatch=function(e,t,n,i,o,r){this._assertNotDisposed();var s=this.validatePosition(t) +;return L.TextModelSearch.findPreviousMatch(this,new L.SearchParams(e,n,i,o),s,r)},f.prototype.pushStackElement=function(){this._commandManager.pushStackElement()},f.prototype.pushEOL=function(e){if(("\n"===this.getEOL()?r.EndOfLineSequence.LF:r.EndOfLineSequence.CRLF)!==e)try{this._onDidChangeDecorations.beginDeferredEmit(),this._eventEmitter.beginDeferredEmit(),this._commandManager.pushEOL(e)}finally{this._eventEmitter.endDeferredEmit(),this._onDidChangeDecorations.endDeferredEmit()}},f.prototype.pushEditOperations=function(e,t,n){try{return this._onDidChangeDecorations.beginDeferredEmit(),this._eventEmitter.beginDeferredEmit(),this._pushEditOperations(e,t,n)}finally{this._eventEmitter.endDeferredEmit(),this._onDidChangeDecorations.endDeferredEmit()}},f.prototype._pushEditOperations=function(e,t,n){var i=this;if(this._options.trimAutoWhitespace&&this._trimAutoWhitespaceLines){for(var o=t.map(function(e){return{range:i.validateRange(e.range),text:e.text}}),r=!0,s=0,a=e.length;su.endLineNumber,f=u.startLineNumber>_.endLineNumber;if(!p&&!f){d=!0;break}}if(!d){r=!1;break}}if(r)for(var s=0,a=this._trimAutoWhitespaceLines.length;s_.endLineNumber)&&!(g===_.startLineNumber&&_.startColumn===m&&_.isEmpty()&&y&&y.length>0&&"\n"===y.charAt(0)||g===_.startLineNumber&&1===_.startColumn&&_.isEmpty()&&y&&y.length>0&&"\n"===y.charAt(y.length-1))){v=!1;break}}v&&t.push({range:new l.Range(g,1,g,m),text:null})}this._trimAutoWhitespaceLines=null}return this._commandManager.pushEditOperation(e,t,n)},f.prototype.applyEdits=function(e){try{return this._onDidChangeDecorations.beginDeferredEmit(),this._eventEmitter.beginDeferredEmit(),this._applyEdits(e)}finally{this._eventEmitter.endDeferredEmit(),this._onDidChangeDecorations.endDeferredEmit()}}, +f._eolCount=function(e){for(var t=0,n=0,i=0,o=e.length;i=0;b--){var S=g+b,w=r-l-C+S;a.push(new d.ModelRawLineChanged(S,this.getLineContent(w)))}if(ythis.getLineCount()?[]:this.getLinesDecorations(e,e,t,n)},f.prototype.getLinesDecorations=function(e,t,n,i){void 0===n&&(n=0),void 0===i&&(i=!1);var o=this.getLineCount(),r=Math.min(o,Math.max(1,e)),s=Math.min(o,Math.max(1,t)),a=this.getLineMaxColumn(s);return this._getDecorationsInRange(new l.Range(r,1,s,a),n,i)},f.prototype.getDecorationsInRange=function(e,t,n){void 0===t&&(t=0),void 0===n&&(n=!1);var i=this.validateRange(e);return this._getDecorationsInRange(i,t,n)},f.prototype.getOverviewRulerDecorations=function(e,t){void 0===e&&(e=0),void 0===t&&(t=!1);var n=this.getVersionId(),i=this._decorationsTree.search(e,t,!0,n);return this._ensureNodesHaveRanges(i)},f.prototype.getAllDecorations=function(e,t){void 0===e&&(e=0),void 0===t&&(t=!1);var n=this.getVersionId(),i=this._decorationsTree.search(e,t,!1,n) +;return this._ensureNodesHaveRanges(i)},f.prototype._getDecorationsInRange=function(e,t,n){var i=this._buffer.getOffsetAt(e.startLineNumber,e.startColumn),o=this._buffer.getOffsetAt(e.endLineNumber,e.endColumn),r=this.getVersionId(),s=this._decorationsTree.intervalSearch(i,o,t,n,r);return this._ensureNodesHaveRanges(s)},f.prototype._ensureNodesHaveRanges=function(e){for(var t=0,n=e.length;t0)for(;o>0&&s>=1;){var l=this.getLineFirstNonWhitespaceColumn(s);if(0!==l){if(l=0;d--){u=(f=this._tokens._tokenizeText(this._buffer,r[d],u))?f.endState.clone():a.clone()}var c=Math.floor(.4*this._tokens.inValidLineStartIndex);t=Math.min(this.getLineCount(),t+c);for(var h=e;h<=t;h++){var p=this.getLineContent(h),f=this._tokens._tokenizeText(this._buffer,p,u);f?(this._tokens._setTokens(this._tokens.languageIdentifier.id,h-1,p.length,f.tokens),this._tokens._setIsInvalid(h-1,!1),this._tokens._setState(h-1,u),u=f.endState.clone(),i.registerChangedTokens(h)):u=a.clone()}var g=i.build();g&&this._onDidChangeTokens.fire(g)}}}, +f.prototype.forceTokenization=function(e){if(e<1||e>this.getLineCount())throw new Error("Illegal value for lineNumber");var t=new S.ModelTokensChangedEventBuilder;this._tokens._updateTokensUntilLine(this._buffer,t,e);var n=t.build();n&&this._onDidChangeTokens.fire(n)},f.prototype.isCheapToTokenize=function(e){return this._tokens.isCheapToTokenize(e)},f.prototype.tokenizeIfCheap=function(e){this.isCheapToTokenize(e)&&this.forceTokenization(e)},f.prototype.getLineTokens=function(e){if(e<1||e>this.getLineCount())throw new Error("Illegal value for lineNumber");return this._getLineTokens(e)},f.prototype._getLineTokens=function(e){var t=this._buffer.getLineContent(e);return this._tokens.getTokens(this._languageIdentifier.id,e-1,t)},f.prototype.getLanguageIdentifier=function(){return this._languageIdentifier},f.prototype.getModeId=function(){return this._languageIdentifier.language},f.prototype.setMode=function(e){if(this._languageIdentifier.id!==e.id){var t={oldLanguage:this._languageIdentifier.language, +newLanguage:e.language};this._languageIdentifier=e,this._resetTokenizationState(),this.emitModelTokensChangedEvent({ranges:[{fromLineNumber:1,toLineNumber:this.getLineCount()}]}),this._onDidChangeLanguage.fire(t),this._onDidChangeLanguageConfiguration.fire({})}},f.prototype.getLanguageIdAtPosition=function(e,t){if(!this._tokens.tokenizationSupport)return this._languageIdentifier.id;var n=this.validatePosition({lineNumber:e,column:t}),i=n.lineNumber,o=n.column,r=this._getLineTokens(i);return r.getLanguageId(r.findTokenIndexAtOffset(o-1))},f.prototype._beginBackgroundTokenization=function(){var e=this;this._shouldAutoTokenize()&&-1===this._revalidateTokensTimeout&&(this._revalidateTokensTimeout=setTimeout(function(){e._revalidateTokensTimeout=-1,e._revalidateTokensNow()},0))},f.prototype._warmUpTokens=function(){var e=Math.min(100,this.getLineCount());this._revalidateTokensNow(e),this._tokens.hasLinesToTokenize(this._buffer)&&this._beginBackgroundTokenization()},f.prototype._revalidateTokensNow=function(e){ +void 0===e&&(e=this._buffer.getLineCount());for(var t=new S.ModelTokensChangedEventBuilder,n=g.StopWatch.create(!1);this._tokens.hasLinesToTokenize(this._buffer)&&!(n.elapsed()>20);){if(this._tokens._tokenizeOneLine(this._buffer,t)>=e)break}this._tokens.hasLinesToTokenize(this._buffer)&&this._beginBackgroundTokenization();var i=t.build();i&&this._onDidChangeTokens.fire(i)},f.prototype.emitModelTokensChangedEvent=function(e){this._isDisposing||this._onDidChangeTokens.fire(e)},f.prototype.getWordAtPosition=function(e){this._assertNotDisposed();var t=this.validatePosition(e),n=this.getLineContent(t.lineNumber),i=this._getLineTokens(t.lineNumber),o=i.findTokenIndexAtOffset(t.column-1),r=f._findLanguageBoundaries(i,o),s=r[0],a=r[1],l=b.getWordAtText(t.column,C.LanguageConfigurationRegistry.getWordDefinition(i.getLanguageId(o)),n.substring(s,a),s);if(l)return l;if(o>0&&s===t.column-1){ +var u=f._findLanguageBoundaries(i,o-1),d=u[0],c=u[1],h=b.getWordAtText(t.column,C.LanguageConfigurationRegistry.getWordDefinition(i.getLanguageId(o-1)),n.substring(d,c),d);if(h)return h}return null},f._findLanguageBoundaries=function(e,t){for(var n,i=e.getLanguageId(t),o=t;o>=0&&e.getLanguageId(o)===i;o--)n=e.getStartOffset(o);for(var r,o=t,s=e.getCount();o0&&n.getStartOffset(o)===e.column-1){a=n.getStartOffset(o);o--;var u=C.LanguageConfigurationRegistry.getBracketsSupport(n.getLanguageId(o)) +;if(u&&!v.ignoreBracketsInToken(n.getStandardTokenType(o))){var s=Math.max(n.getStartOffset(o),e.column-1-u.maxBracketLength),d=_.BracketsUtils.findPrevBracketInToken(u.reversedRegex,t,i,s,a);if(d&&d.startColumn<=e.column&&e.column<=d.endColumn){var c=i.substring(d.startColumn-1,d.endColumn-1);c=c.toLowerCase();var h=this._matchFoundBracket(d,u.textIsBracket[c],u.textIsOpenBracket[c]);if(h)return h}}}return null},f.prototype._matchFoundBracket=function(e,t,n){if(!t)return null;if(n){if(i=this._findMatchingBracketDown(t,e.getEndPosition()))return[e,i]}else{var i=this._findMatchingBracketUp(t,e.getStartPosition());if(i)return[e,i]}return null},f.prototype._findMatchingBracketUp=function(e,t){for(var n=e.languageIdentifier.id,i=e.reversedRegex,o=-1,r=t.lineNumber;r>=1;r--){var s=this._getLineTokens(r),a=s.getCount(),l=this._buffer.getLineContent(r),u=a-1,d=-1;for(r===t.lineNumber&&(u=s.findTokenIndexAtOffset(t.column-1),d=t.column-1);u>=0;u--){ +var c=s.getLanguageId(u),h=s.getStandardTokenType(u),p=s.getStartOffset(u),f=s.getEndOffset(u);if(-1===d&&(d=f),c===n&&!v.ignoreBracketsInToken(h))for(;;){var g=_.BracketsUtils.findPrevBracketInToken(i,r,l,p,d);if(!g)break;var m=l.substring(g.startColumn-1,g.endColumn-1);if((m=m.toLowerCase())===e.open?o++:m===e.close&&o--,0===o)return g;d=g.startColumn-1}d=-1}}return null},f.prototype._findMatchingBracketDown=function(e,t){for(var n=e.languageIdentifier.id,i=e.forwardRegex,o=1,r=t.lineNumber,s=this.getLineCount();r<=s;r++){var a=this._getLineTokens(r),l=a.getCount(),u=this._buffer.getLineContent(r),d=0,c=0;for(r===t.lineNumber&&(d=a.findTokenIndexAtOffset(t.column-1),c=t.column-1);do)throw new Error("Illegal value for lineNumber");for(var r=C.LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id),s=r&&r.offSide,a=-2,l=-1,u=-2,d=-1,c=function(e){if(-1!==a&&(-2===a||a>e-1)){a=-1,l=-1;for(n=e-2;n>=0;n--){var t=i._computeIndentLevel(n);if(t>=0){a=n,l=t;break}}}if(-2===u){u=-1,d=-1;for(var n=e;n=0){u=n,d=r;break}}}},h=-2,p=-1,f=-2,g=-1,m=function(e){if(-2===h){h=-1,p=-1;for(n=e-2;n>=0;n--){var t=i._computeIndentLevel(n);if(t>=0){h=n,p=t;break}}}if(-1!==f&&(-2===f||f=0){f=n,g=r;break}}}},v=0,_=!0,y=0,b=!0,S=0,w=0;_||b;w++){var E=e-w,L=e+w +;if(0!==w&&(E<1||Eo||L>n)&&(b=!1),w>5e4&&(_=!1,b=!1),_){var x=void 0;if((I=this._computeIndentLevel(E-1))>=0?(u=E-1,d=I,x=Math.ceil(I/this._options.tabSize)):(c(E),x=this._getIndentLevelForWhitespaceLine(s,l,d)),0===w){if(v=E,y=L,0===(S=x))return{startLineNumber:v,endLineNumber:y,indent:S};continue}x>=S?v=E:_=!1}if(b){var N=void 0,I=this._computeIndentLevel(L-1);I>=0?(h=L-1,p=I,N=Math.ceil(I/this._options.tabSize)):(m(L),N=this._getIndentLevelForWhitespaceLine(s,p,g)),N>=S?y=L:b=!1}}return{startLineNumber:v,endLineNumber:y,indent:S}},f.prototype.getLinesIndentGuides=function(e,t){this._assertNotDisposed();var n=this.getLineCount();if(e<1||e>n)throw new Error("Illegal value for startLineNumber");if(t<1||t>n)throw new Error("Illegal value for endLineNumber");for(var i=C.LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id),o=i&&i.offSide,r=new Array(t-e+1),s=-2,a=-1,l=-2,u=-1,d=e;d<=t;d++){var c=d-e,h=this._computeIndentLevel(d-1);if(h>=0)s=d-1,a=h, +r[c]=Math.ceil(h/this._options.tabSize);else{if(-2===s){s=-1,a=-1;for(p=d-2;p>=0;p--){if((f=this._computeIndentLevel(p))>=0){s=p,a=f;break}}}if(-1!==l&&(-2===l||l=0){l=p,u=f;break}}}r[c]=this._getIndentLevelForWhitespaceLine(o,a,u)}}return r},f.prototype._getIndentLevelForWhitespaceLine=function(e,t,n){return-1===t||-1===n?0:t0?this._deferredEvent?this._deferredEvent=this._deferredEvent.merge(e):this._deferredEvent=e:(this._fastEmitter.fire(e),this._slowEmitter.fire(e))},t}(f.Disposable);t.DidChangeContentEmitter=W}),define(t[38],n([1,0,12,6,29,21,3,41,10]),function(e,t,n,i,o,r,s,a,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=function(){function e(t,n,i,o){this._languageIdentifier=t;var r=o.editor;this.readOnly=r.readOnly,this.tabSize=i.tabSize,this.insertSpaces=i.insertSpaces,this.oneIndent=n,this.pageSize=Math.max(1,Math.floor(r.layoutInfo.height/r.fontInfo.lineHeight)-2),this.lineHeight=r.lineHeight,this.useTabStops=r.useTabStops,this.wordSeparators=r.wordSeparators,this.emptySelectionClipboard=r.emptySelectionClipboard, +this.multiCursorMergeOverlapping=r.multiCursorMergeOverlapping,this.autoClosingBrackets=r.autoClosingBrackets,this.autoIndent=r.autoIndent,this.autoClosingPairsOpen={},this.autoClosingPairsClose={},this.surroundingPairs={},this._electricChars=null;var s=e._getAutoClosingPairs(t);if(s)for(l=0;l=o.length)&&i.isLowSurrogate(o.charCodeAt(n))},e.isHighSurrogate=function(e,t,n){var o=e.getLineContent(t);return!(n<0||n>=o.length)&&i.isHighSurrogate(o.charCodeAt(n))},e.isInsideSurrogatePair=function(e,t,n){return this.isHighSurrogate(e,t,n-2)},e.visibleColumnFromColumn=function(e,t,n){var o=e.length;o>t-1&&(o=t-1);for(var r=0,s=0;s=t){return l-ts?s:o},e.nextTabStop=function(e,t){return e+t-e%t},e.prevTabStop=function(e,t){return e-1-(e-1)%t},e}();t.CursorColumns=f}),define(t[170],n([1,0,6,38,3,21,41]),function(e,t,n,i,o,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(e,t){this._opts=t,this._selection=e,this._useLastEditRangeForCursorEndPosition=!1,this._selectionStartColumnStaysPut=!1}return e.unshiftIndentCount=function(e,t,n){ +var o=i.CursorColumns.visibleColumnFromColumn(e,t,n);return i.CursorColumns.prevTabStop(o,n)/n},e.shiftIndentCount=function(e,t,n){var o=i.CursorColumns.visibleColumnFromColumn(e,t,n);return i.CursorColumns.nextTabStop(o,n)/n},e.prototype._addEditOperation=function(e,t,n){this._useLastEditRangeForCursorEndPosition?e.addTrackedEditOperation(t,n):e.addEditOperation(t,n)},e.prototype.getEditOperations=function(t,r){var a=this._selection.startLineNumber,l=this._selection.endLineNumber;1===this._selection.endColumn&&a!==l&&(l-=1);var u=this._opts.tabSize,d=this._opts.oneIndent,c=a===l;if(this._selection.isEmpty()&&/^\s*$/.test(t.getLineContent(a))&&(this._useLastEditRangeForCursorEndPosition=!0),this._opts.useTabStops)for(var h=["",d],p=0,f=0,g=a;g<=l;g++,p=f){f=0;var m=t.getLineContent(g),v=n.firstNonWhitespaceIndex(m);if((!this._opts.isUnshift||0!==m.length&&0!==v)&&(c||this._opts.isUnshift||0!==m.length)){if(-1===v&&(v=m.length),g>1){ +if(i.CursorColumns.visibleColumnFromColumn(m,v+1,u)%u!=0&&t.isCheapToTokenize(g-1)){var _=s.LanguageConfigurationRegistry.getRawEnterActionAtPosition(t,g-1,t.getLineMaxColumn(g-1));if(_){if(f=p,_.appendText)for(var y=0,C=_.appendText.length;ya,c=s>l,h=sl)continue;if(ys)continue;if(_1&&o--,this.columnSelect(e,t,n.selection,i,o)},e.columnSelectRight=function(e,t,i,r,s){for(var a=0,l=Math.min(i.position.lineNumber,r),u=Math.max(i.position.lineNumber,r),d=l;d<=u;d++){ +var c=t.getLineMaxColumn(d),h=o.CursorColumns.visibleColumnFromColumn2(e,t,new n.Position(d,c));a=Math.max(a,h)}return st.getLineCount()&&(o=t.getLineCount()),this.columnSelect(e,t,n.selection,o,r)},e}();t.ColumnSelection=r}),define(t[171],n([1,0,38,12,3]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){return function(e,t,n){this.lineNumber=e,this.column=t,this.leftoverVisibleColumns=n}}();t.CursorPosition=r;var s=function(){function e(){}return e.left=function(e,t,i,o){return o>t.getLineMinColumn(i)?n.CursorColumns.isLowSurrogate(t,i,o-2)?o-=2:o-=1:i>1&&(i-=1,o=t.getLineMaxColumn(i)),new r(i,o,0)},e.moveLeft=function(t,n,i,o,r){var s,a;if(i.hasSelection()&&!o)s=i.selection.startLineNumber,a=i.selection.startColumn;else{ +var l=e.left(t,n,i.position.lineNumber,i.position.column-(r-1));s=l.lineNumber,a=l.column}return i.move(o,s,a,0)},e.right=function(e,t,i,o){return od?(i=d,l?o=t.getLineMaxColumn(i):(o=Math.min(t.getLineMaxColumn(i),o),n.CursorColumns.isInsideSurrogatePair(t,i,o)&&(o-=1))):(o=n.CursorColumns.columnFromVisibleColumn2(e,t,i,u),n.CursorColumns.isInsideSurrogatePair(t,i,o)&&(o-=1)),s=u-n.CursorColumns.visibleColumnFromColumn(t.getLineContent(i),o,e.tabSize),new r(i,o,s)}, +e.moveDown=function(t,n,i,o,r){var s,a;i.hasSelection()&&!o?(s=i.selection.endLineNumber,a=i.selection.endColumn):(s=i.position.lineNumber,a=i.position.column);var l=e.down(t,n,s,a,i.leftoverVisibleColumns,r,!0);return i.move(o,l.lineNumber,l.column,l.leftoverVisibleColumns)},e.translateDown=function(t,r,s){var a=s.selection,l=e.down(t,r,a.selectionStartLineNumber,a.selectionStartColumn,s.selectionStartLeftoverVisibleColumns,1,!1),u=e.down(t,r,a.positionLineNumber,a.positionColumn,s.leftoverVisibleColumns,1,!1);return new n.SingleCursorState(new o.Range(l.lineNumber,l.column,l.lineNumber,l.column),l.leftoverVisibleColumns,new i.Position(u.lineNumber,u.column),u.leftoverVisibleColumns)},e.up=function(e,t,i,o,s,a,l){var u=n.CursorColumns.visibleColumnFromColumn(t.getLineContent(i),o,e.tabSize)+s;return(i-=a)<1?(i=1,l?o=t.getLineMinColumn(i):(o=Math.min(t.getLineMaxColumn(i),o),n.CursorColumns.isInsideSurrogatePair(t,i,o)&&(o-=1))):(o=n.CursorColumns.columnFromVisibleColumn2(e,t,i,u), +n.CursorColumns.isInsideSurrogatePair(t,i,o)&&(o-=1)),s=u-n.CursorColumns.visibleColumnFromColumn(t.getLineContent(i),o,e.tabSize),new r(i,o,s)},e.moveUp=function(t,n,i,o,r){var s,a;i.hasSelection()&&!o?(s=i.selection.startLineNumber,a=i.selection.startColumn):(s=i.position.lineNumber,a=i.position.column);var l=e.up(t,n,s,a,i.leftoverVisibleColumns,r,!0);return i.move(o,l.lineNumber,l.column,l.leftoverVisibleColumns)},e.translateUp=function(t,r,s){var a=s.selection,l=e.up(t,r,a.selectionStartLineNumber,a.selectionStartColumn,s.selectionStartLeftoverVisibleColumns,1,!1),u=e.up(t,r,a.positionLineNumber,a.positionColumn,s.leftoverVisibleColumns,1,!1);return new n.SingleCursorState(new o.Range(l.lineNumber,l.column,l.lineNumber,l.column),l.leftoverVisibleColumns,new i.Position(u.lineNumber,u.column),u.leftoverVisibleColumns)},e.moveToBeginningOfLine=function(e,t,n,i){var o,r=n.position.lineNumber,s=t.getLineMinColumn(r),a=t.getLineFirstNonWhitespaceColumn(r)||s;return o=n.position.column===a?s:a,n.move(i,r,o,0)}, +e.moveToEndOfLine=function(e,t,n,i){var o=n.position.lineNumber,r=t.getLineMaxColumn(o);return n.move(i,o,r,0)},e.moveToBeginningOfBuffer=function(e,t,n,i){return n.move(i,1,1,0)},e.moveToEndOfBuffer=function(e,t,n,i){var o=t.getLineCount(),r=t.getLineMaxColumn(o);return n.move(i,o,r,0)},e}();t.MoveOperations=s}),define(t[176],n([1,0,76,38,3,171,6]),function(e,t,n,i,o,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(){}return e.deleteRight=function(e,t,i,s){for(var a=[],l=3!==e,u=0,d=s.length;u1){var m=a.getLineContent(g.lineNumber),v=s.firstNonWhitespaceIndex(m),_=-1===v?m.length+1:v+1;if(g.column<=_){var y=i.CursorColumns.visibleColumnFromColumn2(t,a,g),C=i.CursorColumns.prevTabStop(y,t.tabSize),b=i.CursorColumns.columnFromVisibleColumn2(t,a,g.lineNumber,C);f=new o.Range(g.lineNumber,b,g.lineNumber,g.column)}else f=new o.Range(g.lineNumber,g.column-1,g.lineNumber,g.column)}else{ +var S=r.MoveOperations.left(t,a,g.lineNumber,g.column);f=new o.Range(S.lineNumber,S.column,g.lineNumber,g.column)}}f.isEmpty()?u[c]=null:(f.startLineNumber!==f.endLineNumber&&(d=!0),u[c]=new n.ReplaceCommand(f,""))}return[d,u]},e.cut=function(e,t,r){for(var s=[],a=0,l=r.length;a1?(c=d.lineNumber-1,h=t.getLineMaxColumn(d.lineNumber-1),p=d.lineNumber,f=t.getLineMaxColumn(d.lineNumber)):(c=d.lineNumber,h=1,p=d.lineNumber,f=t.getLineMaxColumn(d.lineNumber));var g=new o.Range(c,h,p,f);g.isEmpty()?s[a]=null:s[a]=new n.ReplaceCommand(g,"")}else s[a]=null;else s[a]=new n.ReplaceCommand(u,"")}return new i.EditOperationResult(0,s,{shouldPushStackElementBefore:!0,shouldPushStackElementAfter:!0})},e}();t.DeleteOperations=a}),define(t[139],n([1,0,10,76,38,3,6,170,41,58,441,89]),function(e,t,n,i,o,r,s,a,l,u,d,c){ +"use strict";Object.defineProperty(t,"__esModule",{value:!0});var h=function(){function e(){}return e.indent=function(e,t,n){for(var i=[],o=0,r=n.length;o1){var c=i-1;for(c=i-1;c>=1;c--){var h=n.getLineContent(c);if(s.lastNonWhitespaceIndex(h)>=0)break}if(c<1)return null;var p=n.getLineMaxColumn(c),f=l.LanguageConfigurationRegistry.getEnterAction(n,new r.Range(c,p,c,p));f&&(a=f.indentation,(o=f.enterAction)&&(a+=o.appendText))}return o&&(o===u.IndentAction.Indent&&(a=e.shiftIndent(t,a)),o===u.IndentAction.Outdent&&(a=e.unshiftIndent(t,a)),a=t.normalizeIndentation(a)),a||null},e._replaceJumpToNextIndent=function(e,t,n,r){var s="",a=n.getStartPosition();if(e.insertSpaces)for(var l=o.CursorColumns.visibleColumnFromColumn2(e,t,a),u=e.tabSize,d=u-l%u,c=0;c=0?d.setEndPosition(d.endLineNumber,Math.max(d.endColumn,M+1)):d.setEndPosition(d.endLineNumber,n.getLineMaxColumn(d.endLineNumber)),a)return new i.ReplaceCommandWithoutChangingPosition(d,N+t.normalizeIndentation(S.afterEnter),!0);var D=0;return x<=M+1&&(t.insertSpaces||(L=Math.ceil(L/t.tabSize)),D=Math.min(L+1-t.normalizeIndentation(S.afterEnter).length-1,0)),new i.ReplaceCommandWithOffsetCursorState(d,N+t.normalizeIndentation(S.afterEnter),0,D,!0)}return e._typeCommand(d,"\n"+t.normalizeIndentation(E),a)},e._isAutoIndentType=function(e,t,n){if(!e.autoIndent)return!1;for(var i=0,o=n.length;i1){var p=c.getMapForWordSeparators(t.wordSeparators),f=h.charCodeAt(d.column-2);if(0===p.get(f))return!1}var g=h.charAt(d.column-1);if(g){if(!e._isBeforeClosingBrace(t,r,g)&&!/\s/.test(g))return!1}if(!i.isCheapToTokenize(d.lineNumber))return!1;i.forceTokenization(d.lineNumber);var m=i.getLineTokens(d.lineNumber),v=!1;try{ +v=l.LanguageConfigurationRegistry.shouldAutoClosePair(r,m,d.column)}catch(e){n.onUnexpectedError(e)}if(!v)return!1}return!0},e._runAutoClosingOpenCharType=function(e,t,n,r,s){for(var a=[],l=0,u=r.length;l2){var m=c.getMapForWordSeparators(r.wordSeparators),v=p.charCodeAt(h.column-3);if(0===m.get(v))continue}var _=p.charAt(h.column-1);if(_){if(!e._isBeforeClosingBrace(r,f,_)&&!/\s/.test(_))continue}if(!s.isCheapToTokenize(h.lineNumber))continue;s.forceTokenization(h.lineNumber);var y=s.getLineTokens(h.lineNumber),C=!1;try{C=l.LanguageConfigurationRegistry.shouldAutoClosePair(f,y,h.column-1)}catch(e){n.onUnexpectedError(e)}if(C){var b=r.autoClosingPairsOpen[f];u[d]=new i.ReplaceCommandWithOffsetCursorState(a[d],b,0,-b.length)}}}return new o.EditOperationResult(1,u,{shouldPushStackElementBefore:!0,shouldPushStackElementAfter:!1})},e.typeWithInterceptors=function(t,n,r,s,a){if("\n"===a){for(var l=[],u=0,d=s.length;u=0;i--){var o=e.charCodeAt(i);if(32===o||9===o||!n&&s.isUpperAsciiLetter(o)||95===o)return i-1;if(n&&i=0;o--){var r=e.charCodeAt(o),s=t.get(r);if(0===s){if(2===i)return this._createWord(e,i,s,o+1,this._findEndOfWord(e,t,i,o+1));i=1}else if(2===s){if(1===i)return this._createWord(e,i,s,o+1,this._findEndOfWord(e,t,i,o+1));i=2 +}else if(1===s&&0!==i)return this._createWord(e,i,s,o+1,this._findEndOfWord(e,t,i,o+1))}return 0!==i?this._createWord(e,i,1,0,this._findEndOfWord(e,t,i,0)):null},e._findEndOfWord=function(e,t,n,i){for(var o=e.length,r=i;r=0;o--){var r=e.charCodeAt(o),s=t.get(r) +;if(1===s)return o+1;if(1===n&&2===s)return o+1;if(2===n&&0===s)return o+1}return 0},e.moveWordLeft=function(t,n,o,r){var s=o.lineNumber,a=o.column;1===a&&s>1&&(s-=1,a=n.getLineMaxColumn(s));var l=e._findPreviousWordOnLine(t,n,new i.Position(s,a));return 0===r?(l&&2===l.wordType&&l.end-l.start==1&&0===l.nextCharClass&&(l=e._findPreviousWordOnLine(t,n,new i.Position(s,l.start+1))),a=l?l.start+1:1):(l&&a<=l.end+1&&(l=e._findPreviousWordOnLine(t,n,new i.Position(s,l.start+1))),a=l?l.end+1:1),new i.Position(s,a)},e.moveWordRight=function(t,n,o,r){var s=o.lineNumber,a=o.column;a===n.getLineMaxColumn(s)&&s=l.start+1&&(l=e._findNextWordOnLine(t,n,new i.Position(s,l.end+1))),a=l?l.start+1:n.getLineMaxColumn(s)),new i.Position(s,a)}, +e._deleteWordLeftWhitespace=function(e,t){var n=e.getLineContent(t.lineNumber),i=t.column-2,o=s.lastNonWhitespaceIndex(n,i);return o+11?d=1:(u--,d=n.getLineMaxColumn(u)):(h&&d<=h.end+1&&(h=e._findPreviousWordOnLine(t,n,new i.Position(u,h.start+1))),h?d=h.end+1:d>1?d=1:(u--,d=n.getLineMaxColumn(u))),new a.Range(u,d,l.lineNumber,l.column)},e._findFirstNonWhitespaceChar=function(e,t){for(var n=e.length,i=t;i=f.start+1&&(f=e._findNextWordOnLine(t,n,new i.Position(u,f.end+1))),f?d=f.start+1:d1?new i.Position(r-1,t.getLineMaxColumn(r-1)):n;var a=d.moveWordLeft(e,t,n,o),u=l(t.getLineContent(r),s-2),c=new i.Position(r,u+2);return c.isBeforeOrEqual(a)?a:c},t.moveWordPartRight=function(e,t,n,o){var r=n.lineNumber,s=n.column;if(s===t.getLineMaxColumn(r))return rd&&(c=d,h=e.model.getLineMaxColumn(c)), +n.CursorState.fromModelState(new n.SingleCursorState(new o.Range(l.lineNumber,1,c,h),0,new i.Position(c,h),0))}var p=t.modelState.selectionStart.getStartPosition().lineNumber;if(l.lineNumberp){var d=e.viewModel.getLineCount(),f=u.lineNumber+1,g=1;return f>d&&(f=d,g=e.viewModel.getLineMaxColumn(f)),n.CursorState.fromViewState(t.viewState.move(t.modelState.hasSelection(),f,g,0))}var m=t.modelState.selectionStart.getEndPosition();return n.CursorState.fromModelState(t.modelState.move(t.modelState.hasSelection(),m.lineNumber,m.column,0))},e.word=function(e,t,i,o){var r=e.model.validatePosition(o);return n.CursorState.fromModelState(s.WordOperations.word(e.config,e.model,t.modelState,i,r))},e.cancelSelection=function(e,t){if(!t.modelState.hasSelection())return new n.CursorState(t.modelState,t.viewState);var r=t.viewState.position.lineNumber,s=t.viewState.position.column +;return n.CursorState.fromViewState(new n.SingleCursorState(new o.Range(r,s,r,s),0,new i.Position(r,s),0))},e.moveTo=function(e,t,o,r,s){var a=e.model.validatePosition(r),l=s?e.validateViewPosition(new i.Position(s.lineNumber,s.column),a):e.convertModelPositionToViewPosition(a);return n.CursorState.fromViewState(t.viewState.move(o,l.lineNumber,l.column,0))},e.move=function(e,t,n){var i=n.select,o=n.value;switch(n.direction){case 0:return 4===n.unit?this._moveHalfLineLeft(e,t,i):this._moveLeft(e,t,i,o);case 1:return 4===n.unit?this._moveHalfLineRight(e,t,i):this._moveRight(e,t,i,o);case 2:return 2===n.unit?this._moveUpByViewLines(e,t,i,o):this._moveUpByModelLines(e,t,i,o);case 3:return 2===n.unit?this._moveDownByViewLines(e,t,i,o):this._moveDownByModelLines(e,t,i,o);case 4:return this._moveToViewMinColumn(e,t,i);case 5:return this._moveToViewFirstNonWhitespaceColumn(e,t,i);case 6:return this._moveToViewCenterColumn(e,t,i);case 7:return this._moveToViewMaxColumn(e,t,i);case 8: +return this._moveToViewLastNonWhitespaceColumn(e,t,i);case 9:var r=t[0],s=e.getCompletelyVisibleModelRange(),a=this._firstLineNumberInRange(e.model,s,o),l=e.model.getLineFirstNonWhitespaceColumn(a);return[this._moveToModelPosition(e,r,i,a,l)];case 11:var r=t[0],s=e.getCompletelyVisibleModelRange(),a=this._lastLineNumberInRange(e.model,s,o),l=e.model.getLineFirstNonWhitespaceColumn(a);return[this._moveToModelPosition(e,r,i,a,l)];case 10:var r=t[0],s=e.getCompletelyVisibleModelRange(),a=Math.round((s.startLineNumber+s.endLineNumber)/2),l=e.model.getLineFirstNonWhitespaceColumn(a);return[this._moveToModelPosition(e,r,i,a,l)];case 12:for(var u=e.getCompletelyVisibleViewRange(),d=[],c=0,h=t.length;ci.endLineNumber-1&&(r=i.endLineNumber-1), +rn)for(var r=t-n,o=0;o=e+1&&this.lastAddedCursorIndex--,this.secondaryCursors[e].dispose(this.context),this.secondaryCursors.splice(e,1)},e.prototype._getAll=function(){var e=[];e[0]=this.primaryCursor;for(var t=0,n=this.secondaryCursors.length;tp&&t[w].index--;e.splice(p,1),t.splice(h,1),this._removeSecondaryCursor(p-1),s--}}}}},e}();t.CursorCollection=r}),define(t[382],n([1,0,299,6,10,381,3,21,66,38,176,139,54,78,9,24]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m){"use strict";Object.defineProperty(t,"__esModule",{value:!0}) +;var v=function(){return function(e,t,n){this.selections=e,this.source=t,this.reason=n}}();t.CursorStateChangedEvent=v;var _=function(){function e(e,t){this.modelVersionId=e.getVersionId(),this.cursorState=t.getAll()}return e.prototype.equals=function(e){if(!e)return!1;if(this.modelVersionId!==e.modelVersionId)return!1;if(this.cursorState.length!==e.cursorState.length)return!1;for(var t=0,n=this.cursorState.length;tt.MAX_CURSOR_COUNT&&(i=i.slice(0,t.MAX_CURSOR_COUNT),this._onDidReachMaxCursorCount.fire(void 0));var o=new _(this._model,this);this._cursors.setStates(i),this._cursors.normalize(),this._columnSelectData=null,this._emitStateChangedIfNecessary(e,n,o)},t.prototype.setColumnSelectData=function(e){this._columnSelectData=e},t.prototype.reveal=function(e,t,n){this._revealRange(t,0,e,n)},t.prototype.revealRange=function(e,t,n,i){this.emitCursorRevealRange(t,n,e,i)},t.prototype.scrollTo=function(e){this._viewModel.viewLayout.setScrollPositionSmooth({scrollTop:e})}, +t.prototype.saveState=function(){for(var e=[],t=this._cursors.getSelections(),n=0,i=t.length;n1)return;var l=new a.Range(r.lineNumber,r.column,r.lineNumber,r.column);this.emitCursorRevealRange(l,t,n,i)},t.prototype.emitCursorRevealRange=function(e,t,n,i){try{this._beginEmit().emit(new f.ViewRevealRangeRequestEvent(e,t,n,i))}finally{this._endEmit()}},t.prototype.trigger=function(e,t,n){var i=u.Handler;if(t!==i.CompositionStart)if(t===i.CompositionEnd&&(this._isDoingComposition=!1),this._configuration.editor.readOnly)this._onDidAttemptReadOnlyEdit.fire(void 0);else{var o=new _(this._model,this),s=p.CursorChangeReason.NotSet +;t!==i.Undo&&t!==i.Redo&&this._cursors.stopTrackingSelections(),this._cursors.ensureValidState(),this._isHandling=!0;try{switch(t){case i.Type:this._type(e,n.text);break;case i.ReplacePreviousChar:this._replacePreviousChar(n.text,n.replaceCharCnt);break;case i.Paste:s=p.CursorChangeReason.Paste,this._paste(n.text,n.pasteOnNewLine,n.multicursorText);break;case i.Cut:this._cut();break;case i.Undo:s=p.CursorChangeReason.Undo,this._interpretCommandResult(this._model.undo());break;case i.Redo:s=p.CursorChangeReason.Redo,this._interpretCommandResult(this._model.redo());break;case i.ExecuteCommand:this._externalExecuteCommand(n);break;case i.ExecuteCommands:this._externalExecuteCommands(n);break;case i.CompositionEnd:this._interpretCompositionEnd(e)}}catch(e){r.onUnexpectedError(e)}this._isHandling=!1,t!==i.Undo&&t!==i.Redo&&this._cursors.startTrackingSelections(),this._emitStateChangedIfNecessary(e,s,o)&&this._revealRange(0,0,!0,0)}else this._isDoingComposition=!0},t.prototype._interpretCompositionEnd=function(e){ +this._isDoingComposition||"keyboard"!==e||this._executeEditOperation(h.TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType,this.context.config,this.context.model,this.getSelections()))},t.prototype._type=function(e,t){if(this._isDoingComposition||"keyboard"!==e)this._executeEditOperation(h.TypeOperations.typeWithoutInterceptors(this._prevEditOperationType,this.context.config,this.context.model,this.getSelections(),t));else for(var n=0,o=t.length;n0&&(r[0]._isTracked=!0);var u=e.model.pushEditOperations(e.selectionsBefore,r,function(n){for(var i=[],o=0;o0?(i[n].sort(s),a[n]=t[n].computeCursorState(e.model,{getInverseEditOperations:function(){return i[n]}, +getTrackedSelection:function(t){var n=parseInt(t,10),i=e.model._getTrackedRange(e.trackedRanges[n]);return e.trackedRangesDirection[n]===l.SelectionDirection.LTR?new l.Selection(i.startLineNumber,i.startColumn,i.endLineNumber,i.endColumn):new l.Selection(i.endLineNumber,i.endColumn,i.startLineNumber,i.startColumn)}})):a[n]=e.selectionsBefore[n]},o=0;oo.identifier.major?i.identifier.major:o.identifier.major).toString()]=!0;for(var s=0;s0&&n--}}return t},e}()}),define(t[182],n([1,0,6,17,60,99]),function(e,t,n,i,o,r){"use strict";function s(e,t){return function(e,t){for(var i='
                                      ',o=e.split(/\r\n|\r|\n/),s=t.getInitialState(),a=0,l=o.length;a0&&(i+="
                                      ");var d=t.tokenize2(u,s,0);r.LineTokens.convertToEndOffset(d.tokens,u.length);for(var c=new r.LineTokens(d.tokens,u).inflate(),h=0,p=0,f=c.getCount();p'+n.escape(u.substring(h,m))+"",h=m}s=d.endState}return i+="
                                      "}(e,function(e){var t=i.TokenizationRegistry.get(e);if(t)return t;return{ +getInitialState:function(){return o.NULL_STATE},tokenize:void 0,tokenize2:function(e,t,n){return o.nullTokenize2(0,e,t,n)}}}(t))}Object.defineProperty(t,"__esModule",{value:!0}),t.tokenizeToString=s,t.tokenizeLineToHTML=function(e,t,n,i,o,r){for(var s="
                                      ",a=i,l=0,u=0,d=t.getCount();u0;)h+=" ",f--;break;case 60:h+="<";break;case 62:h+=">";break;case 38:h+="&";break;case 0:h+="�";break;case 65279:case 8232:h+="�";break;case 13:h+="​";break;default:h+=String.fromCharCode(p)}}if(s+=''+h+"",c>o||a>=o)break}}return s+="
                                      "}}),define(t[107],n([1,0,15]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ITextModelService=n.createDecorator("textModelService")}),define(t[187],n([1,0,15]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}), +t.ITextResourceConfigurationService=n.createDecorator("textResourceConfigurationService")});var u=this&&this.__param||function(e,t){return function(n,i){t(n,i,e)}};define(t[189],n([1,0,14,2,13,160,470,17,48,220,41,187]),function(e,t,n,i,r,s,l,d,c,h,p,f){"use strict";function g(e,t){var n=e.getModel(t);return!!n&&!n.isTooLargeForSyncing()}Object.defineProperty(t,"__esModule",{value:!0});var m=6e4,v=3e5,_=function(e){function t(t,i){var o=e.call(this)||this;return o._modelService=t,o._workerManager=o._register(new C(o._modelService)),o._register(d.LinkProviderRegistry.register("*",{provideLinks:function(e,t){return g(o._modelService,e.uri)?n.wireCancellationToken(t,o._workerManager.withWorker().then(function(t){return t.computeLinks(e.uri)})):r.TPromise.as([])}})),o._register(d.SuggestRegistry.register("*",new y(o._workerManager,i,o._modelService))),o}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this)},t.prototype.canComputeDiff=function(e,t){ +return g(this._modelService,e)&&g(this._modelService,t)},t.prototype.computeDiff=function(e,t,n){return this._workerManager.withWorker().then(function(i){return i.computeDiff(e,t,n)})},t.prototype.computeMoreMinimalEdits=function(e,t){return Array.isArray(t)&&0!==t.length&&g(this._modelService,e)?this._workerManager.withWorker().then(function(n){return n.computeMoreMinimalEdits(e,t)}):r.TPromise.as(t)},t.prototype.canNavigateValueSet=function(e){return g(this._modelService,e)},t.prototype.navigateValueSet=function(e,t,n){return this._workerManager.withWorker().then(function(i){return i.navigateValueSet(e,t,n)})},t=a([u(0,c.IModelService),u(1,f.ITextResourceConfigurationService)],t)}(i.Disposable);t.EditorWorkerServiceImpl=_;var y=function(){function e(e,t,n){this._workerManager=e,this._configurationService=t,this._modelService=n}return e.prototype.provideCompletionItems=function(e,t){ +if(this._configurationService.getValue(e.uri,t,"editor").wordBasedSuggestions&&g(this._modelService,e.uri))return this._workerManager.withWorker().then(function(n){return n.textualSuggest(e.uri,t)})},e}(),C=function(e){function t(t){var i=e.call(this)||this;i._modelService=t,i._editorWorkerClient=null;return i._register(new n.IntervalTimer).cancelAndSet(function(){return i._checkStopIdleWorker()},Math.round(v/2)),i._register(i._modelService.onModelRemoved(function(e){return i._checkStopEmptyWorker()})),i}return o(t,e),t.prototype.dispose=function(){this._editorWorkerClient&&(this._editorWorkerClient.dispose(),this._editorWorkerClient=null),e.prototype.dispose.call(this)},t.prototype._checkStopEmptyWorker=function(){if(this._editorWorkerClient){0===this._modelService.getModels().length&&(this._editorWorkerClient.dispose(),this._editorWorkerClient=null)}},t.prototype._checkStopIdleWorker=function(){if(this._editorWorkerClient){(new Date).getTime()-this._lastWorkerUsedTime>v&&(this._editorWorkerClient.dispose(), +this._editorWorkerClient=null)}},t.prototype.withWorker=function(){return this._lastWorkerUsedTime=(new Date).getTime(),this._editorWorkerClient||(this._editorWorkerClient=new w(this._modelService,"editorWorkerService")),r.TPromise.as(this._editorWorkerClient)},t}(i.Disposable),b=function(e){function t(t,i,o){var r=e.call(this)||this;if(r._syncedModels=Object.create(null),r._syncedModelsLastUsedTime=Object.create(null),r._proxy=t,r._modelService=i,!o){var s=new n.IntervalTimer;s.cancelAndSet(function(){return r._checkStopModelSync()},Math.round(m/2)),r._register(s)}return r}return o(t,e),t.prototype.dispose=function(){for(var t in this._syncedModels)i.dispose(this._syncedModels[t]);this._syncedModels=Object.create(null),this._syncedModelsLastUsedTime=Object.create(null),e.prototype.dispose.call(this)},t.prototype.esureSyncedResources=function(e){for(var t=0;tm&&t.push(n)}for(var i=0;i=.5,this._onDidChange.fire(void 0)},e.prototype.getColor=function(e){return(e<1||e>=this._colors.length)&&(e=2),this._colors[e]},e.prototype.backgroundIsLight=function(){return this._backgroundIsLight},e._INSTANCE=null,e}();t.MinimapTokensColorTracker=r;var s=function(){function e(t,n){if(760!==t.length)throw new Error("Invalid x2CharData");if(190!==n.length)throw new Error("Invalid x1CharData");this.x2charData=t,this.x1charData=n,this.x2charDataLight=e.soften(t,.8),this.x1charDataLight=e.soften(n,50/60)}return e.soften=function(e,t){ +for(var n=new Uint8ClampedArray(e.length),i=0,o=e.length;it.width||i+4>t.height)console.warn("bad render request outside image data");else{var l=a?this.x2charDataLight:this.x2charData,u=e._getChIndex(o),d=4*t.width,c=s.r,h=s.g,p=s.b,f=r.r-c,g=r.g-h,m=r.b-p,v=t.data,_=4*u*2,y=i*d+4*n,C=l[_]/255;v[y+0]=c+f*C,v[y+1]=h+g*C,v[y+2]=p+m*C;C=l[_+1]/255;v[y+4]=c+f*C,v[y+5]=h+g*C,v[y+6]=p+m*C,y+=d;C=l[_+2]/255;v[y+0]=c+f*C,v[y+1]=h+g*C,v[y+2]=p+m*C;C=l[_+3]/255;v[y+4]=c+f*C,v[y+5]=h+g*C,v[y+6]=p+m*C,y+=d;C=l[_+4]/255;v[y+0]=c+f*C,v[y+1]=h+g*C,v[y+2]=p+m*C;C=l[_+5]/255;v[y+4]=c+f*C,v[y+5]=h+g*C,v[y+6]=p+m*C,y+=d;C=l[_+6]/255;v[y+0]=c+f*C,v[y+1]=h+g*C,v[y+2]=p+m*C;C=l[_+7]/255;v[y+4]=c+f*C,v[y+5]=h+g*C,v[y+6]=p+m*C}},e.prototype.x1RenderChar=function(t,n,i,o,r,s,a){if(n+1>t.width||i+2>t.height)console.warn("bad render request outside image data");else{ +var l=a?this.x1charDataLight:this.x1charData,u=e._getChIndex(o),d=4*t.width,c=s.r,h=s.g,p=s.b,f=r.r-c,g=r.g-h,m=r.b-p,v=t.data,_=2*u*1,y=i*d+4*n,C=l[_]/255;v[y+0]=c+f*C,v[y+1]=h+g*C,v[y+2]=p+m*C,y+=d;C=l[_+1]/255;v[y+0]=c+f*C,v[y+1]=h+g*C,v[y+2]=p+m*C}},e.prototype.x2BlockRenderChar=function(e,t,n,i,o,r){if(t+2>e.width||n+4>e.height)console.warn("bad render request outside image data");else{var s=4*e.width,a=o.r,l=o.g,u=o.b,d=a+.5*(i.r-a),c=l+.5*(i.g-l),h=u+.5*(i.b-u),p=e.data,f=n*s+4*t;p[f+0]=d,p[f+1]=c,p[f+2]=h,p[f+4]=d,p[f+5]=c,p[f+6]=h,p[(f+=s)+0]=d,p[f+1]=c,p[f+2]=h,p[f+4]=d,p[f+5]=c,p[f+6]=h,p[(f+=s)+0]=d,p[f+1]=c,p[f+2]=h,p[f+4]=d,p[f+5]=c,p[f+6]=h,p[(f+=s)+0]=d,p[f+1]=c,p[f+2]=h,p[f+4]=d,p[f+5]=c,p[f+6]=h}},e.prototype.x1BlockRenderChar=function(e,t,n,i,o,r){if(t+1>e.width||n+2>e.height)console.warn("bad render request outside image data");else{var s=4*e.width,a=o.r,l=o.g,u=o.b,d=a+.5*(i.r-a),c=l+.5*(i.g-l),h=u+.5*(i.b-u),p=e.data,f=n*s+4*t;p[f+0]=d,p[f+1]=c,p[f+2]=h,p[(f+=s)+0]=d,p[f+1]=c,p[f+2]=h}}, +e}();t.MinimapCharRenderer=s}),define(t[389],n([1,0,108]),function(e,t,n){"use strict";function i(e){for(var t=new Uint8ClampedArray(e.length),n=0,i=e.length;n=l&&f<=d,m=u(this.linePositionMapperFactory,n[p],this.tabSize,this.wrappingColumn,this.columnsForFullWidthChar,this.wrappingIndent,!g);s[p]=m.getViewLineCount(),this.lines[p]=m}this._validModelVersionId=this.model.getVersionId(),this.prefixSumComputer=new o.PrefixSumComputerWithCache(s)},e.prototype.getHiddenAreas=function(){var e=this;return this.hiddenAreasIds.map(function(t){return e.model.getDecorationRange(t)})},e.prototype._reduceRanges=function(e){var t=this;if(0===e.length)return[];for(var n=e.map(function(e){return t.model.validateRange(e)}).sort(i.Range.compareRangesUsingStarts),o=[],r=n[0].startLineNumber,s=n[0].endLineNumber,a=1,l=n.length;as+1?(o.push(new i.Range(r,1,s,1)),r=u.startLineNumber,s=u.endLineNumber):u.endLineNumber>s&&(s=u.endLineNumber)} +return o.push(new i.Range(r,1,s,1)),o},e.prototype.setHiddenAreas=function(e){var t=this,n=this._reduceRanges(e),o=this.hiddenAreasIds.map(function(e){return t.model.getDecorationRange(e)}).sort(i.Range.compareRangesUsingStarts);if(n.length===o.length){for(var r=!1,s=0;s=d&&g<=c?this.lines[s].isVisible()&&(this.lines[s]=this.lines[s].setVisible(!1),m=!0):(f=!0,this.lines[s].isVisible()||(this.lines[s]=this.lines[s].setVisible(!0),m=!0)),m){var v=this.lines[s].getViewLineCount();this.prefixSumComputer.changeValue(s,v)}}return f||this.setHiddenAreas([]),!0}, +e.prototype.modelPositionIsVisible=function(e,t){return!(e<1||e>this.lines.length)&&this.lines[e-1].isVisible()},e.prototype.setTabSize=function(e){return this.tabSize!==e&&(this.tabSize=e,this._constructLines(!1),!0)},e.prototype.setWrappingSettings=function(e,t,n){return(this.wrappingIndent!==e||this.wrappingColumn!==t||this.columnsForFullWidthChar!==n)&&(this.wrappingIndent=e,this.wrappingColumn=t,this.columnsForFullWidthChar=n,this._constructLines(!1),!0)},e.prototype.onModelFlushed=function(){this._constructLines(!0)},e.prototype.onModelLinesDeleted=function(e,t,n){if(e<=this._validModelVersionId)return null;var i=1===t?1:this.prefixSumComputer.getAccumulatedValue(t-2)+1,o=this.prefixSumComputer.getAccumulatedValue(n-1);return this.lines.splice(t-1,n-t+1),this.prefixSumComputer.removeValues(t-1,n-t+1),new s.ViewLinesDeletedEvent(i,o)},e.prototype.onModelLinesInserted=function(e,t,i,o){if(e<=this._validModelVersionId)return null +;for(var r=this.getHiddenAreas(),a=!1,l=new n.Position(t,1),d=0;dl?(m=(g=(h=(c=1===t?1:this.prefixSumComputer.getAccumulatedValue(t-2)+1)+l-1)+1)+(o-l)-1,d=!0):ot?t:e},e.prototype.warmUpLookupCache=function(e,t){this.prefixSumComputer.warmUpCache(e-1,t-1)},e.prototype.getActiveIndentGuide=function(e,t,n){this._ensureValidState(),e=this._toValidViewLineNumber(e), +t=this._toValidViewLineNumber(t),n=this._toValidViewLineNumber(n);var i=this.convertViewPositionToModelPosition(e,this.getViewLineMinColumn(e)),o=this.convertViewPositionToModelPosition(t,this.getViewLineMinColumn(t)),r=this.convertViewPositionToModelPosition(n,this.getViewLineMinColumn(n)),s=this.model.getActiveIndentGuide(i.lineNumber,o.lineNumber,r.lineNumber),a=this.convertModelPositionToViewPosition(s.startLineNumber,1),l=this.convertModelPositionToViewPosition(s.endLineNumber,1);return{startLineNumber:a.lineNumber,endLineNumber:l.lineNumber,indent:s.indent}},e.prototype.getViewLinesIndentGuides=function(e,t){this._ensureValidState(),e=this._toValidViewLineNumber(e),t=this._toValidViewLineNumber(t);for(var i=this.convertViewPositionToModelPosition(e,this.getViewLineMinColumn(e)),o=this.convertViewPositionToModelPosition(t,this.getViewLineMaxColumn(t)),r=[],s=[],a=[],l=i.lineNumber-1,u=o.lineNumber-1,d=null,c=l;c<=u;c++){var h=this.lines[c];if(h.isVisible()){ +var p=h.getViewLineNumberOfModelPosition(0,c===l?i.column:1),f=h.getViewLineNumberOfModelPosition(0,this.model.getLineMaxColumn(c+1)),g=0;(S=f-p+1)>1&&1===h.getViewLineMinColumn(this.model,c+1,f)&&(g=0===p?1:2),s.push(S),a.push(g),null===d&&(d=new n.Position(c+1,0))}else null!==d&&(r=r.concat(this.model.getLinesIndentGuides(d.lineNumber,c)),d=null)}null!==d&&(r=r.concat(this.model.getLinesIndentGuides(d.lineNumber,o.lineNumber)),d=null);for(var m=t-e+1,v=new Array(m),_=0,y=0,C=r.length;yt&&(p=!0,h=t-o+1);var f=c+h;if(d.getViewLinesData(this.model,l+1,c,f,o-e,n,a),o+=h,p)break}}return a},e.prototype.validateViewPosition=function(e,t,i){this._ensureValidState(),e=this._toValidViewLineNumber(e);var o=this.prefixSumComputer.getIndexOf(e-1),r=o.index,s=o.remainder,a=this.lines[r],l=a.getViewLineMinColumn(this.model,r+1,s),u=a.getViewLineMaxColumn(this.model,r+1,s);tu&&(t=u);var d=a.getModelColumnOfViewPosition(s,t);return this.model.validatePosition(new n.Position(r+1,d)).equals(i)?new n.Position(e,t):this.convertModelPositionToViewPosition(i.lineNumber,i.column)},e.prototype.convertViewPositionToModelPosition=function(e,t){this._ensureValidState(),e=this._toValidViewLineNumber(e);var i=this.prefixSumComputer.getIndexOf(e-1),o=i.index,r=i.remainder,s=this.lines[o].getModelColumnOfViewPosition(r,t);return this.model.validatePosition(new n.Position(o+1,s))}, +e.prototype.convertModelPositionToViewPosition=function(e,t){this._ensureValidState();for(var i=this.model.validatePosition(new n.Position(e,t)),o=i.lineNumber,r=i.column,s=o-1,a=!1;s>0&&!this.lines[s].isVisible();)s--,a=!0;if(0===s&&!this.lines[s].isVisible())return new n.Position(1,1);var l=1+(0===s?0:this.prefixSumComputer.getAccumulatedValue(s-1));return a?this.lines[s].getViewPositionOfModelPosition(l,this.model.getLineMaxColumn(s+1)):this.lines[o-1].getViewPositionOfModelPosition(l,r)},e.prototype._getViewLineNumberForModelPosition=function(e,t){var n=e-1;if(this.lines[n].isVisible()){var i=1+(0===n?0:this.prefixSumComputer.getAccumulatedValue(n-1));return this.lines[n].getViewLineNumberOfModelPosition(i,t)}for(;n>0&&!this.lines[n].isVisible();)n--;if(0===n&&!this.lines[n].isVisible())return 1;var o=1+(0===n?0:this.prefixSumComputer.getAccumulatedValue(n-1));return this.lines[n].getViewLineNumberOfModelPosition(o,this.model.getLineMaxColumn(n+1))}, +e.prototype.getAllOverviewRulerDecorations=function(e,t,n){for(var i=this.model.getOverviewRulerDecorations(e,t),o=new y,r=0,s=i.length;r0&&(r=this.wrappedIndent+r),r},e.prototype.getViewLineLength=function(e,t,n){if(!this._isVisible)throw new Error("Not supported");var i=this.getInputStartOffsetOfOutputLineIndex(n),o=this.getInputEndOffsetOfOutputLineIndex(e,t,n)-i;return n>0&&(o=this.wrappedIndent.length+o),o},e.prototype.getViewLineMinColumn=function(e,t,n){if(!this._isVisible)throw new Error("Not supported");return n>0?this.wrappedIndentLength+1:1},e.prototype.getViewLineMaxColumn=function(e,t,n){if(!this._isVisible)throw new Error("Not supported");return this.getViewLineContent(e,t,n).length+1},e.prototype.getViewLineData=function(e,t,n){if(!this._isVisible)throw new Error("Not supported") +;var i=this.getInputStartOffsetOfOutputLineIndex(n),o=this.getInputEndOffsetOfOutputLineIndex(e,t,n),s=e.getValueInRange({startLineNumber:t,startColumn:i+1,endLineNumber:t,endColumn:o+1});n>0&&(s=this.wrappedIndent+s);var a=n>0?this.wrappedIndentLength+1:1,l=s.length+1,u=n+10&&(d=this.wrappedIndentLength);var c=e.getLineTokens(t);return new r.ViewLineData(s,u,a,l,c.sliceAndInflate(i,o,d))},e.prototype.getViewLinesData=function(e,t,n,i,o,r,s){if(!this._isVisible)throw new Error("Not supported");for(var a=n;a0&&(n0&&(r+=this.wrappedIndentLength),new n.Position(e+o,r)},e.prototype.getViewLineNumberOfModelPosition=function(e,t){if(!this._isVisible)throw new Error("Not supported");return e+this.positionMapper.getOutputPositionOfInputOffset(t-1).outputLineIndex},e}();t.SplitLine=m;var v=function(){function e(e){this._lines=e}return e.prototype._validPosition=function(e){return this._lines.model.validatePosition(e)},e.prototype._validRange=function(e){return this._lines.model.validateRange(e)},e.prototype.convertViewPositionToModelPosition=function(e){return this._validPosition(e)},e.prototype.convertViewRangeToModelRange=function(e){return this._validRange(e)},e.prototype.validateViewPosition=function(e,t){return this._validPosition(t)},e.prototype.validateViewRange=function(e,t){return this._validRange(t)},e.prototype.convertModelPositionToViewPosition=function(e){return this._validPosition(e)}, +e.prototype.convertModelRangeToViewRange=function(e){return this._validRange(e)},e.prototype.modelPositionIsVisible=function(e){var t=this._lines.model.getLineCount();return!(e.lineNumber<1||e.lineNumber>t)},e}();t.IdentityCoordinatesConverter=v;var _=function(){function e(e){this.model=e}return e.prototype.dispose=function(){},e.prototype.createCoordinatesConverter=function(){return new v(this)},e.prototype.getHiddenAreas=function(){return[]},e.prototype.setHiddenAreas=function(e){return!1},e.prototype.setTabSize=function(e){return!1},e.prototype.setWrappingSettings=function(e,t,n){return!1},e.prototype.onModelFlushed=function(){},e.prototype.onModelLinesDeleted=function(e,t,n){return new s.ViewLinesDeletedEvent(t,n)},e.prototype.onModelLinesInserted=function(e,t,n,i){return new s.ViewLinesInsertedEvent(t,n)},e.prototype.onModelLineChanged=function(e,t,n){return[!1,new s.ViewLinesChangedEvent(t,t),null,null]},e.prototype.acceptVersionId=function(e){},e.prototype.getViewLineCount=function(){ +return this.model.getLineCount()},e.prototype.warmUpLookupCache=function(e,t){},e.prototype.getActiveIndentGuide=function(e,t,n){return{startLineNumber:e,endLineNumber:e,indent:0}},e.prototype.getViewLinesIndentGuides=function(e,t){for(var n=t-e+1,i=new Array(n),o=0;o=t)return void(n>s&&(o[o.length-1]=n));o.push(i,t,n)}else this.result[e]=[i,t,n]},e}()}),define(t[391],n([1,0,6,129,191,83,94,47]),function(e,t,n,i,r,s,a,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=function(e){function t(t,n,i){for(var o=e.call(this,0)||this,r=0;r=12352&&t<=12543||t>=13312&&t<=19903||t>=19968&&t<=40959?4:e.prototype.get.call(this,t)},t}(s.CharacterClassifier),d=function(){function e(e,t,n){this.classifier=new u(e,t,n)}return e.nextVisibleColumn=function(e,t,n,i){return e=+e,t=+t,i=+i,n?e+(t-e%t):e+i},e.prototype.createLineMapping=function(t,o,r,s,u){if(-1===r)return null;o=+o,r=+r,s=+s;var d=0,h="",p=-1;if((u=+u)!==l.WrappingIndent.None&&-1!==(p=n.firstNonWhitespaceIndex(t))){h=t.substring(0,p);for(L=0;Lr&&(h="",d=0)}for(var g=this.classifier,m=0,v=[],_=0,y=0,C=-1,b=0,S=-1,w=0,E=t.length,L=0;L0){var M=t.charCodeAt(L-1);1!==g.get(M)&&(C=L,b=d)}var D=1 +;if(n.isFullWidthCharacter(x)&&(D=s),(y=e.nextVisibleColumn(y,o,N,D))>r&&0!==L){var T=void 0,k=void 0;-1!==C&&b<=r?(T=C,k=b):-1!==S&&w<=r?(T=S,k=w):(T=L,k=d),v[_++]=T-m,m=T,y=e.nextVisibleColumn(k,o,N,D),C=-1,b=0,S=-1,w=0}if(-1!==C&&(b=e.nextVisibleColumn(b,o,N,D)),-1!==S&&(w=e.nextVisibleColumn(w,o,N,D)),2===I&&(u===l.WrappingIndent.None||L>=p)&&(C=L+1,b=d),4===I&&L=2&&e.viewportStartLineTrackedRange){var m=e.model._getTrackedRange(e.viewportStartLineTrackedRange);if(m){var v=e.coordinatesConverter.convertModelPositionToViewPosition(m.getStartPosition()),_=e.viewLayout.getVerticalOffsetForLineNumber(v.lineNumber);e.viewLayout.deltaScrollNow(0,_-e.viewportStartLineTop)}}})), +this._register(this.model.onDidChangeTokens(function(t){for(var n=[],o=0,r=t.ranges.length;ol||(s0&&l[d-1]===l[d]||(u+=this.model.getLineContent(l[d])+s);return u} +for(var c=[],d=0;d'+this._getHTMLToCopy(n,s)+""},t.prototype._getHTMLToCopy=function(e,t){for(var n=e.startLineNumber,i=e.startColumn,o=e.endLineNumber,r=e.endColumn,s=this.getTabSize(),l="",u=n;u<=o;u++){ +var d=this.model.getLineTokens(u),c=d.getLineContent(),h=u===n?i-1:0,p=u===o?r-1:c.length;l+=""===c?"
                                      ":a.tokenizeLineToHTML(c,d.inflate(),t,h,p,s)}return l},t.prototype._getColorMap=function(){for(var e=s.TokenizationRegistry.getColorMap(),t=[null],n=1,i=e.length;n=t._editor.getModel().getLineCount()&&t._futureFixes.cancel()})),this._disposables.push(n.addStandardDisposableListener(this._domNode,"click",function(e){t._editor.focus();var i=n.getDomNodePagePosition(t._domNode),o=i.top,r=i.height,s=t._editor.getConfiguration().lineHeight,a=Math.floor(s/3);t._position&&t._position.position.lineNumber0?i.isEmpty()&&e.every(function(e){return e.kind&&u.CodeActionKind.Refactor.contains(e.kind)})?t.hide():t._show():t.hide()}).catch(function(e){t.hide()})},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"title",{get:function(){return this._domNode.title},set:function(e){this._domNode.title=e},enumerable:!0,configurable:!0}), +e.prototype._show=function(){var t=this._editor.getConfiguration();if(t.contribInfo.lightbulbEnabled){var n=this._model.position.lineNumber,i=this._editor.getModel();if(i){var o=i.getOptions().tabSize,r=i.getLineContent(n),s=l.TextModel.computeIndentLevel(r,o),a=n;t.fontInfo.spaceWidth*s>22||(n>1?a-=1:a+=1),this._position={position:{lineNumber:a,column:1},preference:e._posPref},this._editor.layoutContentWidget(this)}}},e.prototype.hide=function(){this._position=null,this._model=null,this._futureFixes.cancel(),this._editor.layoutContentWidget(this)},e._posPref=[a.ContentWidgetPositionPreference.EXACT],e}();t.LightBulbWidget=d}),define(t[394],n([1,0,24,29]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e){this.editor=e,this.autoHideFoldingControls=!0}return e.prototype.getDecorationOption=function(t){return t?e.COLLAPSED_VISUAL_DECORATION:this.autoHideFoldingControls?e.EXPANDED_AUTO_HIDE_VISUAL_DECORATION:e.EXPANDED_VISUAL_DECORATION}, +e.prototype.deltaDecorations=function(e,t){return this.editor.deltaDecorations(e,t)},e.prototype.changeDecorations=function(e){return this.editor.changeDecorations(e)},e.COLLAPSED_VISUAL_DECORATION=i.ModelDecorationOptions.register({stickiness:n.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,afterContentClassName:"inline-folded",linesDecorationsClassName:"folding collapsed"}),e.EXPANDED_AUTO_HIDE_VISUAL_DECORATION=i.ModelDecorationOptions.register({stickiness:n.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,linesDecorationsClassName:"folding"}),e.EXPANDED_VISUAL_DECORATION=i.ModelDecorationOptions.register({stickiness:n.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,linesDecorationsClassName:"folding alwaysShowFoldIcons"}),e}();t.FoldingDecorationProvider=o}),define(t[395],n([1,0,109,29,13,41]),function(e,t,n,i,o,r){"use strict";function s(e,t,n,o){void 0===o&&(o=a);var r=e.getOptions().tabSize,s=new u(o),l=void 0;n&&(l=new RegExp("("+n.start.source+")|(?:"+n.end.source+")"));var d=[];d.push({ +indent:-1,line:e.getLineCount()+1,marker:!1});for(var c=e.getLineCount();c>0;c--){var h=e.getLineContent(c),p=i.TextModel.computeIndentLevel(h,r),f=d[d.length-1];if(-1!==p){var g=void 0;if(l&&(g=h.match(l))){if(!g[1]){d.push({indent:-2,line:c,marker:!0});continue}for(var m=d.length-1;m>0&&!d[m].marker;)m--;if(m>0){d.length=m+1,f=d[m],s.insertFirst(c,f.line,p),f.marker=!1,f.indent=p,f.line=c;continue}}if(f.indent>p){do{d.pop(),f=d[d.length-1]}while(f.indent>p);var v=f.line-1;v-c>=1&&s.insertFirst(c,v,p)}f.indent===p?f.line=c:d.push({indent:p,line:c,marker:!1})}else t&&!f.marker&&(f.line=c)}return s.toIndentRanges(e)}Object.defineProperty(t,"__esModule",{value:!0});var a=5e3;t.ID_INDENT_PROVIDER="indent";var l=function(){function e(e){this.editorModel=e,this.id=t.ID_INDENT_PROVIDER}return e.prototype.dispose=function(){},e.prototype.compute=function(e){var t=r.LanguageConfigurationRegistry.getFoldingRules(this.editorModel.getLanguageIdentifier().id),n=t&&t.offSide,i=t&&t.markers +;return o.TPromise.as(s(this.editorModel,n,i))},e}();t.IndentRangeProvider=l;var u=function(){function e(e){this._startIndexes=[],this._endIndexes=[],this._indentOccurrences=[],this._length=0,this._foldingRangesLimit=e}return e.prototype.insertFirst=function(e,t,i){if(!(e>n.MAX_LINE_NUMBER||t>n.MAX_LINE_NUMBER)){var o=this._length;this._startIndexes[o]=e,this._endIndexes[o]=t,this._length++,i<1e3&&(this._indentOccurrences[i]=(this._indentOccurrences[i]||0)+1)}},e.prototype.toIndentRanges=function(e){if(this._length<=this._foldingRangesLimit){for(var t=new Uint32Array(this._length),o=new Uint32Array(this._length),r=this._length-1,s=0;r>=0;r--,s++)t[s]=this._startIndexes[r],o[s]=this._endIndexes[r];return new n.FoldingRegions(t,o)}for(var a=0,l=this._indentOccurrences.length,r=0;rthis._foldingRangesLimit){l=r;break}a+=u}} +for(var d=e.getOptions().tabSize,t=new Uint32Array(this._foldingRangesLimit),o=new Uint32Array(this._foldingRangesLimit),r=this._length-1,s=0;r>=0;r--){var c=this._startIndexes[r],h=e.getLineContent(c),p=i.TextModel.computeIndentLevel(h,d);(p=l.startLineNumber+1&&t<=l.endLineNumber+1?e.getLineContent(t-1):e.getLineContent(t)};var w=r.LanguageConfigurationRegistry.getGoodIndentForLine(h,e.getLanguageIdAtPosition(g,1),l.startLineNumber+1,c);if(null!==w){ +y=n.getLeadingWhitespace(e.getLineContent(l.startLineNumber));if((C=a.getSpaceCnt(w,u))!==(N=a.getSpaceCnt(y,u))){I=C-N;this.getIndentEditsOfMovingBlock(e,t,l,u,d,I)}}}}else t.addEditOperation(new i.Range(l.startLineNumber,1,l.startLineNumber,1),v+"\n")}else if(g=l.startLineNumber-1,m=e.getLineContent(g),t.addEditOperation(new i.Range(g,1,g+1,1),null),t.addEditOperation(new i.Range(l.endLineNumber,e.getLineMaxColumn(l.endLineNumber),l.endLineNumber,e.getLineMaxColumn(l.endLineNumber)),"\n"+m),this.shouldAutoIndent(e,l)){h.getLineContent=function(t){return t===g?e.getLineContent(l.startLineNumber):e.getLineContent(t)};var E=this.matchEnterRule(e,c,u,l.startLineNumber,l.startLineNumber-2);if(null!==E)0!==E&&this.getIndentEditsOfMovingBlock(e,t,l,u,d,E);else{var L=r.LanguageConfigurationRegistry.getGoodIndentForLine(h,e.getLanguageIdAtPosition(l.startLineNumber,1),g,c);if(null!==L){var x=n.getLeadingWhitespace(e.getLineContent(l.startLineNumber)),C=a.getSpaceCnt(L,u),N=a.getSpaceCnt(x,u);if(C!==N){var I=C-N +;this.getIndentEditsOfMovingBlock(e,t,l,u,d,I)}}}}}this._selectionId=t.trackSelection(l)}},e.prototype.buildIndentConverter=function(e){return{shiftIndent:function(t){for(var n=s.ShiftCommand.shiftIndentCount(t,t.length+1,e),i="",o=0;o=1;){var h=void 0;h=c===u&&void 0!==d?d:e.getLineContent(c);if(n.lastNonWhitespaceIndex(h)>=0)break;c--}if(c<1||s>e.getLineCount())return null;var p=e.getLineMaxColumn(c),f=r.LanguageConfigurationRegistry.getEnterAction(e,new i.Range(c,p,c,p));if(f){var g=f.indentation,m=f.enterAction;m.indentAction===l.IndentAction.None?g=f.indentation+m.appendText:m.indentAction===l.IndentAction.Indent?g=f.indentation+m.appendText:m.indentAction===l.IndentAction.IndentOutdent?g=f.indentation:m.indentAction===l.IndentAction.Outdent&&(g=t.unshiftIndent(f.indentation)+m.appendText) +;var v=e.getLineContent(s);if(this.trimLeft(v).indexOf(this.trimLeft(g))>=0){var _=n.getLeadingWhitespace(e.getLineContent(s)),y=n.getLeadingWhitespace(g);2&r.LanguageConfigurationRegistry.getIndentMetadata(e,s)&&(y=t.unshiftIndent(y));return a.getSpaceCnt(y,o)-a.getSpaceCnt(_,o)}}return null},e.prototype.trimLeft=function(e){return e.replace(/^\s+/,"")},e.prototype.shouldAutoIndent=function(e,t){if(!this._autoIndent)return!1;if(!e.isCheapToTokenize(t.startLineNumber))return!1;var n=e.getLanguageIdAtPosition(t.startLineNumber,1);return n===e.getLanguageIdAtPosition(t.endLineNumber,1)&&null!==r.LanguageConfigurationRegistry.getIndentRulesSupport(n)},e.prototype.getIndentEditsOfMovingBlock=function(e,t,o,r,s,l){for(var u=o.startLineNumber;u<=o.endLineNumber;u++){var d=e.getLineContent(u),c=n.getLeadingWhitespace(d),h=a.getSpaceCnt(c,r)+l,p=a.generateIndent(h,r,s);p!==c&&(t.addEditOperation(new i.Range(u,1,u,c.length+1),p), +u===o.endLineNumber&&o.endColumn<=c.length+1&&""===p&&(this._moveEndLineSelectionShrink=!0))}},e.prototype.computeCursorState=function(e,t){var n=t.getTrackedSelection(this._selectionId);return this._moveEndPositionDown&&(n=n.setEndPosition(n.endLineNumber+1,1)),this._moveEndLineSelectionShrink&&n.startLineNumber0&&0===e.minimapLeft?e.minimapWidth:0},e.prototype._onViewZoneTop=function(e){this.domNode.style.top=e+"px"},e.prototype._onViewZoneHeight=function(e){this.domNode.style.height=e+"px";var t=e-this._decoratingElementsHeight();this.container.style.height=t+"px";var n=this.editor.getLayoutInfo();this._doLayout(t,this._getWidth(n)),this._resizeSash.layout()},Object.defineProperty(e.prototype,"position",{get:function(){var e=this._positionMarkerId[0];if(e){var t=this.editor.getModel().getDecorationRange(e);if(t)return t.getStartPosition()}},enumerable:!0,configurable:!0}),e.prototype.show=function(e,t){var n=s.Range.isIRange(e)?e:new s.Range(e.lineNumber,e.column,e.lineNumber,e.column);this._isShowing=!0,this._showImpl(n,t),this._isShowing=!1,this._positionMarkerId=this.editor.deltaDecorations(this._positionMarkerId,[{range:n,options:l.ModelDecorationOptions.EMPTY}])},e.prototype.hide=function(){var e=this +;this._viewZone&&(this.editor.changeViewZones(function(t){t.removeZone(e._viewZone.id)}),this._viewZone=null),this._overlayWidget&&(this.editor.removeOverlayWidget(this._overlayWidget),this._overlayWidget=null),this._arrow&&this._arrow.hide()},e.prototype._decoratingElementsHeight=function(){var e=this.editor.getConfiguration().lineHeight,t=0;if(this.options.showArrow){t+=2*Math.round(e/3)}if(this.options.showFrame){t+=2*Math.round(e/9)}return t},e.prototype._showImpl=function(e,t){var n=this,i={lineNumber:e.startLineNumber,column:e.startColumn},o=this.editor.getLayoutInfo(),r=this._getWidth(o);this.domNode.style.width=r+"px",this.domNode.style.left=this._getLeft(o)+"px";var s=document.createElement("div");s.style.overflow="hidden";var a=this.editor.getConfiguration().lineHeight,l=this.editor.getLayoutInfo().height/a*.8;t>=l&&(t=l);var u=0,d=0;if(this.options.showArrow&&(u=Math.round(a/3),this._arrow.height=u,this._arrow.show(i)),this.options.showFrame&&(d=Math.round(a/9)), +this.editor.changeViewZones(function(e){n._viewZone&&e.removeZone(n._viewZone.id),n._overlayWidget&&(n.editor.removeOverlayWidget(n._overlayWidget),n._overlayWidget=null),n.domNode.style.top="-1000px",n._viewZone=new p(s,i.lineNumber,i.column,t,function(e){return n._onViewZoneTop(e)},function(e){return n._onViewZoneHeight(e)}),n._viewZone.id=e.addZone(n._viewZone),n._overlayWidget=new f("vs.editor.contrib.zoneWidget"+n._viewZone.id,n.domNode),n.editor.addOverlayWidget(n._overlayWidget)}),this.options.showFrame){var c=this.options.frameWidth?this.options.frameWidth:d;this.container.style.borderTopWidth=c+"px",this.container.style.borderBottomWidth=c+"px"}var h=t*a-this._decoratingElementsHeight();this.container.style.top=u+"px",this.container.style.height=h+"px",this.container.style.overflow="hidden",this._doLayout(h,r),this.options.keepEditorSelection||this.editor.setSelection(e);var g=Math.min(this.editor.getModel().getLineCount(),Math.max(1,e.endLineNumber+1));this.revealLine(g)}, +e.prototype.revealLine=function(e){this.editor.revealLine(e,0)},e.prototype.setCssClass=function(e,t){t&&this.container.classList.remove(t),o.addClass(this.container,e)},e.prototype._onWidth=function(e){},e.prototype._doLayout=function(e,t){},e.prototype._relayout=function(e){var t=this;this._viewZone.heightInLines!==e&&this.editor.changeViewZones(function(n){t._viewZone.heightInLines=e,n.layoutZone(t._viewZone.id)})},e.prototype._initSash=function(){var e=this;this._resizeSash=new r.Sash(this.domNode,this,{orientation:r.Orientation.HORIZONTAL}),this.options.isResizeable||(this._resizeSash.hide(),this._resizeSash.state=r.SashState.Disabled);var t;this._disposables.push(this._resizeSash.onDidStart(function(n){e._viewZone&&(t={startY:n.startY,heightInLines:e._viewZone.heightInLines})})),this._disposables.push(this._resizeSash.onDidEnd(function(){t=void 0})),this._disposables.push(this._resizeSash.onDidChange(function(n){if(t){ +var i=(n.currentY-t.startY)/e.editor.getConfiguration().lineHeight,o=i<0?Math.ceil(i):Math.floor(i),r=t.heightInLines+o;r>5&&r<35&&e._relayout(r)}}))},e.prototype.getHorizontalSashLeft=function(){return 0},e.prototype.getHorizontalSashTop=function(){return parseInt(this.domNode.style.height)-this._decoratingElementsHeight()/2},e.prototype.getHorizontalSashWidth=function(){var e=this.editor.getLayoutInfo();return e.width-e.minimapWidth},e}();t.ZoneWidget=m}),define(t[399],n([1,0,13,17,96,99,6,63]),function(e,t,n,i,o,r,s,a){"use strict";function l(e,t,n){return function(e,t,n){for(var i=[],s=n.getInitialState(),l=0,u=e.length;l"),s=c.endState}return i.join("")}(e,t,n)} +Object.defineProperty(t,"__esModule",{value:!0});var u=function(){function e(){}return e.colorizeElement=function(e,t,n,i){var o=(i=i||{}).theme||"vs",r=i.mimeType||n.getAttribute("lang")||n.getAttribute("data-lang");if(r){e.setTheme(o);var s=n.firstChild.nodeValue;n.className+=" "+o;return this.colorize(t,s,r,i).then(function(e){n.innerHTML=e},function(e){return console.error(e)})}console.error("Mode not detected")},e._tokenizationSupportChangedPromise=function(e){var t=null,o=function(){t&&(t.dispose(),t=null)};return new n.TPromise(function(n,r){t=i.TokenizationRegistry.onDidChange(function(t){t.changedLanguages.indexOf(e)>=0&&(o(),n(void 0))})},o)},e.colorize=function(e,t,u,d){s.startsWithUTF8BOM(t)&&(t=t.substr(1));var c=t.split(/\r\n|\r|\n/),h=e.getModeId(u);void 0===(d=d||{}).tabSize&&(d.tabSize=4),e.getOrCreateMode(h);var p=i.TokenizationRegistry.get(h);return p?n.TPromise.as(l(c,d.tabSize,p)):n.TPromise.any([this._tokenizationSupportChangedPromise(h),n.TPromise.timeout(500)]).then(function(e){ +var t=i.TokenizationRegistry.get(h);return t?l(c,d.tabSize,t):function(e,t){var n=[],i=new Uint32Array(2);i[0]=0,i[1]=16793600;for(var s=0,l=e.length;s")}return n.join("")}(c,d.tabSize)})},e.colorizeLine=function(e,t,n,i,r){void 0===r&&(r=4);var s=a.ViewLineRenderingData.isBasicASCII(e,t),l=a.ViewLineRenderingData.containsRTL(e,s,n);return o.renderViewLine2(new o.RenderLineInput(!1,e,!1,s,l,0,i,[],r,0,-1,"none",!1,!1)).html},e.colorizeModelLine=function(e,t,n){void 0===n&&(n=4);var i=e.getLineContent(t);e.forceTokenization(t);var o=e.getLineTokens(t).inflate();return this.colorizeLine(i,e.mightContainNonBasicASCII(),e.mightContainRTL(),o,n)},e}();t.Colorizer=u}),define(t[400],n([1,0,17,190,95,60]),function(e,t,n,i,o,r){"use strict" +;Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e){this._maxCacheDepth=e,this._entries=Object.create(null)}return e.create=function(e,t){return this._INSTANCE.create(e,t)},e.prototype.create=function(e,t){if(null!==e&&e.depth>=this._maxCacheDepth)return new a(e,t);var n=a.getStackElementId(e);n.length>0&&(n+="|"),n+=t;var i=this._entries[n];return i||(i=new a(e,t),this._entries[n]=i,i)},e._INSTANCE=new e(5),e}(),a=function(){function e(e,t){this.parent=e,this.state=t,this.depth=(this.parent?this.parent.depth:0)+1}return e.getStackElementId=function(e){for(var t="";null!==e;)t.length>0&&(t+="|"),t+=e.state,e=e.parent;return t},e._equals=function(e,t){for(;null!==e&&null!==t;){if(e===t)return!0;if(e.state!==t.state)return!1;e=e.parent,t=t.parent}return null===e&&null===t},e.prototype.equals=function(t){return e._equals(this,t)},e.prototype.push=function(e){return s.create(this,e)},e.prototype.pop=function(){return this.parent},e.prototype.popall=function(){ +for(var e=this;e.parent;)e=e.parent;return e},e.prototype.switchTo=function(e){return s.create(this.parent,e)},e}(),l=function(){function e(e,t){this.modeId=e,this.state=t}return e.prototype.equals=function(e){return this.modeId===e.modeId&&this.state.equals(e.state)},e.prototype.clone=function(){return this.state.clone()===this.state?this:new e(this.modeId,this.state)},e}(),u=function(){function e(e){this._maxCacheDepth=e,this._entries=Object.create(null)}return e.create=function(e,t){return this._INSTANCE.create(e,t)},e.prototype.create=function(e,t){if(null!==t)return new d(e,t);if(null!==e&&e.depth>=this._maxCacheDepth)return new d(e,t);var n=a.getStackElementId(e),i=this._entries[n];return i||(i=new d(e,null),this._entries[n]=i,i)},e._INSTANCE=new e(5),e}(),d=function(){function e(e,t){this.stack=e,this.embeddedModeData=t}return e.prototype.clone=function(){return(this.embeddedModeData?this.embeddedModeData.clone():null)===this.embeddedModeData?this:u.create(this.stack,this.embeddedModeData)}, +e.prototype.equals=function(t){return t instanceof e&&(!!this.stack.equals(t.stack)&&(null===this.embeddedModeData&&null===t.embeddedModeData||null!==this.embeddedModeData&&null!==t.embeddedModeData&&this.embeddedModeData.equals(t.embeddedModeData)))},e}(),c=Object.hasOwnProperty,h=function(){function e(){this._tokens=[],this._language=null,this._lastTokenType=null,this._lastTokenLanguage=null}return e.prototype.enterMode=function(e,t){this._language=t},e.prototype.emit=function(e,t){this._lastTokenType===t&&this._lastTokenLanguage===this._language||(this._lastTokenType=t,this._lastTokenLanguage=this._language,this._tokens.push(new o.Token(e,t,this._language)))},e.prototype.nestedModeTokenize=function(e,t,i){var o=t.modeId,r=t.state,s=n.TokenizationRegistry.get(o);if(!s)return this.enterMode(i,o),this.emit(i,""),r;var a=s.tokenize(e,r,i);return this._tokens=this._tokens.concat(a.tokens),this._lastTokenType=null,this._lastTokenLanguage=null,this._language=null,a.endState},e.prototype.finalize=function(e){ +return new o.TokenizationResult(this._tokens,e)},e}(),p=function(){function e(e,t){this._modeService=e,this._theme=t,this._prependTokens=null,this._tokens=[],this._currentLanguageId=0,this._lastTokenMetadata=0}return e.prototype.enterMode=function(e,t){this._currentLanguageId=this._modeService.getLanguageIdentifier(t).id},e.prototype.emit=function(e,t){var n=this._theme.match(this._currentLanguageId,t);this._lastTokenMetadata!==n&&(this._lastTokenMetadata=n,this._tokens.push(e),this._tokens.push(n))},e._merge=function(e,t,n){var i=null!==e?e.length:0,o=t.length,r=null!==n?n.length:0;if(0===i&&0===o&&0===r)return new Uint32Array(0);if(0===i&&0===o)return n;if(0===o&&0===r)return e;var s=new Uint32Array(i+o+r);null!==e&&s.set(e);for(var a=0;a0&&i.nestedModeTokenize(s,t.embeddedModeData,n);var a=e.substring(o);return this._myTokenize(a,t,n+o,i)},e.prototype._myTokenize=function(e,t,n,o){o.enterMode(n,this._modeId);for(var r=e.length,s=t.embeddedModeData,a=t.stack,l=0,d=null,h=null,p=null,f=null;l=r)break;var E=this._lexer.tokenizer[_];E||(E=i.findRules(this._lexer,_))||i.throwError(this._lexer,"tokenizer state is not defined: "+_);F=e.substr(l);for(var L in E)if(c.call(E,L)){var x=E[L];if((0===l||!x.matchOnlyAtLineStart)&&(y=F.match(x.regex))){C=y[0],b=x.action;break}}}for(y||(y=[""],C=""),b||(l=this._lexer.maxStack?i.throwError(this._lexer,"maximum tokenizer stack size reached: ["+a.state+","+a.parent.state+",...]"):a=a.push(_);else if("@pop"===b.next)a.depth<=1?i.throwError(this._lexer,"trying to pop an empty stack in rule: "+S.name):a=a.pop();else if("@popall"===b.next)a=a.popall();else{var I=i.substituteMatches(this._lexer,b.next,C,y,_);"@"===I[0]&&(I=I.substr(1)),i.findRules(this._lexer,I)?a=a.push(I):i.throwError(this._lexer,"trying to set a next state '"+I+"' that is undefined in rule: "+S.name)}b.log&&"string"==typeof b.log&&i.log(this._lexer,this._lexer.languageId+": "+i.substituteMatches(this._lexer,b.log,C,y,_))}if(null===N&&i.throwError(this._lexer,"lexer rule has no well-defined action in rule: "+S.name),Array.isArray(N)){d&&d.length>0&&i.throwError(this._lexer,"groups cannot be nested: "+S.name), +y.length!==N.length+1&&i.throwError(this._lexer,"matched number of groups does not match the number of actions in rule: "+S.name);for(var M=0,D=1;D=0){for(var i=[],r=0,a=this._placeholderGroups[this._placeholderGroupsIdx];r0&&this._editor.executeEdits("snippet.placeholderTransform",i)}return!0===t&&this._placeholderGroupsIdx0&&(this._placeholderGroupsIdx-=1), +this._editor.getModel().changeDecorations(function(t){for(var i=new Set,o=[],r=0,a=n._placeholderGroups[n._placeholderGroupsIdx];r0},enumerable:!0,configurable:!0}),e.prototype.computePossibleSelections=function(){for(var e=new Map,t=0,n=this._placeholderGroups;t ")+'"'},e.prototype.insert=function(){var t=this,n=this._editor.getModel(),i=e.createEditsAndSnippets(this._editor,this._template,this._overwriteBefore,this._overwriteAfter,!1),o=i.edits,r=i.snippets;this._snippets=r;var a=n.pushEditOperations(this._editor.getSelections(),o,function(e){ +return t._snippets[0].hasPlaceholder?t._move(!0):e.map(function(e){return s.Selection.fromPositions(e.range.getEndPosition())})});this._editor.setSelections(a),this._editor.revealRange(a[0])},e.prototype.merge=function(t,n,i){var o=this;void 0===n&&(n=0),void 0===i&&(i=0),this._templateMerges.push([this._snippets[0]._nestingLevel,this._snippets[0]._placeholderGroupsIdx,t]);var r=e.createEditsAndSnippets(this._editor,t,n,i,!0),a=r.edits,l=r.snippets;this._editor.setSelections(this._editor.getModel().pushEditOperations(this._editor.getSelections(),a,function(e){for(var t=0,n=o._snippets;t0},e}();t.SnippetSession=g}),define(t[34],n([1,0,2,33,15,166]),function(e,t,n,i,o,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ICommandService=o.createDecorator("commandService"),t.CommandsRegistry=new(function(){function e(){this._commands=new Map}return e.prototype.registerCommand=function(e,t){var o=this;if(!e)throw new Error("invalid command");if("string"==typeof e){if(!t)throw new Error("invalid command") +;return this.registerCommand({id:e,handler:t})}if(e.description){for(var s=[],a=0,l=e.description.args;a=0){t=e.split("!=");return new d(t[0].trim(),this._deserializeValue(t[1]))}if(e.indexOf("==")>=0){t=e.split("==") +;return new u(t[0].trim(),this._deserializeValue(t[1]))}if(e.indexOf("=~")>=0){var t=e.split("=~");return new h(t[0].trim(),this._deserializeRegexValue(t[1]))}return/^\!\s*/.test(e)?new c(e.substr(1).trim()):new l(e)},e._deserializeValue=function(e){if("true"===(e=e.trim()))return!0;if("false"===e)return!1;var t=/^'([^']*)'$/.exec(e);return t?t[1].trim():e},e._deserializeRegexValue=function(e){if(i.isFalsyOrWhitespace(e))return console.warn("missing regexp-value for =~-expression"),null;var t=e.indexOf("/"),n=e.lastIndexOf("/");if(t===n||t<0)return console.warn("bad regexp-value '"+e+"', missing /-enclosure"),null;var o=e.slice(t+1,n),r="i"===e[n+1]?"i":"";try{return new RegExp(o,r)}catch(t){return console.warn("bad regexp-value '"+e+"', parse error: "+t),null}},e}();t.ContextKeyExpr=a;var l=function(){function e(e){this.key=e}return e.prototype.getType=function(){return s.Defined},e.prototype.cmp=function(e){return this.keye.key?1:0},e.prototype.equals=function(t){ +return t instanceof e&&this.key===t.key},e.prototype.evaluate=function(e){return!!e.getValue(this.key)},e.prototype.normalize=function(){return this},e.prototype.keys=function(){return[this.key]},e}();t.ContextKeyDefinedExpr=l;var u=function(){function e(e,t){this.key=e,this.value=t}return e.prototype.getType=function(){return s.Equals},e.prototype.cmp=function(e){return this.keye.key?1:this.valuee.value?1:0},e.prototype.equals=function(t){return t instanceof e&&(this.key===t.key&&this.value===t.value)},e.prototype.evaluate=function(e){return e.getValue(this.key)==this.value},e.prototype.normalize=function(){return"boolean"==typeof this.value?this.value?new l(this.key):new c(this.key):this},e.prototype.keys=function(){return[this.key]},e}();t.ContextKeyEqualsExpr=u;var d=function(){function e(e,t){this.key=e,this.value=t}return e.prototype.getType=function(){return s.NotEquals},e.prototype.cmp=function(e){ +return this.keye.key?1:this.valuee.value?1:0},e.prototype.equals=function(t){return t instanceof e&&(this.key===t.key&&this.value===t.value)},e.prototype.evaluate=function(e){return e.getValue(this.key)!=this.value},e.prototype.normalize=function(){return"boolean"==typeof this.value?this.value?new c(this.key):new l(this.key):this},e.prototype.keys=function(){return[this.key]},e}();t.ContextKeyNotEqualsExpr=d;var c=function(){function e(e){this.key=e}return e.prototype.getType=function(){return s.Not},e.prototype.cmp=function(e){return this.keye.key?1:0},e.prototype.equals=function(t){return t instanceof e&&this.key===t.key},e.prototype.evaluate=function(e){return!e.getValue(this.key)},e.prototype.normalize=function(){return this},e.prototype.keys=function(){return[this.key]},e}();t.ContextKeyNotExpr=c;var h=function(){function e(e,t){this.key=e,this.regexp=t}return e.prototype.getType=function(){return s.Regex},e.prototype.cmp=function(e){ +if(this.keye.key)return 1;var t=this.regexp?this.regexp.source:void 0;return te.regexp.source?1:0},e.prototype.equals=function(t){if(t instanceof e){var n=this.regexp?this.regexp.source:void 0;return this.key===t.key&&n===t.regexp.source}return!1},e.prototype.evaluate=function(e){return!!this.regexp&&this.regexp.test(e.getValue(this.key))},e.prototype.normalize=function(){return this},e.prototype.keys=function(){return[this.key]},e}();t.ContextKeyRegexExpr=h;var p=function(){function e(t){this.expr=e._normalizeArr(t)}return e.prototype.getType=function(){return s.And},e.prototype.equals=function(t){if(t instanceof e){if(this.expr.length!==t.expr.length)return!1;for(var n=0,i=this.expr.length;n=0&&i.splice(e,1)}}},e.prototype.getMenuItems=function(e){var t=e.id,n=this._menuItems[t]||[];return t===d.CommandPalette.id&&this._appendImplicitItems(n),n},e.prototype._appendImplicitItems=function(e){ +for(var t=new Set,n=0,i=e.filter(function(e){return l(e)});n0&&t.push([s,a])}return t},e._fillInKbExprKeys=function(e,t){if(e)for(var n=0,i=e.keys();ns)return 1 +;var a="string"==typeof e.command.title?e.command.title:e.command.title.value,l="string"==typeof t.command.title?t.command.title:t.command.title.value;return a.localeCompare(l)},e=a([u(2,s.ICommandService),u(3,o.IContextKeyService)],e)}();t.Menu=l}),define(t[77],n([1,0,15]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.IContextViewService=n.createDecorator("contextViewService"),t.IContextMenuService=n.createDecorator("contextMenuService")}),define(t[411],n([1,0,15]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.IDialogService=n.createDecorator("dialogService")}),define(t[412],n([1,0,15]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.IEnvironmentService=n.createDecorator("environmentService")}),define(t[106],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(){for(var e=[],t=0;t0?o[0].index:n.length +;if(n.length!==c){console.warn("[createInstance] First service dependency of "+e.ctor.name+" at position "+(c+1)+" conflicts with "+n.length+" static arguments");var h=c-n.length;n=h>0?n.concat(new Array(h)):n.slice(0,c)}var p=[e.ctor];return p.push.apply(p,n),p.push.apply(p,r),i.create.apply(null,p)},e.prototype._getOrCreateServiceInstance=function(e){var t=this._services.get(e);return t instanceof s.SyncDescriptor?this._createAndCacheServiceInstance(e,t):t},e.prototype._createAndCacheServiceInstance=function(e,t){function n(){var e=new Error("[createInstance] cyclic dependency between services");throw e.message=i.toString(),e}o.ok(this._services.get(e)instanceof s.SyncDescriptor);for(var i=new r.Graph(function(e){return e.id.toString()}),l=0,u=[{id:e,desc:t}];u.length;){var d=u.pop();i.lookupOrInsertNode(d),l++>100&&n();for(var c=0,h=a._util.getServiceDependencies(d.desc.ctor);c5e3&&i._leaveChordMode():i._leaveChordMode()},500)},t.prototype._leaveChordMode=function(){this._currentChordStatusMessage&&(this._currentChordStatusMessage.dispose(),this._currentChordStatusMessage=null),this._currentChordChecker.cancel(),this._currentChord=null},t.prototype._dispatch=function(e,t){var i=this,o=!1,r=this.resolveKeyboardEvent(e) +;if(r.isChord())return console.warn("Unexpected keyboard event mapped to a chord"),null;var s=r.getDispatchParts()[0];if(null===s)return o;var a=this._contextKeyService.getContext(t),l=this._currentChord?this._currentChord.keypress:null,u=r.getLabel(),d=this._getResolver().resolve(a,l,s);return d&&d.enterChord?(o=!0,this._enterChordMode(s,u),o):(this._statusService&&this._currentChord&&(d&&d.commandId||(this._statusService.setStatusMessage(n.localize(1,null,this._currentChord.label,u),1e4),o=!0)),this._leaveChordMode(),d&&d.commandId&&(d.bubble||(o=!0),void 0===d.commandArgs?this._commandService.executeCommand(d.commandId).done(void 0,function(e){return i._notificationService.warn(e)}):this._commandService.executeCommand(d.commandId,d.commandArgs).done(void 0,function(e){return i._notificationService.warn(e)}),this._telemetryService.publicLog("workbenchActionExecuted",{id:d.commandId,from:"keybinding"})),o)},t}(i.Disposable);t.AbstractKeybindingService=a}),define(t[49],n([1,0,15]),function(e,t,n){"use strict" +;Object.defineProperty(t,"__esModule",{value:!0});!function(e){e[e.Default=1]="Default",e[e.User=2]="User"}(t.KeybindingSource||(t.KeybindingSource={})),t.IKeybindingService=n.createDecorator("keybindingService")}),define(t[154],n([1,0,19]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(t,n){this._defaultKeybindings=t,this._defaultBoundCommands=new Map;for(var i=0,o=t.length;i=0;d--)this._isTargetedForRemoval(e[d],a,l,s,u)&&e.splice(d,1);else n.push(r)}return e.concat(n)},e.prototype._addKeyPress=function(t,n){var i=this._map.get(t);if(void 0===i)return this._map.set(t,[n]),void this._addToLookupMap(n);for(var o=i.length-1;o>=0;o--){var r=i[o];if(r.command!==n.command){var s=null!==r.keypressChordPart,a=null!==n.keypressChordPart;s&&a&&r.keypressChordPart!==n.keypressChordPart||e.whenIsEntirelyIncluded(r.when,n.when)&&this._removeFromLookupMap(r)}}i.push(n),this._addToLookupMap(n)},e.prototype._addToLookupMap=function(e){if(e.command){var t=this._lookupMap.get(e.command);void 0===t?(t=[e],this._lookupMap.set(e.command,t)):t.push(e)}},e.prototype._removeFromLookupMap=function(e){var t=this._lookupMap.get(e.command);if(void 0!==t)for(var n=0,i=t.length;n=0;i--){var o=n[i];if(e.contextMatchesRules(t,o.when))return o}return null}, +e.contextMatchesRules=function(e,t){return!t||t.evaluate(e)},e}();t.KeybindingResolver=i}),define(t[418],n([1,0]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){return function(e,t,n,i,o){if(this.resolvedKeybinding=e,e){var r=e.getDispatchParts(),s=r[0],a=r[1];this.keypressFirstPart=s,this.keypressChordPart=a}else this.keypressFirstPart=null,this.keypressChordPart=null;this.bubble=!!t&&94===t.charCodeAt(0),this.command=this.bubble?t.substr(1):t,this.commandArgs=n,this.when=i,this.isDefault=o}}();t.ResolvedKeybindingItem=n}),define(t[419],n([1,0,39,162]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(e){function t(t,n){var i=e.call(this)||this;if(i._os=n,null===t)throw new Error("Invalid USLayoutResolvedKeybinding");return 2===t.type?(i._firstPart=t.firstPart,i._chordPart=t.chordPart):(i._firstPart=t,i._chordPart=null),i}return o(t,e),t.prototype._keyCodeToUILabel=function(e){if(2===this._os)switch(e){case 15: +return"←";case 16:return"↑";case 17:return"→";case 18:return"↓"}return n.KeyCodeUtils.toString(e)},t.prototype._getUILabelForKeybinding=function(e){return e?e.isDuplicateModifierCase()?"":this._keyCodeToUILabel(e.keyCode):null},t.prototype.getLabel=function(){var e=this._getUILabelForKeybinding(this._firstPart),t=this._getUILabelForKeybinding(this._chordPart);return i.UILabelProvider.toLabel(this._firstPart,e,this._chordPart,t,this._os)},t.prototype._getAriaLabelForKeybinding=function(e){return e?e.isDuplicateModifierCase()?"":n.KeyCodeUtils.toString(e.keyCode):null},t.prototype.getAriaLabel=function(){var e=this._getAriaLabelForKeybinding(this._firstPart),t=this._getAriaLabelForKeybinding(this._chordPart);return i.AriaLabelProvider.toLabel(this._firstPart,e,this._chordPart,t,this._os)},t.prototype.isChord=function(){return!!this._chordPart},t.prototype.getParts=function(){return[this._toResolvedKeybindingPart(this._firstPart),this._toResolvedKeybindingPart(this._chordPart)]}, +t.prototype._toResolvedKeybindingPart=function(e){return e?new n.ResolvedKeybindingPart(e.ctrlKey,e.shiftKey,e.altKey,e.metaKey,this._getUILabelForKeybinding(e),this._getAriaLabelForKeybinding(e)):null},t.prototype.getDispatchParts=function(){return[this._firstPart?t.getDispatchStr(this._firstPart):null,this._chordPart?t.getDispatchStr(this._chordPart):null]},t.getDispatchStr=function(e){if(e.isModifierKey())return null;var t="";return e.ctrlKey&&(t+="ctrl+"),e.shiftKey&&(t+="shift+"),e.altKey&&(t+="alt+"),e.metaKey&&(t+="meta+"),t+=n.KeyCodeUtils.toString(e.keyCode)},t}(n.ResolvedKeybinding);t.USLayoutResolvedKeybinding=r}),define(t[117],n([1,0,15]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ILogService=n.createDecorator("logService");var i=function(){function e(){}return e.prototype.trace=function(e){for(var t=[],n=1;n0?a:1,l=l>0?l:1,u=u>=a?u:a,d=d>0?d:l,{resource:t,owner:e,code:i,severity:o,message:r,source:s,startLineNumber:a,startColumn:l,endLineNumber:u,endColumn:d,relatedInformation:c,tags:h}},e.prototype.read=function(t){void 0===t&&(t=Object.create(null));var n=t.owner,i=t.resource,o=t.severities,r=t.take;if((!r||r<0)&&(r=-1),n&&i){if(y=a.get(this._byResource,i.toString(),n)){for(var s=[],l=0,u=y;l0&&C===r)break}}return s}return[]}if(n||i){var c=n?this._byOwner[n]:this._byResource[i.toString()];if(!c)return[];s=[];for(var h in c)for(var p=0,f=c[h];p0&&C===r)return s}}return s}s=[] +;for(var g in this._byResource)for(var m in this._byResource[g])for(var v=0,_=this._byResource[g][m];v<_.length;v++){var y=_[v];if(e._accept(y,o)){var C=s.push(y);if(r>0&&C===r)return s}}return s},e._accept=function(e,t){return void 0===t||(t&e.severity)===e.severity},e._debouncer=function(t,n){t||(e._dedupeMap=Object.create(null),t=[]);for(var i=0,o=n;i'+e+""})},codeBlockRenderCallback:function(){return t._onDidRenderCodeBlock.fire()},actionHandler:{callback:function(e){t._openerService.open(r.default.parse(e)).then(void 0,s.onUnexpectedError)},disposeables:e}}},e.prototype.render=function(e){ +var t,i=[];return t=e?n.renderMarkdown(e,this.getOptions(i)):document.createElement("span"),{element:t,dispose:function(){return h.dispose(i)}}},e=a([u(1,o.IModeService),u(2,d.optional(i.IOpenerService))],e)}();t.MarkdownRenderer=p}),define(t[92],n([1,0,15]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.IProgressService=n.createDecorator("progressService")}),define(t[45],n([1,0,33,85]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(){this.data={}}return e.prototype.add=function(e,t){i.ok(n.isString(e)),i.ok(n.isObject(t)),i.ok(!this.data.hasOwnProperty(e),"There is already an extension with this id"),this.data[e]=t},e.prototype.as=function(e){return this.data[e]||null},e}();t.Registry=new o}),define(t[124],n([1,0,300,9,45,41,17]),function(e,t,n,i,o,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Extensions={ModesRegistry:"editor.modesRegistry"};var a=function(){function e(){ +this._onDidAddLanguages=new i.Emitter,this.onDidAddLanguages=this._onDidAddLanguages.event,this._languages=[]}return e.prototype.registerLanguage=function(e){this._languages.push(e),this._onDidAddLanguages.fire([e])},e.prototype.getLanguages=function(){return this._languages.slice(0)},e}();t.EditorModesRegistry=a,t.ModesRegistry=new a,o.Registry.add(t.Extensions.ModesRegistry,t.ModesRegistry),t.PLAINTEXT_MODE_ID="plaintext",t.PLAINTEXT_LANGUAGE_IDENTIFIER=new s.LanguageIdentifier(t.PLAINTEXT_MODE_ID,1),t.ModesRegistry.registerLanguage({id:t.PLAINTEXT_MODE_ID,extensions:[".txt",".gitignore"],aliases:[n.localize(0,null),"text"],mimetypes:["text/plain"]}),r.LanguageConfigurationRegistry.register(t.PLAINTEXT_LANGUAGE_IDENTIFIER,{brackets:[["(",")"],["[","]"],["{","}"]]})}),define(t[429],n([1,0,45,9]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Extensions={JSONContribution:"base.contributions.json"};var o=new(function(){function e(){this._onDidChangeSchema=new i.Emitter, +this.schemasById={}}return e.prototype.registerSchema=function(e,t){this.schemasById[function(e){return e.length>0&&"#"===e.charAt(e.length-1)?e.substring(0,e.length-1):e}(e)]=t,this._onDidChangeSchema.fire(e)},e}());n.Registry.add(t.Extensions.JSONContribution,o)}),define(t[82],n([1,0,352,9,45,33,6,429]),function(e,t,n,i,o,r,s,a){"use strict";function l(e){return t.OVERRIDE_PROPERTY_PATTERN.test(e)?n.localize(3,null,e):void 0!==g.getConfigurationProperties()[e]?n.localize(4,null,e):null}Object.defineProperty(t,"__esModule",{value:!0}),t.Extensions={Configuration:"base.contributions.configuration"};var u;!function(e){e[e.APPLICATION=1]="APPLICATION",e[e.WINDOW=2]="WINDOW",e[e.RESOURCE=3]="RESOURCE"}(u=t.ConfigurationScope||(t.ConfigurationScope={})),t.allSettings={properties:{},patternProperties:{}},t.applicationSettings={properties:{},patternProperties:{}},t.windowSettings={properties:{},patternProperties:{}},t.resourceSettings={properties:{},patternProperties:{}}, +t.editorConfigurationSchemaId="vscode://schemas/settings/editor";var d=o.Registry.as(a.Extensions.JSONContribution),c=function(){function e(){this.overrideIdentifiers=[],this._onDidSchemaChange=new i.Emitter,this._onDidRegisterConfiguration=new i.Emitter,this.configurationContributors=[],this.editorConfigurationSchema={properties:{},patternProperties:{},additionalProperties:!1,errorMessage:"Unknown editor configuration setting"},this.configurationProperties={},this.excludedConfigurationProperties={},this.computeOverridePropertyPattern(),d.registerSchema(t.editorConfigurationSchemaId,this.editorConfigurationSchema)}return e.prototype.registerConfiguration=function(e,t){void 0===t&&(t=!0),this.registerConfigurations([e],[],t)},e.prototype.registerConfigurations=function(e,t,n){var i=this;void 0===n&&(n=!0);var o=this.toConfiguration(t);o&&e.push(o);var r=[];e.forEach(function(e){r.push.apply(r,i.validateAndRegisterProperties(e,n)),i.configurationContributors.push(e),i.registerJSONConfiguration(e), +i.updateSchemaForOverrideSettingsConfiguration(e)}),this._onDidRegisterConfiguration.fire(r)},e.prototype.registerOverrideIdentifiers=function(e){var t;(t=this.overrideIdentifiers).push.apply(t,e),this.updateOverridePropertyPatternKey()},e.prototype.toConfiguration=function(e){for(var i={id:"defaultOverrides",title:n.localize(0,null),properties:{}},o=0,r=e;o.001){C=!1;break}}var L=s.getTimeSinceLastZoomLevelChanged()>2e3;return new l.FontInfo({zoomLevel:s.getZoomLevel(),fontFamily:e.fontFamily,fontWeight:e.fontWeight,fontSize:e.fontSize,lineHeight:e.lineHeight,letterSpacing:e.letterSpacing,isMonospace:C,typicalHalfwidthCharacterWidth:i.width,typicalFullwidthCharacterWidth:o.width, +spaceWidth:r.width,maxDigitWidth:y},L)},t.INSTANCE=new t,t}(i.Disposable),p=function(e){function t(t,n){void 0===n&&(n=null);var i=e.call(this,t)||this;return i._elementSizeObserver=i._register(new u.ElementSizeObserver(n,function(){return i._onReferenceDomElementSizeChanged()})),i._register(h.INSTANCE.onDidChange(function(){return i._onCSSBasedConfigurationChanged()})),i._validatedOptions.automaticLayout&&i._elementSizeObserver.startObserving(),i._register(s.onDidChangeZoomLevel(function(e){return i._recomputeOptions()})),i._register(s.onDidChangeAccessibilitySupport(function(){return i._recomputeOptions()})),i._recomputeOptions(),i}return o(t,e),t._massageFontFamily=function(e){return/[,"']/.test(e)?e:/[+ ]/.test(e)?'"'+e+'"':e},t.applyFontInfoSlow=function(e,n){e.style.fontFamily=t._massageFontFamily(n.fontFamily),e.style.fontWeight=n.fontWeight,e.style.fontSize=n.fontSize+"px",e.style.lineHeight=n.lineHeight+"px",e.style.letterSpacing=n.letterSpacing+"px"},t.applyFontInfo=function(e,n){ +e.setFontFamily(t._massageFontFamily(n.fontFamily)),e.setFontWeight(n.fontWeight),e.setFontSize(n.fontSize),e.setLineHeight(n.lineHeight),e.setLetterSpacing(n.letterSpacing)},t.prototype._onReferenceDomElementSizeChanged=function(){this._recomputeOptions()},t.prototype._onCSSBasedConfigurationChanged=function(){this._recomputeOptions()},t.prototype.observeReferenceElement=function(e){this._elementSizeObserver.observe(e)},t.prototype.dispose=function(){e.prototype.dispose.call(this)},t.prototype._getExtraEditorClassName=function(){var e="";return s.isIE?e+="ie ":s.isFirefox?e+="ff ":s.isEdge?e+="edge ":s.isSafari&&(e+="safari "),r.isMacintosh&&(e+="mac "),e},t.prototype._getEnvConfiguration=function(){return{extraEditorClassName:this._getExtraEditorClassName(),outerWidth:this._elementSizeObserver.getWidth(),outerHeight:this._elementSizeObserver.getHeight(),emptySelectionClipboard:s.isWebKit||s.isFirefox,pixelRatio:s.getPixelRatio(),zoomLevel:s.getZoomLevel(),accessibilitySupport:s.getAccessibilitySupport()}}, +t.prototype.readConfiguration=function(e){return h.INSTANCE.readConfiguration(e)},t}(a.CommonEditorConfiguration);t.Configuration=p}),define(t[433],n([1,0,26,113,65,36]),function(e,t,n,i,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(e){function t(t){var n=e.call(this,t)||this;return n._visibleLines=new i.VisibleLinesCollection(n),n.domNode=n._visibleLines.domNode,n._dynamicOverlays=[],n._isFocused=!1,n.domNode.setClassName("view-overlays"),n}return o(t,e),t.prototype.shouldRender=function(){if(e.prototype.shouldRender.call(this))return!0;for(var t=0,n=this._dynamicOverlays.length;t'),i.appendASCIIString(o),i.appendASCIIString(""),!0)},e.prototype.layoutLine=function(e,t){this._domNode&&(this._domNode.setTop(t),this._domNode.setHeight(this._lineHeight))},e}();t.ViewOverlayLine=l;var u=function(e){function t(t){var n=e.call(this,t)||this;return n._contentWidth=n._context.configuration.editor.layoutInfo.contentWidth,n.domNode.setHeight(0),n}return o(t,e),t.prototype.onConfigurationChanged=function(t){return t.layoutInfo&&(this._contentWidth=this._context.configuration.editor.layoutInfo.contentWidth), +e.prototype.onConfigurationChanged.call(this,t)},t.prototype.onScrollChanged=function(t){return e.prototype.onScrollChanged.call(this,t)||t.scrollWidthChanged},t.prototype._viewOverlaysRender=function(t){e.prototype._viewOverlaysRender.call(this,t),this.domNode.setWidth(Math.max(t.scrollWidth,this._contentWidth))},t}(a);t.ContentViewOverlays=u;var d=function(e){function t(t){var n=e.call(this,t)||this;return n._contentLeft=n._context.configuration.editor.layoutInfo.contentLeft,n.domNode.setClassName("margin-view-overlays"),n.domNode.setWidth(1),r.Configuration.applyFontInfo(n.domNode,n._context.configuration.editor.fontInfo),n}return o(t,e),t.prototype.onConfigurationChanged=function(t){var n=!1;return t.fontInfo&&(r.Configuration.applyFontInfo(this.domNode,this._context.configuration.editor.fontInfo),n=!0),t.layoutInfo&&(this._contentLeft=this._context.configuration.editor.layoutInfo.contentLeft,n=!0),e.prototype.onConfigurationChanged.call(this,t)||n},t.prototype.onScrollChanged=function(t){ +return e.prototype.onScrollChanged.call(this,t)||t.scrollHeightChanged},t.prototype._viewOverlaysRender=function(t){e.prototype._viewOverlaysRender.call(this,t);var n=Math.min(t.scrollHeight,1e6);this.domNode.setHeight(n),this.domNode.setWidth(this._contentLeft)},t}(a);t.MarginViewOverlays=d}),define(t[434],n([1,0,26,12,3,47,65,7,6]),function(e,t,n,i,o,r,s,a,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=function(){return function(e,t,n,i,o,r){this.top=e,this.left=t,this.width=n,this.height=i,this.textContent=o,this.textContentClassName=r}}(),d=function(){function e(e){this._context=e,this._cursorStyle=this._context.configuration.editor.viewInfo.cursorStyle,this._lineHeight=this._context.configuration.editor.lineHeight,this._typicalHalfwidthCharacterWidth=this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth,this._lineCursorWidth=Math.min(this._context.configuration.editor.viewInfo.cursorWidth,this._typicalHalfwidthCharacterWidth),this._isVisible=!0, +this._domNode=n.createFastDomNode(document.createElement("div")),this._domNode.setClassName("cursor"),this._domNode.setHeight(this._lineHeight),this._domNode.setTop(0),this._domNode.setLeft(0),s.Configuration.applyFontInfo(this._domNode,this._context.configuration.editor.fontInfo),this._domNode.setDisplay("none"),this.updatePosition(new i.Position(1,1)),this._lastRenderedContent="",this._renderData=null}return e.prototype.getDomNode=function(){return this._domNode},e.prototype.getPosition=function(){return this._position},e.prototype.show=function(){this._isVisible||(this._domNode.setVisibility("inherit"),this._isVisible=!0)},e.prototype.hide=function(){this._isVisible&&(this._domNode.setVisibility("hidden"),this._isVisible=!1)},e.prototype.onConfigurationChanged=function(e){return e.lineHeight&&(this._lineHeight=this._context.configuration.editor.lineHeight),e.fontInfo&&(s.Configuration.applyFontInfo(this._domNode,this._context.configuration.editor.fontInfo), +this._typicalHalfwidthCharacterWidth=this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth),e.viewInfo&&(this._cursorStyle=this._context.configuration.editor.viewInfo.cursorStyle,this._lineCursorWidth=Math.min(this._context.configuration.editor.viewInfo.cursorWidth,this._typicalHalfwidthCharacterWidth)),!0},e.prototype.onCursorPositionChanged=function(e){return this.updatePosition(e),!0},e.prototype._prepareRender=function(e){var t="",n="";if(this._cursorStyle===r.TextEditorCursorStyle.Line||this._cursorStyle===r.TextEditorCursorStyle.LineThin){var i=e.visibleRangeForPosition(this._position);if(!i)return null;var s;if(this._cursorStyle===r.TextEditorCursorStyle.Line){if((s=a.computeScreenAwareSize(this._lineCursorWidth>0?this._lineCursorWidth:2))>2){t=this._context.model.getLineContent(this._position.lineNumber).charAt(this._position.column-1)}}else s=a.computeScreenAwareSize(1);var d=e.getVerticalOffsetForLineNumber(this._position.lineNumber)-e.bigNumbersDelta +;return new u(d,i.left,s,this._lineHeight,t,n)}var c=e.linesVisibleRangesForRange(new o.Range(this._position.lineNumber,this._position.column,this._position.lineNumber,this._position.column+1),!1);if(!c||0===c.length||0===c[0].ranges.length)return null;var h=c[0].ranges[0],p=h.width<1?this._typicalHalfwidthCharacterWidth:h.width;if(this._cursorStyle===r.TextEditorCursorStyle.Block){var f=this._context.model.getViewLineData(this._position.lineNumber);t=f.content.charAt(this._position.column-1),l.isHighSurrogate(f.content.charCodeAt(this._position.column-1))&&(t+=f.content.charAt(this._position.column));var g=f.tokens.findTokenIndexAtOffset(this._position.column-1);n=f.tokens.getClassName(g)}var m=e.getVerticalOffsetForLineNumber(this._position.lineNumber)-e.bigNumbersDelta,v=this._lineHeight;return this._cursorStyle!==r.TextEditorCursorStyle.Underline&&this._cursorStyle!==r.TextEditorCursorStyle.UnderlineThin||(m+=this._lineHeight-2,v=2),new u(m,h.left,p,v,t,n)},e.prototype.prepareRender=function(e){ +this._renderData=this._prepareRender(e)},e.prototype.render=function(e){return this._renderData?(this._lastRenderedContent!==this._renderData.textContent&&(this._lastRenderedContent=this._renderData.textContent,this._domNode.domNode.textContent=this._lastRenderedContent),this._domNode.setClassName("cursor "+this._renderData.textContentClassName),this._domNode.setDisplay("block"),this._domNode.setTop(this._renderData.top),this._domNode.setLeft(this._renderData.left),this._domNode.setWidth(this._renderData.width),this._domNode.setLineHeight(this._renderData.height),this._domNode.setHeight(this._renderData.height),{domNode:this._domNode.domNode,position:this._position,contentLeft:this._renderData.left,height:this._renderData.height,width:2}):(this._domNode.setDisplay("none"),null)},e.prototype.updatePosition=function(e){this._position=e},e}();t.ViewCursor=d}),define(t[435],n([1,0,10,424,6,45,124,17,60,82]),function(e,t,n,i,o,r,s,a,l,u){"use strict";Object.defineProperty(t,"__esModule",{value:!0}) +;var d=Object.prototype.hasOwnProperty,c=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=!1);var n=this;this._nextLanguageId=1,this._languages={},this._mimeTypesMap={},this._nameMap={},this._lowercaseNameMap={},this._languageIds=[],this._warnOnOverwrite=t,e&&(this._registerLanguages(s.ModesRegistry.getLanguages()),s.ModesRegistry.onDidAddLanguages(function(e){return n._registerLanguages(e)}))}return e.prototype._registerLanguages=function(e){var t=this;if(0!==e.length){for(var n=0;n0&&((r=e.mimetypes).push.apply(r,t.mimetypes),a=t.mimetypes[0]),a||(a="text/x-"+s,e.mimetypes.push(a)),Array.isArray(t.extensions))for(var l=0,u=t.extensions;l0){var v=t.firstLine;"^"!==v.charAt(0)&&(v="^"+v);try{var _=new RegExp(v);o.regExpLeadsToEndlessLoop(_)||i.registerTextMime({id:s,mime:a,firstline:_},this._warnOnOverwrite)}catch(e){n.onUnexpectedError(e)}}e.aliases.push(s);var y=null;if(void 0!==t.aliases&&Array.isArray(t.aliases)&&(y=0===t.aliases.length?[null]:t.aliases),null!==y)for(var C=0;C0;if(b&&null===y[0]);else{var S=(b?y[0]:null)||s;!b&&e.name||(e.name=S)}t.configuration&&e.configurationFiles.push(t.configuration)},e.prototype.isRegisteredMode=function(e){return!!d.call(this._mimeTypesMap,e)||d.call(this._languages,e)},e.prototype.getModeIdForLanguageNameLowercase=function(e){return d.call(this._lowercaseNameMap,e)?this._lowercaseNameMap[e].language:null},e.prototype.extractModeIds=function(e){var t=this;return e?e.split(",").map(function(e){return e.trim() +}).map(function(e){return d.call(t._mimeTypesMap,e)?t._mimeTypesMap[e].language:e}).filter(function(e){return d.call(t._languages,e)}):[]},e.prototype.getLanguageIdentifier=function(e){if(e===l.NULL_MODE_ID||0===e)return l.NULL_LANGUAGE_IDENTIFIER;var t;if("string"==typeof e)t=e;else if(!(t=this._languageIds[e]))return null;return d.call(this._languages,t)?this._languages[t].identifier:null},e.prototype.getModeIdsFromFilenameOrFirstLine=function(e,t){if(!e&&!t)return[];var n=i.guessMimeTypes(e,t);return this.extractModeIds(n.join(","))},e}();t.LanguagesRegistry=c}),define(t[436],n([1,0,10,9,13,528,435]),function(e,t,n,i,o,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(e){void 0===e&&(e=!1),this._onDidCreateMode=new i.Emitter,this.onDidCreateMode=this._onDidCreateMode.event,this._instantiatedModes={},this._registry=new s.LanguagesRegistry(!0,e)}return e.prototype._onReady=function(){return o.TPromise.as(!0)},e.prototype.isRegisteredMode=function(e){ +return this._registry.isRegisteredMode(e)},e.prototype.getModeIdForLanguageName=function(e){return this._registry.getModeIdForLanguageNameLowercase(e)},e.prototype.getModeIdByFilenameOrFirstLine=function(e,t){var n=this._registry.getModeIdsFromFilenameOrFirstLine(e,t);return n.length>0?n[0]:null},e.prototype.getModeId=function(e){var t=this._registry.extractModeIds(e);return t.length>0?t[0]:null},e.prototype.getLanguageIdentifier=function(e){return this._registry.getLanguageIdentifier(e)},e.prototype.getMode=function(e){for(var t=this._registry.extractModeIds(e),i=!1,o=0;ot.command?1:e.weight2-t.weight2}Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(){this._keybindings=[],this._keybindingsSorted=!0}return e.bindToCurrentPlatform=function(e){if(1===i.OS){if(e&&e.win)return e.win}else if(2===i.OS){if(e&&e.mac)return e.mac}else if(e&&e.linux)return e.linux;return e},e.prototype.registerKeybindingRule=function(t,o){void 0===o&&(o=0);var r=e.bindToCurrentPlatform(t);if(r&&r.primary&&this._registerDefaultKeybinding(n.createKeybinding(r.primary,i.OS),t.id,t.weight,0,t.when,o),r&&Array.isArray(r.secondary))for(var s=0,a=r.secondary.length;s=21&&e<=30||(e>=31&&e<=56||(80===e||81===e||82===e||83===e||84===e||85===e||86===e||110===e||111===e||87===e||88===e||89===e||90===e||91===e||92===e))},e.prototype._assertNoCtrlAlt=function(t,n){t.ctrlKey&&t.altKey&&!t.metaKey&&e._mightProduceChar(t.keyCode)&&console.warn("Ctrl+Alt+ keybindings should not be used by default under Windows. Offender: ",t," for ",n)},e.prototype._registerDefaultKeybinding=function(e,t,n,o,r,s){0===s&&1===i.OS&&(2===e.type?this._assertNoCtrlAlt(e.firstPart,t):this._assertNoCtrlAlt(e,t)),this._keybindings.push({keybinding:e,command:t,commandArgs:void 0,when:r,weight1:n,weight2:o}),this._keybindingsSorted=!1},e.prototype.getDefaultKeybindings=function(){return this._keybindingsSorted||(this._keybindings.sort(s),this._keybindingsSorted=!0),this._keybindings.slice(0)},e}();t.KeybindingsRegistry=new a,t.Extensions={EditorModes:"platform.keybindingsRegistry"}, +r.Registry.add(t.Extensions.EditorModes,t.KeybindingsRegistry)}),define(t[72],n([1,0,15]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ID="storageService",t.IStorageService=n.createDecorator(t.ID);!function(e){e[e.GLOBAL=0]="GLOBAL",e[e.WORKSPACE=1]="WORKSPACE"}(t.StorageScope||(t.StorageScope={})),t.NullStorageService={_serviceBrand:void 0,store:function(){},remove:function(){},get:function(e,t,n){return n},getInteger:function(e,t,n){return n},getBoolean:function(e,t,n){return n}}}),define(t[442],n([1,0,70,72,14]),function(e,t,n,i,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(){}return e.prototype.select=function(e,t,n){if(0===n.length)return 0;for(var i=n[0].score,o=1;os&&d.type===l.type&&d.insertText===l.insertText&&(s=d.touch,r=a)}return-1===r?e.prototype.select.call(this,t,n,i):r},t.prototype.toJSON=function(){var e=[];return this._cache.forEach(function(t,n){ +e.push([n,t])}),e},t.prototype.fromJSON=function(e){this._cache.clear();for(var t=0,n=e;t0){this._seq=e[0][1].touch+1;for(var t=0,n=e;t1)for(var r=n.modelState?n.modelState.position:null,s=n.viewState?n.viewState.position:null,a=0,d=o.length;ao&&(i=o);var s=new r.Range(i,1,i,e.context.model.getLineMaxColumn(i)),a=0;if(n.at)switch(n.at){case x.RawAtArgument.Top:a=3;break;case x.RawAtArgument.Center:a=1;break;case x.RawAtArgument.Bottom:a=4}var l=e.context.convertModelRangeToViewRange(s);e.revealRange(!1,l,a,0)},t}(E))),e.SelectAll=d.registerEditorCommand(new(function(e){function t(){return e.call(this,{id:"selectAll",precondition:null})||this}return o(t,e),t.prototype.runCoreEditorCommand=function(e,t){e.context.model.pushStackElement(), +e.setStates(t.source,l.CursorChangeReason.Explicit,[u.CursorMoveCommands.selectAll(e.context,e.getPrimaryCursor())])},t}(E))),e.SetSelection=d.registerEditorCommand(new(function(e){function t(){return e.call(this,{id:"setSelection",precondition:null})||this}return o(t,e),t.prototype.runCoreEditorCommand=function(e,t){e.context.model.pushStackElement(),e.setStates(t.source,l.CursorChangeReason.Explicit,[a.CursorState.fromModelSelection(t.selection)])},t}(E)))}(N=t.CoreNavigationCommands||(t.CoreNavigationCommands={}));!function(e){e.LineBreakInsert=d.registerEditorCommand(new(function(e){function t(){return e.call(this,{id:"lineBreakInsert",precondition:h.EditorContextKeys.writable,kbOpts:{weight:w,kbExpr:h.EditorContextKeys.textInputFocus,primary:null,mac:{primary:301}}})||this}return o(t,e),t.prototype.runEditorCommand=function(e,t,n){t.pushUndoStop(),t.executeCommands(this.id,m.TypeOperations.lineBreakInsert(t._getCursorConfiguration(),t.getModel(),t.getSelections()))},t}(d.EditorCommand))), +e.Outdent=d.registerEditorCommand(new(function(e){function t(){return e.call(this,{id:"outdent",precondition:h.EditorContextKeys.writable,kbOpts:{weight:w,kbExpr:f.ContextKeyExpr.and(h.EditorContextKeys.editorTextFocus,h.EditorContextKeys.tabDoesNotMoveFocus),primary:1026}})||this}return o(t,e),t.prototype.runEditorCommand=function(e,t,n){t.pushUndoStop(),t.executeCommands(this.id,m.TypeOperations.outdent(t._getCursorConfiguration(),t.getModel(),t.getSelections())),t.pushUndoStop()},t}(d.EditorCommand))),e.Tab=d.registerEditorCommand(new(function(e){function t(){return e.call(this,{id:"tab",precondition:h.EditorContextKeys.writable,kbOpts:{weight:w,kbExpr:f.ContextKeyExpr.and(h.EditorContextKeys.editorTextFocus,h.EditorContextKeys.tabDoesNotMoveFocus),primary:2}})||this}return o(t,e),t.prototype.runEditorCommand=function(e,t,n){t.pushUndoStop(),t.executeCommands(this.id,m.TypeOperations.tab(t._getCursorConfiguration(),t.getModel(),t.getSelections())),t.pushUndoStop()},t}(d.EditorCommand))), +e.DeleteLeft=d.registerEditorCommand(new(function(e){function t(){return e.call(this,{id:"deleteLeft",precondition:h.EditorContextKeys.writable,kbOpts:{weight:w,kbExpr:h.EditorContextKeys.textInputFocus,primary:1,secondary:[1025],mac:{primary:1,secondary:[1025,294,257]}}})||this}return o(t,e),t.prototype.runEditorCommand=function(e,t,n){var i=t._getCursors(),o=v.DeleteOperations.deleteLeft(i.getPrevEditOperationType(),t._getCursorConfiguration(),t.getModel(),t.getSelections()),r=o[0],s=o[1];r&&t.pushUndoStop(),t.executeCommands(this.id,s),i.setPrevEditOperationType(2)},t}(d.EditorCommand))),e.DeleteRight=d.registerEditorCommand(new(function(e){function t(){return e.call(this,{id:"deleteRight",precondition:h.EditorContextKeys.writable,kbOpts:{weight:w,kbExpr:h.EditorContextKeys.textInputFocus,primary:20,mac:{primary:20,secondary:[290,276]}}})||this}return o(t,e),t.prototype.runEditorCommand=function(e,t,n){ +var i=t._getCursors(),o=v.DeleteOperations.deleteRight(i.getPrevEditOperationType(),t._getCursorConfiguration(),t.getModel(),t.getSelections()),r=o[0],s=o[1];r&&t.pushUndoStop(),t.executeCommands(this.id,s),i.setPrevEditOperationType(3)},t}(d.EditorCommand)))}(t.CoreEditingCommands||(t.CoreEditingCommands={}));var I=function(e){function t(t){var n=e.call(this,t)||this;return n._editorHandler=t.editorHandler,n._inputHandler=t.inputHandler,n}return o(t,e),t.prototype.runCommand=function(e,t){var n=y(e);if(n&&n.hasTextFocus())return this._runEditorHandler(n,t);var i=document.activeElement;if(!(i&&["input","textarea"].indexOf(i.tagName.toLowerCase())>=0)){var o=e.get(p.ICodeEditorService).getActiveCodeEditor();return o?(o.focus(),this._runEditorHandler(o,t)):void 0}document.execCommand(this._inputHandler)},t.prototype._runEditorHandler=function(e,t){var n=this._editorHandler;"string"==typeof n?e.trigger("keyboard",n,t):((t=t||{}).source="keyboard",n.runEditorCommand(null,e,t))},t}(d.Command),M=function(e){ +function t(t,n){var i=e.call(this,{id:t,precondition:null})||this;return i._handlerId=n,i}return o(t,e),t.prototype.runCommand=function(e,t){var n=y(e);n&&n.trigger("keyboard",this._handlerId,t)},t}(d.Command);C(new I({editorHandler:N.SelectAll,inputHandler:"selectAll",id:"editor.action.selectAll",precondition:h.EditorContextKeys.textInputFocus,kbOpts:{weight:w,kbExpr:null,primary:2079},menubarOpts:{menuId:_.MenuId.MenubarSelectionMenu,group:"1_basic",title:n.localize(0,null),order:1}})),C(new I({editorHandler:S.Undo,inputHandler:"undo",id:S.Undo,precondition:h.EditorContextKeys.writable,kbOpts:{weight:w,kbExpr:h.EditorContextKeys.textInputFocus,primary:2104},menubarOpts:{menuId:_.MenuId.MenubarEditMenu,group:"1_do",title:n.localize(1,null),order:1}})),C(new M("default:"+S.Undo,S.Undo)),C(new I({editorHandler:S.Redo,inputHandler:"redo",id:S.Redo,precondition:h.EditorContextKeys.writable,kbOpts:{weight:w,kbExpr:h.EditorContextKeys.textInputFocus,primary:2103,secondary:[3128],mac:{primary:3128}},menubarOpts:{ +menuId:_.MenuId.MenubarEditMenu,group:"1_do",title:n.localize(2,null),order:2}})),C(new M("default:"+S.Redo,S.Redo)),b(S.Type),b(S.ReplacePreviousChar),b(S.CompositionStart),b(S.CompositionEnd),b(S.Paste),b(S.Cut)}),define(t[446],n([1,0,12,133]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t,n,i,o){this.configuration=e,this.viewModel=t,this._execCoreEditorCommandFunc=n,this.outgoingEvents=i,this.commandDelegate=o}return e.prototype._execMouseCommand=function(e,t){t.source="mouse",this._execCoreEditorCommandFunc(e,t)},e.prototype.paste=function(e,t,n,i){this.commandDelegate.paste(e,t,n,i)},e.prototype.type=function(e,t){this.commandDelegate.type(e,t)},e.prototype.replacePreviousChar=function(e,t,n){this.commandDelegate.replacePreviousChar(e,t,n)},e.prototype.compositionStart=function(e){this.commandDelegate.compositionStart(e)},e.prototype.compositionEnd=function(e){this.commandDelegate.compositionEnd(e)},e.prototype.cut=function(e){ +this.commandDelegate.cut(e)},e.prototype.setSelection=function(e,t){this._execCoreEditorCommandFunc(i.CoreNavigationCommands.SetSelection,{source:e,selection:t})},e.prototype._validateViewColumn=function(e){var t=this.viewModel.getLineMinColumn(e.lineNumber);return e.column=4?this.selectAll():3===e.mouseDownCount?this._hasMulticursorModifier(e)?e.inSelectionMode?this.lastCursorLineSelectDrag(e.position):this.lastCursorLineSelect(e.position):e.inSelectionMode?this.lineSelectDrag(e.position):this.lineSelect(e.position):2===e.mouseDownCount?this._hasMulticursorModifier(e)?this.lastCursorWordSelect(e.position):e.inSelectionMode?this.wordSelectDrag(e.position):this.wordSelect(e.position):this._hasMulticursorModifier(e)?this._hasNonMulticursorModifier(e)||(e.shiftKey?this.columnSelect(e.position,e.mouseColumn):e.inSelectionMode?this.lastCursorMoveToSelect(e.position):this.createCursor(e.position,!1)):e.inSelectionMode?this.moveToSelect(e.position):this.moveTo(e.position) +},e.prototype._usualArgs=function(e){return e=this._validateViewColumn(e),{position:this.convertViewToModelPosition(e),viewPosition:e}},e.prototype.moveTo=function(e){this._execMouseCommand(i.CoreNavigationCommands.MoveTo,this._usualArgs(e))},e.prototype.moveToSelect=function(e){this._execMouseCommand(i.CoreNavigationCommands.MoveToSelect,this._usualArgs(e))},e.prototype.columnSelect=function(e,t){e=this._validateViewColumn(e),this._execMouseCommand(i.CoreNavigationCommands.ColumnSelect,{position:this.convertViewToModelPosition(e),viewPosition:e,mouseColumn:t})},e.prototype.createCursor=function(e,t){e=this._validateViewColumn(e),this._execMouseCommand(i.CoreNavigationCommands.CreateCursor,{position:this.convertViewToModelPosition(e),viewPosition:e,wholeLine:t})},e.prototype.lastCursorMoveToSelect=function(e){this._execMouseCommand(i.CoreNavigationCommands.LastCursorMoveToSelect,this._usualArgs(e))},e.prototype.wordSelect=function(e){ +this._execMouseCommand(i.CoreNavigationCommands.WordSelect,this._usualArgs(e))},e.prototype.wordSelectDrag=function(e){this._execMouseCommand(i.CoreNavigationCommands.WordSelectDrag,this._usualArgs(e))},e.prototype.lastCursorWordSelect=function(e){this._execMouseCommand(i.CoreNavigationCommands.LastCursorWordSelect,this._usualArgs(e))},e.prototype.lineSelect=function(e){this._execMouseCommand(i.CoreNavigationCommands.LineSelect,this._usualArgs(e))},e.prototype.lineSelectDrag=function(e){this._execMouseCommand(i.CoreNavigationCommands.LineSelectDrag,this._usualArgs(e))},e.prototype.lastCursorLineSelect=function(e){this._execMouseCommand(i.CoreNavigationCommands.LastCursorLineSelect,this._usualArgs(e))},e.prototype.lastCursorLineSelectDrag=function(e){this._execMouseCommand(i.CoreNavigationCommands.LastCursorLineSelectDrag,this._usualArgs(e))},e.prototype.selectAll=function(){this._execMouseCommand(i.CoreNavigationCommands.SelectAll,{})},e.prototype.convertViewToModelPosition=function(e){ +return this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(e)},e.prototype.emitKeyDown=function(e){this.outgoingEvents.emitKeyDown(e)},e.prototype.emitKeyUp=function(e){this.outgoingEvents.emitKeyUp(e)},e.prototype.emitContextMenu=function(e){this.outgoingEvents.emitContextMenu(e)},e.prototype.emitMouseMove=function(e){this.outgoingEvents.emitMouseMove(e)},e.prototype.emitMouseLeave=function(e){this.outgoingEvents.emitMouseLeave(e)},e.prototype.emitMouseUp=function(e){this.outgoingEvents.emitMouseUp(e)},e.prototype.emitMouseDown=function(e){this.outgoingEvents.emitMouseDown(e)},e.prototype.emitMouseDrag=function(e){this.outgoingEvents.emitMouseDrag(e)},e.prototype.emitMouseDrop=function(e){this.outgoingEvents.emitMouseDrop(e)},e}();t.ViewController=o}),define(t[447],n([1,0,304,20,11,236]),function(e,t,n,i,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(e){function t(t,n){var i=e.call(this,n)||this;return i.left=t,i}return o(t,e), +t.prototype.run=function(e,t){for(var n=[],i=t.getSelections(),o=0;ot.getLineMinColumn(o)?i.isLowSurrogate(t.getLineContent(o).charCodeAt(n-2))?n-=2:n-=1:o>1&&(o-=1,n=t.getLineMaxColumn(o)),new s.Position(o,n)},t.prototype.positionRightOf=function(e,t){var n=e.column,o=e.lineNumber;return n0&&(t.pushUndoStop(),t.executeCommands(this.id,i),t.pushUndoStop())},t}(l.EditorAction);l.registerEditorAction(d)}),define(t[449],n([1,0,306,30,18,32,11,165,20,44,367]),function(e,t,n,i,r,s,a,l,u,d){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var c="9_cutcopypaste",h=r.isNative||document.queryCommandSupported("cut"),p=r.isNative||document.queryCommandSupported("copy"),f=p&&!i.isEdgeOrIE,g=r.isNative||!i.isChrome&&document.queryCommandSupported("paste"),m=function(e){function t(t,n){var i=e.call(this,n)||this;return i.browserCommand=t,i}return o(t,e),t.prototype.runCommand=function(e,t){var n=e.get(s.ICodeEditorService).getFocusedCodeEditor();n&&n.hasTextFocus()?n.trigger("keyboard",this.id,t):document.execCommand(this.browserCommand)},t.prototype.run=function(e,t){t.focus(),document.execCommand(this.browserCommand)},t}(a.EditorAction),v=function(e){function t(){var t={kbExpr:u.EditorContextKeys.textInputFocus,primary:2102,win:{primary:2102, +secondary:[1044]},weight:100};return r.isNative||(t=null),e.call(this,"cut",{id:"editor.action.clipboardCutAction",label:n.localize(0,null),alias:"Cut",precondition:u.EditorContextKeys.writable,kbOpts:t,menuOpts:{group:c,order:1},menubarOpts:{menuId:d.MenuId.MenubarEditMenu,group:"2_ccp",title:n.localize(1,null),order:1}})||this}return o(t,e),t.prototype.run=function(t,n){!n.getConfiguration().emptySelectionClipboard&&n.getSelection().isEmpty()||e.prototype.run.call(this,t,n)},t}(m),_=function(e){function t(){var t={kbExpr:u.EditorContextKeys.textInputFocus,primary:2081,win:{primary:2081,secondary:[2067]},weight:100};return r.isNative||(t=null),e.call(this,"copy",{id:"editor.action.clipboardCopyAction",label:n.localize(2,null),alias:"Copy",precondition:null,kbOpts:t,menuOpts:{group:c,order:2},menubarOpts:{menuId:d.MenuId.MenubarEditMenu,group:"2_ccp",title:n.localize(3,null),order:2}})||this}return o(t,e),t.prototype.run=function(t,n){ +!n.getConfiguration().emptySelectionClipboard&&n.getSelection().isEmpty()||e.prototype.run.call(this,t,n)},t}(m),y=function(e){function t(){var t={kbExpr:u.EditorContextKeys.textInputFocus,primary:2100,win:{primary:2100,secondary:[1043]},weight:100};return r.isNative||(t=null),e.call(this,"paste",{id:"editor.action.clipboardPasteAction",label:n.localize(4,null),alias:"Paste",precondition:u.EditorContextKeys.writable,kbOpts:t,menuOpts:{group:c,order:3},menubarOpts:{menuId:d.MenuId.MenubarEditMenu,group:"2_ccp",title:n.localize(5,null),order:3}})||this}return o(t,e),t}(m),C=function(e){function t(){return e.call(this,"copy",{id:"editor.action.clipboardCopyWithSyntaxHighlightingAction",label:n.localize(6,null),alias:"Copy With Syntax Highlighting",precondition:null,kbOpts:{kbExpr:u.EditorContextKeys.textInputFocus,primary:null,weight:100}})||this}return o(t,e),t.prototype.run=function(t,n){ +!n.getConfiguration().emptySelectionClipboard&&n.getSelection().isEmpty()||(l.CopyOptions.forceCopyWithSyntaxHighlighting=!0,e.prototype.run.call(this,t,n),l.CopyOptions.forceCopyWithSyntaxHighlighting=!1)},t}(m);h&&a.registerEditorAction(v),p&&a.registerEditorAction(_),g&&a.registerEditorAction(y),f&&a.registerEditorAction(C)}),define(t[450],n([1,0,25,14,40,10,31,11,3,17,48,137]),function(e,t,n,i,o,r,s,a,l,u,d,c){"use strict";function h(e,t,s,a){void 0===a&&(a=o.CancellationToken.None);var l={only:s&&s.filter&&s.filter.kind?s.filter.kind.value:void 0,trigger:s&&"manual"===s.type?u.CodeActionTrigger.Manual:u.CodeActionTrigger.Automatic},d=u.CodeActionProviderRegistry.all(e).map(function(n){return i.asWinJsPromise(function(i){return n.provideCodeActions(e,t,l,i)}).then(function(e){return Array.isArray(e)?e.filter(function(e){return function(e,t){if(!t)return!1;if(e&&e.kind&&(!t.kind||!e.kind.contains(t.kind)))return!1;if(t.kind&&c.CodeActionKind.Source.contains(t.kind)&&(!e||!e.includeSourceActions))return!1 +;return!0}(s&&s.filter,e)}):[]},function(e){if(r.isPromiseCanceledError(e))throw e;return r.onUnexpectedExternalError(e),[]})});return Promise.all(d).then(n.flatten).then(function(e){return n.mergeSort(e,p)})}function p(e,t){var i=!n.isFalsyOrEmpty(e.diagnostics),o=!n.isFalsyOrEmpty(t.diagnostics);return i?o?e.diagnostics[0].message.localeCompare(t.diagnostics[0].message):-1:o?1:0}Object.defineProperty(t,"__esModule",{value:!0}),t.getCodeActions=h,a.registerLanguageCommand("_executeCodeActionProvider",function(e,t){var n=t.resource,i=t.range;if(!(n instanceof s.default&&l.Range.isIRange(i)))throw r.illegalArgument();var o=e.get(d.IModelService).getModel(n);if(!o)throw r.illegalArgument();return h(o,o.validateRange(i),{type:"manual",filter:{includeSourceActions:!0}})})}),define(t[451],n([1,0,14,9,2,13,3,17,19,450]),function(e,t,n,i,o,r,s,a,l,u){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.SUPPORTED_CODE_ACTIONS=new l.RawContextKey("supportedCodeAction","");var d=function(){ +function e(e,t,n,o,r){void 0===o&&(o=250);var s=this;this._editor=e,this._markerService=t,this._signalChange=n,this._progressService=r,this._disposables=[],this._disposables.push(i.debounceEvent(this._markerService.onMarkerChanged,function(e,t){return e?e.concat(t):t},o/2)(function(e){return s._onMarkerChanges(e)}),i.debounceEvent(this._editor.onDidChangeCursorPosition,function(e,t){return t},o)(function(e){return s._onCursorChange()}))}return e.prototype.dispose=function(){this._disposables=o.dispose(this._disposables)},e.prototype.trigger=function(e){var t=this._getRangeOfSelectionUnlessWhitespaceEnclosed(e);return this._createEventAndSignalChange(e,t)},e.prototype._onMarkerChanges=function(e){for(var t=this._editor.getModel().uri,n=0,i=e;nt.symbol.range.startLineNumber?1:r.indexOf(e.provider)r.indexOf(t.provider)?1:e.symbol.range.startColumnt.symbol.range.startColumn?1:0})})}Object.defineProperty(t,"__esModule",{value:!0}),t.getCodeLensData=u,r.registerLanguageCommand("_executeCodeLensProvider",function(e,t){var i=t.resource,r=t.itemResolveCount;if(!(i instanceof o.default))throw n.illegalArgument();var s=e.get(a.IModelService).getModel(i);if(!s)throw n.illegalArgument();var d=[];return u(s,l.CancellationToken.None).then(function(e){for(var t=[],n=0,i=e;n0&&t.push(Promise.resolve(o.provider.resolveCodeLens(s,o.symbol,l.CancellationToken.None)).then(function(e){return d.push(e)}))}return Promise.all(t)}).then(function(){return d})})}),define(t[172],n([1,0,31,13,17,14,11,3,10,48]),function(e,t,n,i,o,r,s,a,l,u){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getColors=function(e,t){var n=[],i=o.ColorProviderRegistry.ordered(e).reverse().map(function(i){return Promise.resolve(i.provideDocumentColors(e,t)).then(function(e){if(Array.isArray(e))for(var t=0,o=e;t0&&s._contextViewService.hideContextView()})),this._toDispose.push(this._editor.onKeyDown(function(e){58===e.keyCode&&(e.preventDefault(),e.stopPropagation(),s.showContextMenu())}))}return e.get=function(t){return t.getContribution(e.ID)},e.prototype._onContextMenu=function(e){if(!this._editor.getConfiguration().contribInfo.contextmenu)return this._editor.focus(),void(e.target.position&&!this._editor.getSelection().containsPosition(e.target.position)&&this._editor.setPosition(e.target.position));if(e.target.type!==m.MouseTargetType.OVERLAY_WIDGET&&(e.event.preventDefault(), +e.target.type===m.MouseTargetType.CONTENT_TEXT||e.target.type===m.MouseTargetType.CONTENT_EMPTY||e.target.type===m.MouseTargetType.TEXTAREA)){this._editor.focus(),e.target.position&&!this._editor.getSelection().containsPosition(e.target.position)&&this._editor.setPosition(e.target.position);var t;e.target.type!==m.MouseTargetType.TEXTAREA&&(t={x:e.event.posx,y:e.event.posy+1}),this.showContextMenu(t)}},e.prototype.showContextMenu=function(e){if(this._editor.getConfiguration().contribInfo.contextmenu)if(this._contextMenuService){var t=this._getMenuActions();t.length>0&&this._doShowContextMenu(t,e)}else this._editor.focus()},e.prototype._getMenuActions=function(){var e=[],t=this._menuService.createMenu(p.MenuId.EditorContext,this._contextKeyService),n=t.getActions({arg:this._editor.getModel().uri});t.dispose();for(var i=0,o=n;i0&&this._contextViewService.hideContextView(),this._toDispose=i.dispose(this._toDispose)},e.ID="editor.contrib.contextmenu",e=a([u(1,d.IContextMenuService),u(2,d.IContextViewService),u(3,h.IContextKeyService),u(4,c.IKeybindingService),u(5,p.IMenuService)],e)}();t.ContextMenuController=v;var _=function(e){function t(){return e.call(this,{id:"editor.action.showContextMenu",label:n.localize(0,null),alias:"Show Editor Context Menu",precondition:null,kbOpts:{kbExpr:f.EditorContextKeys.textInputFocus,primary:1092,weight:100}})||this}return o(t,e),t.prototype.run=function(e,t){v.get(t).showContextMenu()},t}(g.EditorAction);g.registerEditorContribution(v),g.registerEditorAction(_)}),define(t[457],n([1,0,310,11,2,20]),function(e,t,n,i,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(e){this.selections=e} +return e.prototype.equals=function(e){var t=this.selections.length;if(t!==e.selections.length)return!1;for(var n=0;n50&&n._undoStack.shift()),n._prevState=n._readState()})),n}return o(t,e),t.get=function(e){return e.getContribution(t.ID)},t.prototype._readState=function(){return this._editor.getModel()?new a(this._editor.getSelections()):null},t.prototype.getId=function(){return t.ID},t.prototype.cursorUndo=function(){for(var e=new a(this._editor.getSelections());this._undoStack.length>0;){ +var t=this._undoStack.pop();if(!t.equals(e))return this._isCursorUndo=!0,this._editor.setSelections(t.selections),this._editor.revealRangeInCenterIfOutsideViewport(t.selections[0],0),void(this._isCursorUndo=!1)}},t.ID="editor.contrib.cursorUndoController",t}(r.Disposable);t.CursorUndoController=l;var u=function(e){function t(){return e.call(this,{id:"cursorUndo",label:n.localize(0,null),alias:"Soft Undo",precondition:null,kbOpts:{kbExpr:s.EditorContextKeys.textInputFocus,primary:2099,weight:100}})||this}return o(t,e),t.prototype.run=function(e,t,n){l.get(t).cursorUndo()},t}(i.EditorAction);t.CursorUndo=u,i.registerEditorContribution(l),i.registerEditorAction(u)}),define(t[458],n([1,0,2,18,23,11,12,3,21,242,29,372]),function(e,t,n,i,o,r,s,a,l,u,d){"use strict";function c(e){return i.isMacintosh?e.altKey:e.ctrlKey}Object.defineProperty(t,"__esModule",{value:!0});var h=function(){function e(e){var t=this;this._editor=e,this._toUnhook=[],this._toUnhook.push(this._editor.onMouseDown(function(e){ +return t._onEditorMouseDown(e)})),this._toUnhook.push(this._editor.onMouseUp(function(e){return t._onEditorMouseUp(e)})),this._toUnhook.push(this._editor.onMouseDrag(function(e){return t._onEditorMouseDrag(e)})),this._toUnhook.push(this._editor.onMouseDrop(function(e){return t._onEditorMouseDrop(e)})),this._toUnhook.push(this._editor.onKeyDown(function(e){return t.onEditorKeyDown(e)})),this._toUnhook.push(this._editor.onKeyUp(function(e){return t.onEditorKeyUp(e)})),this._dndDecorationIds=[],this._mouseDown=!1,this._modiferPressed=!1,this._dragSelection=null}return e.prototype.onEditorKeyDown=function(e){this._editor.getConfiguration().dragAndDrop&&(c(e)&&(this._modiferPressed=!0),this._mouseDown&&c(e)&&this._editor.updateOptions({mouseStyle:"copy"}))},e.prototype.onEditorKeyUp=function(t){this._editor.getConfiguration().dragAndDrop&&(c(t)&&(this._modiferPressed=!1),this._mouseDown&&t.keyCode===e.TRIGGER_KEY_VALUE&&this._editor.updateOptions({mouseStyle:"default"}))}, +e.prototype._onEditorMouseDown=function(e){this._mouseDown=!0},e.prototype._onEditorMouseUp=function(e){this._mouseDown=!1,this._editor.updateOptions({mouseStyle:"text"})},e.prototype._onEditorMouseDrag=function(e){var t=e.target;if(null===this._dragSelection){var n=this._editor.getSelections().filter(function(e){return e.containsPosition(t.position)});if(1!==n.length)return;this._dragSelection=n[0]}c(e.event)?this._editor.updateOptions({mouseStyle:"copy"}):this._editor.updateOptions({mouseStyle:"default"}),this._dragSelection.containsPosition(t.position)?this._removeDecoration():this.showAt(t.position)},e.prototype._onEditorMouseDrop=function(t){if(t.target&&(this._hitContent(t.target)||this._hitMargin(t.target))&&t.target.position){var n=new s.Position(t.target.position.lineNumber,t.target.position.column);if(null===this._dragSelection)if(t.event.shiftKey){var i=this._editor.getSelection(),o=i.startLineNumber,r=i.startColumn;this._editor.setSelections([new l.Selection(o,r,n.lineNumber,n.column)])}else{ +var a=this._editor.getSelections().map(function(e){return e.containsPosition(n)?new l.Selection(n.lineNumber,n.column,n.lineNumber,n.column):e});this._editor.setSelections(a)}else(!this._dragSelection.containsPosition(n)||(c(t.event)||this._modiferPressed)&&(this._dragSelection.getEndPosition().equals(n)||this._dragSelection.getStartPosition().equals(n)))&&(this._editor.pushUndoStop(),this._editor.executeCommand(e.ID,new u.DragAndDropCommand(this._dragSelection,n,c(t.event)||this._modiferPressed)),this._editor.pushUndoStop())}this._editor.updateOptions({mouseStyle:"text"}),this._removeDecoration(),this._dragSelection=null,this._mouseDown=!1},e.prototype.showAt=function(t){var n=[{range:new a.Range(t.lineNumber,t.column,t.lineNumber,t.column),options:e._DECORATION_OPTIONS}];this._dndDecorationIds=this._editor.deltaDecorations(this._dndDecorationIds,n),this._editor.revealPosition(t,1)},e.prototype._removeDecoration=function(){this._dndDecorationIds=this._editor.deltaDecorations(this._dndDecorationIds,[])}, +e.prototype._hitContent=function(e){return e.type===o.MouseTargetType.CONTENT_TEXT||e.type===o.MouseTargetType.CONTENT_EMPTY},e.prototype._hitMargin=function(e){return e.type===o.MouseTargetType.GUTTER_GLYPH_MARGIN||e.type===o.MouseTargetType.GUTTER_LINE_NUMBERS||e.type===o.MouseTargetType.GUTTER_LINE_DECORATIONS},e.prototype.getId=function(){return e.ID},e.prototype.dispose=function(){this._removeDecoration(),this._dragSelection=null,this._mouseDown=!1,this._modiferPressed=!1,this._toUnhook=n.dispose(this._toUnhook)},e.ID="editor.contrib.dragAndDrop",e.TRIGGER_KEY_VALUE=i.isMacintosh?6:5,e._DECORATION_OPTIONS=d.ModelDecorationOptions.register({className:"dnd-target"}),e}();t.DragAndDropController=h,r.registerEditorContribution(h)}),define(t[459],n([1,0,313,33,6,14,39,2,13,11,23,247,394,20,248,41,395,17,168,250,10,375]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m,v,_,y,C,b){"use strict";function S(e){if(!i.isUndefined(e)){if(!i.isObject(e))return!1;var t=e +;if(!i.isUndefined(t.levels)&&!i.isNumber(t.levels))return!1;if(!i.isUndefined(t.direction)&&!i.isString(t.direction))return!1;if(!(i.isUndefined(t.selectionLines)||i.isArray(t.selectionLines)&&t.selectionLines.every(i.isNumber)))return!1}return!0}Object.defineProperty(t,"__esModule",{value:!0}),t.ID="editor.contrib.folding";var w=function(){function e(e){var t=this;this.editor=e,this._isEnabled=this.editor.getConfiguration().contribInfo.folding,this._autoHideFoldingControls="mouseover"===this.editor.getConfiguration().contribInfo.showFoldingControls,this._useFoldingProviders="indentation"!==this.editor.getConfiguration().contribInfo.foldingStrategy,this.globalToDispose=[],this.localToDispose=[],this.foldingDecorationProvider=new p.FoldingDecorationProvider(e),this.foldingDecorationProvider.autoHideFoldingControls=this._autoHideFoldingControls,this.globalToDispose.push(this.editor.onDidChangeModel(function(){return t.onModelChanged()})), +this.globalToDispose.push(_.FoldingRangeProviderRegistry.onDidChange(function(){return t.onFoldingStrategyChanged()})),this.globalToDispose.push(this.editor.onDidChangeConfiguration(function(e){if(e.contribInfo){var n=t._isEnabled;t._isEnabled=t.editor.getConfiguration().contribInfo.folding,n!==t._isEnabled&&t.onModelChanged();var i=t._autoHideFoldingControls;t._autoHideFoldingControls="mouseover"===t.editor.getConfiguration().contribInfo.showFoldingControls,i!==t._autoHideFoldingControls&&(t.foldingDecorationProvider.autoHideFoldingControls=t._autoHideFoldingControls,t.onModelContentChanged());var o=t._useFoldingProviders;t._useFoldingProviders="indentation"!==t.editor.getConfiguration().contribInfo.foldingStrategy,o!==t._useFoldingProviders&&t.onFoldingStrategyChanged()}})),this.globalToDispose.push({dispose:function(){return l.dispose(t.localToDispose)}}),this.onModelChanged()}return e.get=function(e){return e.getContribution(t.ID)},e.prototype.getId=function(){return t.ID},e.prototype.dispose=function(){ +this.globalToDispose=l.dispose(this.globalToDispose)},e.prototype.saveViewState=function(){var e=this.editor.getModel();if(!e||!this._isEnabled||e.isTooLargeForTokenization())return{};if(this.foldingModel){var t=this.foldingModel.isInitialized?this.foldingModel.getMemento():this.hiddenRangeModel.getMemento(),n=this.rangeProvider?this.rangeProvider.id:void 0;return{collapsedRegions:t,lineCount:e.getLineCount(),provider:n}}},e.prototype.restoreViewState=function(e){var t=this.editor.getModel();t&&this._isEnabled&&!t.isTooLargeForTokenization()&&e&&e.collapsedRegions&&e.lineCount===t.getLineCount()&&(e.provider!==y.ID_SYNTAX_PROVIDER&&e.provider!==C.ID_INIT_PROVIDER||(this.foldingStateMemento=e),this.hiddenRangeModel.applyMemento(e.collapsedRegions)&&this.getFoldingModel().then(function(t){t&&t.applyMemento(e.collapsedRegions)}).done(void 0,b.onUnexpectedError))},e.prototype.onModelChanged=function(){var e=this;this.localToDispose=l.dispose(this.localToDispose);var t=this.editor.getModel() +;this._isEnabled&&t&&!t.isTooLargeForTokenization()&&(this.foldingModel=new h.FoldingModel(t,this.foldingDecorationProvider),this.localToDispose.push(this.foldingModel),this.hiddenRangeModel=new g.HiddenRangeModel(this.foldingModel),this.localToDispose.push(this.hiddenRangeModel),this.localToDispose.push(this.hiddenRangeModel.onDidChange(function(t){return e.onHiddenRangesChanges(t)})),this.updateScheduler=new s.Delayer(200),this.cursorChangedScheduler=new s.RunOnceScheduler(function(){return e.revealCursor()},200),this.localToDispose.push(this.cursorChangedScheduler),this.localToDispose.push(this.editor.onDidChangeModelLanguageConfiguration(function(t){return e.onModelContentChanged()})),this.localToDispose.push(this.editor.onDidChangeModelContent(function(t){return e.onModelContentChanged()})),this.localToDispose.push(this.editor.onDidChangeCursorPosition(function(t){return e.onCursorPositionChanged()})),this.localToDispose.push(this.editor.onMouseDown(function(t){return e.onEditorMouseDown(t)})), +this.localToDispose.push(this.editor.onMouseUp(function(t){return e.onEditorMouseUp(t)})),this.localToDispose.push({dispose:function(){e.foldingRegionPromise&&(e.foldingRegionPromise.cancel(),e.foldingRegionPromise=null),e.updateScheduler.cancel(),e.updateScheduler=null,e.foldingModel=null,e.foldingModelPromise=null,e.hiddenRangeModel=null,e.cursorChangedScheduler=null,e.foldingStateMemento=null,e.rangeProvider&&e.rangeProvider.dispose(),e.rangeProvider=null}}),this.onModelContentChanged())},e.prototype.onFoldingStrategyChanged=function(){this.rangeProvider&&this.rangeProvider.dispose(),this.rangeProvider=null,this.onModelContentChanged()},e.prototype.getRangeProvider=function(e){var t=this;if(this.rangeProvider)return this.rangeProvider;if(this.rangeProvider=new v.IndentRangeProvider(e),this._useFoldingProviders){var n=_.FoldingRangeProviderRegistry.ordered(this.foldingModel.textModel) +;if(0===n.length&&this.foldingStateMemento)return this.rangeProvider=new C.InitializingRangeProvider(e,this.foldingStateMemento.collapsedRegions,function(){t.foldingStateMemento=null,t.onFoldingStrategyChanged()},3e4),this.rangeProvider;n.length>0&&(this.rangeProvider=new y.SyntaxRangeProvider(e,n))}return this.foldingStateMemento=null,this.rangeProvider},e.prototype.getFoldingModel=function(){return this.foldingModelPromise},e.prototype.onModelContentChanged=function(){var e=this;this.updateScheduler&&(this.foldingRegionPromise&&(this.foldingRegionPromise.cancel(),this.foldingRegionPromise=null),this.foldingModelPromise=this.updateScheduler.trigger(function(){if(!e.foldingModel)return null;var t=e.foldingRegionPromise=s.createCancelablePromise(function(t){return e.getRangeProvider(e.foldingModel.textModel).compute(t)});return u.TPromise.wrap(t.then(function(n){if(n&&t===e.foldingRegionPromise){var i=e.editor.getSelections(),o=i?i.map(function(e){return e.startLineNumber}):[];e.foldingModel.update(n,o)} +return e.foldingModel}))}))},e.prototype.onHiddenRangesChanges=function(e){if(e.length){var t=this.editor.getSelections();t&&this.hiddenRangeModel.adjustSelections(t)&&this.editor.setSelections(t)}this.editor.setHiddenAreas(e)},e.prototype.onCursorPositionChanged=function(){this.hiddenRangeModel.hasRanges()&&this.cursorChangedScheduler.schedule()},e.prototype.revealCursor=function(){var e=this;this.getFoldingModel().then(function(t){if(t){var n=e.editor.getSelections();if(n&&n.length>0){for(var i=[],o=function(n){var o=n.selectionStartLineNumber;e.hiddenRangeModel.isHidden(o)&&i.push.apply(i,t.getAllRegionsAtLine(o,function(e){return e.isCollapsed&&o>e.startLineNumber}))},r=0,s=n;r1)){var n=this.editor.getModel(),o=this.editor.getPosition(),r=!1,s=this.editor.onDidChangeModelContent(function(e){if(e.isFlush)return r=!0,void s.dispose();for(var t=0,n=e.changes.length;t1)){var n=this.editor.getModel(),o=n.getOptions(),r=o.tabSize,s=o.insertSpaces,a=new b.EditorState(this.editor,5) +;p.getDocumentRangeFormattingEdits(n,e,{tabSize:r,insertSpaces:s}).then(function(e){return t.workerService.computeMoreMinimalEdits(n.uri,e)}).then(function(e){a.validate(t.editor)&&!i.isFalsyOrEmpty(e)&&(f.FormattingEdit.execute(t.editor,e),E(e))})}},e.prototype.getId=function(){return e.ID},e.prototype.dispose=function(){this.callOnDispose=s.dispose(this.callOnDispose),this.callOnModel=s.dispose(this.callOnModel)},e.ID="editor.contrib.formatOnPaste",e=a([u(1,v.IEditorWorkerService)],e)}(),N=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype.run=function(e,t){var n=this,o=e.get(v.IEditorWorkerService),r=e.get(w.INotificationService),s=this._getFormattingEdits(t);if(!s)return l.TPromise.as(void 0);var a=new b.EditorState(t,5);return s.then(function(e){return o.computeMoreMinimalEdits(t.getModel().uri,e)}).then(function(e){a.validate(t)&&!i.isFalsyOrEmpty(e)&&(f.FormattingEdit.execute(t,e),E(e),t.focus())},function(e){ +if(!(e instanceof Error&&e.name===p.NoProviderError.Name))throw e;n._notifyNoProviderError(r,t.getModel().getLanguageIdentifier().language)})},t.prototype._notifyNoProviderError=function(e,t){e.info(n.localize(4,null,t))},t}(c.EditorAction);t.AbstractFormatAction=N;var I=function(e){function t(){return e.call(this,{id:"editor.action.formatDocument",label:n.localize(5,null),alias:"Format Document",precondition:S.EditorContextKeys.writable,kbOpts:{kbExpr:S.EditorContextKeys.editorTextFocus,primary:1572,linux:{primary:3111},weight:100},menuOpts:{when:S.EditorContextKeys.hasDocumentFormattingProvider,group:"1_modification",order:1.3}})||this}return o(t,e),t.prototype._getFormattingEdits=function(e){var t=e.getModel(),n=t.getOptions(),i=n.tabSize,o=n.insertSpaces;return p.getDocumentFormattingEdits(t,{tabSize:i,insertSpaces:o})},t.prototype._notifyNoProviderError=function(e,t){e.info(n.localize(6,null,t))},t}(N);t.FormatDocumentAction=I;var M=function(e){function t(){return e.call(this,{ +id:"editor.action.formatSelection",label:n.localize(7,null),alias:"Format Code",precondition:d.ContextKeyExpr.and(S.EditorContextKeys.writable,S.EditorContextKeys.hasNonEmptySelection),kbOpts:{kbExpr:S.EditorContextKeys.editorTextFocus,primary:r.KeyChord(2089,2084),weight:100},menuOpts:{when:d.ContextKeyExpr.and(S.EditorContextKeys.hasDocumentSelectionFormattingProvider,S.EditorContextKeys.hasNonEmptySelection),group:"1_modification",order:1.31}})||this}return o(t,e),t.prototype._getFormattingEdits=function(e){var t=e.getModel(),n=t.getOptions(),i=n.tabSize,o=n.insertSpaces;return p.getDocumentRangeFormattingEdits(t,e.getSelection(),{tabSize:i,insertSpaces:o})},t.prototype._notifyNoProviderError=function(e,t){e.info(n.localize(8,null,t))},t}(N);t.FormatSelectionAction=M,c.registerEditorContribution(L),c.registerEditorContribution(x),c.registerEditorAction(I),c.registerEditorAction(M),g.CommandsRegistry.registerCommand("editor.action.format",function(e){var t=e.get(m.ICodeEditorService).getFocusedCodeEditor() +;if(t)return(new(function(e){function t(){return e.call(this,{})||this}return o(t,e),t.prototype._getFormattingEdits=function(e){var t=e.getModel(),n=e.getSelection(),i=t.getOptions(),o=i.tabSize,r=i.insertSpaces;return n.isEmpty()?p.getDocumentFormattingEdits(t,{tabSize:o,insertSpaces:r}):p.getDocumentRangeFormattingEdits(t,n,{tabSize:o,insertSpaces:r})},t}(N))).run(e,t)})}),define(t[174],n([1,0,25,14,10,13,11,17]),function(e,t,n,i,o,r,s,a){"use strict";function l(e,t,s,a){var l=s.ordered(e).map(function(n){return i.asWinJsPromise(function(i){return a(n,e,t,i)}).then(void 0,function(e){return o.onUnexpectedExternalError(e),null})});return r.TPromise.join(l).then(n.flatten).then(function(e){return n.coalesce(e)})}function u(e,t){return l(e,t,a.DefinitionProviderRegistry,function(e,t,n,i){return e.provideDefinition(t,n,i)})}function d(e,t){return l(e,t,a.ImplementationProviderRegistry,function(e,t,n,i){return e.provideImplementation(t,n,i)})}function c(e,t){ +return l(e,t,a.TypeDefinitionProviderRegistry,function(e,t,n,i){return e.provideTypeDefinition(t,n,i)})}Object.defineProperty(t,"__esModule",{value:!0}),t.getDefinitionsAtPosition=u,t.getImplementationsAtPosition=d,t.getTypeDefinitionsAtPosition=c,s.registerDefaultLanguageCommand("_executeDefinitionProvider",u),s.registerDefaultLanguageCommand("_executeImplementationProvider",d),s.registerDefaultLanguageCommand("_executeTypeDefinitionProvider",c)}),define(t[464],n([1,0,25,10,11,17,40]),function(e,t,n,i,o,r,s){"use strict";function a(e,t,o){var s=r.HoverProviderRegistry.ordered(e).map(function(n){return Promise.resolve(n.provideHover(e,t,o)).then(function(e){return e&&function(e){var t=void 0!==e.range,n=void 0!==e.contents&&e.contents&&e.contents.length>0;return t&&n}(e)?e:void 0},function(e){i.onUnexpectedExternalError(e)})});return Promise.all(s).then(function(e){return n.coalesce(e)})}Object.defineProperty(t,"__esModule",{value:!0}),t.getHover=a, +o.registerDefaultLanguageCommand("_executeHoverProvider",function(e,t){return a(e,t,s.CancellationToken.None)})}),define(t[465],n([1,0,323,39,260,53,431,20,76,3,21,12,11,258,259,396,139,133,44]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m,v,_,y){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var C=function(e){function t(t,n){var i=e.call(this,n)||this;return i.down=t,i}return o(t,e),t.prototype.run=function(e,t){for(var n=[],i=t.getSelections(),o=0;o0){var s=t.startLineNumber-o;r=new c.Selection(s,t.startColumn,s,t.startColumn) +}else r=new c.Selection(t.startLineNumber,t.startColumn,t.startLineNumber,t.startColumn);o+=t.endLineNumber-t.startLineNumber,t.intersectRanges(e)?n=r:i.push(r)}),n&&i.unshift(n),i},t.prototype._getRangesToDelete=function(e){var t=e.getSelections(),n=e.getModel();return t.sort(d.Range.compareRangesUsingStarts),t=t.map(function(e){if(e.isEmpty()){if(1===e.startColumn){var t=Math.max(1,e.startLineNumber-1),i=1===e.startLineNumber?1:n.getLineContent(t).length+1;return new d.Range(t,i,e.startLineNumber,1)}return new d.Range(e.startLineNumber,1,e.startLineNumber,e.startColumn)}return e})},t}(P);t.DeleteAllLeftAction=A;var F=function(e){function t(){return e.call(this,{id:"deleteAllRight",label:n.localize(17,null),alias:"Delete All Right",precondition:l.EditorContextKeys.writable,kbOpts:{kbExpr:l.EditorContextKeys.textInputFocus,primary:null,mac:{primary:297,secondary:[2068]},weight:100}})||this}return o(t,e),t.prototype._getEndCursorState=function(e,t){for(var n,i=[],o=0,r=t.length;oe.endLineNumber+1?(o.push(e),t):new c.Selection(e.startLineNumber,e.startColumn,t.endLineNumber,t.endColumn):t.startLineNumber>e.endLineNumber?(o.push(e),t):new c.Selection(e.startLineNumber,e.startColumn,t.endLineNumber,t.endColumn)});o.push(r);for(var a=t.getModel(),l=[],u=[],h=i,p=0,f=0,g=o.length;f=1){var N=!0;""===w&&(N=!1),!N||" "!==w.charAt(w.length-1)&&"\t"!==w.charAt(w.length-1)||(N=!1,w=w.replace(/[\s\uFEFF\xA0]+$/g," ")) +;var I=L.substr(x-1);w+=(N?" ":"")+I,_=N?I.length+1:I.length}else _=0}var M=new d.Range(v,1,y,C);if(!M.isEmpty()){var D=void 0;m.isEmpty()?(l.push(s.EditOperation.replace(M,w)),D=new c.Selection(M.startLineNumber-p,w.length-_+1,v-p,w.length-_+1)):m.startLineNumber===m.endLineNumber?(l.push(s.EditOperation.replace(M,w)),D=new c.Selection(m.startLineNumber-p,m.startColumn,m.endLineNumber-p,m.endColumn)):(l.push(s.EditOperation.replace(M,w)),D=new c.Selection(m.startLineNumber-p,m.startColumn,m.startLineNumber-p,w.length-b)),null!==d.Range.intersectRanges(M,i)?h=D:u.push(D)}p+=M.endLineNumber-M.startLineNumber}u.unshift(h),t.pushUndoStop(),t.executeEdits(this.id,l,u),t.pushUndoStop()},t}(p.EditorAction);t.JoinLinesAction=W;var V=function(e){function t(){return e.call(this,{id:"editor.action.transpose",label:n.localize(19,null),alias:"Transpose characters around the cursor",precondition:l.EditorContextKeys.writable})||this}return o(t,e),t.prototype.run=function(e,t){ +for(var n=t.getSelections(),i=t.getModel(),o=[],r=0,s=n.length;r=h){if(l.lineNumber===i.getLineCount())continue;var p=new d.Range(l.lineNumber,Math.max(1,l.column-1),l.lineNumber+1,1),f=i.getValueInRange(p).split("").reverse().join("");o.push(new u.ReplaceCommand(new c.Selection(l.lineNumber,Math.max(1,l.column-1),l.lineNumber+1,1),f))}else{var p=new d.Range(l.lineNumber,Math.max(1,l.column-1),l.lineNumber,l.column+1),f=i.getValueInRange(p).split("").reverse().join("");o.push(new u.ReplaceCommandThatPreservesSelection(p,f,new c.Selection(l.lineNumber,l.column+1,l.lineNumber,l.column+1)))}}}t.pushUndoStop(),t.executeCommands(this.id,o),t.pushUndoStop()},t}(p.EditorAction);t.TransposeAction=V;var B=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype.run=function(e,t){for(var n=t.getSelections(),i=t.getModel(),o=[],r=0,s=n.length;r")}},e.prototype._doInsert=function(e,t,n,i,s){var a=this;void 0===t&&(t=0),void 0===n&&(n=0),void 0===i&&(i=!0),void 0===s&&(s=!0),this._snippetListener=o.dispose(this._snippetListener),i&&this._editor.getModel().pushStackElement(),this._session?this._session.merge(e,t,n):(this._modelVersionId=this._editor.getModel().getAlternativeVersionId(),this._session=new r.SnippetSession(this._editor,e,t,n),this._session.insert()),s&&this._editor.getModel().pushStackElement(),this._updateState(),this._snippetListener=[this._editor.onDidChangeModelContent(function(e){return e.isFlush&&a.cancel() +}),this._editor.onDidChangeModel(function(){return a.cancel()}),this._editor.onDidChangeCursorSelection(function(){return a._updateState()})]},e.prototype._updateState=function(){if(this._session){if(this._modelVersionId===this._editor.getModel().getAlternativeVersionId())return this.cancel();if(!this._session.hasPlaceholder)return this.cancel();if(this._session.isAtLastPlaceholder||!this._session.isSelectionWithinPlaceholders())return this.cancel();this._inSnippet.set(!0),this._hasPrevTabstop.set(!this._session.isAtFirstPlaceholder),this._hasNextTabstop.set(!this._session.isAtLastPlaceholder),this._handleChoice()}},e.prototype._handleChoice=function(){var e=this._session.choice;if(e){if(this._currentChoice!==e){this._currentChoice=e,this._editor.setSelections(this._editor.getSelections().map(function(e){return d.Selection.fromPositions(e.getStartPosition())}));var t=e.options[0];l.showSimpleSuggestions(this._editor,e.options.map(function(e,n){return{type:"value",label:e.value,insertText:e.value, +sortText:c.repeat("a",n),overwriteAfter:t.value.length}}))}}else this._currentChoice=void 0},e.prototype.finish=function(){for(;this._inSnippet.get();)this.next()},e.prototype.cancel=function(){this._inSnippet.reset(),this._hasPrevTabstop.reset(),this._hasNextTabstop.reset(),o.dispose(this._snippetListener),o.dispose(this._session),this._session=void 0,this._modelVersionId=-1},e.prototype.prev=function(){this._session.prev(),this._updateState()},e.prototype.next=function(){this._session.next(),this._updateState()},e.prototype.isInSnippet=function(){return this._inSnippet.get()},e.InSnippetMode=new n.RawContextKey("inSnippetMode",!1),e.HasNextTabstop=new n.RawContextKey("hasNextTabstop",!1),e.HasPrevTabstop=new n.RawContextKey("hasPrevTabstop",!1),e=a([u(1,h.ILogService),u(2,n.IContextKeyService)],e)}();t.SnippetController2=p,i.registerEditorContribution(p);var f=i.EditorCommand.bindToContribution(p.get);i.registerEditorCommand(new f({id:"jumpToNextSnippetPlaceholder", +precondition:n.ContextKeyExpr.and(p.InSnippetMode,p.HasNextTabstop),handler:function(e){return e.next()},kbOpts:{weight:130,kbExpr:s.EditorContextKeys.editorTextFocus,primary:2}})),i.registerEditorCommand(new f({id:"jumpToPrevSnippetPlaceholder",precondition:n.ContextKeyExpr.and(p.InSnippetMode,p.HasPrevTabstop),handler:function(e){return e.prev()},kbOpts:{weight:130,kbExpr:s.EditorContextKeys.editorTextFocus,primary:1026}})),i.registerEditorCommand(new f({id:"leaveSnippet",precondition:p.InSnippetMode,handler:function(e){return e.cancel()},kbOpts:{weight:130,kbExpr:s.EditorContextKeys.editorTextFocus,primary:9,secondary:[1033]}})),i.registerEditorCommand(new f({id:"acceptSnippet",precondition:p.InSnippetMode,handler:function(e){return e.finish()}}))}),define(t[471],n([1,0,25,14,10,9,2,70,54,21,17,298,101,135]),function(e,t,n,i,o,r,s,a,l,u,d,c,h,p){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var f=function(){function e(e,t,n){ +this.leadingLineContent=e.getLineContent(t.lineNumber).substr(0,t.column-1),this.leadingWord=e.getWordUntilPosition(t),this.lineNumber=t.lineNumber,this.column=t.column,this.auto=n}return e.shouldAutoTrigger=function(e){var t=e.getModel();if(!t)return!1;var n=e.getPosition();t.tokenizeIfCheap(n.lineNumber);var i=t.getWordAtPosition(n);return!!i&&(i.endColumn===n.column&&!!isNaN(Number(i.word)))},e}();t.LineContext=f;var g=function(){function e(e){var t=this;this._toDispose=[],this._triggerQuickSuggest=new i.TimeoutTimer,this._triggerRefilter=new i.TimeoutTimer,this._onDidCancel=new r.Emitter,this._onDidTrigger=new r.Emitter,this._onDidSuggest=new r.Emitter,this.onDidCancel=this._onDidCancel.event,this.onDidTrigger=this._onDidTrigger.event,this.onDidSuggest=this._onDidSuggest.event,this._editor=e,this._state=0,this._requestPromise=null,this._completionModel=null,this._context=null,this._currentSelection=this._editor.getSelection()||new u.Selection(1,1,1,1), +this._toDispose.push(this._editor.onDidChangeModel(function(){t._updateTriggerCharacters(),t.cancel()})),this._toDispose.push(this._editor.onDidChangeModelLanguage(function(){t._updateTriggerCharacters(),t.cancel()})),this._toDispose.push(this._editor.onDidChangeConfiguration(function(){t._updateTriggerCharacters(),t._updateQuickSuggest()})),this._toDispose.push(d.SuggestRegistry.onDidChange(function(){t._updateTriggerCharacters(),t._updateActiveSuggestSession()})),this._toDispose.push(this._editor.onDidChangeCursorSelection(function(e){t._onCursorChange(e)})),this._toDispose.push(this._editor.onDidChangeModelContent(function(e){t._refilterCompletionItems()})),this._updateTriggerCharacters(),this._updateQuickSuggest()}return e.prototype.dispose=function(){s.dispose([this._onDidCancel,this._onDidSuggest,this._onDidTrigger,this._triggerCharacterListener,this._triggerQuickSuggest,this._triggerRefilter]),this._toDispose=s.dispose(this._toDispose),s.dispose(this._completionModel),this.cancel()}, +e.prototype._updateQuickSuggest=function(){this._quickSuggestDelay=this._editor.getConfiguration().contribInfo.quickSuggestionsDelay,(isNaN(this._quickSuggestDelay)||!this._quickSuggestDelay&&0!==this._quickSuggestDelay||this._quickSuggestDelay<0)&&(this._quickSuggestDelay=10)},e.prototype._updateTriggerCharacters=function(){var e=this;if(s.dispose(this._triggerCharacterListener),!this._editor.getConfiguration().readOnly&&this._editor.getModel()&&this._editor.getConfiguration().contribInfo.suggestOnTriggerCharacters){for(var t=Object.create(null),i=0,o=d.SuggestRegistry.all(this._editor.getModel());ithis._context.column&&this._completionModel.incomplete.size>0&&0!==e.leadingWord.word.length){var t=this._completionModel.incomplete,n=this._completionModel.adopt(t);this.trigger({auto:2===this._state},!0,a.values(t),n)}else{var i=this._completionModel.lineContext,o=!1;if(this._completionModel.lineContext={ +leadingLineContent:e.leadingLineContent,characterCountDelta:e.column-this._context.column},0===this._completionModel.items.length){if(f.shouldAutoTrigger(this._editor)&&this._context.leadingWord.endColumn0)&&0===e.leadingWord.word.length)return void this.cancel()}this._onDidSuggest.fire({completionModel:this._completionModel,auto:this._context.auto,isFrozen:o})}}else this.cancel()},e}();t.SuggestModel=g}),define(t[178],n([1,0,342,11,126]),function(e,t,n,i,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=function(e){function t(){return e.call(this,{id:t.ID,label:n.localize(0,null),alias:"Toggle Tab Key Moves Focus",precondition:null,kbOpts:{kbExpr:null,primary:2091,mac:{primary:1323},weight:100}})||this}return o(t,e),t.prototype.run=function(e,t){var n=r.TabFocus.getTabFocusMode() +;r.TabFocus.setTabFocusMode(!n)},t.ID="editor.action.toggleTabFocusMode",t}(i.EditorAction);t.ToggleTabFocusModeAction=s,i.registerEditorAction(s)}),define(t[179],n([1,0,20,21,11,12,3,140,76,89,38,54]),function(e,t,n,i,r,s,a,l,u,d,c,h){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var p=function(e){function t(t){var n=e.call(this,t)||this;return n._inSelectionMode=t.inSelectionMode,n._wordNavigationType=t.wordNavigationType,n}return o(t,e),t.prototype.runEditorCommand=function(e,t,n){var i=this,o=t.getConfiguration(),r=d.getMapForWordSeparators(o.wordSeparators),a=t.getModel(),l=t.getSelections().map(function(e){var t=new s.Position(e.positionLineNumber,e.positionColumn),n=i._move(r,a,t,i._wordNavigationType);return i._moveTo(e,n,i._inSelectionMode)});if(t._getCursors().setStates("moveWordCommand",h.CursorChangeReason.NotSet,l.map(function(e){return c.CursorState.fromModelSelection(e)})),1===l.length){var u=new s.Position(l[0].positionLineNumber,l[0].positionColumn);t.revealPosition(u,0)}}, +t.prototype._moveTo=function(e,t,n){return n?new i.Selection(e.selectionStartLineNumber,e.selectionStartColumn,t.lineNumber,t.column):new i.Selection(t.lineNumber,t.column,t.lineNumber,t.column)},t}(r.EditorCommand);t.MoveWordCommand=p;var f=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype._move=function(e,t,n,i){return l.WordOperations.moveWordLeft(e,t,n,i)},t}(p);t.WordLeftCommand=f;var g=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype._move=function(e,t,n,i){return l.WordOperations.moveWordRight(e,t,n,i)},t}(p);t.WordRightCommand=g;var m=function(e){function t(){return e.call(this,{inSelectionMode:!1,wordNavigationType:0,id:"cursorWordStartLeft",precondition:null,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:2063,mac:{primary:527},weight:100}})||this}return o(t,e),t}(f);t.CursorWordStartLeft=m;var v=function(e){function t(){return e.call(this,{inSelectionMode:!1,wordNavigationType:1, +id:"cursorWordEndLeft",precondition:null})||this}return o(t,e),t}(f);t.CursorWordEndLeft=v;var _=function(e){function t(){return e.call(this,{inSelectionMode:!1,wordNavigationType:0,id:"cursorWordLeft",precondition:null})||this}return o(t,e),t}(f);t.CursorWordLeft=_;var y=function(e){function t(){return e.call(this,{inSelectionMode:!0,wordNavigationType:0,id:"cursorWordStartLeftSelect",precondition:null,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:3087,mac:{primary:1551},weight:100}})||this}return o(t,e),t}(f);t.CursorWordStartLeftSelect=y;var C=function(e){function t(){return e.call(this,{inSelectionMode:!0,wordNavigationType:1,id:"cursorWordEndLeftSelect",precondition:null})||this}return o(t,e),t}(f);t.CursorWordEndLeftSelect=C;var b=function(e){function t(){return e.call(this,{inSelectionMode:!0,wordNavigationType:0,id:"cursorWordLeftSelect",precondition:null})||this}return o(t,e),t}(f);t.CursorWordLeftSelect=b;var S=function(e){function t(){return e.call(this,{inSelectionMode:!1, +wordNavigationType:0,id:"cursorWordStartRight",precondition:null})||this}return o(t,e),t}(g);t.CursorWordStartRight=S;var w=function(e){function t(){return e.call(this,{inSelectionMode:!1,wordNavigationType:1,id:"cursorWordEndRight",precondition:null,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:2065,mac:{primary:529},weight:100}})||this}return o(t,e),t}(g);t.CursorWordEndRight=w;var E=function(e){function t(){return e.call(this,{inSelectionMode:!1,wordNavigationType:1,id:"cursorWordRight",precondition:null})||this}return o(t,e),t}(g);t.CursorWordRight=E;var L=function(e){function t(){return e.call(this,{inSelectionMode:!0,wordNavigationType:0,id:"cursorWordStartRightSelect",precondition:null})||this}return o(t,e),t}(g);t.CursorWordStartRightSelect=L;var x=function(e){function t(){return e.call(this,{inSelectionMode:!0,wordNavigationType:1,id:"cursorWordEndRightSelect",precondition:null,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:3089,mac:{primary:1553},weight:100}})||this} +return o(t,e),t}(g);t.CursorWordEndRightSelect=x;var N=function(e){function t(){return e.call(this,{inSelectionMode:!0,wordNavigationType:1,id:"cursorWordRightSelect",precondition:null})||this}return o(t,e),t}(g);t.CursorWordRightSelect=N;var I=function(e){function t(t){var n=e.call(this,t)||this;return n._whitespaceHeuristics=t.whitespaceHeuristics,n._wordNavigationType=t.wordNavigationType,n}return o(t,e),t.prototype.runEditorCommand=function(e,t,n){var i=this,o=t.getConfiguration(),r=d.getMapForWordSeparators(o.wordSeparators),s=t.getModel(),a=t.getSelections().map(function(e){var t=i._delete(r,s,e,i._whitespaceHeuristics,i._wordNavigationType);return new u.ReplaceCommand(t,"")});t.pushUndoStop(),t.executeCommands(this.id,a),t.pushUndoStop()},t}(r.EditorCommand);t.DeleteWordCommand=I;var M=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype._delete=function(e,t,n,i,o){var r=l.WordOperations.deleteWordLeft(e,t,n,i,o);return r||new a.Range(1,1,1,1)},t}(I) +;t.DeleteWordLeftCommand=M;var D=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype._delete=function(e,t,n,i,o){var r=l.WordOperations.deleteWordRight(e,t,n,i,o);if(r)return r;var s=t.getLineCount(),u=t.getLineMaxColumn(s);return new a.Range(s,u,s,u)},t}(I);t.DeleteWordRightCommand=D;var T=function(e){function t(){return e.call(this,{whitespaceHeuristics:!1,wordNavigationType:0,id:"deleteWordStartLeft",precondition:n.EditorContextKeys.writable})||this}return o(t,e),t}(M);t.DeleteWordStartLeft=T;var k=function(e){function t(){return e.call(this,{whitespaceHeuristics:!1,wordNavigationType:1,id:"deleteWordEndLeft",precondition:n.EditorContextKeys.writable})||this}return o(t,e),t}(M);t.DeleteWordEndLeft=k;var R=function(e){function t(){return e.call(this,{whitespaceHeuristics:!0,wordNavigationType:0,id:"deleteWordLeft",precondition:n.EditorContextKeys.writable,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:2049,mac:{primary:513},weight:100}})||this} +return o(t,e),t}(M);t.DeleteWordLeft=R;var O=function(e){function t(){return e.call(this,{whitespaceHeuristics:!1,wordNavigationType:0,id:"deleteWordStartRight",precondition:n.EditorContextKeys.writable})||this}return o(t,e),t}(D);t.DeleteWordStartRight=O;var P=function(e){function t(){return e.call(this,{whitespaceHeuristics:!1,wordNavigationType:1,id:"deleteWordEndRight",precondition:n.EditorContextKeys.writable})||this}return o(t,e),t}(D);t.DeleteWordEndRight=P;var A=function(e){function t(){return e.call(this,{whitespaceHeuristics:!0,wordNavigationType:1,id:"deleteWordRight",precondition:n.EditorContextKeys.writable,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:2068,mac:{primary:532},weight:100}})||this}return o(t,e),t}(D);t.DeleteWordRight=A,r.registerEditorCommand(new m),r.registerEditorCommand(new v),r.registerEditorCommand(new _),r.registerEditorCommand(new y),r.registerEditorCommand(new C),r.registerEditorCommand(new b),r.registerEditorCommand(new S),r.registerEditorCommand(new w), +r.registerEditorCommand(new E),r.registerEditorCommand(new L),r.registerEditorCommand(new x),r.registerEditorCommand(new N),r.registerEditorCommand(new T),r.registerEditorCommand(new k),r.registerEditorCommand(new R),r.registerEditorCommand(new O),r.registerEditorCommand(new P),r.registerEditorCommand(new A)}),define(t[474],n([1,0,20,11,3,140,179,34]),function(e,t,n,i,r,s,a,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=function(e){function t(){return e.call(this,{whitespaceHeuristics:!0,wordNavigationType:0,id:"deleteWordPartLeft",precondition:n.EditorContextKeys.writable,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:0,mac:{primary:769},weight:100}})||this}return o(t,e),t.prototype._delete=function(e,t,n,i,o){var a=s.WordPartOperations.deleteWordPartLeft(e,t,n,i,o);return a||new r.Range(1,1,1,1)},t}(a.DeleteWordCommand);t.DeleteWordPartLeft=u;var d=function(e){function t(){return e.call(this,{whitespaceHeuristics:!0,wordNavigationType:1,id:"deleteWordPartRight", +precondition:n.EditorContextKeys.writable,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:0,mac:{primary:788},weight:100}})||this}return o(t,e),t.prototype._delete=function(e,t,n,i,o){var a=s.WordPartOperations.deleteWordPartRight(e,t,n,i,o);if(a)return a;var l=t.getLineCount(),u=t.getLineMaxColumn(l);return new r.Range(l,u,l,u)},t}(a.DeleteWordCommand);t.DeleteWordPartRight=d;var c=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype._move=function(e,t,n,i){return s.WordPartOperations.moveWordPartLeft(e,t,n,i)},t}(a.MoveWordCommand);t.WordPartLeftCommand=c;var h=function(e){function t(){return e.call(this,{inSelectionMode:!1,wordNavigationType:0,id:"cursorWordPartLeft",precondition:null,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:0,mac:{primary:783},weight:100}})||this}return o(t,e),t}(c);t.CursorWordPartLeft=h,l.CommandsRegistry.registerCommandAlias("cursorWordPartStartLeft","cursorWordPartLeft");var p=function(e){function t(){ +return e.call(this,{inSelectionMode:!0,wordNavigationType:0,id:"cursorWordPartLeftSelect",precondition:null,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:0,mac:{primary:1807},weight:100}})||this}return o(t,e),t}(c);t.CursorWordPartLeftSelect=p,l.CommandsRegistry.registerCommandAlias("cursorWordPartStartLeftSelect","cursorWordPartLeftSelect");var f=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype._move=function(e,t,n,i){return s.WordPartOperations.moveWordPartRight(e,t,n,i)},t}(a.MoveWordCommand);t.WordPartRightCommand=f;var g=function(e){function t(){return e.call(this,{inSelectionMode:!1,wordNavigationType:1,id:"cursorWordPartRight",precondition:null,kbOpts:{kbExpr:n.EditorContextKeys.textInputFocus,primary:0,mac:{primary:785},weight:100}})||this}return o(t,e),t}(f);t.CursorWordPartRight=g;var m=function(e){function t(){return e.call(this,{inSelectionMode:!0,wordNavigationType:1,id:"cursorWordPartRightSelect",precondition:null,kbOpts:{ +kbExpr:n.EditorContextKeys.textInputFocus,primary:0,mac:{primary:1809},weight:100}})||this}return o(t,e),t}(f);t.CursorWordPartRightSelect=m,i.registerEditorCommand(new u),i.registerEditorCommand(new d),i.registerEditorCommand(new h),i.registerEditorCommand(new p),i.registerEditorCommand(new g),i.registerEditorCommand(new m)}),define(t[475],n([1,0,2,30,7,23,11,404]),function(e,t,n,i,o,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(){function e(e){var t=this;this.editor=e,this.toDispose=[],i.isIPad&&(this.toDispose.push(e.onDidChangeConfiguration(function(){return t.update()})),this.update())}return e.prototype.update=function(){var e=!!this.widget,t=!this.editor.getConfiguration().readOnly;!e&&t?this.widget=new l(this.editor):e&&!t&&(this.widget.dispose(),this.widget=null)},e.prototype.getId=function(){return e.ID},e.prototype.dispose=function(){this.toDispose=n.dispose(this.toDispose),this.widget&&(this.widget.dispose(),this.widget=null)}, +e.ID="editor.contrib.iPadShowKeyboard",e}();t.IPadShowKeyboard=a;var l=function(){function e(e){var t=this;this.editor=e,this._domNode=document.createElement("textarea"),this._domNode.className="iPadShowKeyboard",this._toDispose=[],this._toDispose.push(o.addDisposableListener(this._domNode,"touchstart",function(e){t.editor.focus()})),this._toDispose.push(o.addDisposableListener(this._domNode,"focus",function(e){t.editor.focus()})),this.editor.addOverlayWidget(this)}return e.prototype.dispose=function(){this.editor.removeOverlayWidget(this),this._toDispose=n.dispose(this._toDispose)},e.prototype.getId=function(){return e.ID},e.prototype.getDomNode=function(){return this._domNode},e.prototype.getPosition=function(){return{preference:r.OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER}},e.ID="editor.contrib.ShowKeyboardWidget",e}();s.registerEditorContribution(a)}),define(t[476],n([1,0,351,11,84]),function(e,t,n,i,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=function(e){function t(){ +var t=e.call(this,{id:"editor.action.toggleHighContrast",label:n.localize(0,null),alias:"Toggle High Contrast Theme",precondition:null})||this;return t._originalThemeName=null,t}return o(t,e),t.prototype.run=function(e,t){var n=e.get(r.IStandaloneThemeService);this._originalThemeName?(n.setTheme(this._originalThemeName),this._originalThemeName=null):(this._originalThemeName=n.getTheme().themeName,n.setTheme("hc-black"))},t}(i.EditorAction);i.registerEditorAction(s)}),define(t[477],n([1,0,197,86,117]),function(e,t,n,i,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t,i){this.logService=i,this.contextView=new n.ContextView(e)}return e.prototype.dispose=function(){this.contextView.dispose()},e.prototype.setContainer=function(e){this.logService.trace("ContextViewService#setContainer"),this.contextView.setContainer(e)},e.prototype.showContextView=function(e){this.logService.trace("ContextViewService#showContextView"),this.contextView.show(e)}, +e.prototype.layout=function(){this.contextView.layout()},e.prototype.hideContextView=function(e){this.logService.trace("ContextViewService#hideContextView"),this.contextView.hide(e)},e=a([u(1,i.ITelemetryService),u(2,o.ILogService)],e)}();t.ContextViewService=r}),define(t[478],n([1,0,13]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.NullTelemetryService=new(function(){function e(){}return e.prototype.publicLog=function(e,t){return n.TPromise.wrap(null)},e.prototype.getTelemetryInfo=function(){return n.TPromise.wrap({instanceId:"someValue.instanceId",sessionId:"someValue.sessionId",machineId:"someValue.machineId"})},e}())}),define(t[479],n([1,0,7,480,61,13,32,50,34,86,15,478]),function(e,t,n,i,o,r,s,l,d,c,h,p){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var f=function(){function e(e,t,n){void 0===n&&(n=p.NullTelemetryService),this._editorService=e,this._commandService=t,this._telemetryService=n}return e.prototype.open=function(e,t){var s +;this._telemetryService.publicLog("openerService",{scheme:e.scheme});var a=e.scheme,u=e.path,c=e.query,h=e.fragment,p=r.TPromise.wrap(void 0);if(a===o.Schemas.http||a===o.Schemas.https||a===o.Schemas.mailto)n.windowOpenNoOpener(e.toString(!0));else if("command"===a&&d.CommandsRegistry.getCommand(u)){var f=[];try{f=i.parse(c),Array.isArray(f)||(f=[f])}catch(e){}p=(s=this._commandService).executeCommand.apply(s,[u].concat(f))}else{var g=void 0,m=/^L?(\d+)(?:,(\d+))?/.exec(h);if(m&&(g={startLineNumber:parseInt(m[1]),startColumn:m[2]?parseInt(m[2]):1},e=e.with({fragment:""})),!e.scheme)return r.TPromise.as(void 0);e.scheme===o.Schemas.file&&(e=e.with({path:l.normalize(e.path)})),p=this._editorService.openCodeEditor({resource:e,options:{selection:g}},this._editorService.getFocusedCodeEditor(),t&&t.openToSide)}return p},e=a([u(0,s.ICodeEditorService),u(1,d.ICommandService),u(2,h.optional(c.ITelemetryService))],e)}();t.OpenerService=f}),define(t[22],n([1,0,45,27,356]),function(e,t,n,i,o){"use strict" +;function r(e,t,n,i,o){return u.registerColor(e,t,n,i,o)}function s(e,t){return function(n){var i=l(e,n);return i?i.transparent(t):null}}function a(e,t,n,o){return function(r){var s=l(e,r);if(s){var a=l(t,r);return a?s.isDarkerThan(a)?i.Color.getLighterColor(s,a,n).transparent(o):i.Color.getDarkerColor(s,a,n).transparent(o):s.transparent(n*o)}return null}}function l(e,t){return null===e?null:"string"==typeof e?"#"===e[0]?i.Color.fromHex(e):t.getColor(e):e instanceof i.Color?e:"function"==typeof e?e(t):null}Object.defineProperty(t,"__esModule",{value:!0}),t.Extensions={ColorContribution:"base.contributions.colors"};var u=new(function(){function e(){this.colorSchema={type:"object",description:o.localize(0,null),properties:{},additionalProperties:!1},this.colorReferenceSchema={type:"string",enum:[],enumDescriptions:[]},this.colorsById={}}return e.prototype.registerColor=function(e,t,n,i,o){void 0===i&&(i=!1);var r={id:e,description:n,defaults:t,needsTransparency:i,deprecationMessage:o};this.colorsById[e]=r +;var s={type:"string",description:n,format:"color-hex",default:"#ff0000"};return o&&(s.deprecationMessage=o),this.colorSchema.properties[e]=s,this.colorReferenceSchema.enum.push(e),this.colorReferenceSchema.enumDescriptions.push(n),e},e.prototype.resolveDefaultColor=function(e,t){var n=this.colorsById[e];if(n&&n.defaults){return l(n.defaults[t.type],t)}return null},e.prototype.toString=function(){var e=this;return Object.keys(this.colorsById).sort(function(e,t){var n=-1===e.indexOf(".")?0:1,i=-1===t.indexOf(".")?0:1;return n!==i?n-i:e.localeCompare(t)}).map(function(t){return"- `"+t+"`: "+e.colorsById[t].description}).join("\n")},e}());n.Registry.add(t.Extensions.ColorContribution,u),t.registerColor=r,t.foreground=r("foreground",{dark:"#CCCCCC",light:"#616161",hc:"#FFFFFF"},o.localize(1,null)),t.errorForeground=r("errorForeground",{dark:"#F48771",light:"#A1260D",hc:"#F48771"},o.localize(2,null)),t.focusBorder=r("focusBorder",{dark:i.Color.fromHex("#0E639C").transparent(.6), +light:i.Color.fromHex("#007ACC").transparent(.4),hc:"#F38518"},o.localize(3,null)),t.contrastBorder=r("contrastBorder",{light:null,dark:null,hc:"#6FC3DF"},o.localize(4,null)),t.activeContrastBorder=r("contrastActiveBorder",{light:null,dark:null,hc:t.focusBorder},o.localize(5,null)),t.textLinkForeground=r("textLink.foreground",{light:"#006AB1",dark:"#3794FF",hc:"#3794FF"},o.localize(6,null)),t.textCodeBlockBackground=r("textCodeBlock.background",{light:"#dcdcdc66",dark:"#0a0a0a66",hc:i.Color.black},o.localize(7,null)),t.widgetShadow=r("widget.shadow",{dark:"#000000",light:"#A8A8A8",hc:null},o.localize(8,null)),t.inputBackground=r("input.background",{dark:"#3C3C3C",light:i.Color.white,hc:i.Color.black},o.localize(9,null)),t.inputForeground=r("input.foreground",{dark:t.foreground,light:t.foreground,hc:t.foreground},o.localize(10,null)),t.inputBorder=r("input.border",{dark:null,light:null,hc:t.contrastBorder},o.localize(11,null)),t.inputActiveOptionBorder=r("inputOption.activeBorder",{dark:"#007ACC", +light:"#007ACC",hc:t.activeContrastBorder},o.localize(12,null)),t.inputValidationInfoBackground=r("inputValidation.infoBackground",{dark:"#063B49",light:"#D6ECF2",hc:i.Color.black},o.localize(13,null)),t.inputValidationInfoBorder=r("inputValidation.infoBorder",{dark:"#007acc",light:"#007acc",hc:t.contrastBorder},o.localize(14,null)),t.inputValidationWarningBackground=r("inputValidation.warningBackground",{dark:"#352A05",light:"#F6F5D2",hc:i.Color.black},o.localize(15,null)),t.inputValidationWarningBorder=r("inputValidation.warningBorder",{dark:"#B89500",light:"#B89500",hc:t.contrastBorder},o.localize(16,null)),t.inputValidationErrorBackground=r("inputValidation.errorBackground",{dark:"#5A1D1D",light:"#F2DEDE",hc:i.Color.black},o.localize(17,null)),t.inputValidationErrorBorder=r("inputValidation.errorBorder",{dark:"#BE1100",light:"#BE1100",hc:t.contrastBorder},o.localize(18,null)),t.listFocusBackground=r("list.focusBackground",{dark:"#062F4A",light:"#DFF0FF",hc:null},o.localize(19,null)), +t.listFocusForeground=r("list.focusForeground",{dark:null,light:null,hc:null},o.localize(20,null)),t.listActiveSelectionBackground=r("list.activeSelectionBackground",{dark:"#094771",light:"#2477CE",hc:null},o.localize(21,null)),t.listActiveSelectionForeground=r("list.activeSelectionForeground",{dark:i.Color.white,light:i.Color.white,hc:null},o.localize(22,null)),t.listInactiveSelectionBackground=r("list.inactiveSelectionBackground",{dark:"#37373D",light:"#dddfea",hc:null},o.localize(23,null)),t.listInactiveSelectionForeground=r("list.inactiveSelectionForeground",{dark:null,light:null,hc:null},o.localize(24,null)),t.listInactiveFocusBackground=r("list.inactiveFocusBackground",{dark:"#313135",light:"#d8dae6",hc:null},o.localize(25,null)),t.listHoverBackground=r("list.hoverBackground",{dark:"#2A2D2E",light:"#F0F0F0",hc:null},o.localize(26,null)),t.listHoverForeground=r("list.hoverForeground",{dark:null,light:null,hc:null},o.localize(27,null)),t.listDropBackground=r("list.dropBackground",{ +dark:t.listFocusBackground,light:t.listFocusBackground,hc:null},o.localize(28,null)),t.listHighlightForeground=r("list.highlightForeground",{dark:"#0097fb",light:"#007acc",hc:t.focusBorder},o.localize(29,null)),t.pickerGroupForeground=r("pickerGroup.foreground",{dark:"#3794FF",light:"#006AB1",hc:i.Color.white},o.localize(30,null)),t.pickerGroupBorder=r("pickerGroup.border",{dark:"#3F3F46",light:"#CCCEDB",hc:i.Color.white},o.localize(31,null)),t.badgeBackground=r("badge.background",{dark:"#4D4D4D",light:"#C4C4C4",hc:i.Color.black},o.localize(32,null)),t.badgeForeground=r("badge.foreground",{dark:i.Color.white,light:"#333",hc:i.Color.white},o.localize(33,null)),t.scrollbarShadow=r("scrollbar.shadow",{dark:"#000000",light:"#DDDDDD",hc:null},o.localize(34,null)),t.scrollbarSliderBackground=r("scrollbarSlider.background",{dark:i.Color.fromHex("#797979").transparent(.4),light:i.Color.fromHex("#646464").transparent(.4),hc:s(t.contrastBorder,.6)},o.localize(35,null)), +t.scrollbarSliderHoverBackground=r("scrollbarSlider.hoverBackground",{dark:i.Color.fromHex("#646464").transparent(.7),light:i.Color.fromHex("#646464").transparent(.7),hc:s(t.contrastBorder,.8)},o.localize(36,null)),t.scrollbarSliderActiveBackground=r("scrollbarSlider.activeBackground",{dark:i.Color.fromHex("#BFBFBF").transparent(.4),light:i.Color.fromHex("#000000").transparent(.6),hc:t.contrastBorder},o.localize(37,null)),t.progressBarBackground=r("progressBar.background",{dark:i.Color.fromHex("#0E70C0"),light:i.Color.fromHex("#0E70C0"),hc:t.contrastBorder},o.localize(38,null)),t.editorBackground=r("editor.background",{light:"#fffffe",dark:"#1E1E1E",hc:i.Color.black},o.localize(39,null)),t.editorForeground=r("editor.foreground",{light:"#333333",dark:"#BBBBBB",hc:i.Color.white},o.localize(40,null)),t.editorWidgetBackground=r("editorWidget.background",{dark:"#2D2D30",light:"#EFEFF2",hc:"#0C141F"},o.localize(41,null)),t.editorWidgetBorder=r("editorWidget.border",{dark:"#454545",light:"#C8C8C8", +hc:t.contrastBorder},o.localize(42,null)),t.editorWidgetResizeBorder=r("editorWidget.resizeBorder",{light:null,dark:null,hc:null},o.localize(43,null)),t.editorSelectionBackground=r("editor.selectionBackground",{light:"#ADD6FF",dark:"#264F78",hc:"#f3f518"},o.localize(44,null)),t.editorSelectionForeground=r("editor.selectionForeground",{light:null,dark:null,hc:"#000000"},o.localize(45,null)),t.editorInactiveSelection=r("editor.inactiveSelectionBackground",{light:s(t.editorSelectionBackground,.5),dark:s(t.editorSelectionBackground,.5),hc:s(t.editorSelectionBackground,.5)},o.localize(46,null),!0),t.editorSelectionHighlight=r("editor.selectionHighlightBackground",{light:a(t.editorSelectionBackground,t.editorBackground,.3,.6),dark:a(t.editorSelectionBackground,t.editorBackground,.3,.6),hc:null},o.localize(47,null),!0),t.editorSelectionHighlightBorder=r("editor.selectionHighlightBorder",{light:null,dark:null,hc:t.activeContrastBorder},o.localize(48,null)),t.editorFindMatch=r("editor.findMatchBackground",{ +light:"#A8AC94",dark:"#515C6A",hc:null},o.localize(49,null)),t.editorFindMatchHighlight=r("editor.findMatchHighlightBackground",{light:"#EA5C0055",dark:"#EA5C0055",hc:null},o.localize(50,null),!0),t.editorFindRangeHighlight=r("editor.findRangeHighlightBackground",{dark:"#3a3d4166",light:"#b4b4b44d",hc:null},o.localize(51,null),!0),t.editorFindMatchBorder=r("editor.findMatchBorder",{light:null,dark:null,hc:t.activeContrastBorder},o.localize(52,null)),t.editorFindMatchHighlightBorder=r("editor.findMatchHighlightBorder",{light:null,dark:null,hc:t.activeContrastBorder},o.localize(53,null)),t.editorFindRangeHighlightBorder=r("editor.findRangeHighlightBorder",{dark:null,light:null,hc:s(t.activeContrastBorder,.4)},o.localize(54,null),!0),t.editorHoverHighlight=r("editor.hoverHighlightBackground",{light:"#ADD6FF26",dark:"#264f7840",hc:"#ADD6FF26"},o.localize(55,null),!0),t.editorHoverBackground=r("editorHoverWidget.background",{light:t.editorWidgetBackground,dark:t.editorWidgetBackground,hc:t.editorWidgetBackground +},o.localize(56,null)),t.editorHoverBorder=r("editorHoverWidget.border",{light:t.editorWidgetBorder,dark:t.editorWidgetBorder,hc:t.editorWidgetBorder},o.localize(57,null)),t.editorActiveLinkForeground=r("editorLink.activeForeground",{dark:"#4E94CE",light:i.Color.blue,hc:i.Color.cyan},o.localize(58,null)),t.defaultInsertColor=new i.Color(new i.RGBA(155,185,85,.2)),t.defaultRemoveColor=new i.Color(new i.RGBA(255,0,0,.2)),t.diffInserted=r("diffEditor.insertedTextBackground",{dark:t.defaultInsertColor,light:t.defaultInsertColor,hc:null},o.localize(59,null),!0),t.diffRemoved=r("diffEditor.removedTextBackground",{dark:t.defaultRemoveColor,light:t.defaultRemoveColor,hc:null},o.localize(60,null),!0),t.diffInsertedOutline=r("diffEditor.insertedTextBorder",{dark:null,light:null,hc:"#33ff2eff"},o.localize(61,null)),t.diffRemovedOutline=r("diffEditor.removedTextBorder",{dark:null,light:null,hc:"#FF008F"},o.localize(62,null)),t.diffBorder=r("diffEditor.border",{dark:null,light:null,hc:t.contrastBorder +},o.localize(63,null));var d=new i.Color(new i.RGBA(246,185,77,.7));t.overviewRulerFindMatchForeground=r("editorOverviewRuler.findMatchForeground",{dark:d,light:d,hc:d},o.localize(64,null),!0),t.overviewRulerSelectionHighlightForeground=r("editorOverviewRuler.selectionHighlightForeground",{dark:"#A0A0A0CC",light:"#A0A0A0CC",hc:"#A0A0A0CC"},o.localize(65,null),!0),t.transparent=s,t.oneOf=function(){for(var e=[],t=0;t0&&(o.insertRule(this._unThemedSelector+" {"+e+"}",0),r=!0),t.length>0&&(o.insertRule(".vs"+this._unThemedSelector+" {"+t+"}",0),r=!0),n.length>0&&(o.insertRule(".vs-dark"+this._unThemedSelector+", .hc-black"+this._unThemedSelector+" {"+n+"}",0),r=!0),this._hasContent=r},e.prototype._removeCSS=function(){r.removeCSSRulesContainingSelector(this._unThemedSelector,this._providerArgs.styleSheet)},e.prototype.getCSSTextForModelDecorationClassName=function(e){if(!e)return"";var t=[];return this.collectCSSText(e,["backgroundColor"],t),this.collectCSSText(e,["outline","outlineColor","outlineStyle","outlineWidth"],t),this.collectBorderSettingsCSSText(e,t),t.join("")},e.prototype.getCSSTextForModelDecorationInlineClassName=function(e){if(!e)return"" +;var t=[];return this.collectCSSText(e,["fontStyle","fontWeight","textDecoration","cursor","color","opacity","letterSpacing"],t),e.letterSpacing&&(this._hasLetterSpacing=!0),t.join("")},e.prototype.getCSSTextForModelDecorationContentClassName=function(e){if(!e)return"";var t=[];if(void 0!==e){if(this.collectBorderSettingsCSSText(e,t),void 0!==e.contentIconPath&&("string"==typeof e.contentIconPath?t.push(n.format(m.contentIconPath,i.default.file(e.contentIconPath).toString().replace(/'/g,"%27"))):t.push(n.format(m.contentIconPath,i.default.revive(e.contentIconPath).toString(!0).replace(/'/g,"%27")))),"string"==typeof e.contentText){var o=e.contentText.match(/^.*$/m)[0].replace(/['\\]/g,"\\$&");t.push(n.format(m.contentText,o))}this.collectCSSText(e,["fontStyle","fontWeight","textDecoration","color","opacity","backgroundColor","margin"],t),this.collectCSSText(e,["width","height"],t)&&t.push("display:inline-block;")}return t.join("")},e.prototype.getCSSTextForModelDecorationGlyphMarginClassName=function(e){ +if(!e)return"";var t=[];return void 0!==e.gutterIconPath&&("string"==typeof e.gutterIconPath?t.push(n.format(m.gutterIconPath,i.default.file(e.gutterIconPath).toString())):t.push(n.format(m.gutterIconPath,i.default.revive(e.gutterIconPath).toString(!0).replace(/'/g,"%27"))),void 0!==e.gutterIconSize&&t.push(n.format(m.gutterIconSize,e.gutterIconSize))),t.join("")},e.prototype.collectBorderSettingsCSSText=function(e,t){return!!this.collectCSSText(e,["border","borderColor","borderRadius","borderSpacing","borderStyle","borderWidth"],t)&&(t.push(n.format("box-sizing: border-box;")),!0)},e.prototype.collectCSSText=function(e,t,i){for(var o=i.length,r=0,s=t;rt)){var v=m.startLineNumber===t?m.startColumn:r.minColumn,y=m.endLineNumber===t?m.endColumn:r.maxColumn;v') +;var S=a.renderViewLine(C,o);o.appendASCIIString("");var w=null;return p&&r.isBasicASCII&&l.useMonospaceOptimizations&&0===S.containsForeignElements&&r.content.length<300&&C.lineTokens.getCount()<100&&(w=new _(this._renderedViewLine?this._renderedViewLine.domNode:null,C,S.characterMapping)),w||(w=b(this._renderedViewLine?this._renderedViewLine.domNode:null,C,S.characterMapping,S.containsRTL,S.containsForeignElements)),this._renderedViewLine=w,!0},e.prototype.layoutLine=function(e,t){this._renderedViewLine&&this._renderedViewLine.domNode&&(this._renderedViewLine.domNode.setTop(t),this._renderedViewLine.domNode.setHeight(this._options.lineHeight))},e.prototype.getWidth=function(){return this._renderedViewLine?this._renderedViewLine.getWidth():0},e.prototype.getWidthIsFast=function(){return!this._renderedViewLine||this._renderedViewLine.getWidthIsFast()},e.prototype.getVisibleRangesForRange=function(e,t,n){e|=0,t|=0,e=Math.min(this._renderedViewLine.input.lineContent.length+1,Math.max(1,e)), +t=Math.min(this._renderedViewLine.input.lineContent.length+1,Math.max(1,t));var i=0|this._renderedViewLine.input.stopRenderingLineAfter;return-1!==i&&e>i&&t>i?null:(-1!==i&&e>i&&(e=i),-1!==i&&t>i&&(t=i),this._renderedViewLine.getVisibleRangesForRange(e,t,n))},e.prototype.getColumnOfNodeOffset=function(e,t,n){return this._renderedViewLine.getColumnOfNodeOffset(e,t,n)},e.CLASS_NAME="view-line",e}();t.ViewLine=v;var _=function(){function e(e,t,n){this.domNode=e,this.input=t,this._characterMapping=n,this._charWidth=t.spaceWidth}return e.prototype.getWidth=function(){return this._getCharPosition(this._characterMapping.length)},e.prototype.getWidthIsFast=function(){return!0},e.prototype.getVisibleRangesForRange=function(e,t,n){var i=this._getCharPosition(e),o=this._getCharPosition(t);return[new u.HorizontalRange(i,o-i)]},e.prototype._getCharPosition=function(e){var t=this._characterMapping.getAbsoluteOffsets();return 0===t.length?0:Math.round(this._charWidth*t[e-1])}, +e.prototype.getColumnOfNodeOffset=function(e,t,n){for(var i=t.textContent.length,o=-1;t;)t=t.previousSibling,o++;return this._characterMapping.partDataToCharOffset(o,i,n)+1},e}(),y=function(){function e(e,t,n,i,o){if(this.domNode=e,this.input=t,this._characterMapping=n,this._isWhitespaceOnly=/^\s*$/.test(t.lineContent),this._containsForeignElements=o,this._cachedWidth=-1,this._pixelOffsetCache=null,!i||0===this._characterMapping.length){this._pixelOffsetCache=new Int32Array(Math.max(2,this._characterMapping.length+1));for(var r=0,s=this._characterMapping.length;r<=s;r++)this._pixelOffsetCache[r]=-1}}return e.prototype._getReadingTarget=function(){return this.domNode.domNode.firstChild},e.prototype.getWidth=function(){return-1===this._cachedWidth&&(this._cachedWidth=this._getReadingTarget().offsetWidth),this._cachedWidth},e.prototype.getWidthIsFast=function(){return-1!==this._cachedWidth},e.prototype.getVisibleRangesForRange=function(e,t,n){if(null!==this._pixelOffsetCache){var i=this._readPixelOffset(e,n) +;if(-1===i)return null;var o=this._readPixelOffset(t,n);return-1===o?null:[new u.HorizontalRange(i,o-i)]}return this._readVisibleRangesForRange(e,t,n)},e.prototype._readVisibleRangesForRange=function(e,t,n){if(e===t){var i=this._readPixelOffset(e,n);return-1===i?null:[new u.HorizontalRange(i,0)]}return this._readRawVisibleRangesForRange(e,t,n)},e.prototype._readPixelOffset=function(e,t){if(0===this._characterMapping.length){if(0===this._containsForeignElements)return 0;if(2===this._containsForeignElements)return 0;if(1===this._containsForeignElements)return this.getWidth()}if(null!==this._pixelOffsetCache){var n=this._pixelOffsetCache[e];if(-1!==n)return n;var i=this._actualReadPixelOffset(e,t);return this._pixelOffsetCache[e]=i,i}return this._actualReadPixelOffset(e,t)},e.prototype._actualReadPixelOffset=function(e,t){if(0===this._characterMapping.length){var n=l.RangeUtil.readHorizontalRanges(this._getReadingTarget(),0,0,0,0,t.clientRectDeltaLeft,t.endNode);return n&&0!==n.length?n[0].left:-1} +if(e===this._characterMapping.length&&this._isWhitespaceOnly&&0===this._containsForeignElements)return this.getWidth();var i=this._characterMapping.charOffsetToPartData(e-1),o=a.CharacterMapping.getPartIndex(i),r=a.CharacterMapping.getCharIndex(i),s=l.RangeUtil.readHorizontalRanges(this._getReadingTarget(),o,r,o,r,t.clientRectDeltaLeft,t.endNode);return s&&0!==s.length?s[0].left:-1},e.prototype._readRawVisibleRangesForRange=function(e,t,n){if(1===e&&t===this._characterMapping.length)return[new u.HorizontalRange(0,this.getWidth())];var i=this._characterMapping.charOffsetToPartData(e-1),o=a.CharacterMapping.getPartIndex(i),r=a.CharacterMapping.getCharIndex(i),s=this._characterMapping.charOffsetToPartData(t-1),d=a.CharacterMapping.getPartIndex(s),c=a.CharacterMapping.getCharIndex(s);return l.RangeUtil.readHorizontalRanges(this._getReadingTarget(),o,r,d,c,n.clientRectDeltaLeft,n.endNode)},e.prototype.getColumnOfNodeOffset=function(e,t,n){for(var i=t.textContent.length,o=-1;t;)t=t.previousSibling,o++ +;return this._characterMapping.partDataToCharOffset(o,i,n)+1},e}(),C=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype._readVisibleRangesForRange=function(t,n,i){var o=e.prototype._readVisibleRangesForRange.call(this,t,n,i);if(!o||0===o.length||t===n||1===t&&n===this._characterMapping.length)return o;var r=this._readPixelOffset(n-1,i),s=this._readPixelOffset(n,i);if(-1!==r&&-1!==s){var a=r<=s,l=o[o.length-1];a&&l.left=4&&3===e[0]&&7===e[3]},e.isStrictChildOfViewLines=function(e){return e.length>4&&3===e[0]&&7===e[3]},e.isChildOfScrollableElement=function(e){return e.length>=2&&3===e[0]&&5===e[1]},e.isChildOfMinimap=function(e){return e.length>=2&&3===e[0]&&8===e[1]},e.isChildOfContentWidgets=function(e){return e.length>=4&&3===e[0]&&1===e[3]},e.isChildOfOverflowingContentWidgets=function(e){return e.length>=1&&2===e[0]},e.isChildOfOverlayWidgets=function(e){return e.length>=2&&3===e[0]&&4===e[1]},e}(),p=function(){function e(e,t,n){this.model=e.model,this.layoutInfo=e.configuration.editor.layoutInfo,this.viewDomNode=t.viewDomNode,this.lineHeight=e.configuration.editor.lineHeight,this.typicalHalfwidthCharacterWidth=e.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth,this.lastViewCursorsRenderData=n,this._context=e,this._viewHelper=t}return e.prototype.getZoneAtCoord=function(t){return e.getZoneAtCoord(this._context,t)},e.getZoneAtCoord=function(e,t){ +var i=e.viewLayout.getWhitespaceAtVerticalOffset(t);if(i){var o=i.verticalOffset+i.height/2,r=e.model.getLineCount(),s=null,a=void 0,l=null;return i.afterLineNumber!==r&&(l=new n.Position(i.afterLineNumber+1,1)),i.afterLineNumber>0&&(s=new n.Position(i.afterLineNumber,e.model.getLineMaxColumn(i.afterLineNumber))),a=null===l?s:null===s?l:t=e.layoutInfo.glyphMarginLeft, +this.isInContentArea=!this.isInMarginArea,this.mouseColumn=Math.max(0,m._getMouseColumn(this.mouseContentHorizontalOffset,e.typicalHalfwidthCharacterWidth))}}()),g={isAfterLines:!0},m=function(){function e(e,t){this._context=e,this._viewHelper=t}return e.prototype.mouseTargetIsWidget=function(e){var t=e.target,n=l.PartFingerprints.collect(t,this._viewHelper.viewDomNode);return!(!h.isChildOfContentWidgets(n)&&!h.isChildOfOverflowingContentWidgets(n))||!!h.isChildOfOverlayWidgets(n)},e.prototype.createMouseTarget=function(t,n,i,o){var s=new p(this._context,this._viewHelper,t),a=new f(s,n,i,o);try{return e._createMouseTarget(s,a,!1)}catch(e){return a.fulfill(r.MouseTargetType.UNKNOWN)}},e._createMouseTarget=function(t,n,i){if(null===n.target){if(i)return n.fulfill(r.MouseTargetType.UNKNOWN);var o=e._doHitTest(t,n);return o.position?e.createMouseTargetFromHitTestPosition(t,n,o.position.lineNumber,o.position.column):this._createMouseTarget(t,n.withTarget(o.hitTarget),!0)}var s=null +;return s=s||e._hitTestContentWidget(t,n),s=s||e._hitTestOverlayWidget(t,n),s=s||e._hitTestMinimap(t,n),s=s||e._hitTestScrollbarSlider(t,n),s=s||e._hitTestViewZone(t,n),s=s||e._hitTestMargin(t,n),s=s||e._hitTestViewCursor(t,n),s=s||e._hitTestTextArea(t,n),s=s||e._hitTestViewLines(t,n,i),(s=s||e._hitTestScrollbar(t,n))||n.fulfill(r.MouseTargetType.UNKNOWN)},e._hitTestContentWidget=function(e,t){if(h.isChildOfContentWidgets(t.targetPath)||h.isChildOfOverflowingContentWidgets(t.targetPath)){var n=e.findAttribute(t.target,"widgetId");return n?t.fulfill(r.MouseTargetType.CONTENT_WIDGET,null,null,n):t.fulfill(r.MouseTargetType.UNKNOWN)}return null},e._hitTestOverlayWidget=function(e,t){if(h.isChildOfOverlayWidgets(t.targetPath)){var n=e.findAttribute(t.target,"widgetId");return n?t.fulfill(r.MouseTargetType.OVERLAY_WIDGET,null,null,n):t.fulfill(r.MouseTargetType.UNKNOWN)}return null},e._hitTestViewCursor=function(e,t){if(t.target)for(var n=0,i=(o=e.lastViewCursorsRenderData).length;nl.contentLeft+l.width)){var u=e.getVerticalOffsetForLineNumber(l.position.lineNumber);if(u<=a&&a<=u+l.height)return t.fulfill(r.MouseTargetType.CONTENT_TEXT,l.position)}}return null},e._hitTestViewZone=function(e,t){var n=e.getZoneAtCoord(t.mouseVerticalOffset);if(n){var i=t.isInContentArea?r.MouseTargetType.CONTENT_VIEW_ZONE:r.MouseTargetType.GUTTER_VIEW_ZONE;return t.fulfill(i,n.position,null,n)}return null},e._hitTestTextArea=function(e,t){return h.isTextArea(t.targetPath)?t.fulfill(r.MouseTargetType.TEXTAREA):null},e._hitTestMargin=function(e,t){if(t.isInMarginArea){var n=e.getFullLineRangeAtCoord(t.mouseVerticalOffset),i=n.range.getStartPosition(),o=Math.abs(t.pos.x-t.editorPos.x),s={isAfterLines:n.isAfterLines, +glyphMarginLeft:e.layoutInfo.glyphMarginLeft,glyphMarginWidth:e.layoutInfo.glyphMarginWidth,lineNumbersWidth:e.layoutInfo.lineNumbersWidth,offsetX:o};return(o-=e.layoutInfo.glyphMarginLeft)<=e.layoutInfo.glyphMarginWidth?t.fulfill(r.MouseTargetType.GUTTER_GLYPH_MARGIN,i,n.range,s):(o-=e.layoutInfo.glyphMarginWidth)<=e.layoutInfo.lineNumbersWidth?t.fulfill(r.MouseTargetType.GUTTER_LINE_NUMBERS,i,n.range,s):(o-=e.layoutInfo.lineNumbersWidth,t.fulfill(r.MouseTargetType.GUTTER_LINE_DECORATIONS,i,n.range,s))}return null},e._hitTestViewLines=function(t,i,o){if(!h.isChildOfViewLines(i.targetPath))return null;if(t.isAfterLines(i.mouseVerticalOffset)){var s=t.model.getLineCount(),a=t.model.getLineMaxColumn(s);return i.fulfill(r.MouseTargetType.CONTENT_EMPTY,new n.Position(s,a),void 0,g)}if(o){if(h.isStrictChildOfViewLines(i.targetPath)){var l=t.getLineNumberAtVerticalOffset(i.mouseVerticalOffset);if(0===t.model.getLineLength(l)){var u=t.getLineWidth(l),c=d(i.mouseContentHorizontalOffset-u) +;return i.fulfill(r.MouseTargetType.CONTENT_EMPTY,new n.Position(l,1),void 0,c)}}return i.fulfill(r.MouseTargetType.UNKNOWN)}var p=e._doHitTest(t,i);return p.position?e.createMouseTargetFromHitTestPosition(t,i,p.position.lineNumber,p.position.column):this._createMouseTarget(t,i.withTarget(p.hitTarget),!0)},e._hitTestMinimap=function(e,t){if(h.isChildOfMinimap(t.targetPath)){var i=e.getLineNumberAtVerticalOffset(t.mouseVerticalOffset),o=e.model.getLineMaxColumn(i);return t.fulfill(r.MouseTargetType.SCROLLBAR,new n.Position(i,o))}return null},e._hitTestScrollbarSlider=function(e,t){if(h.isChildOfScrollableElement(t.targetPath)&&t.target&&1===t.target.nodeType){var i=t.target.className;if(i&&/\b(slider|scrollbar)\b/.test(i)){var o=e.getLineNumberAtVerticalOffset(t.mouseVerticalOffset),s=e.model.getLineMaxColumn(o);return t.fulfill(r.MouseTargetType.SCROLLBAR,new n.Position(o,s))}}return null},e._hitTestScrollbar=function(e,t){if(h.isChildOfScrollableElement(t.targetPath)){ +var i=e.getLineNumberAtVerticalOffset(t.mouseVerticalOffset),o=e.model.getLineMaxColumn(i);return t.fulfill(r.MouseTargetType.SCROLLBAR,new n.Position(i,o))}return null},e.prototype.getMouseColumn=function(t,n){var i=this._context.configuration.editor.layoutInfo,o=this._context.viewLayout.getCurrentScrollLeft()+n.x-t.x-i.contentLeft;return e._getMouseColumn(o,this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth)},e._getMouseColumn=function(e,t){if(e<0)return 1;return Math.round(e/t)+1},e.createMouseTargetFromHitTestPosition=function(e,t,o,s){var l=new n.Position(o,s),u=e.getLineWidth(o);if(t.mouseContentHorizontalOffset>u){if(a.isEdge&&1===l.column){var c=d(t.mouseContentHorizontalOffset-u);return t.fulfill(r.MouseTargetType.CONTENT_EMPTY,new n.Position(o,e.model.getLineMaxColumn(o)),void 0,c)}var h=d(t.mouseContentHorizontalOffset-u);return t.fulfill(r.MouseTargetType.CONTENT_EMPTY,l,void 0,h)}var p=e.visibleRangeForPosition2(o,s);if(!p)return t.fulfill(r.MouseTargetType.UNKNOWN,l) +;var f=p.left;if(t.mouseContentHorizontalOffset===f)return t.fulfill(r.MouseTargetType.CONTENT_TEXT,l);var g=[];if(g.push({offset:p.left,column:s}),s>1){var m=e.visibleRangeForPosition2(o,s-1);m&&g.push({offset:m.left,column:s-1})}if(s=t.editorPos.y+e.layoutInfo.height&&(o=t.editorPos.y+e.layoutInfo.height-1) +;var r=new s.PageCoordinates(t.pos.x,o),a=this._actualDoHitTestWithCaretRangeFromPoint(e,r.toClientCoordinates());return a.position?a:this._actualDoHitTestWithCaretRangeFromPoint(e,t.pos.toClientCoordinates())},e._actualDoHitTestWithCaretRangeFromPoint=function(e,t){var n=document.caretRangeFromPoint(t.clientX,t.clientY);if(!n||!n.startContainer)return{position:null,hitTarget:null};var i,o=n.startContainer;if(o.nodeType===o.TEXT_NODE){var r=(a=(s=o.parentNode)?s.parentNode:null)?a.parentNode:null;if((r&&r.nodeType===r.ELEMENT_NODE?r.className:null)===u.ViewLine.CLASS_NAME){return{position:l=e.getPositionFromDOMInfo(s,n.startOffset),hitTarget:null}}i=o.parentNode}else if(o.nodeType===o.ELEMENT_NODE){var s=o.parentNode,a=s?s.parentNode:null;if((a&&a.nodeType===a.ELEMENT_NODE?a.className:null)===u.ViewLine.CLASS_NAME){var l=e.getPositionFromDOMInfo(o,o.textContent.length);return{position:l,hitTarget:null}}i=o}return{position:null,hitTarget:i}},e._doHitTestWithCaretPositionFromPoint=function(e,t){ +var n=document.caretPositionFromPoint(t.clientX,t.clientY);if(n.offsetNode.nodeType===n.offsetNode.TEXT_NODE){var i=n.offsetNode.parentNode,o=i?i.parentNode:null,r=o?o.parentNode:null;if((r&&r.nodeType===r.ELEMENT_NODE?r.className:null)===u.ViewLine.CLASS_NAME){return{position:e.getPositionFromDOMInfo(n.offsetNode.parentNode,n.offset),hitTarget:null}}return{position:null,hitTarget:n.offsetNode.parentNode}}return{position:null,hitTarget:n.offsetNode}},e._doHitTestWithMoveToPoint=function(e,t){var n=null,i=null,o=document.body.createTextRange();try{o.moveToPoint(t.clientX,t.clientY)}catch(e){return{position:null,hitTarget:null}}o.collapse(!0);var r=o?o.parentElement():null,s=r?r.parentNode:null,a=s?s.parentNode:null;if((a&&a.nodeType===a.ELEMENT_NODE?a.className:"")===u.ViewLine.CLASS_NAME){var l=o.duplicate();l.moveToElementText(r),l.setEndPoint("EndToStart",o),n=e.getPositionFromDOMInfo(r,l.text.length),l.moveToElementText(e.viewDomNode)}else i=r;return o.moveToElementText(e.viewDomNode),{position:n, +hitTarget:i}},e._doHitTest=function(e,t){return document.caretRangeFromPoint?this._doHitTestWithCaretRangeFromPoint(e,t):document.caretPositionFromPoint?this._doHitTestWithCaretPositionFromPoint(e,t.pos.toClientCoordinates()):document.body.createTextRange?this._doHitTestWithMoveToPoint(e,t.pos.toClientCoordinates()):{position:null,hitTarget:null}},e}();t.MouseTargetFactory=m}),define(t[488],n([1,0,2,18,30,7,12,21,80,184,23,14,116,42,98]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g){"use strict";function m(e){return function(t,n){var i=!1;return e&&(i=e.mouseTargetIsWidget(n)),i||n.preventDefault(),n}}Object.defineProperty(t,"__esModule",{value:!0});var v=function(e){function t(n,i,o){var r=e.call(this)||this;r._isFocused=!1,r._context=n,r.viewController=i,r.viewHelper=o,r.mouseTargetFactory=new d.MouseTargetFactory(r._context,o),r._mouseDownOperation=r._register(new _(r._context,r.viewController,r.viewHelper,function(e,t){return r._createMouseTarget(e,t)},function(e){return r._getMouseColumn(e)})), +r._asyncFocus=r._register(new h.RunOnceScheduler(function(){return r.viewHelper.focusTextArea()},0)),r.lastMouseLeaveTime=-1;var a=new p.EditorMouseEventFactory(r.viewHelper.viewDomNode);r._register(a.onContextMenu(r.viewHelper.viewDomNode,function(e){return r._onContextMenu(e,!0)})),r._register(a.onMouseMoveThrottled(r.viewHelper.viewDomNode,function(e){return r._onMouseMove(e)},m(r.mouseTargetFactory),t.MOUSE_MOVE_MINIMUM_TIME)),r._register(a.onMouseUp(r.viewHelper.viewDomNode,function(e){return r._onMouseUp(e)})),r._register(a.onMouseLeave(r.viewHelper.viewDomNode,function(e){return r._onMouseLeave(e)})),r._register(a.onMouseDown(r.viewHelper.viewDomNode,function(e){return r._onMouseDown(e)}));var l=function(e){if(r._context.configuration.editor.viewInfo.mouseWheelZoom){var t=new f.StandardMouseWheelEvent(e);if(t.browserEvent.ctrlKey||t.browserEvent.metaKey){var n=g.EditorZoom.getZoomLevel(),i=t.deltaY>0?1:-1;g.EditorZoom.setZoomLevel(n+i),t.preventDefault(),t.stopPropagation()}}} +;return r._register(s.addDisposableListener(r.viewHelper.viewDomNode,"mousewheel",l,!0)),r._register(s.addDisposableListener(r.viewHelper.viewDomNode,"DOMMouseScroll",l,!0)),r._context.addEventHandler(r),r}return o(t,e),t.prototype.dispose=function(){this._context.removeEventHandler(this),e.prototype.dispose.call(this)},t.prototype.onCursorStateChanged=function(e){return this._mouseDownOperation.onCursorStateChanged(e),!1},t.prototype.onFocusChanged=function(e){return this._isFocused=e.isFocused,!1},t.prototype.onScrollChanged=function(e){return this._mouseDownOperation.onScrollChanged(),!1},t.prototype.getTargetAtClientPoint=function(e,t){var n=new p.ClientCoordinates(e,t).toPageCoordinates(),i=p.createEditorPagePosition(this.viewHelper.viewDomNode);if(n.yi.y+i.height||n.xi.x+i.width)return null;var o=this.viewHelper.getLastViewCursorsRenderData();return this.mouseTargetFactory.createMouseTarget(o,i,n,null)},t.prototype._createMouseTarget=function(e,t){ +var n=this.viewHelper.getLastViewCursorsRenderData();return this.mouseTargetFactory.createMouseTarget(n,e.editorPos,e.pos,t?e.target:null)},t.prototype._getMouseColumn=function(e){return this.mouseTargetFactory.getMouseColumn(e.editorPos,e.pos)},t.prototype._onContextMenu=function(e,t){this.viewController.emitContextMenu({event:e,target:this._createMouseTarget(e,t)})},t.prototype._onMouseMove=function(e){if(!this._mouseDownOperation.isActive()){e.timestampt.y+t.height){var s=i.getCurrentScrollTop()+(e.posy-t.y),l=d.HitTestContext.getZoneAtCoord(this._context,s);if(l){var u=this._helpPositionJumpOverViewZone(l);if(u)return new d.MouseTarget(null,c.MouseTargetType.OUTSIDE_EDITOR,o,u)}var h=i.getLineNumberAtVerticalOffset(s);return new d.MouseTarget(null,c.MouseTargetType.OUTSIDE_EDITOR,o,new a.Position(h,n.getLineMaxColumn(h)))}var p=i.getLineNumberAtVerticalOffset(i.getCurrentScrollTop()+(e.posy-t.y));return e.posxt.x+t.width?new d.MouseTarget(null,c.MouseTargetType.OUTSIDE_EDITOR,o,new a.Position(p,n.getLineMaxColumn(p))):null},t.prototype._findMousePosition=function(e,t){var n=this._getPositionOutsideEditor(e);if(n)return n;var i=this._createMouseTarget(e,t);if(!i.position)return null +;if(i.type===c.MouseTargetType.CONTENT_VIEW_ZONE||i.type===c.MouseTargetType.GUTTER_VIEW_ZONE){var o=this._helpPositionJumpOverViewZone(i.detail);if(o)return new d.MouseTarget(i.element,i.type,i.mouseColumn,o,null,i.detail)}return i},t.prototype._helpPositionJumpOverViewZone=function(e){var t=new a.Position(this._currentSelection.selectionStartLineNumber,this._currentSelection.selectionStartColumn),n=e.positionBefore,i=e.positionAfter;return n&&i?n.isBefore(t)?n:i:null},t.prototype._dispatchMouse=function(e,t){this._viewController.dispatchMouse({position:e.position,mouseColumn:e.mouseColumn,startedOnLineNumbers:this._mouseState.startedOnLineNumbers,inSelectionMode:t,mouseDownCount:this._mouseState.count,altKey:this._mouseState.altKey,ctrlKey:this._mouseState.ctrlKey,metaKey:this._mouseState.metaKey,shiftKey:this._mouseState.shiftKey,leftButton:this._mouseState.leftButton,middleButton:this._mouseState.middleButton})},t}(n.Disposable),y=function(){function e(){this._altKey=!1,this._ctrlKey=!1,this._metaKey=!1, +this._shiftKey=!1,this._leftButton=!1,this._middleButton=!1,this._startedOnLineNumbers=!1,this._lastMouseDownPosition=null,this._lastMouseDownPositionEqualCount=0,this._lastMouseDownCount=0,this._lastSetMouseDownCountTime=0,this.isDragAndDrop=!1}return Object.defineProperty(e.prototype,"altKey",{get:function(){return this._altKey},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"ctrlKey",{get:function(){return this._ctrlKey},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"metaKey",{get:function(){return this._metaKey},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"shiftKey",{get:function(){return this._shiftKey},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"leftButton",{get:function(){return this._leftButton},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"middleButton",{get:function(){return this._middleButton},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"startedOnLineNumbers",{ +get:function(){return this._startedOnLineNumbers},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"count",{get:function(){return this._lastMouseDownCount},enumerable:!0,configurable:!0}),e.prototype.setModifiers=function(e){this._altKey=e.altKey,this._ctrlKey=e.ctrlKey,this._metaKey=e.metaKey,this._shiftKey=e.shiftKey},e.prototype.setStartButtons=function(e){this._leftButton=e.leftButton,this._middleButton=e.middleButton},e.prototype.setStartedOnLineNumbers=function(e){this._startedOnLineNumbers=e},e.prototype.trySetCount=function(t,n){var i=(new Date).getTime();i-this._lastSetMouseDownCountTime>e.CLEAR_MOUSE_DOWN_COUNT_TIME&&(t=1),this._lastSetMouseDownCountTime=i,t>this._lastMouseDownCount+1&&(t=this._lastMouseDownCount+1),this._lastMouseDownPosition&&this._lastMouseDownPosition.equals(n)?this._lastMouseDownPositionEqualCount++:this._lastMouseDownPositionEqualCount=1,this._lastMouseDownPosition=n,this._lastMouseDownCount=Math.min(t,this._lastMouseDownPositionEqualCount)}, +e.CLEAR_MOUSE_DOWN_COUNT_TIME=400,e}()}),define(t[489],n([1,0,7,74,488,116]),function(e,t,n,i,r,s){"use strict";function a(e,t){var n={translationY:t.translationY,translationX:t.translationX};return e&&(n.translationY+=e.translationY,n.translationX+=e.translationX),n}Object.defineProperty(t,"__esModule",{value:!0});var l=function(e){function t(t,i,o){var r=e.call(this,t,i,o)||this;return r.viewHelper.linesContentDomNode.style.msTouchAction="none",r.viewHelper.linesContentDomNode.style.msContentZooming="none",r._installGestureHandlerTimeout=window.setTimeout(function(){if(r._installGestureHandlerTimeout=-1,window.MSGesture){var e=new MSGesture,t=new MSGesture;e.target=r.viewHelper.linesContentDomNode,t.target=r.viewHelper.linesContentDomNode,r.viewHelper.linesContentDomNode.addEventListener("MSPointerDown",function(n){var i=n.pointerType;i!==(n.MSPOINTER_TYPE_MOUSE||"mouse")?i===(n.MSPOINTER_TYPE_TOUCH||"touch")?(r._lastPointerType="touch",e.addPointer(n.pointerId)):(r._lastPointerType="pen", +t.addPointer(n.pointerId)):r._lastPointerType="mouse"}),r._register(n.addDisposableThrottledListener(r.viewHelper.linesContentDomNode,"MSGestureChange",function(e){return r._onGestureChange(e)},a)),r._register(n.addDisposableListener(r.viewHelper.linesContentDomNode,"MSGestureTap",function(e){return r._onCaptureGestureTap(e)},!0))}},100),r._lastPointerType="mouse",r}return o(t,e),t.prototype._onMouseDown=function(t){"mouse"===this._lastPointerType&&e.prototype._onMouseDown.call(this,t)},t.prototype._onCaptureGestureTap=function(e){var t=this,n=new s.EditorMouseEvent(e,this.viewHelper.viewDomNode),i=this._createMouseTarget(n,!1);i.position&&this.viewController.moveTo(i.position),n.browserEvent.fromElement?(n.preventDefault(),this.viewHelper.focusTextArea()):setTimeout(function(){t.viewHelper.focusTextArea()})},t.prototype._onGestureChange=function(e){this._context.viewLayout.deltaScrollNow(-e.translationX,-e.translationY)},t.prototype.dispose=function(){window.clearTimeout(this._installGestureHandlerTimeout), +e.prototype.dispose.call(this)},t}(r.MouseHandler),u=function(e){function t(t,i,o){var r=e.call(this,t,i,o)||this;return r.viewHelper.linesContentDomNode.style.touchAction="none",r._installGestureHandlerTimeout=window.setTimeout(function(){if(r._installGestureHandlerTimeout=-1,window.MSGesture){var e=new MSGesture,t=new MSGesture;e.target=r.viewHelper.linesContentDomNode,t.target=r.viewHelper.linesContentDomNode,r.viewHelper.linesContentDomNode.addEventListener("pointerdown",function(n){var i=n.pointerType;"mouse"!==i?"touch"===i?(r._lastPointerType="touch",e.addPointer(n.pointerId)):(r._lastPointerType="pen",t.addPointer(n.pointerId)):r._lastPointerType="mouse"}),r._register(n.addDisposableThrottledListener(r.viewHelper.linesContentDomNode,"MSGestureChange",function(e){return r._onGestureChange(e)},a)),r._register(n.addDisposableListener(r.viewHelper.linesContentDomNode,"MSGestureTap",function(e){return r._onCaptureGestureTap(e)},!0))}},100),r._lastPointerType="mouse",r}return o(t,e), +t.prototype._onMouseDown=function(t){"mouse"===this._lastPointerType&&e.prototype._onMouseDown.call(this,t)},t.prototype._onCaptureGestureTap=function(e){var t=this,n=new s.EditorMouseEvent(e,this.viewHelper.viewDomNode),i=this._createMouseTarget(n,!1);i.position&&this.viewController.moveTo(i.position),n.browserEvent.fromElement?(n.preventDefault(),this.viewHelper.focusTextArea()):setTimeout(function(){t.viewHelper.focusTextArea()})},t.prototype._onGestureChange=function(e){this._context.viewLayout.deltaScrollNow(-e.translationX,-e.translationY)},t.prototype.dispose=function(){window.clearTimeout(this._installGestureHandlerTimeout),e.prototype.dispose.call(this)},t}(r.MouseHandler),d=function(e){function t(t,o,r){var a=e.call(this,t,o,r)||this;return i.Gesture.addTarget(a.viewHelper.linesContentDomNode),a._register(n.addDisposableListener(a.viewHelper.linesContentDomNode,i.EventType.Tap,function(e){return a.onTap(e)})), +a._register(n.addDisposableListener(a.viewHelper.linesContentDomNode,i.EventType.Change,function(e){return a.onChange(e)})),a._register(n.addDisposableListener(a.viewHelper.linesContentDomNode,i.EventType.Contextmenu,function(e){return a._onContextMenu(new s.EditorMouseEvent(e,a.viewHelper.viewDomNode),!1)})),a}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this)},t.prototype.onTap=function(e){e.preventDefault(),this.viewHelper.focusTextArea();var t=this._createMouseTarget(new s.EditorMouseEvent(e,this.viewHelper.viewDomNode),!1);t.position&&this.viewController.moveTo(t.position)},t.prototype.onChange=function(e){this._context.viewLayout.deltaScrollNow(-e.translationX,-e.translationY)},t}(r.MouseHandler),c=function(){function e(e,t,n){window.navigator.msPointerEnabled?this.handler=new l(e,t,n):window.TouchEvent?this.handler=new d(e,t,n):window.navigator.pointerEnabled||window.PointerEvent?this.handler=new u(e,t,n):this.handler=new r.MouseHandler(e,t,n)} +return e.prototype.getTargetAtClientPoint=function(e,t){return this.handler.getTargetAtClientPoint(e,t)},e.prototype.dispose=function(){this.handler.dispose()},e}();t.PointerHandler=c}),define(t[490],n([1,0,2,184]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(e){function t(t){var n=e.call(this)||this;return n.onDidScroll=null,n.onDidGainFocus=null,n.onDidLoseFocus=null,n.onKeyDown=null,n.onKeyUp=null,n.onContextMenu=null,n.onMouseMove=null,n.onMouseLeave=null,n.onMouseUp=null,n.onMouseDown=null,n.onMouseDrag=null,n.onMouseDrop=null,n._viewModel=t,n}return o(t,e),t.prototype.emitScrollChanged=function(e){this.onDidScroll&&this.onDidScroll(e)},t.prototype.emitViewFocusGained=function(){this.onDidGainFocus&&this.onDidGainFocus(void 0)},t.prototype.emitViewFocusLost=function(){this.onDidLoseFocus&&this.onDidLoseFocus(void 0)},t.prototype.emitKeyDown=function(e){this.onKeyDown&&this.onKeyDown(e)},t.prototype.emitKeyUp=function(e){this.onKeyUp&&this.onKeyUp(e)}, +t.prototype.emitContextMenu=function(e){this.onContextMenu&&this.onContextMenu(this._convertViewToModelMouseEvent(e))},t.prototype.emitMouseMove=function(e){this.onMouseMove&&this.onMouseMove(this._convertViewToModelMouseEvent(e))},t.prototype.emitMouseLeave=function(e){this.onMouseLeave&&this.onMouseLeave(this._convertViewToModelMouseEvent(e))},t.prototype.emitMouseUp=function(e){this.onMouseUp&&this.onMouseUp(this._convertViewToModelMouseEvent(e))},t.prototype.emitMouseDown=function(e){this.onMouseDown&&this.onMouseDown(this._convertViewToModelMouseEvent(e))},t.prototype.emitMouseDrag=function(e){this.onMouseDrag&&this.onMouseDrag(this._convertViewToModelMouseEvent(e))},t.prototype.emitMouseDrop=function(e){this.onMouseDrop&&this.onMouseDrop(this._convertViewToModelMouseEvent(e))},t.prototype._convertViewToModelMouseEvent=function(e){return e.target?{event:e.event,target:this._convertViewToModelMouseTarget(e.target)}:e},t.prototype._convertViewToModelMouseTarget=function(e){ +return new s(e.element,e.type,e.mouseColumn,e.position?this._convertViewToModelPosition(e.position):null,e.range?this._convertViewToModelRange(e.range):null,e.detail)},t.prototype._convertViewToModelPosition=function(e){return this._viewModel.coordinatesConverter.convertViewPositionToModelPosition(e)},t.prototype._convertViewToModelRange=function(e){return this._viewModel.coordinatesConverter.convertViewRangeToModelRange(e)},t}(n.Disposable);t.ViewOutgoingEvents=r;var s=function(){function e(e,t,n,i,o,r){this.element=e,this.type=t,this.mouseColumn=n,this.position=i,this.range=o,this.detail=r}return e.prototype.toString=function(){return i.MouseTarget.toString(this)},e}()}),define(t[491],n([1,0,14,3,12,113,183,65,88,36,273]),function(e,t,n,i,r,s,a,l,u,d){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var c=function(){function e(){this._currentVisibleRange=new i.Range(1,1,1,1)}return e.prototype.getCurrentVisibleRange=function(){return this._currentVisibleRange}, +e.prototype.setCurrentVisibleRange=function(e){this._currentVisibleRange=e},e}(),h=function(){return function(e,t,n,i,o,r){this.lineNumber=e,this.startColumn=t,this.endColumn=n,this.startScrollTop=i,this.stopScrollTop=o,this.scrollType=r}}(),p=function(e){function t(t,i){var o=e.call(this,t)||this;o._linesContent=i,o._textRangeRestingSpot=document.createElement("div"),o._visibleLines=new s.VisibleLinesCollection(o),o.domNode=o._visibleLines.domNode;var r=o._context.configuration;return o._lineHeight=r.editor.lineHeight,o._typicalHalfwidthCharacterWidth=r.editor.fontInfo.typicalHalfwidthCharacterWidth,o._isViewportWrapping=r.editor.wrappingInfo.isViewportWrapping,o._revealHorizontalRightPadding=r.editor.viewInfo.revealHorizontalRightPadding,o._canUseLayerHinting=r.editor.canUseLayerHinting,o._viewLineOptions=new a.ViewLineOptions(r,o._context.theme.type),d.PartFingerprints.write(o.domNode,7),o.domNode.setClassName("view-lines"),l.Configuration.applyFontInfo(o.domNode,r.editor.fontInfo),o._maxLineWidth=0, +o._asyncUpdateLineWidths=new n.RunOnceScheduler(function(){o._updateLineWidthsSlow()},200),o._lastRenderedData=new c,o._horizontalRevealRequest=null,o}return o(t,e),t.prototype.dispose=function(){this._asyncUpdateLineWidths.dispose(),e.prototype.dispose.call(this)},t.prototype.getDomNode=function(){return this.domNode},t.prototype.createVisibleLine=function(){return new a.ViewLine(this._viewLineOptions)},t.prototype.onConfigurationChanged=function(e){this._visibleLines.onConfigurationChanged(e),e.wrappingInfo&&(this._maxLineWidth=0);var t=this._context.configuration;return e.lineHeight&&(this._lineHeight=t.editor.lineHeight),e.fontInfo&&(this._typicalHalfwidthCharacterWidth=t.editor.fontInfo.typicalHalfwidthCharacterWidth),e.wrappingInfo&&(this._isViewportWrapping=t.editor.wrappingInfo.isViewportWrapping),e.viewInfo&&(this._revealHorizontalRightPadding=t.editor.viewInfo.revealHorizontalRightPadding),e.canUseLayerHinting&&(this._canUseLayerHinting=t.editor.canUseLayerHinting), +e.fontInfo&&l.Configuration.applyFontInfo(this.domNode,t.editor.fontInfo),this._onOptionsMaybeChanged(),e.layoutInfo&&(this._maxLineWidth=0),!0},t.prototype._onOptionsMaybeChanged=function(){var e=this._context.configuration,t=new a.ViewLineOptions(e,this._context.theme.type);if(!this._viewLineOptions.equals(t)){this._viewLineOptions=t;for(var n=this._visibleLines.getStartLineNumber(),i=this._visibleLines.getEndLineNumber(),o=n;o<=i;o++){this._visibleLines.getVisibleLine(o).onOptionsChanged(this._viewLineOptions)}return!0}return!1},t.prototype.onCursorStateChanged=function(e){for(var t=this._visibleLines.getStartLineNumber(),n=this._visibleLines.getEndLineNumber(),i=!1,o=t;o<=n;o++)i=this._visibleLines.getVisibleLine(o).onSelectionChanged()||i;return i},t.prototype.onDecorationsChanged=function(e){for(var t=this._visibleLines.getStartLineNumber(),n=this._visibleLines.getEndLineNumber(),i=t;i<=n;i++)this._visibleLines.getVisibleLine(i).onDecorationsChanged();return!0},t.prototype.onFlushed=function(e){ +var t=this._visibleLines.onFlushed(e);return this._maxLineWidth=0,t},t.prototype.onLinesChanged=function(e){return this._visibleLines.onLinesChanged(e)},t.prototype.onLinesDeleted=function(e){return this._visibleLines.onLinesDeleted(e)},t.prototype.onLinesInserted=function(e){return this._visibleLines.onLinesInserted(e)},t.prototype.onRevealRangeRequest=function(e){var t=this._computeScrollTopToRevealRange(this._context.viewLayout.getFutureViewport(),e.range,e.verticalType),n=this._context.viewLayout.validateScrollPosition({scrollTop:t});e.revealHorizontal?e.range.startLineNumber!==e.range.endLineNumber?n={scrollTop:n.scrollTop,scrollLeft:0}:this._horizontalRevealRequest=new h(e.range.startLineNumber,e.range.startColumn,e.range.endColumn,this._context.viewLayout.getCurrentScrollTop(),n.scrollTop,e.scrollType):this._horizontalRevealRequest=null;var i=Math.abs(this._context.viewLayout.getCurrentScrollTop()-n.scrollTop) +;return 0===e.scrollType&&i>this._lineHeight?this._context.viewLayout.setScrollPositionSmooth(n):this._context.viewLayout.setScrollPositionNow(n),!0},t.prototype.onScrollChanged=function(e){if(this._horizontalRevealRequest&&e.scrollLeftChanged&&(this._horizontalRevealRequest=null),this._horizontalRevealRequest&&e.scrollTopChanged){var t=Math.min(this._horizontalRevealRequest.startScrollTop,this._horizontalRevealRequest.stopScrollTop),n=Math.max(this._horizontalRevealRequest.startScrollTop,this._horizontalRevealRequest.stopScrollTop);(e.scrollTopn)&&(this._horizontalRevealRequest=null)}return this.domNode.setWidth(e.scrollWidth),this._visibleLines.onScrollChanged(e)||!0},t.prototype.onTokensChanged=function(e){return this._visibleLines.onTokensChanged(e)},t.prototype.onZonesChanged=function(e){return this._context.viewLayout.onMaxLineWidthChanged(this._maxLineWidth),this._visibleLines.onZonesChanged(e)},t.prototype.onThemeChanged=function(e){return this._onOptionsMaybeChanged()}, +t.prototype.getPositionFromDOMInfo=function(e,t){var n=this._getViewLineDomNode(e);if(null===n)return null;var i=this._getLineNumberFor(n);if(-1===i)return null;if(i<1||i>this._context.model.getLineCount())return null;if(1===this._context.model.getLineMaxColumn(i))return new r.Position(i,1);var o=this._visibleLines.getStartLineNumber(),s=this._visibleLines.getEndLineNumber();if(is)return null;var a=this._visibleLines.getVisibleLine(i).getColumnOfNodeOffset(i,e,t),l=this._context.model.getLineMinColumn(i);return an?-1:this._visibleLines.getVisibleLine(e).getWidth()},t.prototype.linesVisibleRangesForRange=function(e,t){if(this.shouldRender())return null;var n=e.endLineNumber;if(!(e=i.Range.intersectRanges(e,this._lastRenderedData.getCurrentVisibleRange())))return null;var o,s=[],l=0,d=new a.DomReadingContext(this.domNode.domNode,this._textRangeRestingSpot);t&&(o=this._context.model.coordinatesConverter.convertViewPositionToModelPosition(new r.Position(e.startLineNumber,1)).lineNumber);for(var c=this._visibleLines.getStartLineNumber(),h=this._visibleLines.getEndLineNumber(),p=e.startLineNumber;p<=e.endLineNumber;p++)if(!(ph)){var f=p===e.startLineNumber?e.startColumn:1,g=p===e.endLineNumber?e.endColumn:this._context.model.getLineMaxColumn(p),m=this._visibleLines.getVisibleLine(p).getVisibleRangesForRange(f,g,d);if(m&&0!==m.length){if(t&&pr)){var l=s===e.startLineNumber?e.startColumn:1,u=s===e.endLineNumber?e.endColumn:this._context.model.getLineMaxColumn(s),d=this._visibleLines.getVisibleLine(s).getVisibleRangesForRange(l,u,n);d&&0!==d.length&&(t=t.concat(d))}return 0===t.length?null:t},t.prototype.updateLineWidths=function(){this._updateLineWidths(!1)},t.prototype._updateLineWidthsFast=function(){ +return this._updateLineWidths(!0)},t.prototype._updateLineWidthsSlow=function(){this._updateLineWidths(!1)},t.prototype._updateLineWidths=function(e){for(var t=this._visibleLines.getStartLineNumber(),n=this._visibleLines.getEndLineNumber(),i=1,o=!0,r=t;r<=n;r++){var s=this._visibleLines.getVisibleLine(r);!e||s.getWidthIsFast()?i=Math.max(i,s.getWidth()):o=!1}return o&&1===t&&n===this._context.model.getLineCount()&&(this._maxLineWidth=0),this._ensureMaxLineWidth(i),o},t.prototype.prepareRender=function(){throw new Error("Not supported")},t.prototype.render=function(){throw new Error("Not supported")},t.prototype.renderText=function(e){if(this._visibleLines.renderLines(e),this._lastRenderedData.setCurrentVisibleRange(e.visibleRange),this.domNode.setWidth(this._context.viewLayout.getScrollWidth()),this.domNode.setHeight(Math.min(this._context.viewLayout.getScrollHeight(),1e6)),this._horizontalRevealRequest){ +var t=this._horizontalRevealRequest.lineNumber,n=this._horizontalRevealRequest.startColumn,i=this._horizontalRevealRequest.endColumn,o=this._horizontalRevealRequest.scrollType;if(e.startLineNumber<=t&&t<=e.endLineNumber){this._horizontalRevealRequest=null,this.onDidRender();var r=this._computeScrollLeftToRevealRange(t,n,i);this._isViewportWrapping||this._ensureMaxLineWidth(r.maxHorizontalOffset),0===o?this._context.viewLayout.setScrollPositionSmooth({scrollLeft:r.scrollLeft}):this._context.viewLayout.setScrollPositionNow({scrollLeft:r.scrollLeft})}}this._updateLineWidthsFast()||this._asyncUpdateLineWidths.schedule(),this._linesContent.setLayerHinting(this._canUseLayerHinting);var s=this._context.viewLayout.getCurrentScrollTop()-e.bigNumbersDelta;this._linesContent.setTop(-s),this._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft())},t.prototype._ensureMaxLineWidth=function(e){var t=Math.ceil(e);this._maxLineWidthc&&(c=p.left+p.width)}r=c,d=Math.max(0,d-t.HORIZONTAL_EXTRA_PX),c+=this._revealHorizontalRightPadding;return{scrollLeft:this._computeMinimumScrolling(a,l,d,c), +maxHorizontalOffset:r}},t.prototype._computeMinimumScrolling=function(e,t,n,i,o,r){o=!!o,r=!!r;var s=(t|=0)-(e|=0);return(i|=0)-(n|=0)t?Math.max(0,i-s):e:n},t.HORIZONTAL_EXTRA_PX=30,t}(d.ViewPart);t.ViewLines=p}),define(t[492],n([1,0,36,6,389,7,108,26,113,3,78,73,18,16,22,285]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g){"use strict";function m(e){return 2===e?4:4===e?6:1===e?2:3}function v(e){return 2===e?2:4===e?2:1}Object.defineProperty(t,"__esModule",{value:!0});var _=140,y=function(){function e(e){var t=e.editor.pixelRatio,n=e.editor.layoutInfo,i=e.editor.viewInfo,o=e.editor.fontInfo;this.renderMinimap=0|n.renderMinimap,this.scrollBeyondLastLine=i.scrollBeyondLastLine,this.showSlider=i.minimap.showSlider,this.pixelRatio=t,this.typicalHalfwidthCharacterWidth=o.typicalHalfwidthCharacterWidth,this.lineHeight=e.editor.lineHeight,this.minimapLeft=n.minimapLeft,this.minimapWidth=n.minimapWidth,this.minimapHeight=n.height, +this.canvasInnerWidth=Math.max(1,Math.floor(t*this.minimapWidth)),this.canvasInnerHeight=Math.max(1,Math.floor(t*this.minimapHeight)),this.canvasOuterWidth=this.canvasInnerWidth/t,this.canvasOuterHeight=this.canvasInnerHeight/t}return e.prototype.equals=function(e){return this.renderMinimap===e.renderMinimap&&this.scrollBeyondLastLine===e.scrollBeyondLastLine&&this.showSlider===e.showSlider&&this.pixelRatio===e.pixelRatio&&this.typicalHalfwidthCharacterWidth===e.typicalHalfwidthCharacterWidth&&this.lineHeight===e.lineHeight&&this.minimapLeft===e.minimapLeft&&this.minimapWidth===e.minimapWidth&&this.minimapHeight===e.minimapHeight&&this.canvasInnerWidth===e.canvasInnerWidth&&this.canvasInnerHeight===e.canvasInnerHeight&&this.canvasOuterWidth===e.canvasOuterWidth&&this.canvasOuterHeight===e.canvasOuterHeight},e}(),C=function(){function e(e,t,n,i,o,r,s){this.scrollTop=e,this.scrollHeight=t,this._computedSliderRatio=n,this.sliderTop=i,this.sliderHeight=o,this.startLineNumber=r,this.endLineNumber=s} +return e.prototype.getDesiredScrollTopFromDelta=function(e){var t=this.sliderTop+e;return Math.round(t/this._computedSliderRatio)},e.create=function(t,n,i,o,r,s,a,l,u){var d,c=t.pixelRatio,h=m(t.renderMinimap),p=Math.floor(t.canvasInnerHeight/h),f=t.lineHeight;if(r&&i!==s){var g=i-n+1;d=Math.floor(g*h/c)}else{var v=o/f;d=Math.floor(v*h/c)}var _;_=t.scrollBeyondLastLine?(s-1)*h/c:Math.max(0,s*h/c-d);var y=(_=Math.min(t.minimapHeight-d,_))/(l-o),C=a*y;if(p>=s){return new e(a,l,y,C,d,b=1,S=s)}var b=Math.max(1,Math.floor(n-C*c/h));u&&u.scrollHeight===l&&(u.scrollTop>a&&(b=Math.min(b,u.startLineNumber)),u.scrollTop_)i._context.viewLayout.setScrollPositionNow({scrollTop:o.scrollTop});else{var s=e.posy-t;i._context.viewLayout.setScrollPositionNow({scrollTop:o.getDesiredScrollTopFromDelta(s)})}},function(){i._slider.toggleClassName("active",!1)})}}),i}return o(t,e),t.prototype.dispose=function(){this._mouseDownListener.dispose(),this._sliderMouseMoveMonitor.dispose(),this._sliderMouseDownListener.dispose(),e.prototype.dispose.call(this)},t.prototype._getMinimapDomNodeClassName=function(){ +return"always"===this._options.showSlider?"minimap slider-always":"minimap slider-mouseover"},t.prototype.getDomNode=function(){return this._domNode},t.prototype._applyLayout=function(){this._domNode.setLeft(this._options.minimapLeft),this._domNode.setWidth(this._options.minimapWidth),this._domNode.setHeight(this._options.minimapHeight),this._shadow.setHeight(this._options.minimapHeight),this._canvas.setWidth(this._options.canvasOuterWidth),this._canvas.setHeight(this._options.canvasOuterHeight),this._canvas.domNode.width=this._options.canvasInnerWidth,this._canvas.domNode.height=this._options.canvasInnerHeight,this._slider.setWidth(this._options.minimapWidth)},t.prototype._getBuffer=function(){return this._buffers||(this._buffers=new w(this._canvas.domNode.getContext("2d"),this._options.canvasInnerWidth,this._options.canvasInnerHeight,this._tokensColorTracker.getColor(2))),this._buffers.getBuffer()},t.prototype._onOptionsMaybeChanged=function(){var e=new y(this._context.configuration) +;return!this._options.equals(e)&&(this._options=e,this._lastRenderData=null,this._buffers=null,this._applyLayout(),this._domNode.setClassName(this._getMinimapDomNodeClassName()),!0)},t.prototype.onConfigurationChanged=function(e){return this._onOptionsMaybeChanged()},t.prototype.onFlushed=function(e){return this._lastRenderData=null,!0},t.prototype.onLinesChanged=function(e){return!!this._lastRenderData&&this._lastRenderData.onLinesChanged(e)},t.prototype.onLinesDeleted=function(e){return this._lastRenderData&&this._lastRenderData.onLinesDeleted(e),!0},t.prototype.onLinesInserted=function(e){return this._lastRenderData&&this._lastRenderData.onLinesInserted(e),!0},t.prototype.onScrollChanged=function(e){return!0},t.prototype.onTokensChanged=function(e){return!!this._lastRenderData&&this._lastRenderData.onTokensChanged(e)},t.prototype.onTokensColorsChanged=function(e){return this._lastRenderData=null,this._buffers=null,!0},t.prototype.onZonesChanged=function(e){return this._lastRenderData=null,!0}, +t.prototype.prepareRender=function(e){},t.prototype.render=function(e){if(0===this._options.renderMinimap)return this._shadow.setClassName("minimap-shadow-hidden"),this._sliderHorizontal.setWidth(0),void this._sliderHorizontal.setHeight(0);e.scrollLeft+e.viewportWidth>=e.scrollWidth?this._shadow.setClassName("minimap-shadow-hidden"):this._shadow.setClassName("minimap-shadow-visible");var t=C.create(this._options,e.visibleRange.startLineNumber,e.visibleRange.endLineNumber,e.viewportHeight,e.viewportData.whitespaceViewportData.length>0,this._context.model.getLineCount(),e.scrollTop,e.scrollHeight,this._lastRenderData?this._lastRenderData.renderedLayout:null);this._slider.setTop(t.sliderTop),this._slider.setHeight(t.sliderHeight);var n=e.scrollLeft/this._options.typicalHalfwidthCharacterWidth,i=Math.min(this._options.minimapWidth,Math.round(n*v(this._options.renderMinimap)/this._options.pixelRatio));this._sliderHorizontal.setLeft(i),this._sliderHorizontal.setWidth(this._options.minimapWidth-i), +this._sliderHorizontal.setTop(0),this._sliderHorizontal.setHeight(t.sliderHeight),this._lastRenderData=this.renderLines(t)},t.prototype.renderLines=function(e){var n=this._options.renderMinimap,i=e.startLineNumber,o=e.endLineNumber,s=m(n);if(this._lastRenderData&&this._lastRenderData.linesEquals(e)){var a=this._lastRenderData._get();return new S(e,a.imageData,a.lines)}for(var l=this._getBuffer(),u=t._renderUntouchedLines(l,i,o,s,this._lastRenderData),d=u[0],c=u[1],h=u[2],p=this._context.model.getMinimapLinesRenderingData(i,o,h),f=p.tabSize,g=this._tokensColorTracker.getColor(2),v=this._tokensColorTracker.backgroundIsLight(),_=0,y=[],C=0,w=o-i+1;C=0&&Lp)return;var w=d.charCodeAt(g);if(9===w){var E=l-(g+m)%l;m+=E-1,f+=E*h +}else if(32===w)f+=h;else for(var L=i.isFullWidthCharacter(w)?2:1,x=0;xp)return}},t}(n.ViewPart);t.Minimap=E,f.registerThemingParticipant(function(e,t){var n=e.getColor(g.scrollbarSliderBackground);if(n){var i=n.transparent(.5);t.addRule(".monaco-editor .minimap-slider, .monaco-editor .minimap-slider .minimap-slider-horizontal { background: "+i+"; }")}var o=e.getColor(g.scrollbarSliderHoverBackground);if(o){var r=o.transparent(.5);t.addRule(".monaco-editor .minimap-slider:hover, .monaco-editor .minimap-slider:hover .minimap-slider-horizontal { background: "+r+"; }")}var s=e.getColor(g.scrollbarSliderActiveBackground);if(s){var a=s.transparent(.5);t.addRule(".monaco-editor .minimap-slider.active, .monaco-editor .minimap-slider.active .minimap-slider-horizontal { background: "+a+"; }")}var l=e.getColor(g.scrollbarShadow) +;l&&t.addRule(".monaco-editor .minimap-shadow-visible { box-shadow: "+l+" -6px 0 6px -6px inset; }")})}),define(t[493],n([1,0,26,36,16,22,297]),function(e,t,n,i,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(e){function t(t){var i=e.call(this,t)||this;return i._scrollTop=0,i._width=0,i._updateWidth(),i._shouldShow=!1,i._useShadows=i._context.configuration.editor.viewInfo.scrollbar.useShadows,i._domNode=n.createFastDomNode(document.createElement("div")),i._domNode.setAttribute("role","presentation"),i._domNode.setAttribute("aria-hidden","true"),i}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this)},t.prototype._updateShouldShow=function(){var e=this._useShadows&&this._scrollTop>0;return this._shouldShow!==e&&(this._shouldShow=e,!0)},t.prototype.getDomNode=function(){return this._domNode},t.prototype._updateWidth=function(){var e=this._context.configuration.editor.layoutInfo,t=0 +;return t=0===e.renderMinimap||e.minimapWidth>0&&0===e.minimapLeft?e.width:e.width-e.minimapWidth-e.verticalScrollbarWidth,this._width!==t&&(this._width=t,!0)},t.prototype.onConfigurationChanged=function(e){var t=!1;return e.viewInfo&&(this._useShadows=this._context.configuration.editor.viewInfo.scrollbar.useShadows),e.layoutInfo&&(t=this._updateWidth()),this._updateShouldShow()||t},t.prototype.onScrollChanged=function(e){return this._scrollTop=e.scrollTop,this._updateShouldShow()},t.prototype.prepareRender=function(e){},t.prototype.render=function(e){this._domNode.setWidth(this._width),this._domNode.setClassName(this._shouldShow?"scroll-decoration":"")},t}(i.ViewPart);t.ScrollDecorationViewPart=a,r.registerThemingParticipant(function(e,t){var n=e.getColor(s.scrollbarShadow);n&&t.addRule(".monaco-editor .scroll-decoration { box-shadow: "+n+" 0 6px 6px -6px inset; }")})}),define(t[494],n([1,0,16,22,59,30,333]),function(e,t,n,i,r,s){"use strict";function a(e){return new d(e)}function l(e){ +return new c(e.lineNumber,e.ranges.map(a))}function u(e){return e<0?-e:e}Object.defineProperty(t,"__esModule",{value:!0});var d=function(){return function(e){this.left=e.left,this.width=e.width,this.startStyle=null,this.endStyle=null}}(),c=function(){return function(e,t){this.lineNumber=e,this.ranges=t}}(),h=s.isEdgeOrIE,p=function(e){function t(t){var n=e.call(this)||this;return n._previousFrameVisibleRangesWithStyle=[],n._context=t,n._lineHeight=n._context.configuration.editor.lineHeight,n._roundedSelection=n._context.configuration.editor.viewInfo.roundedSelection,n._typicalHalfwidthCharacterWidth=n._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth,n._selections=[],n._renderResult=null,n._context.addEventHandler(n),n}return o(t,e),t.prototype.dispose=function(){this._context.removeEventHandler(this),this._context=null,this._selections=null,this._renderResult=null,e.prototype.dispose.call(this)},t.prototype.onConfigurationChanged=function(e){ +return e.lineHeight&&(this._lineHeight=this._context.configuration.editor.lineHeight),e.viewInfo&&(this._roundedSelection=this._context.configuration.editor.viewInfo.roundedSelection),e.fontInfo&&(this._typicalHalfwidthCharacterWidth=this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth),!0},t.prototype.onCursorStateChanged=function(e){return this._selections=e.selections.slice(0),!0},t.prototype.onDecorationsChanged=function(e){return!0},t.prototype.onFlushed=function(e){return!0},t.prototype.onLinesChanged=function(e){return!0},t.prototype.onLinesDeleted=function(e){return!0},t.prototype.onLinesInserted=function(e){return!0},t.prototype.onScrollChanged=function(e){return e.scrollTopChanged},t.prototype.onZonesChanged=function(e){return!0},t.prototype._visibleRangesHaveGaps=function(e){for(var t=0,n=e.length;t1)return!0}return!1},t.prototype._enrichVisibleRangesWithStyle=function(e,t,n){var i=this._typicalHalfwidthCharacterWidth/4,o=null,r=null +;if(n&&n.length>0&&t.length>0){var s=t[0].lineNumber;if(s===e.startLineNumber)for(l=0;!o&&l=0;l--)n[l].lineNumber===a&&(r=n[l].ranges[0]);o&&!o.startStyle&&(o=null),r&&!r.startStyle&&(r=null)}for(var l=0,d=t.length;l0){var m=t[l-1].ranges[0].left,v=t[l-1].ranges[0].left+t[l-1].ranges[0].width;u(h-m)m&&(f.top=1),u(p-v)'},t.prototype._actualRenderOneSelection=function(e,n,i,o){for(var r=o.length>0&&o[0].ranges[0].startStyle,s=this._lineHeight.toString(),a=(this._lineHeight-1).toString(),l=o.length>0?o[0].lineNumber:0,u=o.length>0?o[o.length-1].lineNumber:0,d=0,c=o.length;d1,u)}}this._previousFrameVisibleRangesWithStyle=r,this._renderResult=t},t.prototype.render=function(e,t){if(!this._renderResult)return"";var n=t-e;return n<0||n>=this._renderResult.length?"":this._renderResult[n]},t.SELECTION_CLASS_NAME="selected-text",t.SELECTION_TOP_LEFT="top-left-radius",t.SELECTION_BOTTOM_LEFT="bottom-left-radius",t.SELECTION_TOP_RIGHT="top-right-radius",t.SELECTION_BOTTOM_RIGHT="bottom-right-radius",t.EDITOR_BACKGROUND_CLASS_NAME="monaco-editor-background",t.ROUNDED_PIECE_WIDTH=10,t}(r.DynamicViewOverlay);t.SelectionsOverlay=p,n.registerThemingParticipant(function(e,t){var n=e.getColor(i.editorSelectionBackground);n&&t.addRule(".monaco-editor .focused .selected-text { background-color: "+n+"; }");var o=e.getColor(i.editorInactiveSelection) +;o&&t.addRule(".monaco-editor .selected-text { background-color: "+o+"; }");var r=e.getColor(i.editorSelectionForeground);r&&t.addRule(".monaco-editor .view-line span.inline-selected-text { color: "+r+"; }")})}),define(t[35],n([1,0,302,22,16,27]),function(e,t,n,i,o,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.editorLineHighlight=i.registerColor("editor.lineHighlightBackground",{dark:null,light:null,hc:null},n.localize(0,null)),t.editorLineHighlightBorder=i.registerColor("editor.lineHighlightBorder",{dark:"#282828",light:"#eeeeee",hc:"#f38518"},n.localize(1,null)),t.editorRangeHighlight=i.registerColor("editor.rangeHighlightBackground",{dark:"#ffffff0b",light:"#fdff0033",hc:null},n.localize(2,null),!0),t.editorRangeHighlightBorder=i.registerColor("editor.rangeHighlightBorder",{dark:null,light:null,hc:i.activeContrastBorder},n.localize(3,null),!0),t.editorCursorForeground=i.registerColor("editorCursor.foreground",{dark:"#AEAFAD",light:r.Color.black,hc:r.Color.white},n.localize(4,null)), +t.editorCursorBackground=i.registerColor("editorCursor.background",null,n.localize(5,null)),t.editorWhitespaces=i.registerColor("editorWhitespace.foreground",{dark:"#e3e4e229",light:"#33333333",hc:"#e3e4e229"},n.localize(6,null)),t.editorIndentGuides=i.registerColor("editorIndentGuide.background",{dark:t.editorWhitespaces,light:t.editorWhitespaces,hc:t.editorWhitespaces},n.localize(7,null)),t.editorActiveIndentGuides=i.registerColor("editorIndentGuide.activeBackground",{dark:t.editorWhitespaces,light:t.editorWhitespaces,hc:t.editorWhitespaces},n.localize(8,null)),t.editorLineNumbers=i.registerColor("editorLineNumber.foreground",{dark:"#858585",light:"#237893",hc:r.Color.white},n.localize(9,null));var s=i.registerColor("editorActiveLineNumber.foreground",{dark:"#c6c6c6",light:"#0B216F",hc:i.activeContrastBorder},n.localize(10,null),!1,n.localize(11,null));t.editorActiveLineNumber=i.registerColor("editorLineNumber.activeForeground",{dark:s,light:s,hc:s},n.localize(12,null)), +t.editorRuler=i.registerColor("editorRuler.foreground",{dark:"#5A5A5A",light:r.Color.lightgrey,hc:r.Color.white},n.localize(13,null)),t.editorCodeLensForeground=i.registerColor("editorCodeLens.foreground",{dark:"#999999",light:"#999999",hc:"#999999"},n.localize(14,null)),t.editorBracketMatchBackground=i.registerColor("editorBracketMatch.background",{dark:"#0064001a",light:"#0064001a",hc:"#0064001a"},n.localize(15,null)),t.editorBracketMatchBorder=i.registerColor("editorBracketMatch.border",{dark:"#888",light:"#B9B9B9",hc:"#fff"},n.localize(16,null)),t.editorOverviewRulerBorder=i.registerColor("editorOverviewRuler.border",{dark:"#7f7f7f4d",light:"#7f7f7f4d",hc:"#7f7f7f4d"},n.localize(17,null)),t.editorGutter=i.registerColor("editorGutter.background",{dark:i.editorBackground,light:i.editorBackground,hc:i.editorBackground},n.localize(18,null)),t.editorErrorForeground=i.registerColor("editorError.foreground",{dark:"#ea4646",light:"#d60a0a",hc:null},n.localize(19,null)), +t.editorErrorBorder=i.registerColor("editorError.border",{dark:null,light:null,hc:r.Color.fromHex("#E47777").transparent(.8)},n.localize(20,null)),t.editorWarningForeground=i.registerColor("editorWarning.foreground",{dark:"#4d9e4d",light:"#117711",hc:null},n.localize(21,null)),t.editorWarningBorder=i.registerColor("editorWarning.border",{dark:null,light:null,hc:r.Color.fromHex("#71B771").transparent(.8)},n.localize(22,null)),t.editorInfoForeground=i.registerColor("editorInfo.foreground",{dark:"#008000",light:"#008000",hc:null},n.localize(23,null)),t.editorInfoBorder=i.registerColor("editorInfo.border",{dark:null,light:null,hc:r.Color.fromHex("#71B771").transparent(.8)},n.localize(24,null)),t.editorHintForeground=i.registerColor("editorHint.foreground",{dark:r.Color.fromHex("#eeeeee").transparent(.7),light:"#6c6c6c",hc:null},n.localize(25,null)),t.editorHintBorder=i.registerColor("editorHint.border",{dark:null,light:null,hc:r.Color.fromHex("#eeeeee").transparent(.8)},n.localize(26,null)), +t.editorUnnecessaryCodeBorder=i.registerColor("editorUnnecessaryCode.border",{dark:null,light:null,hc:r.Color.fromHex("#fff").transparent(.8)},n.localize(27,null)),t.editorUnnecessaryCodeOpacity=i.registerColor("editorUnnecessaryCode.opacity",{dark:r.Color.fromHex("#000a"),light:r.Color.fromHex("#0007"),hc:null},n.localize(28,null)),t.overviewRulerError=i.registerColor("editorOverviewRuler.errorForeground",{dark:new r.Color(new r.RGBA(255,18,18,.7)),light:new r.Color(new r.RGBA(255,18,18,.7)),hc:new r.Color(new r.RGBA(255,50,50,1))},n.localize(29,null)),t.overviewRulerWarning=i.registerColor("editorOverviewRuler.warningForeground",{dark:new r.Color(new r.RGBA(18,136,18,.7)),light:new r.Color(new r.RGBA(18,136,18,.7)),hc:new r.Color(new r.RGBA(50,255,50,1))},n.localize(30,null)),t.overviewRulerInfo=i.registerColor("editorOverviewRuler.infoForeground",{dark:new r.Color(new r.RGBA(18,18,136,.7)),light:new r.Color(new r.RGBA(18,18,136,.7)),hc:new r.Color(new r.RGBA(50,50,255,1))},n.localize(31,null)), +o.registerThemingParticipant(function(e,n){var o=e.getColor(i.editorBackground);o&&n.addRule(".monaco-editor, .monaco-editor-background, .monaco-editor .inputarea.ime-input { background-color: "+o+"; }");var r=e.getColor(i.editorForeground);r&&n.addRule(".monaco-editor, .monaco-editor .inputarea.ime-input { color: "+r+"; }");var s=e.getColor(t.editorGutter);s&&n.addRule(".monaco-editor .margin { background-color: "+s+"; }");var a=e.getColor(t.editorRangeHighlight);a&&n.addRule(".monaco-editor .rangeHighlight { background-color: "+a+"; }");var l=e.getColor(t.editorRangeHighlightBorder);l&&n.addRule(".monaco-editor .rangeHighlight { border: 1px "+("hc"===e.type?"dotted":"solid")+" "+l+"; }");var u=e.getColor(t.editorWhitespaces);u&&n.addRule(".vs-whitespace { color: "+u+" !important; }")})}),define(t[496],n([1,0,59,16,35,262]),function(e,t,n,i,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=function(e){function t(t){var n=e.call(this)||this;return n._context=t, +n._lineHeight=n._context.configuration.editor.lineHeight,n._renderLineHighlight=n._context.configuration.editor.viewInfo.renderLineHighlight,n._selectionIsEmpty=!0,n._primaryCursorLineNumber=1,n._scrollWidth=0,n._contentWidth=n._context.configuration.editor.layoutInfo.contentWidth,n._context.addEventHandler(n),n}return o(t,e),t.prototype.dispose=function(){this._context.removeEventHandler(this),this._context=null,e.prototype.dispose.call(this)},t.prototype.onConfigurationChanged=function(e){return e.lineHeight&&(this._lineHeight=this._context.configuration.editor.lineHeight),e.viewInfo&&(this._renderLineHighlight=this._context.configuration.editor.viewInfo.renderLineHighlight),e.layoutInfo&&(this._contentWidth=this._context.configuration.editor.layoutInfo.contentWidth),!0},t.prototype.onCursorStateChanged=function(e){var t=!1,n=e.selections[0].positionLineNumber;this._primaryCursorLineNumber!==n&&(this._primaryCursorLineNumber=n,t=!0);var i=e.selections[0].isEmpty() +;return this._selectionIsEmpty!==i?(this._selectionIsEmpty=i,t=!0,!0):t},t.prototype.onFlushed=function(e){return!0},t.prototype.onLinesDeleted=function(e){return!0},t.prototype.onLinesInserted=function(e){return!0},t.prototype.onScrollChanged=function(e){return e.scrollWidthChanged},t.prototype.onZonesChanged=function(e){return!0},t.prototype.prepareRender=function(e){this._scrollWidth=e.scrollWidth},t.prototype.render=function(e,t){if(t===this._primaryCursorLineNumber){if(this._shouldShowCurrentLine()){return'
                                      '}return""}return""},t.prototype._shouldShowCurrentLine=function(){return("line"===this._renderLineHighlight||"all"===this._renderLineHighlight)&&this._selectionIsEmpty},t.prototype._willRenderMarginCurrentLine=function(){ +return"gutter"===this._renderLineHighlight||"all"===this._renderLineHighlight},t}(n.DynamicViewOverlay);t.CurrentLineHighlightOverlay=s,i.registerThemingParticipant(function(e,t){var n=e.getColor(r.editorLineHighlight);if(n&&t.addRule(".monaco-editor .view-overlays .current-line { background-color: "+n+"; }"),!n||n.isTransparent()||e.defines(r.editorLineHighlightBorder)){var i=e.getColor(r.editorLineHighlightBorder);i&&(t.addRule(".monaco-editor .view-overlays .current-line { border: 2px solid "+i+"; }"),"hc"===e.type&&t.addRule(".monaco-editor .view-overlays .current-line { border-width: 1px; }"))}})}),define(t[497],n([1,0,59,16,35,263]),function(e,t,n,i,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var s=function(e){function t(t){var n=e.call(this)||this;return n._context=t,n._lineHeight=n._context.configuration.editor.lineHeight,n._renderLineHighlight=n._context.configuration.editor.viewInfo.renderLineHighlight,n._selectionIsEmpty=!0,n._primaryCursorLineNumber=1, +n._contentLeft=n._context.configuration.editor.layoutInfo.contentLeft,n._context.addEventHandler(n),n}return o(t,e),t.prototype.dispose=function(){this._context.removeEventHandler(this),this._context=null,e.prototype.dispose.call(this)},t.prototype.onConfigurationChanged=function(e){return e.lineHeight&&(this._lineHeight=this._context.configuration.editor.lineHeight),e.viewInfo&&(this._renderLineHighlight=this._context.configuration.editor.viewInfo.renderLineHighlight),e.layoutInfo&&(this._contentLeft=this._context.configuration.editor.layoutInfo.contentLeft),!0},t.prototype.onCursorStateChanged=function(e){var t=!1,n=e.selections[0].positionLineNumber;this._primaryCursorLineNumber!==n&&(this._primaryCursorLineNumber=n,t=!0);var i=e.selections[0].isEmpty();return this._selectionIsEmpty!==i?(this._selectionIsEmpty=i,t=!0,!0):t},t.prototype.onFlushed=function(e){return!0},t.prototype.onLinesDeleted=function(e){return!0},t.prototype.onLinesInserted=function(e){return!0},t.prototype.onZonesChanged=function(e){ +return!0},t.prototype.prepareRender=function(e){},t.prototype.render=function(e,t){if(t===this._primaryCursorLineNumber){var n="current-line";if(this._shouldShowCurrentLine()){n="current-line current-line-margin"+(this._willRenderContentCurrentLine()?" current-line-margin-both":"")}return'
                                      '}return""},t.prototype._shouldShowCurrentLine=function(){return"gutter"===this._renderLineHighlight||"all"===this._renderLineHighlight},t.prototype._willRenderContentCurrentLine=function(){return("line"===this._renderLineHighlight||"all"===this._renderLineHighlight)&&this._selectionIsEmpty},t}(n.DynamicViewOverlay);t.CurrentLineMarginHighlightOverlay=s,i.registerThemingParticipant(function(e,t){var n=e.getColor(r.editorLineHighlight);if(n)t.addRule(".monaco-editor .margin-view-overlays .current-line-margin { background-color: "+n+"; border: none; }");else{var i=e.getColor(r.editorLineHighlightBorder) +;i&&t.addRule(".monaco-editor .margin-view-overlays .current-line-margin { border: 2px solid "+i+"; }"),"hc"===e.type&&t.addRule(".monaco-editor .margin-view-overlays .current-line-margin { border-width: 1px; }")}})}),define(t[498],n([1,0,59,16,35,12,268]),function(e,t,n,i,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(e){function t(t){var n=e.call(this)||this;return n._context=t,n._primaryLineNumber=0,n._lineHeight=n._context.configuration.editor.lineHeight,n._spaceWidth=n._context.configuration.editor.fontInfo.spaceWidth,n._enabled=n._context.configuration.editor.viewInfo.renderIndentGuides,n._activeIndentEnabled=n._context.configuration.editor.viewInfo.highlightActiveIndentGuide,n._renderResult=null,n._context.addEventHandler(n),n}return o(t,e),t.prototype.dispose=function(){this._context.removeEventHandler(this),this._context=null,this._renderResult=null,e.prototype.dispose.call(this)},t.prototype.onConfigurationChanged=function(e){ +return e.lineHeight&&(this._lineHeight=this._context.configuration.editor.lineHeight),e.fontInfo&&(this._spaceWidth=this._context.configuration.editor.fontInfo.spaceWidth),e.viewInfo&&(this._enabled=this._context.configuration.editor.viewInfo.renderIndentGuides,this._activeIndentEnabled=this._context.configuration.editor.viewInfo.highlightActiveIndentGuide),!0},t.prototype.onCursorStateChanged=function(e){var t=e.selections[0],n=t.isEmpty()?t.positionLineNumber:0;return this._primaryLineNumber!==n&&(this._primaryLineNumber=n,!0)},t.prototype.onDecorationsChanged=function(e){return!0},t.prototype.onFlushed=function(e){return!0},t.prototype.onLinesChanged=function(e){return!0},t.prototype.onLinesDeleted=function(e){return!0},t.prototype.onLinesInserted=function(e){return!0},t.prototype.onScrollChanged=function(e){return e.scrollTopChanged},t.prototype.onZonesChanged=function(e){return!0},t.prototype.onLanguageConfigurationChanged=function(e){return!0},t.prototype.prepareRender=function(e){if(this._enabled){ +var t=e.visibleRange.startLineNumber,n=e.visibleRange.endLineNumber,i=this._context.model.getTabSize()*this._spaceWidth,o=e.scrollWidth,r=this._lineHeight,a=i,l=this._context.model.getLinesIndentGuides(t,n),u=0,d=0,c=0;if(this._activeIndentEnabled&&this._primaryLineNumber){var h=this._context.model.getActiveIndentGuide(this._primaryLineNumber,t,n);u=h.startLineNumber,d=h.endLineNumber,c=h.indent}for(var p=[],f=t;f<=n;f++){for(var g=u<=f&&f<=d,m=f-t,v=l[m],_="",y=e.visibleRangeForPosition(new s.Position(f,1)),C=y?y.left:0,b=1;b<=v;b++){if(_+='
                                      ',(C+=i)>o)break}p[m]=_}this._renderResult=p}else this._renderResult=null},t.prototype.render=function(e,t){if(!this._renderResult)return"";var n=t-e;return n<0||n>=this._renderResult.length?"":this._renderResult[n]},t}(n.DynamicViewOverlay);t.IndentGuidesOverlay=a,i.registerThemingParticipant(function(e,t){var n=e.getColor(r.editorIndentGuides) +;n&&t.addRule(".monaco-editor .lines-content .cigr { box-shadow: 1px 0 0 0 "+n+" inset; }");var i=e.getColor(r.editorActiveIndentGuides)||n;i&&t.addRule(".monaco-editor .lines-content .cigra { box-shadow: 1px 0 0 0 "+i+" inset; }")})}),define(t[186],n([1,0,35,16,18,59,12,270]),function(e,t,n,i,r,s,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var l=function(e){function t(t){var n=e.call(this)||this;return n._context=t,n._readConfig(),n._lastCursorModelPosition=new a.Position(1,1),n._renderResult=null,n._context.addEventHandler(n),n}return o(t,e),t.prototype._readConfig=function(){var e=this._context.configuration.editor;this._lineHeight=e.lineHeight,this._renderLineNumbers=e.viewInfo.renderLineNumbers,this._renderCustomLineNumbers=e.viewInfo.renderCustomLineNumbers,this._lineNumbersLeft=e.layoutInfo.lineNumbersLeft,this._lineNumbersWidth=e.layoutInfo.lineNumbersWidth},t.prototype.dispose=function(){this._context.removeEventHandler(this),this._context=null,this._renderResult=null, +e.prototype.dispose.call(this)},t.prototype.onConfigurationChanged=function(e){return this._readConfig(),!0},t.prototype.onCursorStateChanged=function(e){var t=e.selections[0].getPosition();return this._lastCursorModelPosition=this._context.model.coordinatesConverter.convertViewPositionToModelPosition(t),2===this._renderLineNumbers||3===this._renderLineNumbers},t.prototype.onFlushed=function(e){return!0},t.prototype.onLinesChanged=function(e){return!0},t.prototype.onLinesDeleted=function(e){return!0},t.prototype.onLinesInserted=function(e){return!0},t.prototype.onScrollChanged=function(e){return e.scrollTopChanged},t.prototype.onZonesChanged=function(e){return!0},t.prototype._getLineRenderLineNumber=function(e){var t=this._context.model.coordinatesConverter.convertViewPositionToModelPosition(new a.Position(e,1));if(1!==t.column)return"";var n=t.lineNumber;if(this._renderCustomLineNumbers)return this._renderCustomLineNumbers(n);if(2===this._renderLineNumbers){ +var i=Math.abs(this._lastCursorModelPosition.lineNumber-n);return 0===i?''+n+"":String(i)}return 3===this._renderLineNumbers?this._lastCursorModelPosition.lineNumber===n?String(n):n%10==0?String(n):"":String(n)},t.prototype.prepareRender=function(e){if(0!==this._renderLineNumbers){for(var n=r.isLinux?this._lineHeight%2==0?" lh-even":" lh-odd":"",i=e.visibleRange.startLineNumber,o=e.visibleRange.endLineNumber,s='
                                      ',a=[],l=i;l<=o;l++){var u=l-i,d=this._getLineRenderLineNumber(l);a[u]=d?s+d+"
                                      ":""}this._renderResult=a}else this._renderResult=null},t.prototype.render=function(e,t){if(!this._renderResult)return"";var n=t-e;return n<0||n>=this._renderResult.length?"":this._renderResult[n]},t.CLASS_NAME="line-numbers",t}(s.DynamicViewOverlay);t.LineNumbersOverlay=l,i.registerThemingParticipant(function(e,t){ +var i=e.getColor(n.editorLineNumbers);i&&t.addRule(".monaco-editor .line-numbers { color: "+i+"; }");var o=e.getColor(n.editorActiveLineNumber);o&&t.addRule(".monaco-editor .current-line ~ .line-numbers { color: "+o+"; }")})}),define(t[500],n([1,0,18,30,6,165,164,3,21,12,65,78,26,36,163,186,89,254]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m,v){"use strict";function _(e,t){var n=document.createElement("canvas").getContext("2d");n.font=function(e){return function(e,t,n,i,o){return e+" normal "+t+" "+n+"px / "+i+"px "+o}("normal",e.fontWeight,e.fontSize,e.lineHeight,e.fontFamily)}(t);var o=n.measureText(e);return i.isFirefox?o.width+2:o.width}Object.defineProperty(t,"__esModule",{value:!0});var y=function(){function e(e,t,n){this.top=e,this.left=t,this.width=n}return e.prototype.setWidth=function(t){return new e(this.top,this.left,t)},e}(),C=i.isEdgeOrIE||i.isFirefox,b=function(){function e(){this._lastState=null}return e.prototype.set=function(e){this._lastState=e},e.prototype.get=function(e){ +return this._lastState&&this._lastState.lastCopiedValue===e?this._lastState:(this._lastState=null,null)},e.INSTANCE=new e,e}(),S=function(e){function t(t,o,r){var d=e.call(this,t)||this;d._primaryCursorVisibleRange=null,d._viewController=o,d._viewHelper=r;var c=d._context.configuration.editor;d._accessibilitySupport=c.accessibilitySupport,d._contentLeft=c.layoutInfo.contentLeft,d._contentWidth=c.layoutInfo.contentWidth,d._contentHeight=c.layoutInfo.contentHeight,d._scrollLeft=0,d._scrollTop=0,d._fontInfo=c.fontInfo,d._lineHeight=c.lineHeight,d._emptySelectionClipboard=c.emptySelectionClipboard,d._visibleTextArea=null,d._selections=[new u.Selection(1,1,1,1)],d.textArea=p.createFastDomNode(document.createElement("textarea")),f.PartFingerprints.write(d.textArea,6),d.textArea.setClassName("inputarea"),d.textArea.setAttribute("wrap","off"),d.textArea.setAttribute("autocorrect","off"),d.textArea.setAttribute("autocapitalize","off"),d.textArea.setAttribute("autocomplete","off"), +d.textArea.setAttribute("spellcheck","false"),d.textArea.setAttribute("aria-label",c.viewInfo.ariaLabel),d.textArea.setAttribute("role","textbox"),d.textArea.setAttribute("aria-multiline","true"),d.textArea.setAttribute("aria-haspopup","false"),d.textArea.setAttribute("aria-autocomplete","both"),d.textAreaCover=p.createFastDomNode(document.createElement("div")),d.textAreaCover.setPosition("absolute");var g={getLineCount:function(){return d._context.model.getLineCount()},getLineMaxColumn:function(e){return d._context.model.getLineMaxColumn(e)},getValueInRange:function(e,t){return d._context.model.getValueInRange(e,t)}},m={getPlainTextToCopy:function(){var e=d._context.model.getPlainTextToCopy(d._selections,d._emptySelectionClipboard,n.isWindows),t=d._context.model.getEOL(),o=d._emptySelectionClipboard&&1===d._selections.length&&d._selections[0].isEmpty(),r=Array.isArray(e)?e:null,s=Array.isArray(e)?e.join(t):e,a=null;if(o||r){a={lastCopiedValue:i.isFirefox?s.replace(/\r\n/g,"\n"):s, +isFromEmptySelection:d._emptySelectionClipboard&&1===d._selections.length&&d._selections[0].isEmpty(),multicursorText:r}}return b.INSTANCE.set(a),s},getHTMLToCopy:function(){return d._context.model.getHTMLToCopy(d._selections,d._emptySelectionClipboard)},getScreenReaderContent:function(e){if(i.isIPad)return a.TextAreaState.EMPTY;if(1===d._accessibilitySupport){if(n.isMacintosh){var t=d._selections[0];if(t.isEmpty()){var o=t.getStartPosition(),r=d._getWordBeforePosition(o);if(0===r.length&&(r=d._getCharacterBeforePosition(o)),r.length>0)return new a.TextAreaState(r,r.length,r.length,o,o)}}return a.TextAreaState.EMPTY}return a.PagedScreenReaderStrategy.fromEditorSelection(e,g,d._selections[0],0===d._accessibilitySupport)},deduceModelPosition:function(e,t,n){return d._context.model.deduceModelPositionRelativeToViewPosition(e,t,n)}};return d._textAreaInput=d._register(new s.TextAreaInput(m,d.textArea)),d._register(d._textAreaInput.onKeyDown(function(e){d._viewController.emitKeyDown(e)})), +d._register(d._textAreaInput.onKeyUp(function(e){d._viewController.emitKeyUp(e)})),d._register(d._textAreaInput.onPaste(function(e){var t=b.INSTANCE.get(e.text),n=!1,i=null;t&&(n=d._emptySelectionClipboard&&t.isFromEmptySelection,i=t.multicursorText),d._viewController.paste("keyboard",e.text,n,i)})),d._register(d._textAreaInput.onCut(function(){d._viewController.cut("keyboard")})),d._register(d._textAreaInput.onType(function(e){e.replaceCharCnt?d._viewController.replacePreviousChar("keyboard",e.text,e.replaceCharCnt):d._viewController.type("keyboard",e.text)})),d._register(d._textAreaInput.onSelectionChangeRequest(function(e){d._viewController.setSelection("keyboard",e)})),d._register(d._textAreaInput.onCompositionStart(function(){var e=d._selections[0].startLineNumber,t=d._selections[0].startColumn;d._context.privateViewEventBus.emit(new h.ViewRevealRangeRequestEvent(new l.Range(e,t,e,t),0,!0,1));var n=d._viewHelper.visibleRangeForPositionRelativeToEditor(e,t) +;n&&(d._visibleTextArea=new y(d._context.viewLayout.getVerticalOffsetForLineNumber(e),n.left,C?0:1),d._render()),d.textArea.setClassName("inputarea ime-input"),d._viewController.compositionStart("keyboard")})),d._register(d._textAreaInput.onCompositionUpdate(function(e){i.isEdgeOrIE?d._visibleTextArea=d._visibleTextArea.setWidth(0):d._visibleTextArea=d._visibleTextArea.setWidth(_(e.data,d._fontInfo)),d._render()})),d._register(d._textAreaInput.onCompositionEnd(function(){d._visibleTextArea=null,d._render(),d.textArea.setClassName("inputarea"),d._viewController.compositionEnd("keyboard")})),d._register(d._textAreaInput.onFocus(function(){d._context.privateViewEventBus.emit(new h.ViewFocusChangedEvent(!0))})),d._register(d._textAreaInput.onBlur(function(){d._context.privateViewEventBus.emit(new h.ViewFocusChangedEvent(!1))})),d}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this)},t.prototype._getWordBeforePosition=function(e){ +for(var t=this._context.model.getLineContent(e.lineNumber),n=v.getMapForWordSeparators(this._context.configuration.editor.wordSeparators),i=e.column,o=0;i>1;){var r=t.charCodeAt(i-2);if(0!==n.get(r)||o>50)return t.substring(i-1,e.column-1);o++,i--}return t.substring(0,e.column-1)},t.prototype._getCharacterBeforePosition=function(e){if(e.column>1){var t=this._context.model.getLineContent(e.lineNumber).charAt(e.column-2);if(!r.isHighSurrogate(t.charCodeAt(0)))return t}return""},t.prototype.onConfigurationChanged=function(e){var t=this._context.configuration.editor;return e.fontInfo&&(this._fontInfo=t.fontInfo),e.viewInfo&&this.textArea.setAttribute("aria-label",t.viewInfo.ariaLabel),e.layoutInfo&&(this._contentLeft=t.layoutInfo.contentLeft,this._contentWidth=t.layoutInfo.contentWidth,this._contentHeight=t.layoutInfo.contentHeight),e.lineHeight&&(this._lineHeight=t.lineHeight),e.accessibilitySupport&&(this._accessibilitySupport=t.accessibilitySupport, +this._textAreaInput.writeScreenReaderContent("strategy changed")),e.emptySelectionClipboard&&(this._emptySelectionClipboard=t.emptySelectionClipboard),!0},t.prototype.onCursorStateChanged=function(e){return this._selections=e.selections.slice(0),this._textAreaInput.writeScreenReaderContent("selection changed"),!0},t.prototype.onDecorationsChanged=function(e){return!0},t.prototype.onFlushed=function(e){return!0},t.prototype.onLinesChanged=function(e){return!0},t.prototype.onLinesDeleted=function(e){return!0},t.prototype.onLinesInserted=function(e){return!0},t.prototype.onScrollChanged=function(e){return this._scrollLeft=e.scrollLeft,this._scrollTop=e.scrollTop,!0},t.prototype.onZonesChanged=function(e){return!0},t.prototype.isFocused=function(){return this._textAreaInput.isFocused()},t.prototype.focusTextArea=function(){this._textAreaInput.focusTextArea()},t.prototype.prepareRender=function(e){if(2===this._accessibilitySupport)this._primaryCursorVisibleRange=null;else{ +var t=new d.Position(this._selections[0].positionLineNumber,this._selections[0].positionColumn);this._primaryCursorVisibleRange=e.visibleRangeForPosition(t)}},t.prototype.render=function(e){this._textAreaInput.writeScreenReaderContent("render"),this._render()},t.prototype._render=function(){if(this._visibleTextArea)this._renderInsideEditor(this._visibleTextArea.top-this._scrollTop,this._contentLeft+this._visibleTextArea.left-this._scrollLeft,this._visibleTextArea.width,this._lineHeight,!0);else if(this._primaryCursorVisibleRange){var e=this._contentLeft+this._primaryCursorVisibleRange.left-this._scrollLeft;if(ethis._contentLeft+this._contentWidth)this._renderAtTopLeft();else{var t=this._context.viewLayout.getVerticalOffsetForLineNumber(this._selections[0].positionLineNumber)-this._scrollTop;t<0||t>this._contentHeight?this._renderAtTopLeft():this._renderInsideEditor(t,e,C?0:1,C?0:1,!1)}}else this._renderAtTopLeft()},t.prototype._renderInsideEditor=function(e,t,n,i,o){ +var r=this.textArea,s=this.textAreaCover;o?c.Configuration.applyFontInfo(r,this._fontInfo):(r.setFontSize(1),r.setLineHeight(this._fontInfo.lineHeight)),r.setTop(e),r.setLeft(t),r.setWidth(n),r.setHeight(i),s.setTop(0),s.setLeft(0),s.setWidth(0),s.setHeight(0)},t.prototype._renderAtTopLeft=function(){var e=this.textArea,t=this.textAreaCover;if(c.Configuration.applyFontInfo(e,this._fontInfo),e.setTop(0),e.setLeft(0),t.setTop(0),t.setLeft(0),C)return e.setWidth(0),e.setHeight(0),t.setWidth(0),void t.setHeight(0);e.setWidth(1),e.setHeight(1),t.setWidth(1),t.setHeight(1),this._context.configuration.editor.viewInfo.glyphMargin?t.setClassName("monaco-editor-background textAreaCover "+g.Margin.OUTER_CLASS_NAME):0!==this._context.configuration.editor.viewInfo.renderLineNumbers?t.setClassName("monaco-editor-background textAreaCover "+m.LineNumbersOverlay.CLASS_NAME):t.setClassName("monaco-editor-background textAreaCover")},t}(f.ViewPart);t.TextAreaHandler=S}), +define(t[501],n([1,0,36,12,17,35,27,26]),function(e,t,n,i,r,s,a,l){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var u=function(){function e(e,t){this.lineHeight=e.editor.lineHeight,this.pixelRatio=e.editor.pixelRatio,this.overviewRulerLanes=e.editor.viewInfo.overviewRulerLanes,this.renderBorder=e.editor.viewInfo.overviewRulerBorder;var n=t.getColor(s.editorOverviewRulerBorder);this.borderColor=n?n.toString():null,this.hideCursor=e.editor.viewInfo.hideCursorInOverviewRuler;var i=t.getColor(s.editorCursorForeground);this.cursorColor=i?i.transparent(.7).toString():null,this.themeType=t.type;var o=e.editor.viewInfo.minimap.enabled,l=e.editor.viewInfo.minimap.side,u=o?r.TokenizationRegistry.getDefaultBackground():null;this.backgroundColor=null===u||"left"===l?null:a.Color.Format.CSS.formatHex(u);var d=e.editor.layoutInfo.overviewRuler;this.top=d.top,this.right=d.right,this.domWidth=d.width,this.domHeight=d.height,this.canvasWidth=this.domWidth*this.pixelRatio|0, +this.canvasHeight=this.domHeight*this.pixelRatio|0;var c=this._initLanes(1,this.canvasWidth,this.overviewRulerLanes),h=c[0],p=c[1];this.x=h,this.w=p}return e.prototype._initLanes=function(e,t,n){var i=t-e;if(n>=3){var o=i-(s=Math.floor(i/3))-(a=Math.floor(i/3)),r=(l=e)+s;return[[0,l,r,l,u=l+s+o,l,r,l],[0,s,o,s+o,a,s+o+a,o+a,s+o+a]]}if(2===n){var s=Math.floor(i/2),a=i-s,l=e,u=l+s;return[[0,l,l,l,u,l,l,l],[0,s,s,s,a,s+a,s+a,s+a]]}var d=e,c=i;return[[0,d,d,d,d,d,d,d],[0,c,c,c,c,c,c,c]]},e.prototype.equals=function(e){return this.lineHeight===e.lineHeight&&this.pixelRatio===e.pixelRatio&&this.overviewRulerLanes===e.overviewRulerLanes&&this.renderBorder===e.renderBorder&&this.borderColor===e.borderColor&&this.hideCursor===e.hideCursor&&this.cursorColor===e.cursorColor&&this.themeType===e.themeType&&this.backgroundColor===e.backgroundColor&&this.top===e.top&&this.right===e.right&&this.domWidth===e.domWidth&&this.domHeight===e.domHeight&&this.canvasWidth===e.canvasWidth&&this.canvasHeight===e.canvasHeight},e +}(),d=function(e){function t(t){var n=e.call(this,t)||this;return n._domNode=l.createFastDomNode(document.createElement("canvas")),n._domNode.setClassName("decorationsOverviewRuler"),n._domNode.setPosition("absolute"),n._domNode.setLayerHinting(!0),n._domNode.setAttribute("aria-hidden","true"),n._settings=null,n._updateSettings(!1),n._tokensColorTrackerListener=r.TokenizationRegistry.onDidChange(function(e){e.changedColorMap&&n._updateSettings(!0)}),n._cursorPositions=[],n}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this),this._tokensColorTrackerListener.dispose()},t.prototype._updateSettings=function(e){var t=new u(this._context.configuration,this._context.theme);return(null===this._settings||!this._settings.equals(t))&&(this._settings=t,this._domNode.setTop(this._settings.top),this._domNode.setRight(this._settings.right),this._domNode.setWidth(this._settings.domWidth),this._domNode.setHeight(this._settings.domHeight),this._domNode.domNode.width=this._settings.canvasWidth, +this._domNode.domNode.height=this._settings.canvasHeight,e&&this._render(),!0)},t.prototype.onConfigurationChanged=function(e){return this._updateSettings(!1)},t.prototype.onCursorStateChanged=function(e){this._cursorPositions=[];for(var t=0,n=e.selections.length;tt&&(D=t-a),E=D-a,T=D+a}E>_+1||b!==m?(0!==y&&l.fillRect(u[m],v,d[m],_-v),m=b,v=E,_=T):T>_&&(_=T)}l.fillRect(u[m],v,d[m],_-v)}if(!this._settings.hideCursor){var L=2*this._settings.pixelRatio|0,x=L/2|0,N=this._settings.x[7],I=this._settings.w[7] +;l.fillStyle=this._settings.cursorColor;for(var v=-100,_=-100,y=0,C=this._cursorPositions.length;yt&&(D=t-x);var T=(E=D-x)+L;E>_+1?(0!==y&&l.fillRect(N,v,I,_-v),v=E,_=T):T>_&&(_=T)}l.fillRect(N,v,I,_-v)}this._settings.renderBorder&&this._settings.borderColor&&this._settings.overviewRulerLanes>0&&(l.beginPath(),l.lineWidth=1,l.strokeStyle=this._settings.borderColor,l.moveTo(0,0),l.lineTo(0,t),l.stroke(),l.moveTo(0,0),l.lineTo(e,0),l.stroke())},t}(n.ViewPart);t.DecorationsOverviewRuler=d}),define(t[502],n([1,0,26,36,16,35,296]),function(e,t,n,i,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(e){function t(t){var i=e.call(this,t)||this;return i.domNode=n.createFastDomNode(document.createElement("div")),i.domNode.setAttribute("role","presentation"),i.domNode.setAttribute("aria-hidden","true"),i.domNode.setClassName("view-rulers"),i._renderedRulers=[], +i._rulers=i._context.configuration.editor.viewInfo.rulers,i._typicalHalfwidthCharacterWidth=i._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth,i}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this)},t.prototype.onConfigurationChanged=function(e){return!!(e.viewInfo||e.layoutInfo||e.fontInfo)&&(this._rulers=this._context.configuration.editor.viewInfo.rulers,this._typicalHalfwidthCharacterWidth=this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth,!0)},t.prototype.onScrollChanged=function(e){return e.scrollHeightChanged},t.prototype.prepareRender=function(e){},t.prototype._ensureRulersCount=function(){var e=this._renderedRulers.length,t=this._rulers.length;if(e!==t)if(e0;){(s=n.createFastDomNode(document.createElement("div"))).setClassName("view-ruler"),s.setWidth(i),this.domNode.appendChild(s),this._renderedRulers.push(s),o--}else for(var r=e-t;r>0;){var s=this._renderedRulers.pop() +;this.domNode.removeChild(s),r--}},t.prototype.render=function(e){this._ensureRulersCount();for(var t=0,n=this._rulers.length;tt.length)for(var s=this._secondaryCursors.length-t.length,o=0;o1),this._hasNonEmptySelection.set(e.some(function(e){return!e.isEmpty()}))):(this._hasMultipleSelections.reset(),this._hasNonEmptySelection.reset())},t.prototype._updateFromFocus=function(){this._editorFocus.set(this._editor.hasWidgetFocus()&&!this._editor.isSimpleWidget),this._editorTextFocus.set(this._editor.hasTextFocus()&&!this._editor.isSimpleWidget),this._textInputFocus.set(this._editor.hasTextFocus())},t.prototype._updateFromModel=function(){var e=this._editor.getModel();this._canUndo.set(e&&e.canUndo()),this._canRedo.set(e&&e.canRedo())},t}(l.Disposable),B=function(e){function t(t,n){var i=e.call(this)||this;i._editor=t,i._langId=S.EditorContextKeys.languageId.bindTo(n),i._hasCompletionItemProvider=S.EditorContextKeys.hasCompletionItemProvider.bindTo(n),i._hasCodeActionsProvider=S.EditorContextKeys.hasCodeActionsProvider.bindTo(n),i._hasCodeLensProvider=S.EditorContextKeys.hasCodeLensProvider.bindTo(n), +i._hasDefinitionProvider=S.EditorContextKeys.hasDefinitionProvider.bindTo(n),i._hasImplementationProvider=S.EditorContextKeys.hasImplementationProvider.bindTo(n),i._hasTypeDefinitionProvider=S.EditorContextKeys.hasTypeDefinitionProvider.bindTo(n),i._hasHoverProvider=S.EditorContextKeys.hasHoverProvider.bindTo(n),i._hasDocumentHighlightProvider=S.EditorContextKeys.hasDocumentHighlightProvider.bindTo(n),i._hasDocumentSymbolProvider=S.EditorContextKeys.hasDocumentSymbolProvider.bindTo(n),i._hasReferenceProvider=S.EditorContextKeys.hasReferenceProvider.bindTo(n),i._hasRenameProvider=S.EditorContextKeys.hasRenameProvider.bindTo(n),i._hasDocumentFormattingProvider=S.EditorContextKeys.hasDocumentFormattingProvider.bindTo(n),i._hasDocumentSelectionFormattingProvider=S.EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(n),i._hasSignatureHelpProvider=S.EditorContextKeys.hasSignatureHelpProvider.bindTo(n),i._isInWalkThrough=S.EditorContextKeys.isInEmbeddedEditor.bindTo(n);var o=function(){return i._update() +};return i._register(t.onDidChangeModel(o)),i._register(t.onDidChangeModelLanguage(o)),i._register(w.SuggestRegistry.onDidChange(o)),i._register(w.CodeActionProviderRegistry.onDidChange(o)),i._register(w.CodeLensProviderRegistry.onDidChange(o)),i._register(w.DefinitionProviderRegistry.onDidChange(o)),i._register(w.ImplementationProviderRegistry.onDidChange(o)),i._register(w.TypeDefinitionProviderRegistry.onDidChange(o)),i._register(w.HoverProviderRegistry.onDidChange(o)),i._register(w.DocumentHighlightProviderRegistry.onDidChange(o)),i._register(w.DocumentSymbolProviderRegistry.onDidChange(o)),i._register(w.ReferenceProviderRegistry.onDidChange(o)),i._register(w.RenameProviderRegistry.onDidChange(o)),i._register(w.DocumentFormattingEditProviderRegistry.onDidChange(o)),i._register(w.DocumentRangeFormattingEditProviderRegistry.onDidChange(o)),i._register(w.SignatureHelpProviderRegistry.onDidChange(o)),o(),i}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this)}, +t.prototype.reset=function(){this._langId.reset(),this._hasCompletionItemProvider.reset(),this._hasCodeActionsProvider.reset(),this._hasCodeLensProvider.reset(),this._hasDefinitionProvider.reset(),this._hasImplementationProvider.reset(),this._hasTypeDefinitionProvider.reset(),this._hasHoverProvider.reset(),this._hasDocumentHighlightProvider.reset(),this._hasDocumentSymbolProvider.reset(),this._hasReferenceProvider.reset(),this._hasRenameProvider.reset(),this._hasDocumentFormattingProvider.reset(),this._hasDocumentSelectionFormattingProvider.reset(),this._hasSignatureHelpProvider.reset(),this._isInWalkThrough.reset()},t.prototype._update=function(){var e=this._editor.getModel();e?(this._langId.set(e.getLanguageIdentifier().language),this._hasCompletionItemProvider.set(w.SuggestRegistry.has(e)),this._hasCodeActionsProvider.set(w.CodeActionProviderRegistry.has(e)),this._hasCodeLensProvider.set(w.CodeLensProviderRegistry.has(e)),this._hasDefinitionProvider.set(w.DefinitionProviderRegistry.has(e)), +this._hasImplementationProvider.set(w.ImplementationProviderRegistry.has(e)),this._hasTypeDefinitionProvider.set(w.TypeDefinitionProviderRegistry.has(e)),this._hasHoverProvider.set(w.HoverProviderRegistry.has(e)),this._hasDocumentHighlightProvider.set(w.DocumentHighlightProviderRegistry.has(e)),this._hasDocumentSymbolProvider.set(w.DocumentSymbolProviderRegistry.has(e)),this._hasReferenceProvider.set(w.ReferenceProviderRegistry.has(e)),this._hasRenameProvider.set(w.RenameProviderRegistry.has(e)),this._hasSignatureHelpProvider.set(w.SignatureHelpProviderRegistry.has(e)),this._hasDocumentFormattingProvider.set(w.DocumentFormattingEditProviderRegistry.has(e)||w.DocumentRangeFormattingEditProviderRegistry.has(e)),this._hasDocumentSelectionFormattingProvider.set(w.DocumentRangeFormattingEditProviderRegistry.has(e)),this._isInWalkThrough.set(e.uri.scheme===E.Schemas.walkThroughSnippet)):this.reset()},t}(l.Disposable);t.EditorModeContext=B;var H=function(e){function t(t){var n=e.call(this)||this +;return n._onChange=n._register(new s.Emitter),n.onChange=n._onChange.event,n._hasFocus=!1,n._domFocusTracker=n._register(i.trackFocus(t)),n._register(n._domFocusTracker.onDidFocus(function(){n._hasFocus=!0,n._onChange.fire(void 0)})),n._register(n._domFocusTracker.onDidBlur(function(){n._hasFocus=!1,n._onChange.fire(void 0)})),n}return o(t,e),t.prototype.hasFocus=function(){return this._hasFocus},t}(l.Disposable),z=encodeURIComponent(""),U=encodeURIComponent('');M.registerThemingParticipant(function(e,t){var n=e.getColor(R.editorErrorBorder) +;n&&t.addRule(".monaco-editor .squiggly-error { border-bottom: 4px double "+n+"; }");var i=e.getColor(R.editorErrorForeground);i&&t.addRule('.monaco-editor .squiggly-error { background: url("data:image/svg+xml,'+O(i)+'") repeat-x bottom left; }');var o=e.getColor(R.editorWarningBorder);o&&t.addRule(".monaco-editor .squiggly-warning { border-bottom: 4px double "+o+"; }");var r=e.getColor(R.editorWarningForeground);r&&t.addRule('.monaco-editor .squiggly-warning { background: url("data:image/svg+xml,'+O(r)+'") repeat-x bottom left; }');var s=e.getColor(R.editorInfoBorder);s&&t.addRule(".monaco-editor .squiggly-info { border-bottom: 4px double "+s+"; }");var a=e.getColor(R.editorInfoForeground);a&&t.addRule('.monaco-editor .squiggly-info { background: url("data:image/svg+xml,'+O(a)+'") repeat-x bottom left; }');var l=e.getColor(R.editorHintBorder);l&&t.addRule(".monaco-editor .squiggly-hint { border-bottom: 2px dotted "+l+"; }");var u=e.getColor(R.editorHintForeground) +;u&&t.addRule('.monaco-editor .squiggly-hint { background: url("data:image/svg+xml,'+function(e){return U+encodeURIComponent(e.toString())+j}(u)+'") no-repeat bottom left; }');var d=e.getColor(R.editorUnnecessaryCodeOpacity);d&&t.addRule("."+A+" .monaco-editor .squiggly-inline-unnecessary { opacity: "+d.rgba.a+"; will-change: opacity; }");var c=e.getColor(R.editorUnnecessaryCodeBorder);c&&t.addRule("."+A+" .monaco-editor .squiggly-unnecessary { border-bottom: 2px dashed "+c+"; }")})}),define(t[506],n([1,0,293,2,7,26,96,99,65,12,16,22,55,35,69,67,11,19,32,63,362]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m,v,_,y,C){"use strict";function b(e){for(var t=e.get(y.ICodeEditorService).listDiffEditors(),n=0,i=t.length;n0){var _=e[r-1];m=0===_.originalEndLineNumber?_.originalStartLineNumber+1:_.originalEndLineNumber+1,v=0===_.modifiedEndLineNumber?_.modifiedStartLineNumber+1:_.modifiedEndLineNumber+1}var y=f-3+1,C=g-3+1;if(yL){I+=D=L-I,M+=D}if(M>x){var D=x-M;I+=D,M+=D}h[p++]=new S(b,I,E,M),i[o++]=new w(h)} +for(var T=i[0].entries,k=[],R=0,r=1,s=i.length;rg)&&(g=b),0!==S&&(0===m||Sv)&&(v=w)}var E=document.createElement("div");E.className="diff-review-row";var L=document.createElement("div");L.className="diff-review-cell diff-review-summary";var x=g-f+1,N=v-m+1;L.appendChild(document.createTextNode(c+1+"/"+this._diffs.length+": @@ -"+f+","+x+" +"+m+","+N+" @@")),E.setAttribute("data-line",String(m));var I=function(e){return 0===e?n.localize(1,null):1===e?n.localize(2,null):n.localize(3,null,e)},M=I(x),D=I(N);E.setAttribute("aria-label",n.localize(4,null,c+1,this._diffs.length,f,M,m,D)),E.appendChild(L), +E.setAttribute("role","listitem"),p.appendChild(E);for(var T=m,_=0,y=h.length;_0}function A(e){ +return e.originalEndLineNumber>0}Object.defineProperty(t,"__esModule",{value:!0});var F=function(){function e(){this._zones=[],this._zonesMap={},this._decorations=[]}return e.prototype.getForeignViewZones=function(e){var t=this;return e.filter(function(e){return!t._zonesMap[String(e.id)]})},e.prototype.clean=function(e){var t=this;this._zones.length>0&&e.changeViewZones(function(e){for(var n=0,i=t._zones.length;n0?o/n:0;return{height:Math.max(0,Math.floor(e.contentHeight*r)),top:Math.floor(t*r)}},t.prototype._createDataSource=function(){var e=this;return{getWidth:function(){return e._width},getHeight:function(){return e._height-e._reviewHeight},getContainerDomNode:function(){return e._containerDomElement},relayoutEditors:function(){e._doLayout()},getOriginalEditor:function(){return e.originalEditor},getModifiedEditor:function(){return e.modifiedEditor}}},t.prototype._setStrategy=function(e){this._strategy&&this._strategy.dispose(),this._strategy=e,e.applyColors(this._themeService.getTheme()),this._lineChanges&&this._updateDecorations(),this._measureDomElement(!0)},t.prototype._getLineChangeAtOrBeforeLineNumber=function(e,t){ +if(0===this._lineChanges.length||e=s?n=o+1:(n=o,i=o)}return this._lineChanges[n]},t.prototype._getEquivalentLineForOriginalLineNumber=function(e){var t=this._getLineChangeAtOrBeforeLineNumber(e,function(e){return e.originalStartLineNumber});if(!t)return e;var n=t.originalStartLineNumber+(t.originalEndLineNumber>0?-1:0),i=t.modifiedStartLineNumber+(t.modifiedEndLineNumber>0?-1:0),o=t.originalEndLineNumber>0?t.originalEndLineNumber-t.originalStartLineNumber+1:0,r=t.modifiedEndLineNumber>0?t.modifiedEndLineNumber-t.modifiedStartLineNumber+1:0,s=e-n;return s<=o?i+Math.min(s,r):i+r-o+s},t.prototype._getEquivalentLineForModifiedLineNumber=function(e){var t=this._getLineChangeAtOrBeforeLineNumber(e,function(e){return e.modifiedStartLineNumber});if(!t)return e +;var n=t.originalStartLineNumber+(t.originalEndLineNumber>0?-1:0),i=t.modifiedStartLineNumber+(t.modifiedEndLineNumber>0?-1:0),o=t.originalEndLineNumber>0?t.originalEndLineNumber-t.originalStartLineNumber+1:0,r=t.modifiedEndLineNumber>0?t.modifiedEndLineNumber-t.modifiedStartLineNumber+1:0,s=e-i;return s<=r?n+Math.min(s,o):n+o-r+s},t.prototype.getDiffLineInformationForOriginal=function(e){return this._lineChanges?{equivalentLineNumber:this._getEquivalentLineForOriginalLineNumber(e)}:null},t.prototype.getDiffLineInformationForModified=function(e){return this._lineChanges?{equivalentLineNumber:this._getEquivalentLineForModifiedLineNumber(e)}:null},t.ONE_OVERVIEW_WIDTH=15,t.ENTIRE_DIFF_OVERVIEW_WIDTH=30,t.UPDATE_DIFF_DECORATIONS_DELAY=200,t=a([u(2,v.IEditorWorkerService),u(3,p.IContextKeyService),u(4,h.IInstantiationService),u(5,f.ICodeEditorService),u(6,x.IThemeService),u(7,k.INotificationService)],t)}(r.Disposable);t.DiffEditorWidget=V;var B=function(e){function t(t){var n=e.call(this)||this +;return n._dataSource=t,n}return o(t,e),t.prototype.applyColors=function(e){var t=(e.getColor(N.diffInserted)||N.defaultInsertColor).transparent(2),n=(e.getColor(N.diffRemoved)||N.defaultRemoveColor).transparent(2),i=!t.equals(this._insertColor)||!n.equals(this._removeColor);return this._insertColor=t,this._removeColor=n,i},t.prototype.getEditorsDiffDecorations=function(e,t,n,i,o,r,s){o=o.sort(function(e,t){return e.afterLineNumber-t.afterLineNumber}),i=i.sort(function(e,t){return e.afterLineNumber-t.afterLineNumber});var a=this._getViewZones(e,i,o,r,s,n),l=this._getOriginalEditorDecorations(e,t,n,r,s),u=this._getModifiedEditorDecorations(e,t,n,r,s);return{original:{decorations:l.decorations,overviewZones:l.overviewZones,zones:a.original},modified:{decorations:u.decorations,overviewZones:u.overviewZones,zones:a.modified}}},t}(r.Disposable),H=function(){function e(e){this._source=e,this._index=-1,this.advance()}return e.prototype.advance=function(){this._index++, +this._index0){var n=e[e.length-1];if(n.afterLineNumber===t.afterLineNumber&&null===n.domNode)return void(n.heightInLines+=t.heightInLines)}e.push(t)},u=new H(this.modifiedForeignVZ),d=new H(this.originalForeignVZ),c=0,h=this.lineChanges.length;c<=h;c++){var p=c0?-1:0),o=p.modifiedStartLineNumber+(p.modifiedEndLineNumber>0?-1:0),n=p.originalEndLineNumber>0?p.originalEndLineNumber-p.originalStartLineNumber+1:0,t=p.modifiedEndLineNumber>0?p.modifiedEndLineNumber-p.modifiedStartLineNumber+1:0, +r=Math.max(p.originalStartLineNumber,p.originalEndLineNumber),s=Math.max(p.modifiedStartLineNumber,p.modifiedEndLineNumber)):(r=i+=1e7+n,s=o+=1e7+t);for(var f=[],g=[];u.current&&u.current.afterLineNumber<=s;){m=void 0;m=u.current.afterLineNumber<=o?i-o+u.current.afterLineNumber:r,f.push({afterLineNumber:m,heightInLines:u.current.heightInLines,domNode:null}),u.advance()}for(;d.current&&d.current.afterLineNumber<=r;){var m=void 0;m=d.current.afterLineNumber<=i?o-i+d.current.afterLineNumber:s,g.push({afterLineNumber:m,heightInLines:d.current.heightInLines,domNode:null}),d.advance()}if(null!==p&&P(p)){(v=this._produceOriginalFromDiff(p,n,t))&&f.push(v)}if(null!==p&&A(p)){var v=this._produceModifiedFromDiff(p,n,t);v&&g.push(v)}var _=0,y=0;for(f=f.sort(a),g=g.sort(a);_=b.heightInLines?(C.heightInLines-=b.heightInLines,y++):(b.heightInLines-=C.heightInLines,_++)}for(;_2*t.MINIMUM_EDITOR_WIDTH?(in-t.MINIMUM_EDITOR_WIDTH&&(i=n-t.MINIMUM_EDITOR_WIDTH)):i=o,this._sashPosition!==i&&(this._sashPosition=i,this._sash.layout()),this._sashPosition},t.prototype.onSashDragStart=function(){this._startSashPosition=this._sashPosition},t.prototype.onSashDrag=function(e){var t=this._dataSource.getWidth()-V.ENTIRE_DIFF_OVERVIEW_WIDTH,n=this.layout((this._startSashPosition+(e.currentX-e.startX))/t);this._sashRatio=n/t,this._dataSource.relayoutEditors()},t.prototype.onSashDragEnd=function(){this._sash.layout()},t.prototype.onSashReset=function(){this._sashRatio=.5,this._dataSource.relayoutEditors(),this._sash.layout()},t.prototype.getVerticalSashTop=function(e){ +return 0},t.prototype.getVerticalSashLeft=function(e){return this._sashPosition},t.prototype.getVerticalSashHeight=function(e){return this._dataSource.getHeight()},t.prototype._getViewZones=function(e,t,n,i,o){return new j(e,t,n).getViewZones()},t.prototype._getOriginalEditorDecorations=function(e,t,n,i,o){for(var r=this._removeColor.toString(),s={decorations:[],overviewZones:[]},a=i.getModel(),l=0,u=e.length;lt?{afterLineNumber:Math.max(e.originalStartLineNumber,e.originalEndLineNumber),heightInLines:n-t,domNode:null}:null},t.prototype._produceModifiedFromDiff=function(e,t,n){return t>n?{afterLineNumber:Math.max(e.modifiedStartLineNumber,e.modifiedEndLineNumber),heightInLines:t-n,domNode:null}:null},t}(z),q=function(e){function t(t,n){var i=e.call(this,t)||this +;return i.decorationsLeft=t.getOriginalEditor().getLayoutInfo().decorationsLeft,i._register(t.getOriginalEditor().onDidLayoutChange(function(e){i.decorationsLeft!==e.decorationsLeft&&(i.decorationsLeft=e.decorationsLeft,t.relayoutEditors())})),i}return o(t,e),t.prototype.setEnableSplitViewResizing=function(e){},t.prototype._getViewZones=function(e,t,n,i,o,r){return new G(e,t,n,i,o,r).getViewZones()},t.prototype._getOriginalEditorDecorations=function(e,t,n,i,o){for(var r=this._removeColor.toString(),s={decorations:[],overviewZones:[]},a=0,l=e.length;a'])}h+=this.modifiedEditorConfiguration.viewInfo.scrollBeyondLastColumn;var m=document.createElement("div");m.className="view-lines line-delete",m.innerHTML=a.build(),b.Configuration.applyFontInfoSlow(m,this.modifiedEditorConfiguration.fontInfo);var v=document.createElement("div");return v.className="inline-deleted-margin-view-zone",v.innerHTML=l.join(""), +b.Configuration.applyFontInfoSlow(v,this.modifiedEditorConfiguration.fontInfo),{shouldNotShrink:!0,afterLineNumber:0===e.modifiedEndLineNumber?e.modifiedStartLineNumber:e.modifiedStartLineNumber-1,heightInLines:t,minWidthInPx:h*c,domNode:m,marginDomNode:v}},t.prototype._renderOriginalLine=function(e,t,n,i,o,r,s){var a=t.getLineTokens(o),l=a.getLineContent(),u=_.LineDecoration.filter(r,o,1,l.length+1);s.appendASCIIString('
                                      ') +;var d=S.ViewLineRenderingData.isBasicASCII(l,t.mightContainNonBasicASCII()),c=S.ViewLineRenderingData.containsRTL(l,d,t.mightContainRTL()),h=y.renderViewLine(new y.RenderLineInput(n.fontInfo.isMonospace&&!n.viewInfo.disableMonospaceOptimizations,l,!1,d,c,0,a,u,i,n.fontInfo.spaceWidth,n.viewInfo.stopRenderingLineAfter,n.viewInfo.renderWhitespace,n.viewInfo.renderControlCharacters,n.viewInfo.fontLigatures),s);s.appendASCIIString("
                                      ");var p=h.characterMapping.getAbsoluteOffsets();return p.length>0?p[p.length-1]:0},t}(z);x.registerThemingParticipant(function(e,t){var n=e.getColor(N.diffInserted);n&&(t.addRule(".monaco-editor .line-insert, .monaco-editor .char-insert { background-color: "+n+"; }"),t.addRule(".monaco-diff-editor .line-insert, .monaco-diff-editor .char-insert { background-color: "+n+"; }"),t.addRule(".monaco-editor .inline-added-margin-view-zone { background-color: "+n+"; }"));var i=e.getColor(N.diffRemoved) +;i&&(t.addRule(".monaco-editor .line-delete, .monaco-editor .char-delete { background-color: "+i+"; }"),t.addRule(".monaco-diff-editor .line-delete, .monaco-diff-editor .char-delete { background-color: "+i+"; }"),t.addRule(".monaco-editor .inline-deleted-margin-view-zone { background-color: "+i+"; }"));var o=e.getColor(N.diffInsertedOutline);o&&t.addRule(".monaco-editor .line-insert, .monaco-editor .char-insert { border: 1px "+("hc"===e.type?"dashed":"solid")+" "+o+"; }");var r=e.getColor(N.diffRemovedOutline);r&&t.addRule(".monaco-editor .line-delete, .monaco-editor .char-delete { border: 1px "+("hc"===e.type?"dashed":"solid")+" "+r+"; }");var s=e.getColor(N.scrollbarShadow);s&&t.addRule(".monaco-diff-editor.side-by-side .editor.modified { box-shadow: -6px 0 5px -5px "+s+"; }");var a=e.getColor(N.diffBorder);a&&t.addRule(".monaco-diff-editor.side-by-side .editor.modified { border-left: 1px solid "+a+"; }")})}),define(t[141],n([1,0,28,15,34,19,32,104,16,37]),function(e,t,n,i,r,s,l,d,c,h){"use strict" +;Object.defineProperty(t,"__esModule",{value:!0});var p=function(e){function t(t,n,i,o,r,s,a,l,u){var d=e.call(this,t,i.getRawConfiguration(),{},o,r,s,a,l,u)||this;return d._parentEditor=i,d._overwriteOptions=n,e.prototype.updateOptions.call(d,d._overwriteOptions),d._register(i.onDidChangeConfiguration(function(e){return d._onParentConfigurationChanged(e)})),d}return o(t,e),t.prototype.getParentEditor=function(){return this._parentEditor},t.prototype._onParentConfigurationChanged=function(t){e.prototype.updateOptions.call(this,this._parentEditor.getRawConfiguration()),e.prototype.updateOptions.call(this,this._overwriteOptions)},t.prototype.updateOptions=function(t){n.mixin(this._overwriteOptions,t,!0),e.prototype.updateOptions.call(this,this._overwriteOptions)},t=a([u(3,i.IInstantiationService),u(4,l.ICodeEditorService),u(5,r.ICommandService),u(6,s.IContextKeyService),u(7,c.IThemeService),u(8,h.INotificationService)],t)}(d.CodeEditorWidget);t.EmbeddedCodeEditorWidget=p}), +define(t[509],n([1,0,301,61,9,79,2,13,75,3,29,18,51,47,124,16,35,24,25,50]),function(e,t,n,i,o,r,s,l,d,c,h,p,f,g,m,v,_,y,C,b){"use strict";function S(e){return e.toString()}Object.defineProperty(t,"__esModule",{value:!0});var w=function(){function e(e,t,n){this.model=e,this._markerDecorations=[],this._modelEventListeners=[],this._modelEventListeners.push(e.onWillDispose(function(){return t(e)})),this._modelEventListeners.push(e.onDidChangeLanguage(function(t){return n(e,t)}))}return e.prototype.dispose=function(){this._markerDecorations=this.model.deltaDecorations(this._markerDecorations,[]),this._modelEventListeners=s.dispose(this._modelEventListeners),this.model=null},e.prototype.acceptMarkerDecorations=function(e){this._markerDecorations=this.model.deltaDecorations(this._markerDecorations,e)},e}(),E=function(){function e(){}return e.setMarkers=function(e,t){var n=this,i=t.read({resource:e.model.uri,take:500}).map(function(t){return{range:n._createDecorationRange(e.model,t), +options:n._createDecorationOption(t)}});e.acceptMarkerDecorations(i)},e._createDecorationRange=function(e,t){var n=c.Range.lift(t);if(t.severity===d.MarkerSeverity.Hint&&c.Range.spansMultipleLines(n)&&(n=n.setEndPosition(n.startLineNumber,n.startColumn)),(n=e.validateRange(n)).isEmpty()){var i=e.getWordAtPosition(n.getStartPosition());if(i)n=new c.Range(n.startLineNumber,i.startColumn,n.endLineNumber,i.endColumn);else{var o=e.getLineLastNonWhitespaceColumn(n.startLineNumber)||e.getLineMaxColumn(n.startLineNumber);1===o||(n=n.endColumn>=o?new c.Range(n.startLineNumber,o-1,n.endLineNumber,o):new c.Range(n.startLineNumber,n.startColumn,n.endLineNumber,n.endColumn+1))}}else if(t.endColumn===Number.MAX_VALUE&&1===t.startColumn&&n.startLineNumber===n.endLineNumber){var r=e.getLineFirstNonWhitespaceColumn(t.startLineNumber);r=0?"squiggly-unnecessary":"squiggly-hint",s=0;break;case d.MarkerSeverity.Warning:t="squiggly-warning",i=v.themeColorFromId(_.overviewRulerWarning),o=v.themeColorFromId(_.overviewRulerWarning),s=20;break;case d.MarkerSeverity.Info:t="squiggly-info",i=v.themeColorFromId(_.overviewRulerInfo),o=v.themeColorFromId(_.overviewRulerInfo),s=10;break;case d.MarkerSeverity.Error:default:t="squiggly-error",i=v.themeColorFromId(_.overviewRulerError),o=v.themeColorFromId(_.overviewRulerError),s=30}e.tags&&-1!==e.tags.indexOf(d.MarkerTag.Unnecessary)&&(a="squiggly-inline-unnecessary");var l=null,u=e.message,c=e.source,h=e.relatedInformation;if("string"==typeof u&&(u=u.trim(),c&&(u=/\n/g.test(u)?n.localize(0,null,c,u):n.localize(1,null,c,u)),l=(new r.MarkdownString).appendCodeblock("_",u),!C.isFalsyOrEmpty(h))){l.appendMarkdown("\n");for(var p=0,f=h;p0&&(n._decorations=n._editor.deltaDecorations(n._decorations,[])),n._updateBracketsSoon.schedule()})),n}return o(t,e),t.get=function(e){return e.getContribution(t.ID)},t.prototype.getId=function(){return t.ID},t.prototype.jumpToBracket=function(){var e=this._editor.getModel();if(e){var t=this._editor.getSelections().map(function(t){var n=t.getStartPosition(),i=e.matchBracket(n),o=null;if(i)i[0].containsPosition(n)?o=i[1].getStartPosition():i[1].containsPosition(n)&&(o=i[0].getStartPosition());else{var r=e.findNextBracket(n);r&&r.range&&(o=r.range.getStartPosition())}return o?new s.Selection(o.lineNumber,o.column,o.lineNumber,o.column):new s.Selection(n.lineNumber,n.column,n.lineNumber,n.column)});this._editor.setSelections(t),this._editor.revealRange(t[0])}},t.prototype.selectToBracket=function(){ +var e=this._editor.getModel();if(e){var t=[];this._editor.getSelections().forEach(function(n){var i=n.getStartPosition(),o=e.matchBracket(i),r=null,a=null;if(!o){var l=e.findNextBracket(i);l&&l.range&&(o=e.matchBracket(l.range.getStartPosition()))}o&&(o[0].startLineNumber===o[1].startLineNumber?(r=o[1].startColumn0&&(this._editor.setSelections(t),this._editor.revealRange(t[0]))}},t.prototype._updateBrackets=function(){if(this._matchBrackets){this._recomputeBrackets();for(var e=[],n=0,i=0,o=this._lastBracketsData.length;i1&&o.sort(r.Position.compare);for(var d=[],c=0,h=0,p=n.length,a=0,l=o.length;a{1}",n,r),this._commands[n]=o):s=i.format("{0}",r),t.push(s)}this._domNode.innerHTML=t.join(" | "),this._editor.layoutContentWidget(this)}else this._domNode.innerHTML="no commands"},e.prototype.getId=function(){return this._id},e.prototype.getDomNode=function(){return this._domNode},e.prototype.setSymbolRange=function(e){var t=e.startLineNumber,n=this._editor.getModel().getLineFirstNonWhitespaceColumn(t);this._widgetPosition={position:{lineNumber:t,column:n},preference:[s.ContentWidgetPositionPreference.ABOVE] +}},e.prototype.getPosition=function(){return this._widgetPosition},e.prototype.isVisible=function(){return this._domNode.hasAttribute("monaco-visible-content-widget")},e._idPool=0,e}(),p=function(){function e(){this._removeDecorations=[],this._addDecorations=[],this._addDecorationsCallbacks=[]}return e.prototype.addDecoration=function(e,t){this._addDecorations.push(e),this._addDecorationsCallbacks.push(t)},e.prototype.removeDecoration=function(e){this._removeDecorations.push(e)},e.prototype.commit=function(e){for(var t=e.deltaDecorations(this._removeDecorations,this._addDecorations),n=0,i=t.length;n a:hover { color: "+i+" !important; }")})}),define(t[512],n([1,0,14,10,2,68,11,17,511,34,37,452]),function(e,t,n,i,o,r,s,l,d,c,h,p){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var f=function(){function e(e,t,n){var i=this;this._editor=e,this._commandService=t,this._notificationService=n,this._isEnabled=this._editor.getConfiguration().contribInfo.codeLens,this._globalToDispose=[],this._localToDispose=[],this._lenses=[],this._currentFindCodeLensSymbolsPromise=null,this._modelChangeCounter=0,this._globalToDispose.push(this._editor.onDidChangeModel(function(){return i._onModelChange()})),this._globalToDispose.push(this._editor.onDidChangeModelLanguage(function(){return i._onModelChange()})),this._globalToDispose.push(this._editor.onDidChangeConfiguration(function(e){var t=i._isEnabled;i._isEnabled=i._editor.getConfiguration().contribInfo.codeLens,t!==i._isEnabled&&i._onModelChange()})), +this._globalToDispose.push(l.CodeLensProviderRegistry.onDidChange(this._onModelChange,this)),this._onModelChange()}return e.prototype.dispose=function(){this._localDispose(),this._globalToDispose=o.dispose(this._globalToDispose)},e.prototype._localDispose=function(){this._currentFindCodeLensSymbolsPromise&&(this._currentFindCodeLensSymbolsPromise.cancel(),this._currentFindCodeLensSymbolsPromise=null,this._modelChangeCounter++),this._currentResolveCodeLensSymbolsPromise&&(this._currentResolveCodeLensSymbolsPromise.cancel(),this._currentResolveCodeLensSymbolsPromise=null),this._localToDispose=o.dispose(this._localToDispose)},e.prototype.getId=function(){return e.ID},e.prototype._onModelChange=function(){var e=this;this._localDispose();var t=this._editor.getModel();if(t&&this._isEnabled&&l.CodeLensProviderRegistry.has(t)){for(var s=0,a=l.CodeLensProviderRegistry.all(t);s0&&e._detectVisibleLenses.schedule()})),this._localToDispose.push(this._editor.onDidLayoutChange(function(t){e._detectVisibleLenses.schedule()})),this._localToDispose.push(o.toDisposable(function(){if(e._editor.getModel()){var t=r.StableEditorScrollState.capture(e._editor);e._editor.changeDecorations(function(t){e._editor.changeViewZones(function(n){e._disposeAllLenses(t,n)})}),t.restore(e._editor)}else e._disposeAllLenses(null,null)})),h.schedule()}},e.prototype._disposeAllLenses=function(e,t){var n=new d.CodeLensHelper;this._lenses.forEach(function(e){return e.dispose(n,t)}),e&&n.commit(e),this._lenses=[]},e.prototype._renderCodeLensSymbols=function(e){var t=this;if(this._editor.getModel()){for(var n,i=this._editor.getModel().getLineCount(),o=[],s=0,a=e;si||(n&&n[n.length-1].symbol.range.startLineNumber===u?n.push(l):(n=[l],o.push(n)))}var c=r.StableEditorScrollState.capture(this._editor);this._editor.changeDecorations(function(e){t._editor.changeViewZones(function(n){for(var i=0,r=0,s=new d.CodeLensHelper;r=0?t+1:1},e.prototype.getCurrentMatchesPosition=function(t){for(var n=this._editor.getModel().getDecorationsInRange(t),i=0,o=n.length;i1e3){s=e._FIND_MATCH_NO_OVERVIEW_DECORATION +;for(var l=o._editor.getModel().getLineCount(),u=o._editor.getLayoutInfo().height/l,d=Math.max(2,Math.ceil(3/u)),c=t[0].range.startLineNumber,h=t[0].range.endLineNumber,p=1,f=t.length;p=g.startLineNumber?g.endLineNumber>h&&(h=g.endLineNumber):(a.push({range:new n.Range(c,1,h,1),options:e._FIND_MATCH_ONLY_OVERVIEW_DECORATION}),c=g.startLineNumber,h=g.endLineNumber)}a.push({range:new n.Range(c,1,h,1),options:e._FIND_MATCH_ONLY_OVERVIEW_DECORATION})}for(var m=new Array(t.length),p=0,f=t.length;p=0;t--){var n=this._decorations[t],i=this._editor.getModel().getDecorationRange(n);if(i&&!(i.endLineNumber>e.lineNumber)){if(i.endLineNumbere.column))return i}}return this._editor.getModel().getDecorationRange(this._decorations[this._decorations.length-1])},e.prototype.matchAfterPosition=function(e){if(0===this._decorations.length)return null;for(var t=0,n=this._decorations.length;te.lineNumber)return o;if(!(o.startColumn0},e.prototype._cannotFind=function(){if(!this._hasMatches()){var e=this._decorations.getFindScope();return e&&this._editor.revealRangeInCenterIfOutsideViewport(e,0),!0}return!1},e.prototype._setCurrentFindMatch=function(e){var t=this._decorations.setCurrentFindMatch(e);this._state.changeMatchInfo(t,this._decorations.getCount(),e),this._editor.setSelection(e),this._editor.revealRangeInCenterIfOutsideViewport(e,0)}, +e.prototype._prevSearchPosition=function(e){var t=this._state.isRegex&&(this._state.searchString.indexOf("^")>=0||this._state.searchString.indexOf("$")>=0),n=e.lineNumber,i=e.column,o=this._editor.getModel();return t||1===i?(1===n?n=o.getLineCount():n--,i=o.getLineMaxColumn(n)):i--,new s.Position(n,i)},e.prototype._moveToPrevMatch=function(n,i){if(void 0===i&&(i=!1),this._decorations.getCount()=0||this._state.searchString.indexOf("$")>=0),n=e.lineNumber,i=e.column,o=this._editor.getModel() +;return t||i===o.getLineMaxColumn(n)?(n===o.getLineCount()?n=1:n++,i=1):i++,new s.Position(n,i)},e.prototype._moveToNextMatch=function(e){if(this._decorations.getCount()=t.MATCHES_LIMIT?this._largeReplaceAll():this._regularReplaceAll(e),this.research(!1)}},e.prototype._largeReplaceAll=function(){var e=new c.SearchParams(this._state.searchString,this._state.isRegex,this._state.matchCase,this._state.wholeWord?this._editor.getConfiguration().wordSeparators:null).parseSearchRequest();if(e){var t=e.regex;if(!t.multiline){var n="m";t.ignoreCase&&(n+="i"), +t.global&&(n+="g"),t=new RegExp(t.source,n)}var i,o=this._editor.getModel(),s=o.getValue(f.EndOfLinePreference.LF),a=o.getFullModelRange(),l=this._getReplacePattern();i=l.hasReplacementPatterns?s.replace(t,function(){return l.buildReplaceString(arguments)}):s.replace(t,l.buildReplaceString(null));var u=new r.ReplaceCommandThatPreservesSelection(a,i,this._editor.getSelection());this._executeEditorCommand("replaceAll",u)}},e.prototype._regularReplaceAll=function(e){for(var t=this._getReplacePattern(),n=this._findMatches(e,t.hasReplacementPatterns,1073741824),i=[],o=0,r=n.length;o=0?this._markers[this._nextIdx]:void 0;this._markers=e||[],this._markers.sort(b.compareMarker),this._nextIdx=t?Math.max(-1,m.binarySearch(this._markers,t,b.compareMarker)):-1,this._onMarkerSetChanged.fire(this)}, +e.prototype.withoutWatchingEditorPosition=function(e){this._ignoreSelectionChange=!0;try{e()}finally{this._ignoreSelectionChange=!1}},e.prototype._initIdx=function(e){for(var t=!1,n=this._editor.getPosition(),i=0;i0?this._nextIdx=(this._nextIdx-1+this._markers.length)%this._markers.length:i=!0),n!==this._nextIdx){var o=this._markers[this._nextIdx];this._onCurrentMarkerChanged.fire(o)}return i},e.prototype.canNavigate=function(){return this._markers.length>0},e.prototype.findMarkerAtPosition=function(e){for(var t=0,n=this._markers;tthis._editor.getModel().getLineCount())return[];var n=g.ColorDetector.get(this._editor),i=this._editor.getModel().getLineMaxColumn(t),o=!1;return this._editor.getLineDecorations(t).map(function(s){ +var a=s.range.startLineNumber===t?s.range.startColumn:1,l=s.range.endLineNumber===t?s.range.endColumn:i;if(a>e._range.startColumn||e._range.endColumn>l)return null;var u=new r.Range(e._range.startLineNumber,a,e._range.startLineNumber,l),d=n.getColorData(s.range.getStartPosition());if(!o&&d){o=!0;var h=d.colorInfo,p=h.color,f=h.range;return new b(f,p,d.provider)}if(c.isEmptyMarkdownString(s.options.hoverMessage))return null;var g=void 0;return s.options.hoverMessage&&(g=Array.isArray(s.options.hoverMessage)?s.options.hoverMessage.slice():[s.options.hoverMessage]),{contents:g,range:u}}).filter(function(e){return!!e})},e.prototype.onResult=function(e,t){this._result=t?e.concat(this._result.sort(function(e,t){return e instanceof b?-1:t instanceof b?1:0})):this._result.concat(e)},e.prototype.getResult=function(){return this._result.slice(0)},e.prototype.getResultWithLoadingMessage=function(){return this._result.slice(0).concat([this._getLoadingMessage()])},e.prototype._getLoadingMessage=function(){return{ +range:this._range,contents:[(new c.MarkdownString).appendText(n.localize(0,null))]}},e}(),w=function(e){function t(n,o,r){var s=e.call(this,t.ID,n)||this;return s._themeService=r,s.renderDisposable=v.Disposable.None,s._computer=new S(s._editor),s._highlightDecorations=[],s._isChangingDecorations=!1,s._markdownRenderer=o,s._register(o.onDidRenderCodeBlock(s.onContentsChange,s)),s._hoverOperation=new u.HoverOperation(s._computer,function(e){return s._withResult(e,!0)},null,function(e){return s._withResult(e,!1)}),s._register(i.addStandardDisposableListener(s.getDomNode(),i.EventType.FOCUS,function(){s._colorPicker&&i.addClass(s.getDomNode(),"colorpicker-hover")})),s._register(i.addStandardDisposableListener(s.getDomNode(),i.EventType.BLUR,function(){i.removeClass(s.getDomNode(),"colorpicker-hover")})),s._register(n.onDidChangeConfiguration(function(e){s._hoverOperation.setHoverTime(s._editor.getConfiguration().contribInfo.hover.delay)})),s}return o(t,e),t.prototype.dispose=function(){ +this.renderDisposable.dispose(),this.renderDisposable=v.Disposable.None,this._hoverOperation.cancel(),e.prototype.dispose.call(this)},t.prototype.onModelDecorationsChanged=function(){this._isChangingDecorations||this.isVisible&&(this._hoverOperation.cancel(),this._computer.clearResult(),this._colorPicker||this._hoverOperation.start(0))},t.prototype.startShowingAt=function(e,t,n){if(!this._lastRange||!this._lastRange.equalsRange(e)){if(this._hoverOperation.cancel(),this.isVisible)if(this._showAtPosition.lineNumber!==e.startLineNumber)this.hide();else{for(var i=[],o=0,r=this._messages.length;o=e.endColumn&&i.push(s)}if(i.length>0){if(function(e,t){if(!e&&t||e&&!t||e.length!==t.length)return!1;for(var n=0;n0?this._renderMessages(this._lastRange,this._messages):t&&this.hide()},t.prototype._renderMessages=function(e,n){var i=this;this.renderDisposable.dispose(),this._colorPicker=null;var o,a=Number.MAX_VALUE,l=n[0].range,u=document.createDocumentFragment(),d=!0,h=!1;n.forEach(function(t){if(t.range)if(a=Math.min(a,t.range.startColumn),l=r.Range.plusRange(l,t.range),t instanceof b){h=!0 +;var n=t.color,g=n.red,S=n.green,w=n.blue,E=n.alpha,L=new m.RGBA(255*g,255*S,255*w,E),x=new m.Color(L),N=i._editor.getModel(),I=new r.Range(t.range.startLineNumber,t.range.startColumn,t.range.endLineNumber,t.range.endColumn),M={range:t.range,color:t.color},D=new p.ColorPickerModel(x,[],0),T=new f.ColorPickerWidget(u,D,i._editor.getConfiguration().pixelRatio,i._themeService);_.getColorPresentations(N,M,t.provider,y.CancellationToken.None).then(function(n){D.colorPresentations=n;var l=i._editor.getModel().getValueInRange(t.range);D.guessColorPresentation(x,l);var d=function(){var e,t;D.presentation.textEdit?(e=[D.presentation.textEdit],t=(t=new r.Range(D.presentation.textEdit.range.startLineNumber,D.presentation.textEdit.range.startColumn,D.presentation.textEdit.range.endLineNumber,D.presentation.textEdit.range.endColumn)).setEndPosition(t.endLineNumber,t.startColumn+D.presentation.textEdit.text.length)):(e=[{identifier:null,range:I,text:D.presentation.label,forceMoveMarkers:!1}], +t=I.setEndPosition(I.endLineNumber,I.startColumn+D.presentation.label.length)),i._editor.executeEdits("colorpicker",e),D.presentation.additionalTextEdits&&(e=D.presentation.additionalTextEdits.slice(),i._editor.executeEdits("colorpicker",e),i.hide()),i._editor.pushUndoStop(),I=t},c=function(e){return _.getColorPresentations(N,{range:I,color:{red:e.rgba.r/255,green:e.rgba.g/255,blue:e.rgba.b/255,alpha:e.rgba.a}},t.provider,y.CancellationToken.None).then(function(e){D.colorPresentations=e})},h=D.onColorFlushed(function(e){c(e).then(d)}),p=D.onDidChangeColor(c);i._colorPicker=T,i.showAt(new s.Position(e.startLineNumber,a),i._shouldFocus),i.updateContents(u),i._colorPicker.layout(),i.renderDisposable=v.combinedDisposable([h,p,T,o])})}else t.contents.filter(function(e){return!c.isEmptyMarkdownString(e)}).forEach(function(e){var t=i._markdownRenderer.render(e);o=t,u.appendChild(C("div.hover-row",null,t.element)),d=!1})}),h||d||(this.showAt(new s.Position(e.startLineNumber,a),this._shouldFocus), +this.updateContents(u)),this._isChangingDecorations=!0,this._highlightDecorations=this._editor.deltaDecorations(this._highlightDecorations,[{range:l,options:t._DECORATION_OPTIONS}]),this._isChangingDecorations=!1},t.ID="editor.contrib.modesContentHoverWidget",t._DECORATION_OPTIONS=h.ModelDecorationOptions.register({className:"hoverHighlight"}),t}(d.ContentHoverWidget);t.ModesContentHoverWidget=w}),define(t[520],n([1,0,320,39,18,62,64,3,11,23,519,255,2,16,22,20,121,378]),function(e,t,n,i,r,s,l,d,c,h,p,f,g,m,v,_,y){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var C=function(){function e(e,t,n,i){var o=this;this._editor=e,this._openerService=t,this._modeService=n,this._themeService=i,this._toUnhook=[],this._isMouseDown=!1,this._hoverClicked=!1,this._hookEvents(),this._didChangeConfigurationHandler=this._editor.onDidChangeConfiguration(function(e){e.contribInfo&&(o._hideWidgets(),o._unhookEvents(),o._hookEvents())})}return Object.defineProperty(e.prototype,"contentWidget",{get:function(){ +return this._contentWidget||this._createHoverWidget(),this._contentWidget},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"glyphWidget",{get:function(){return this._glyphWidget||this._createHoverWidget(),this._glyphWidget},enumerable:!0,configurable:!0}),e.get=function(t){return t.getContribution(e.ID)},e.prototype._hookEvents=function(){var e=this,t=function(){return e._hideWidgets()},n=this._editor.getConfiguration().contribInfo.hover;this._isHoverEnabled=n.enabled,this._isHoverSticky=n.sticky,this._isHoverEnabled?(this._toUnhook.push(this._editor.onMouseDown(function(t){return e._onEditorMouseDown(t)})),this._toUnhook.push(this._editor.onMouseUp(function(t){return e._onEditorMouseUp(t)})),this._toUnhook.push(this._editor.onMouseMove(function(t){return e._onEditorMouseMove(t)})),this._toUnhook.push(this._editor.onKeyDown(function(t){return e._onKeyDown(t)})),this._toUnhook.push(this._editor.onDidChangeModelDecorations(function(){return e._onModelDecorationsChanged() +}))):this._toUnhook.push(this._editor.onMouseMove(t)),this._toUnhook.push(this._editor.onMouseLeave(t)),this._toUnhook.push(this._editor.onDidChangeModel(t)),this._toUnhook.push(this._editor.onDidScrollChange(function(t){return e._onEditorScrollChanged(t)}))},e.prototype._unhookEvents=function(){this._toUnhook=g.dispose(this._toUnhook)},e.prototype._onModelDecorationsChanged=function(){this.contentWidget.onModelDecorationsChanged(),this.glyphWidget.onModelDecorationsChanged()},e.prototype._onEditorScrollChanged=function(e){(e.scrollTopChanged||e.scrollLeftChanged)&&this._hideWidgets()},e.prototype._onEditorMouseDown=function(e){this._isMouseDown=!0;var t=e.target.type;t!==h.MouseTargetType.CONTENT_WIDGET||e.target.detail!==p.ModesContentHoverWidget.ID?t===h.MouseTargetType.OVERLAY_WIDGET&&e.target.detail===f.ModesGlyphHoverWidget.ID||(t!==h.MouseTargetType.OVERLAY_WIDGET&&e.target.detail!==f.ModesGlyphHoverWidget.ID&&(this._hoverClicked=!1),this._hideWidgets()):this._hoverClicked=!0}, +e.prototype._onEditorMouseUp=function(e){this._isMouseDown=!1},e.prototype._onEditorMouseMove=function(e){var t=e.target.type,n=r.isMacintosh?e.event.metaKey:e.event.ctrlKey;if(!(this._isMouseDown&&this._hoverClicked&&this.contentWidget.isColorPickerVisible())&&(!this._isHoverSticky||t!==h.MouseTargetType.CONTENT_WIDGET||e.target.detail!==p.ModesContentHoverWidget.ID||n)&&(!this._isHoverSticky||t!==h.MouseTargetType.OVERLAY_WIDGET||e.target.detail!==f.ModesGlyphHoverWidget.ID||n)){if(t===h.MouseTargetType.CONTENT_EMPTY){var i=this._editor.getConfiguration().fontInfo.typicalHalfwidthCharacterWidth/2,o=e.target.detail;o&&!o.isAfterLines&&"number"==typeof o.horizontalDistanceToText&&o.horizontalDistanceToText1&&(o=new s.Selection(o.startLineNumber,o.startColumn,o.endLineNumber,o.endColumn+d-1));var c=new h.InPlaceReplaceCommand(a,o,n.value);i.editor.pushUndoStop(),i.editor.executeCommand(t,c),i.editor.pushUndoStop(),i.decorationIds=i.editor.deltaDecorations(i.decorationIds,[{range:u,options:e.DECORATION}]),i.decorationRemover&&i.decorationRemover.cancel(),i.decorationRemover=v.timeout(350),i.decorationRemover.then(function(){ +return i.decorationIds=i.editor.deltaDecorations(i.decorationIds,[])}).catch(_.onUnexpectedError)}}).catch(_.onUnexpectedError)):void 0},e.ID="editor.contrib.inPlaceReplaceController",e.DECORATION=m.ModelDecorationOptions.register({className:"valueSetReplacement"}),e=a([u(1,c.IEditorWorkerService)],e)}(),C=function(e){function t(){return e.call(this,{id:"editor.action.inPlaceReplace.up",label:n.localize(0,null),alias:"Replace with Previous Value",precondition:l.EditorContextKeys.writable,kbOpts:{kbExpr:l.EditorContextKeys.editorTextFocus,primary:3154,weight:100}})||this}return o(t,e),t.prototype.run=function(e,t){var n=y.get(t);if(n)return i.TPromise.wrap(n.run(this.id,!0))},t}(d.EditorAction),b=function(e){function t(){return e.call(this,{id:"editor.action.inPlaceReplace.down",label:n.localize(1,null),alias:"Replace with Next Value",precondition:l.EditorContextKeys.writable,kbOpts:{kbExpr:l.EditorContextKeys.editorTextFocus,primary:3156,weight:100}})||this}return o(t,e),t.prototype.run=function(e,t){ +var n=y.get(t);if(n)return i.TPromise.wrap(n.run(this.id,!1))},t}(d.EditorAction);d.registerEditorContribution(y),d.registerEditorAction(C),d.registerEditorAction(b),f.registerThemingParticipant(function(e,t){var n=e.getColor(g.editorBracketMatchBorder);n&&t.addRule(".monaco-editor.vs .valueSetReplacement { outline: solid 2px "+n+"; }")})});var d=this&&this.__awaiter||function(e,t,n,i){return new(n||(n=Promise))(function(o,r){function s(e){try{l(i.next(e))}catch(e){r(e)}}function a(e){try{l(i.throw(e))}catch(e){r(e)}}function l(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(s,a)}l((i=i.apply(e,t||[])).next())})},c=this&&this.__generator||function(e,t){function n(n){return function(s){return function(n){if(i)throw new TypeError("Generator is already executing.");for(;a;)try{if(i=1,o&&(r=2&n[0]?o.return:n[0]?o.throw||((r=o.return)&&r.call(o),0):o.next)&&!(r=r.call(o,n[1])).done)return r;switch(o=0,r&&(n=[2&n[0],r.value]),n[0]){case 0:case 1:r=n;break;case 4:return a.label++,{value:n[1],done:!1} +;case 5:a.label++,o=n[1],n=[0];continue;case 7:n=a.ops.pop(),a.trys.pop();continue;default:if(r=a.trys,!(r=r.length>0&&r[r.length-1])&&(6===n[0]||2===n[0])){a=0;continue}if(3===n[0]&&(!r||n[1]>r[0]&&n[1]1;s.toggleClass(this.element,"multiple",e),this.keyMultipleSignatures.set(e),this.signature.innerHTML="",this.docs.innerHTML="";var t=this.hints.signatures[this.currentSignature];if(t){var o=s.append(this.signature,L(".code")),r=t.parameters.length>0,a=this.editor.getConfiguration().fontInfo;if(o.style.fontSize=a.fontSize+"px",o.style.fontFamily=a.fontFamily,r)this.renderParameters(o,t,this.hints.activeParameter);else{s.append(o,L("span")).textContent=t.label}i.dispose(this.renderDisposeables),this.renderDisposeables=[];var u=t.parameters[this.hints.activeParameter];if(u&&u.documentation){var d=L("span.documentation");if("string"==typeof u.documentation)d.textContent=u.documentation;else{c=this.markdownRenderer.render(u.documentation);s.addClass(c.element,"markdown-docs"),this.renderDisposeables.push(c), +d.appendChild(c.element)}s.append(this.docs,L("p",null,d))}if(s.toggleClass(this.signature,"has-docs",!!t.documentation),"string"==typeof t.documentation)s.append(this.docs,L("p",null,t.documentation));else{var c=this.markdownRenderer.render(t.documentation);s.addClass(c.element,"markdown-docs"),this.renderDisposeables.push(c),s.append(this.docs,c.element)}var h=String(this.currentSignature+1);if(this.hints.signatures.length<10&&(h+="/"+this.hints.signatures.length),this.overloads.textContent=h,u){var p=u.label;this.announcedLabel!==p&&(l.alert(n.localize(0,null,p)),this.announcedLabel=p)}this.editor.layoutContentWidget(this),this.scrollbar.scanDomNode()}},e.prototype.renderParameters=function(e,t,n){for(var i,o=t.label.length,r=0,a=t.parameters.length-1;a>=0;a--){var l=t.parameters[a],u=0,d=0;(r=t.label.lastIndexOf(l.label,o-1))>=0&&(u=r,d=r+l.label.length),(i=document.createElement("span")).textContent=t.label.substring(d,o),s.prepend(e,i), +(i=document.createElement("span")).className="parameter "+(a===n?"active":""),i.textContent=t.label.substring(u,d),s.prepend(e,i),o=u}(i=document.createElement("span")).textContent=t.label.substring(0,o),s.prepend(e,i)},e.prototype.next=function(){var e=this.hints.signatures.length,t=this.currentSignature%e==e-1;return e<2||t?(this.cancel(),!1):(this.currentSignature++,this.render(),!0)},e.prototype.previous=function(){var e=this.hints.signatures.length,t=0===this.currentSignature;return e<2||t?(this.cancel(),!1):(this.currentSignature--,this.render(),!0)},e.prototype.cancel=function(){this.model.cancel()},e.prototype.getDomNode=function(){return this.element},e.prototype.getId=function(){return e.ID},e.prototype.trigger=function(){this.model.trigger(0)},e.prototype.updateMaxHeight=function(){var e=Math.max(this.editor.getLayoutInfo().height/4,250);this.element.style.maxHeight=e+"px"},e.prototype.dispose=function(){this.disposables=i.dispose(this.disposables), +this.renderDisposeables=i.dispose(this.renderDisposeables),this.model&&(this.model.dispose(),this.model=null)},e.ID="editor.widget.parameterHintsWidget",e=a([u(1,m.IContextKeyService),u(2,S.IOpenerService),u(3,w.IModeService)],e)}();t.ParameterHintsWidget=N,C.registerThemingParticipant(function(e,t){var n=e.getColor(b.editorHoverBorder);if(n){var i=e.type===C.HIGH_CONTRAST?2:1;t.addRule(".monaco-editor .parameter-hints-widget { border: "+i+"px solid "+n+"; }"),t.addRule(".monaco-editor .parameter-hints-widget.multiple .body { border-left: 1px solid "+n.transparent(.5)+"; }"),t.addRule(".monaco-editor .parameter-hints-widget .signature.has-docs { border-bottom: 1px solid "+n.transparent(.5)+"; }")}var o=e.getColor(b.editorHoverBackground);o&&t.addRule(".monaco-editor .parameter-hints-widget { background-color: "+o+"; }");var r=e.getColor(b.textLinkForeground);r&&t.addRule(".monaco-editor .parameter-hints-widget a { color: "+r+"; }");var s=e.getColor(b.textCodeBlockBackground) +;s&&t.addRule(".monaco-editor .parameter-hints-widget code { background-color: "+s+"; }")})}),define(t[527],n([1,0,327,2,15,20,19,11,526,175]),function(e,t,n,i,r,s,l,d,c,h){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var p=function(){function e(e,t){this.editor=e,this.widget=t.createInstance(c.ParameterHintsWidget,this.editor)}return e.get=function(t){return t.getContribution(e.ID)},e.prototype.getId=function(){return e.ID},e.prototype.cancel=function(){this.widget.cancel()},e.prototype.previous=function(){this.widget.previous()},e.prototype.next=function(){this.widget.next()},e.prototype.trigger=function(){this.widget.trigger()},e.prototype.dispose=function(){this.widget=i.dispose(this.widget)},e.ID="editor.controller.parameterHints",e=a([u(1,r.IInstantiationService)],e)}(),f=function(e){function t(){return e.call(this,{id:"editor.action.triggerParameterHints",label:n.localize(0,null),alias:"Trigger Parameter Hints",precondition:s.EditorContextKeys.hasSignatureHelpProvider,kbOpts:{ +kbExpr:s.EditorContextKeys.editorTextFocus,primary:3082,weight:100}})||this}return o(t,e),t.prototype.run=function(e,t){var n=p.get(t);n&&n.trigger()},t}(d.EditorAction);t.TriggerParameterHintsAction=f,d.registerEditorContribution(p),d.registerEditorAction(f);var g=d.EditorCommand.bindToContribution(p.get);d.registerEditorCommand(new g({id:"closeParameterHints",precondition:h.Context.Visible,handler:function(e){return e.cancel()},kbOpts:{weight:175,kbExpr:s.EditorContextKeys.editorTextFocus,primary:9,secondary:[1033]}})),d.registerEditorCommand(new g({id:"showPrevParameterHint",precondition:l.ContextKeyExpr.and(h.Context.Visible,h.Context.MultipleSignatures),handler:function(e){return e.previous()},kbOpts:{weight:175,kbExpr:s.EditorContextKeys.editorTextFocus,primary:16,secondary:[528],mac:{primary:16,secondary:[528,302]}}})),d.registerEditorCommand(new g({id:"showNextParameterHint",precondition:l.ContextKeyExpr.and(h.Context.Visible,h.Context.MultipleSignatures),handler:function(e){return e.next()},kbOpts:{ +weight:175,kbExpr:s.EditorContextKeys.editorTextFocus,primary:18,secondary:[530],mac:{primary:18,secondary:[530,300]}}}))}),define(t[144],n([1,0,329,67,6,28,56,9,7,69,32,192,141,19,27,385]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g){"use strict";Object.defineProperty(t,"__esModule",{value:!0});!function(e){e.inPeekEditor=new f.RawContextKey("inReferenceSearchEditor",!0),e.notInPeekEditor=e.inPeekEditor.toNegated()}(t.PeekContext||(t.PeekContext={})),t.getOuterEditor=function(e){var t=e.get(c.ICodeEditorService).getFocusedCodeEditor();return t instanceof p.EmbeddedCodeEditorWidget?t.getParentEditor():t};var m={headerBackgroundColor:g.Color.white,primaryHeadingColor:g.Color.fromHex("#333333"),secondaryHeadingColor:g.Color.fromHex("#6c6c6cb3")},v=function(e){function t(t,n){void 0===n&&(n={});var i=e.call(this,t,n)||this;return i._onDidClose=new l.Emitter,s.mixin(i.options,m,!1),i}return o(t,e),t.prototype.dispose=function(){e.prototype.dispose.call(this),this._onDidClose.fire(this)}, +Object.defineProperty(t.prototype,"onDidClose",{get:function(){return this._onDidClose.event},enumerable:!0,configurable:!0}),t.prototype.style=function(t){var n=this.options;t.headerBackgroundColor&&(n.headerBackgroundColor=t.headerBackgroundColor),t.primaryHeadingColor&&(n.primaryHeadingColor=t.primaryHeadingColor),t.secondaryHeadingColor&&(n.secondaryHeadingColor=t.secondaryHeadingColor),e.prototype.style.call(this,t)},t.prototype._applyStyles=function(){e.prototype._applyStyles.call(this);var t=this.options;this._headElement&&(this._headElement.style.backgroundColor=t.headerBackgroundColor.toString()),this._primaryHeading&&(this._primaryHeading.style.color=t.primaryHeadingColor.toString()),this._secondaryHeading&&(this._secondaryHeading.style.color=t.secondaryHeadingColor.toString()),this._bodyElement&&(this._bodyElement.style.borderColor=t.frameColor.toString())},t.prototype._fillContainer=function(e){this.setCssClass("peekview-widget"),this._headElement=a.$(".head").getHTMLElement(), +this._bodyElement=a.$(".body").getHTMLElement(),this._fillHead(this._headElement),this._fillBody(this._bodyElement),e.appendChild(this._headElement),e.appendChild(this._bodyElement)},t.prototype._fillHead=function(e){var t=this,o=a.$(".peekview-title").on(u.EventType.CLICK,function(e){return t._onTitleClick(e)}).appendTo(this._headElement).getHTMLElement();this._primaryHeading=a.$("span.filename").appendTo(o).getHTMLElement(),this._secondaryHeading=a.$("span.dirname").appendTo(o).getHTMLElement(),this._metaHeading=a.$("span.meta").appendTo(o).getHTMLElement();var r=a.$(".peekview-actions").appendTo(this._headElement),s=this._getActionBarOptions();this._actionbarWidget=new d.ActionBar(r.getHTMLElement(),s),this._disposables.push(this._actionbarWidget),this._actionbarWidget.push(new i.Action("peekview.close",n.localize(0,null),"close-peekview-action",!0,function(){return t.dispose(),null}),{label:!1,icon:!0})},t.prototype._getActionBarOptions=function(){return{}},t.prototype._onTitleClick=function(e){}, +t.prototype.setTitle=function(e,t){a.$(this._primaryHeading).safeInnerHtml(e),this._primaryHeading.setAttribute("aria-label",e),t?a.$(this._secondaryHeading).safeInnerHtml(t):u.clearNode(this._secondaryHeading)},t.prototype.setMetaTitle=function(e){e?a.$(this._metaHeading).safeInnerHtml(e):u.clearNode(this._metaHeading)},t.prototype._doLayout=function(e,t){if(!this._isShowing&&e<0)this.dispose();else{var n=Math.ceil(1.2*this.editor.getConfiguration().lineHeight),i=e-(n+2);this._doLayoutHead(n,t),this._doLayoutBody(i,t)}},t.prototype._doLayoutHead=function(e,t){this._headElement.style.height=r.format("{0}px",e),this._headElement.style.lineHeight=this._headElement.style.height},t.prototype._doLayoutBody=function(e,t){this._bodyElement.style.height=r.format("{0}px",e)},t}(h.ZoneWidget);t.PeekViewWidget=v}),define(t[529],n([1,0,336,2,13,3,23,16,22,12,388]),function(e,t,n,i,o,r,s,l,d,c){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var h=function(){function e(e,t){var n=this;this.themeService=t, +this._disposables=[],this.allowEditorOverflow=!0,this._currentAcceptInput=null,this._currentCancelInput=null,this._editor=e,this._editor.addContentWidget(this),this._disposables.push(e.onDidChangeConfiguration(function(e){e.fontInfo&&n.updateFont()})),this._disposables.push(t.onThemeChange(function(e){return n.onThemeChange(e)}))}return e.prototype.onThemeChange=function(e){this.updateStyles(e)},e.prototype.dispose=function(){this._disposables=i.dispose(this._disposables),this._editor.removeContentWidget(this)},e.prototype.getId=function(){return"__renameInputWidget"},e.prototype.getDomNode=function(){return this._domNode||(this._inputField=document.createElement("input"),this._inputField.className="rename-input",this._inputField.type="text",this._inputField.setAttribute("aria-label",n.localize(0,null)),this._domNode=document.createElement("div"),this._domNode.style.height=this._editor.getConfiguration().lineHeight+"px",this._domNode.className="monaco-editor rename-box", +this._domNode.appendChild(this._inputField),this.updateFont(),this.updateStyles(this.themeService.getTheme())),this._domNode},e.prototype.updateStyles=function(e){if(this._inputField){var t=e.getColor(d.inputBackground),n=e.getColor(d.inputForeground),i=e.getColor(d.widgetShadow),o=e.getColor(d.inputBorder);this._inputField.style.backgroundColor=t?t.toString():null,this._inputField.style.color=n?n.toString():null,this._inputField.style.borderWidth=o?"1px":"0px",this._inputField.style.borderStyle=o?"solid":"none",this._inputField.style.borderColor=o?o.toString():"none",this._domNode.style.boxShadow=i?" 0 2px 8px "+i:null}},e.prototype.updateFont=function(){if(this._inputField){var e=this._editor.getConfiguration().fontInfo;this._inputField.style.fontFamily=e.fontFamily,this._inputField.style.fontWeight=e.fontWeight,this._inputField.style.fontSize=e.fontSize+"px"}},e.prototype.getPosition=function(){return this._visible?{position:this._position, +preference:[s.ContentWidgetPositionPreference.BELOW,s.ContentWidgetPositionPreference.ABOVE]}:null},e.prototype.acceptInput=function(){this._currentAcceptInput&&this._currentAcceptInput()},e.prototype.cancelInput=function(e){this._currentCancelInput&&this._currentCancelInput(e)},e.prototype.getInput=function(e,t,n,s){var a=this;this._position=new c.Position(e.startLineNumber,e.startColumn),this._inputField.value=t,this._inputField.setAttribute("selectionStart",n.toString()),this._inputField.setAttribute("selectionEnd",s.toString()),this._inputField.size=Math.max(1.1*(e.endColumn-e.startColumn),20);var l,u=[];return l=function(){i.dispose(u),a._hide()},new o.TPromise(function(n){a._currentCancelInput=function(e){return a._currentAcceptInput=null,a._currentCancelInput=null,n(e),!0},a._currentAcceptInput=function(){0!==a._inputField.value.trim().length&&a._inputField.value!==t?(a._currentAcceptInput=null,a._currentCancelInput=null,n(a._inputField.value)):a.cancelInput(!0)} +;u.push(a._editor.onDidChangeCursorSelection(function(){r.Range.containsPosition(e,a._editor.getPosition())||a.cancelInput(!0)})),u.push(a._editor.onDidBlurEditorWidget(function(){return a.cancelInput(!1)})),a._show()},function(){a._currentCancelInput(!0)}).then(function(e){return l(),e},function(e){return l(),o.TPromise.wrapError(e)})},e.prototype._show=function(){var e=this;this._editor.revealLineInCenterIfOutsideViewport(this._position.lineNumber,0),this._visible=!0,this._editor.layoutContentWidget(this),setTimeout(function(){e._inputField.focus(),e._inputField.setSelectionRange(parseInt(e._inputField.getAttribute("selectionStart")),parseInt(e._inputField.getAttribute("selectionEnd")))},100)},e.prototype._hide=function(){this._visible=!1,this._editor.layoutContentWidget(this)},e=a([u(1,l.IThemeService)],e)}();t.default=h}),define(t[530],n([1,0,335,10,13,19,92,11,20,529,16,14,17,12,52,3,143,68,37,127,31,32]),function(e,t,n,i,r,s,l,h,p,f,g,m,v,_,y,C,b,S,w,E,L,x){"use strict";function N(e,t,n){ +return d(this,void 0,void 0,function(){return c(this,function(i){return[2,new I(e,t).provideRenameEdits(n)]})})}Object.defineProperty(t,"__esModule",{value:!0});var I=function(){function e(e,t){this.model=e,this.position=t,this._provider=v.RenameProviderRegistry.ordered(e)}return e.prototype.hasProvider=function(){return this._provider.length>0},e.prototype.resolveRenameLocation=function(){return d(this,void 0,void 0,function(){var e,t,n,i=this;return c(this,function(o){switch(o.label){case 0:return(e=this._provider[0]).resolveRenameLocation?[4,m.asWinJsPromise(function(t){return e.resolveRenameLocation(i.model,i.position,t)})]:[3,2];case 1:t=o.sent(),o.label=2;case 2:return t||(n=this.model.getWordAtPosition(this.position))&&(t={range:new C.Range(this.position.lineNumber,n.startColumn,this.position.lineNumber,n.endColumn),text:n.word}),[2,t]}})})},e.prototype.provideRenameEdits=function(e,t,i,o){return void 0===t&&(t=0),void 0===i&&(i=[]),void 0===o&&(o=this.position),d(this,void 0,void 0,function(){ +var o,r,s=this;return c(this,function(a){switch(a.label){case 0:return t>=this._provider.length?[2,{edits:void 0,rejectReason:i.join("\n")}]:(o=this._provider[t],[4,m.asWinJsPromise(function(t){return o.provideRenameEdits(s.model,s.position,e,t)})]);case 1:return(r=a.sent())?r.rejectReason?[2,this.provideRenameEdits(e,t+1,i.concat(r.rejectReason))]:[2,r]:[2,this.provideRenameEdits(e,t+1,i.concat(n.localize(0,null)))]}})})},e}();t.rename=N;var M=new s.RawContextKey("renameInputVisible",!1),D=function(){function e(e,t,n,i,o,r){this.editor=e,this._notificationService=t,this._bulkEditService=n,this._progressService=i,this._renameInputField=new f.default(e,r),this._renameInputVisible=M.bindTo(o)}return e.get=function(t){return t.getContribution(e.ID)},e.prototype.dispose=function(){this._renameInputField.dispose()},e.prototype.getId=function(){return e.ID},e.prototype.run=function(){return d(this,void 0,void 0,function(){var e,t,i,o,s,a,l,u=this;return c(this,function(d){switch(d.label){case 0: +if(e=this.editor.getPosition(),!(t=new I(this.editor.getModel(),e)).hasProvider())return[2,void 0];d.label=1;case 1:return d.trys.push([1,3,,4]),[4,t.resolveRenameLocation()];case 2:return i=d.sent(),[3,4];case 3:return o=d.sent(),b.MessageController.get(this.editor).showMessage(o,e),[2,void 0];case 4:return i?(s=this.editor.getSelection(),a=0,l=i.text.length,C.Range.isEmpty(s)||C.Range.spansMultipleLines(s)||!C.Range.containsRange(i.range,s)||(a=Math.max(0,s.startColumn-i.range.startColumn),l=Math.min(i.range.endColumn,s.endColumn)-i.range.startColumn),this._renameInputVisible.set(!0),[2,this._renameInputField.getInput(i.range,i.text,a,l).then(function(e){u._renameInputVisible.reset();if("boolean"!=typeof e){u.editor.focus();var o=new S.EditorState(u.editor,15),s=r.TPromise.wrap(t.provideRenameEdits(e,0,[],C.Range.lift(i.range).getStartPosition()).then(function(t){if(!t.rejectReason)return u._bulkEditService.apply(t,{editor:u.editor}).then(function(t){ +t.ariaSummary&&y.alert(n.localize(1,null,i.text,e,t.ariaSummary))});o.validate(u.editor)?b.MessageController.get(u.editor).showMessage(t.rejectReason,u.editor.getPosition()):u._notificationService.info(t.rejectReason)},function(e){return u._notificationService.error(n.localize(2,null)),r.TPromise.wrapError(e)}));return u._progressService.showWhile(s,250),s}e&&u.editor.focus()},function(e){return u._renameInputVisible.reset(),r.TPromise.wrapError(e)})]):[2,void 0]}})})},e.prototype.acceptRenameInput=function(){this._renameInputField.acceptInput()},e.prototype.cancelRenameInput=function(){this._renameInputField.cancelInput(!0)},e.ID="editor.contrib.renameController",e=a([u(1,w.INotificationService),u(2,E.IBulkEditService),u(3,l.IProgressService),u(4,s.IContextKeyService),u(5,g.IThemeService)],e)}(),T=function(e){function t(){return e.call(this,{id:"editor.action.rename",label:n.localize(3,null),alias:"Rename Symbol", +precondition:s.ContextKeyExpr.and(p.EditorContextKeys.writable,p.EditorContextKeys.hasRenameProvider),kbOpts:{kbExpr:p.EditorContextKeys.editorTextFocus,primary:60,weight:100},menuOpts:{group:"1_modification",order:1.1}})||this}return o(t,e),t.prototype.runCommand=function(t,n){var o=this,r=t.get(x.ICodeEditorService),s=n||[void 0,void 0],a=s[0],l=s[1];return L.default.isUri(a)&&_.Position.isIPosition(l)?r.openCodeEditor({resource:a},r.getActiveCodeEditor()).then(function(e){e.setPosition(l),e.invokeWithinContext(function(t){return o.reportTelemetry(t,e),o.run(t,e)})},i.onUnexpectedError):e.prototype.runCommand.call(this,t,n)},t.prototype.run=function(e,t){var n=D.get(t);if(n)return r.TPromise.wrap(n.run())},t}(h.EditorAction);t.RenameAction=T,h.registerEditorContribution(D),h.registerEditorAction(T);var k=h.EditorCommand.bindToContribution(D.get);h.registerEditorCommand(new k({id:"acceptRenameInput",precondition:M,handler:function(e){return e.acceptRenameInput()},kbOpts:{weight:199, +kbExpr:p.EditorContextKeys.focus,primary:3}})),h.registerEditorCommand(new k({id:"cancelRenameInput",precondition:M,handler:function(e){return e.cancelRenameInput()},kbOpts:{weight:199,kbExpr:p.EditorContextKeys.focus,primary:9,secondary:[1033]}})),h.registerDefaultLanguageCommand("_executeDocumentRenameProvider",function(e,t,n){var o=n.newName;if("string"!=typeof o)throw i.illegalArgument("newName");return N(e,t,o)})}),define(t[531],n([1,0,341,102,6,9,10,2,7,138,278,55,49,19,23,101,52,86,103,16,22,72,121,64,62,14,40,398]),function(e,t,n,i,o,r,s,d,c,h,p,f,g,m,v,_,y,C,b,S,w,E,L,x,N,I,M){"use strict";function D(e){return e&&e.match(R)?e:null}function T(e){if(!e)return!1;var t=e.suggestion;return!!t.documentation||t.detail&&t.detail!==t.label}Object.defineProperty(t,"__esModule",{value:!0});var k=!1;t.editorSuggestWidgetBackground=w.registerColor("editorSuggestWidget.background",{dark:w.editorWidgetBackground,light:w.editorWidgetBackground,hc:w.editorWidgetBackground},n.localize(0,null)), +t.editorSuggestWidgetBorder=w.registerColor("editorSuggestWidget.border",{dark:w.editorWidgetBorder,light:w.editorWidgetBorder,hc:w.editorWidgetBorder},n.localize(1,null)),t.editorSuggestWidgetForeground=w.registerColor("editorSuggestWidget.foreground",{dark:w.editorForeground,light:w.editorForeground,hc:w.editorForeground},n.localize(2,null)),t.editorSuggestWidgetSelectedBackground=w.registerColor("editorSuggestWidget.selectedBackground",{dark:w.listFocusBackground,light:w.listFocusBackground,hc:w.listFocusBackground},n.localize(3,null)),t.editorSuggestWidgetHighlightForeground=w.registerColor("editorSuggestWidget.highlightForeground",{dark:w.listHighlightForeground,light:w.listHighlightForeground,hc:w.listHighlightForeground},n.localize(4,null));var R=/^(#([\da-f]{3}){1,2}|(rgb|hsl)a\(\s*(\d{1,3}%?\s*,\s*){3}(1|0?\.\d+)\)|(rgb|hsl)\(\s*\d{1,3}%?(\s*,\s*\d{1,3}%?){2}\s*\))$/i,O=function(){function e(e,t,n){this.widget=e,this.editor=t,this.triggerKeybindingLabel=n} +return Object.defineProperty(e.prototype,"templateId",{get:function(){return"suggestion"},enumerable:!0,configurable:!0}),e.prototype.renderTemplate=function(e){var t=this,i=Object.create(null);i.disposables=[],i.root=e,i.icon=c.append(e,c.$(".icon")),i.colorspan=c.append(i.icon,c.$("span.colorspan"));var o=c.append(e,c.$(".contents")),s=c.append(o,c.$(".main"));i.highlightedLabel=new h.HighlightedLabel(s),i.disposables.push(i.highlightedLabel),i.typeLabel=c.append(s,c.$("span.type-label")),i.readMore=c.append(s,c.$("span.readMore")),i.readMore.title=n.localize(5,null,this.triggerKeybindingLabel);var a=function(){var e=t.editor.getConfiguration(),n=e.fontInfo.fontFamily,o=(e.contribInfo.suggestFontSize||e.fontInfo.fontSize)+"px",r=(e.contribInfo.suggestLineHeight||e.fontInfo.lineHeight)+"px";i.root.style.fontSize=o,s.style.fontFamily=n,s.style.lineHeight=r,i.icon.style.height=r,i.icon.style.width=r,i.readMore.style.height=r,i.readMore.style.width=r};return a(), +r.chain(this.editor.onDidChangeConfiguration.bind(this.editor)).filter(function(e){return e.fontInfo||e.contribInfo}).on(a,null,i.disposables),i},e.prototype.renderElement=function(e,t,o){var r=this,s=o,a=e.suggestion;if(T(e)?s.root.setAttribute("aria-label",n.localize(6,null,a.label)):s.root.setAttribute("aria-label",n.localize(7,null,a.label)),s.icon.className="icon "+a.type,s.colorspan.style.backgroundColor="","color"===a.type){var l=D(a.label)||"string"==typeof a.documentation&&D(a.documentation);l&&(s.icon.className="icon customcolor",s.colorspan.style.backgroundColor=l)}s.highlightedLabel.set(a.label,i.createMatches(e.matches),"",!0),s.typeLabel.textContent=(a.detail||"").replace(/\n.*$/m,""),T(e)?(c.show(s.readMore),s.readMore.onmousedown=function(e){e.stopPropagation(),e.preventDefault()},s.readMore.onclick=function(e){e.stopPropagation(),e.preventDefault(),r.widget.toggleDetails()}):(c.hide(s.readMore),s.readMore.onmousedown=null,s.readMore.onclick=null)},e.prototype.disposeElement=function(){}, +e.prototype.disposeTemplate=function(e){e.disposables=d.dispose(e.disposables)},e}(),P=function(){function e(e,t,i,o,s){var a=this;this.widget=t,this.editor=i,this.markdownRenderer=o,this.triggerKeybindingLabel=s,this.borderWidth=1,this.disposables=[],this.el=c.append(e,c.$(".details")),this.disposables.push(d.toDisposable(function(){return e.removeChild(a.el)})),this.body=c.$(".body"),this.scrollbar=new f.DomScrollableElement(this.body,{}),c.append(this.el,this.scrollbar.getDomNode()),this.disposables.push(this.scrollbar),this.header=c.append(this.body,c.$(".header")),this.close=c.append(this.header,c.$("span.close")),this.close.title=n.localize(8,null,this.triggerKeybindingLabel),this.type=c.append(this.header,c.$("p.type")),this.docs=c.append(this.body,c.$("p.docs")),this.ariaLabel=null,this.configureFont(),r.chain(this.editor.onDidChangeConfiguration.bind(this.editor)).filter(function(e){return e.fontInfo}).on(this.configureFont,this,this.disposables),o.onDidRenderCodeBlock(function(){ +return a.scrollbar.scanDomNode()},this,this.disposables)}return Object.defineProperty(e.prototype,"element",{get:function(){return this.el},enumerable:!0,configurable:!0}),e.prototype.render=function(e){var t=this;if(this.renderDisposeable=d.dispose(this.renderDisposeable),!e||!T(e))return this.type.textContent="",this.docs.textContent="",c.addClass(this.el,"no-docs"),void(this.ariaLabel=null);if(c.removeClass(this.el,"no-docs"),"string"==typeof e.suggestion.documentation)c.removeClass(this.docs,"markdown-docs"),this.docs.textContent=e.suggestion.documentation;else{c.addClass(this.docs,"markdown-docs"),this.docs.innerHTML="";var n=this.markdownRenderer.render(e.suggestion.documentation);this.renderDisposeable=n,this.docs.appendChild(n.element)}e.suggestion.detail?(this.type.innerText=e.suggestion.detail,c.show(this.type)):(this.type.innerText="",c.hide(this.type)),this.el.style.height=this.header.offsetHeight+this.docs.offsetHeight+2*this.borderWidth+"px",this.close.onmousedown=function(e){e.preventDefault(), +e.stopPropagation()},this.close.onclick=function(e){e.preventDefault(),e.stopPropagation(),t.widget.toggleDetails()},this.body.scrollTop=0,this.scrollbar.scanDomNode(),this.ariaLabel=o.format("{0}\n{1}\n{2}",e.suggestion.label||"",e.suggestion.detail||"",e.suggestion.documentation||"")},e.prototype.getAriaLabel=function(){return this.ariaLabel},e.prototype.scrollDown=function(e){void 0===e&&(e=8),this.body.scrollTop+=e},e.prototype.scrollUp=function(e){void 0===e&&(e=8),this.body.scrollTop-=e},e.prototype.scrollTop=function(){this.body.scrollTop=0},e.prototype.scrollBottom=function(){this.body.scrollTop=this.body.scrollHeight},e.prototype.pageDown=function(){this.scrollDown(80)},e.prototype.pageUp=function(){this.scrollUp(80)},e.prototype.setBorderWidth=function(e){this.borderWidth=e},e.prototype.configureFont=function(){var e=this.editor.getConfiguration(),t=e.fontInfo.fontFamily,n=(e.contribInfo.suggestFontSize||e.fontInfo.fontSize)+"px",i=(e.contribInfo.suggestLineHeight||e.fontInfo.lineHeight)+"px" +;this.el.style.fontSize=n,this.type.style.fontFamily=t,this.close.style.height=i,this.close.style.width=i},e.prototype.dispose=function(){this.disposables=d.dispose(this.disposables),this.renderDisposeable=d.dispose(this.renderDisposeable)},e}(),A=function(){function e(e,n,i,o,s,a,l,u){var d=this;this.editor=e,this.telemetryService=n,this.allowEditorOverflow=!0,this.ignoreFocusEvents=!1,this.editorBlurTimeout=new I.TimeoutTimer,this.showTimeout=new I.TimeoutTimer,this.onDidSelectEmitter=new r.Emitter,this.onDidFocusEmitter=new r.Emitter,this.onDidHideEmitter=new r.Emitter,this.onDidShowEmitter=new r.Emitter,this.onDidSelect=this.onDidSelectEmitter.event,this.onDidFocus=this.onDidFocusEmitter.event,this.onDidHide=this.onDidHideEmitter.event,this.onDidShow=this.onDidShowEmitter.event,this.maxWidgetWidth=660,this.listWidth=330,this.storageServiceAvailable=!0,this.expandSuggestionDocs=!1,this.firstFocusInCurrentList=!1 +;var h=a.lookupKeybinding("editor.action.triggerSuggest"),f=h?" ("+h.getLabel()+")":"",g=new L.MarkdownRenderer(e,l,u);this.isAuto=!1,this.focusedItem=null,this.storageService=s,void 0===this.expandDocsSettingFromStorage()&&(this.storageService.store("expandSuggestionDocs",k,E.StorageScope.GLOBAL),void 0===this.expandDocsSettingFromStorage()&&(this.storageServiceAvailable=!1)),this.element=c.$(".editor-widget.suggest-widget"),this.editor.getConfiguration().contribInfo.iconsInSuggestions||c.addClass(this.element,"no-icons"),this.messageElement=c.append(this.element,c.$(".message")),this.listElement=c.append(this.element,c.$(".tree")),this.details=new P(this.element,this,this.editor,g,f);var m=new O(this,this.editor,f);this.list=new p.List(this.listElement,this,[m],{useShadows:!1,selectOnMouseDown:!0,focusOnMouseDown:!1,openController:{shouldOpen:function(){return!1}}}),this.toDispose=[b.attachListStyler(this.list,o,{listInactiveFocusBackground:t.editorSuggestWidgetSelectedBackground, +listInactiveFocusOutline:w.activeContrastBorder}),o.onThemeChange(function(e){return d.onThemeChange(e)}),e.onDidBlurEditorText(function(){return d.onEditorBlur()}),e.onDidLayoutChange(function(){return d.onEditorLayoutChange()}),this.list.onSelectionChange(function(e){return d.onListSelection(e)}),this.list.onFocusChange(function(e){return d.onListFocus(e)}),this.editor.onDidChangeCursorSelection(function(){return d.onCursorSelectionChanged()})],this.suggestWidgetVisible=_.Context.Visible.bindTo(i),this.suggestWidgetMultipleSuggestions=_.Context.MultipleSuggestions.bindTo(i),this.suggestionSupportsAutoAccept=_.Context.AcceptOnKey.bindTo(i),this.editor.addContentWidget(this),this.setState(0),this.onThemeChange(o.getTheme())}return e.prototype.onCursorSelectionChanged=function(){0!==this.state&&this.editor.layoutContentWidget(this)},e.prototype.onEditorBlur=function(){var e=this;this.editorBlurTimeout.cancelAndSet(function(){e.editor.hasTextFocus()||e.setState(0)},150)}, +e.prototype.onEditorLayoutChange=function(){3!==this.state&&5!==this.state||!this.expandDocsSettingFromStorage()||this.expandSideOrBelow()},e.prototype.onListSelection=function(e){var t=this;if(e.elements.length){var i=e.elements[0],o=e.indexes[0];i.resolve(M.CancellationToken.None).then(function(){t.onDidSelectEmitter.fire({item:i,index:o,model:t.completionModel}),y.alert(n.localize(11,null,i.suggestion.label)),t.editor.focus()})}},e.prototype._getSuggestionAriaAlertLabel=function(e){return T(e)?n.localize(12,null,e.suggestion.label):n.localize(13,null,e.suggestion.label)},e.prototype._ariaAlert=function(e){this._lastAriaAlertLabel!==e&&(this._lastAriaAlertLabel=e,this._lastAriaAlertLabel&&y.alert(this._lastAriaAlertLabel))},e.prototype.onThemeChange=function(e){var n=e.getColor(t.editorSuggestWidgetBackground);n&&(this.listElement.style.backgroundColor=n.toString(),this.details.element.style.backgroundColor=n.toString(),this.messageElement.style.backgroundColor=n.toString()) +;var i=e.getColor(t.editorSuggestWidgetBorder);i&&(this.listElement.style.borderColor=i.toString(),this.details.element.style.borderColor=i.toString(),this.messageElement.style.borderColor=i.toString(),this.detailsBorderColor=i.toString());var o=e.getColor(w.focusBorder);o&&(this.detailsFocusBorderColor=o.toString()),this.details.setBorderWidth("hc"===e.type?2:1)},e.prototype.onListFocus=function(e){var t=this;if(!this.ignoreFocusEvents){if(!e.elements.length)return this.currentSuggestionDetails&&(this.currentSuggestionDetails.cancel(),this.currentSuggestionDetails=null,this.focusedItem=null),void this._ariaAlert(null);var n=e.elements[0];if(this._ariaAlert(this._getSuggestionAriaAlertLabel(n)),this.firstFocusInCurrentList=!this.focusedItem,n!==this.focusedItem){this.currentSuggestionDetails&&(this.currentSuggestionDetails.cancel(),this.currentSuggestionDetails=null);var i=e.indexes[0];this.suggestionSupportsAutoAccept.set(!n.suggestion.noAutoAccept),this.focusedItem=n,this.list.reveal(i), +this.currentSuggestionDetails=I.createCancelablePromise(function(e){return n.resolve(e)}),this.currentSuggestionDetails.then(function(){t.ignoreFocusEvents=!0,t.list.splice(i,1,[n]),t.list.setFocus([i]),t.ignoreFocusEvents=!1,t.expandDocsSettingFromStorage()?t.showDetails():c.removeClass(t.element,"docs-side")}).catch(s.onUnexpectedError).then(function(){t.focusedItem===n&&(t.currentSuggestionDetails=null)}),this.onDidFocusEmitter.fire({item:n,index:i,model:this.completionModel})}}},e.prototype.setState=function(t){if(this.element){var n=this.state!==t;switch(this.state=t,c.toggleClass(this.element,"frozen",4===t),t){case 0:c.hide(this.messageElement,this.details.element,this.listElement),this.hide(),this.listHeight=0,n&&this.list.splice(0,this.list.length),this.focusedItem=null;break;case 1:this.messageElement.textContent=e.LOADING_MESSAGE,c.hide(this.listElement,this.details.element),c.show(this.messageElement),c.removeClass(this.element,"docs-side"),this.show(),this.focusedItem=null;break;case 2: +this.messageElement.textContent=e.NO_SUGGESTIONS_MESSAGE,c.hide(this.listElement,this.details.element),c.show(this.messageElement),c.removeClass(this.element,"docs-side"),this.show(),this.focusedItem=null;break;case 3:case 4:c.hide(this.messageElement),c.show(this.listElement),this.show();break;case 5:c.hide(this.messageElement),c.show(this.details.element,this.listElement),this.show(),this._ariaAlert(this.details.getAriaLabel())}}},e.prototype.showTriggered=function(e){var t=this;0===this.state&&(this.isAuto=!!e,this.isAuto||(this.loadingTimeout=setTimeout(function(){t.loadingTimeout=null,t.setState(1)},50)))},e.prototype.showSuggestions=function(e,t,n,i){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.completionModel!==e&&(this.completionModel=e),n&&2!==this.state&&0!==this.state)this.setState(4);else{var o=this.completionModel.items.length,r=0===o;if(this.suggestWidgetMultipleSuggestions.set(o>1),r)i?this.setState(0):this.setState(2),this.completionModel=null;else{ +var s=this.completionModel.stats;s.wasAutomaticallyTriggered=!!i,this.telemetryService.publicLog("suggestWidget",l({},s,this.editor.getTelemetryData())),this.list.splice(0,this.list.length,this.completionModel.items),n?this.setState(4):this.setState(3),this.list.reveal(t,t),this.list.setFocus([t]),this.detailsBorderColor&&(this.details.element.style.borderColor=this.detailsBorderColor)}}},e.prototype.selectNextPage=function(){switch(this.state){case 0:return!1;case 5:return this.details.pageDown(),!0;case 1:return!this.isAuto;default:return this.list.focusNextPage(),!0}},e.prototype.selectNext=function(){switch(this.state){case 0:return!1;case 1:return!this.isAuto;default:return this.list.focusNext(1,!0),!0}},e.prototype.selectLast=function(){switch(this.state){case 0:return!1;case 5:return this.details.scrollBottom(),!0;case 1:return!this.isAuto;default:return this.list.focusLast(),!0}},e.prototype.selectPreviousPage=function(){switch(this.state){case 0:return!1;case 5:return this.details.pageUp(),!0;case 1: +return!this.isAuto;default:return this.list.focusPreviousPage(),!0}},e.prototype.selectPrevious=function(){switch(this.state){case 0:return!1;case 1:return!this.isAuto;default:return this.list.focusPrevious(1,!0),!1}},e.prototype.selectFirst=function(){switch(this.state){case 0:return!1;case 5:return this.details.scrollTop(),!0;case 1:return!this.isAuto;default:return this.list.focusFirst(),!0}},e.prototype.getFocusedItem=function(){if(0!==this.state&&2!==this.state&&1!==this.state)return{item:this.list.getFocusedElements()[0],index:this.list.getFocus()[0],model:this.completionModel}},e.prototype.toggleDetailsFocus=function(){5===this.state?(this.setState(3),this.detailsBorderColor&&(this.details.element.style.borderColor=this.detailsBorderColor)):3===this.state&&this.expandDocsSettingFromStorage()&&(this.setState(5),this.detailsFocusBorderColor&&(this.details.element.style.borderColor=this.detailsFocusBorderColor)), +this.telemetryService.publicLog("suggestWidget:toggleDetailsFocus",this.editor.getTelemetryData())},e.prototype.toggleDetails=function(){if(T(this.list.getFocusedElements()[0]))if(this.expandDocsSettingFromStorage())this.updateExpandDocsSetting(!1),c.hide(this.details.element),c.removeClass(this.element,"docs-side"),c.removeClass(this.element,"docs-below"),this.editor.layoutContentWidget(this),this.telemetryService.publicLog("suggestWidget:collapseDetails",this.editor.getTelemetryData());else{if(3!==this.state&&5!==this.state&&4!==this.state)return;this.updateExpandDocsSetting(!0),this.showDetails(),this.telemetryService.publicLog("suggestWidget:expandDetails",this.editor.getTelemetryData())}},e.prototype.showDetails=function(){this.expandSideOrBelow(),c.show(this.details.element),this.details.render(this.list.getFocusedElements()[0]),this.details.element.style.maxHeight=this.maxWidgetHeight+"px",this.listElement.style.marginTop="0px",this.editor.layoutContentWidget(this),this.adjustDocsPosition(), +this.editor.focus(),this._ariaAlert(this.details.getAriaLabel())},e.prototype.show=function(){var e=this,t=this.updateListHeight();t!==this.listHeight&&(this.editor.layoutContentWidget(this),this.listHeight=t),this.suggestWidgetVisible.set(!0),this.showTimeout.cancelAndSet(function(){c.addClass(e.element,"visible"),e.onDidShowEmitter.fire(e)},100)},e.prototype.hide=function(){this.suggestWidgetVisible.reset(),this.suggestWidgetMultipleSuggestions.reset(),c.removeClass(this.element,"visible")},e.prototype.hideWidget=function(){clearTimeout(this.loadingTimeout),this.setState(0),this.onDidHideEmitter.fire(this)},e.prototype.getPosition=function(){return 0===this.state?null:{position:this.editor.getPosition(),preference:[v.ContentWidgetPositionPreference.BELOW,v.ContentWidgetPositionPreference.ABOVE]}},e.prototype.getDomNode=function(){return this.element},e.prototype.getId=function(){return e.ID},e.prototype.updateListHeight=function(){var e=0;if(2===this.state||1===this.state)e=this.unfocusedHeight;else{ +var t=this.list.contentHeight/this.unfocusedHeight;e=Math.min(t,12)*this.unfocusedHeight}return this.element.style.lineHeight=this.unfocusedHeight+"px",this.listElement.style.height=e+"px",this.list.layout(e),e},e.prototype.adjustDocsPosition=function(){var e=this.editor.getConfiguration().fontInfo.lineHeight,t=this.editor.getScrolledVisiblePosition(this.editor.getPosition()),n=c.getDomNodePagePosition(this.editor.getDomNode()),i=n.left+t.left,o=n.top+t.top+t.height,r=c.getDomNodePagePosition(this.element),s=r.left,a=r.top;sa&&this.details.element.offsetHeight>this.listElement.offsetHeight&&(this.listElement.style.marginTop=this.details.element.offsetHeight-this.listElement.offsetHeight+"px")},e.prototype.expandSideOrBelow=function(){if(!T(this.focusedItem)&&this.firstFocusInCurrentList)return c.removeClass(this.element,"docs-side"), +void c.removeClass(this.element,"docs-below");var e=this.element.style.maxWidth.match(/(\d+)px/);!e||Number(e[1])0&&this._activeAcceptCharacters.add(i[0])}}else this.reset()},e.prototype.reset=function(){this._activeItem=void 0},e.prototype.dispose=function(){s.dispose(this._disposables)},e}(),E=function(){function e(e,t,n,i){var o=this;this._editor=e,this._commandService=t,this._contextKeyService=n,this._instantiationService=i,this._toDispose=[],this._model=new C.SuggestModel(this._editor),this._memory=i.createInstance(S.SuggestMemories,this._editor.getConfiguration().contribInfo.suggestSelection),this._toDispose.push(this._model.onDidTrigger(function(e){o._widget||o._createSuggestWidget(),o._widget.showTriggered(e.auto)})), +this._toDispose.push(this._model.onDidSuggest(function(e){var t=o._memory.select(o._editor.getModel(),o._editor.getPosition(),e.completionModel.items);o._widget.showSuggestions(e.completionModel,t,e.isFrozen,e.auto)})),this._toDispose.push(this._model.onDidCancel(function(e){o._widget&&!e.retrigger&&o._widget.hideWidget()}));var r=y.Context.AcceptSuggestionsOnEnter.bindTo(n),s=function(){var e=o._editor.getConfiguration().contribInfo,t=e.acceptSuggestionOnEnter,n=e.suggestSelection;r.set("on"===t||"smart"===t),o._memory.setMode(n)};this._toDispose.push(this._editor.onDidChangeConfiguration(function(e){return s()})),s()}return e.get=function(t){return t.getContribution(e.ID)},e.prototype._createSuggestWidget=function(){var e=this;this._widget=this._instantiationService.createInstance(b.SuggestWidget,this._editor),this._toDispose.push(this._widget.onDidSelect(this._onDidSelectItem,this));var t=new w(this._editor,this._widget,function(t){return e._onDidSelectItem(t)}) +;this._toDispose.push(t,this._model.onDidSuggest(function(e){0===e.completionModel.items.length&&t.reset()}));var n=y.Context.MakesTextEdit.bindTo(this._contextKeyService);this._toDispose.push(this._widget.onDidFocus(function(t){var i=t.item,o=e._editor.getPosition(),r=i.position.column-i.suggestion.overwriteBefore,s=o.column,a=!0;if("smart"===e._editor.getConfiguration().contribInfo.acceptSuggestionOnEnter&&2===e._model.state&&!i.suggestion.command&&!i.suggestion.additionalTextEdits&&"textmate"!==i.suggestion.snippetType&&s-r===i.suggestion.insertText.length){a=e._editor.getModel().getValueInRange({startLineNumber:o.lineNumber,startColumn:r,endLineNumber:o.lineNumber,endColumn:s})!==i.suggestion.insertText}n.set(a)})),this._toDispose.push({dispose:function(){n.reset()}})},e.prototype.getId=function(){return e.ID},e.prototype.dispose=function(){this._toDispose=s.dispose(this._toDispose),this._widget&&(this._widget.dispose(),this._widget=null),this._model&&(this._model.dispose(),this._model=null)}, +e.prototype._onDidSelectItem=function(e){var t;if(e&&e.item){var n=e.item,o=n.suggestion,r=n.position,s=this._editor.getPosition().column-r.column;this._editor.pushUndoStop(),Array.isArray(o.additionalTextEdits)&&this._editor.executeEdits("suggestController.additionalTextEdits",o.additionalTextEdits.map(function(e){return g.EditOperation.replace(m.Range.lift(e.range),e.text)})),this._memory.memorize(this._editor.getModel(),this._editor.getPosition(),e.item);var a=o.insertText;"textmate"!==o.snippetType&&(a=v.SnippetParser.escape(a)),_.SnippetController2.get(this._editor).insert(a,o.overwriteBefore+s,o.overwriteAfter,!1,!1),this._editor.pushUndoStop(),o.command?o.command.id===L.id?this._model.trigger({auto:!0},!0):((t=this._commandService).executeCommand.apply(t,[o.command.id].concat(o.command.arguments)).done(void 0,i.onUnexpectedError),this._model.cancel()):this._model.cancel(),this._alertCompletionItem(e.item)}else this._model.cancel()},e.prototype._alertCompletionItem=function(e){ +var t=e.suggestion,i=n.localize(0,null,t.label,t.insertText);f.alert(i)},e.prototype.triggerSuggest=function(e){this._model.trigger({auto:!1},!1,e),this._editor.revealLine(this._editor.getPosition().lineNumber,0),this._editor.focus()},e.prototype.acceptSelectedSuggestion=function(){if(this._widget){var e=this._widget.getFocusedItem();this._onDidSelectItem(e)}},e.prototype.cancelSuggestWidget=function(){this._widget&&(this._model.cancel(),this._widget.hideWidget())},e.prototype.selectNextSuggestion=function(){this._widget&&this._widget.selectNext()},e.prototype.selectNextPageSuggestion=function(){this._widget&&this._widget.selectNextPage()},e.prototype.selectLastSuggestion=function(){this._widget&&this._widget.selectLast()},e.prototype.selectPrevSuggestion=function(){this._widget&&this._widget.selectPrevious()},e.prototype.selectPrevPageSuggestion=function(){this._widget&&this._widget.selectPreviousPage()},e.prototype.selectFirstSuggestion=function(){this._widget&&this._widget.selectFirst()}, +e.prototype.toggleSuggestionDetails=function(){this._widget&&this._widget.toggleDetails()},e.prototype.toggleSuggestionFocus=function(){this._widget&&this._widget.toggleDetailsFocus()},e.ID="editor.contrib.suggestController",e=a([u(1,c.ICommandService),u(2,d.IContextKeyService),u(3,l.IInstantiationService)],e)}();t.SuggestController=E;var L=function(e){function t(){return e.call(this,{id:t.id,label:n.localize(1,null),alias:"Trigger Suggest",precondition:d.ContextKeyExpr.and(h.EditorContextKeys.writable,h.EditorContextKeys.hasCompletionItemProvider),kbOpts:{kbExpr:h.EditorContextKeys.textInputFocus,primary:2058,mac:{primary:266},weight:100}})||this}return o(t,e),t.prototype.run=function(e,t){var n=E.get(t);n&&n.triggerSuggest()},t.id="editor.action.triggerSuggest",t}(p.EditorAction);t.TriggerSuggestAction=L,p.registerEditorContribution(E),p.registerEditorAction(L);var x=p.EditorCommand.bindToContribution(E.get);p.registerEditorCommand(new x({id:"acceptSelectedSuggestion",precondition:y.Context.Visible, +handler:function(e){return e.acceptSelectedSuggestion()},kbOpts:{weight:190,kbExpr:h.EditorContextKeys.textInputFocus,primary:2}})),p.registerEditorCommand(new x({id:"acceptSelectedSuggestionOnEnter",precondition:y.Context.Visible,handler:function(e){return e.acceptSelectedSuggestion()},kbOpts:{weight:190,kbExpr:d.ContextKeyExpr.and(h.EditorContextKeys.textInputFocus,y.Context.AcceptSuggestionsOnEnter,y.Context.MakesTextEdit),primary:3}})),p.registerEditorCommand(new x({id:"hideSuggestWidget",precondition:y.Context.Visible,handler:function(e){return e.cancelSuggestWidget()},kbOpts:{weight:190,kbExpr:h.EditorContextKeys.textInputFocus,primary:9,secondary:[1033]}})),p.registerEditorCommand(new x({id:"selectNextSuggestion",precondition:d.ContextKeyExpr.and(y.Context.Visible,y.Context.MultipleSuggestions),handler:function(e){return e.selectNextSuggestion()},kbOpts:{weight:190,kbExpr:h.EditorContextKeys.textInputFocus,primary:18,secondary:[2066],mac:{primary:18,secondary:[2066,300]}}})), +p.registerEditorCommand(new x({id:"selectNextPageSuggestion",precondition:d.ContextKeyExpr.and(y.Context.Visible,y.Context.MultipleSuggestions),handler:function(e){return e.selectNextPageSuggestion()},kbOpts:{weight:190,kbExpr:h.EditorContextKeys.textInputFocus,primary:12,secondary:[2060]}})),p.registerEditorCommand(new x({id:"selectLastSuggestion",precondition:d.ContextKeyExpr.and(y.Context.Visible,y.Context.MultipleSuggestions),handler:function(e){return e.selectLastSuggestion()}})),p.registerEditorCommand(new x({id:"selectPrevSuggestion",precondition:d.ContextKeyExpr.and(y.Context.Visible,y.Context.MultipleSuggestions),handler:function(e){return e.selectPrevSuggestion()},kbOpts:{weight:190,kbExpr:h.EditorContextKeys.textInputFocus,primary:16,secondary:[2064],mac:{primary:16,secondary:[2064,302]}}})),p.registerEditorCommand(new x({id:"selectPrevPageSuggestion",precondition:d.ContextKeyExpr.and(y.Context.Visible,y.Context.MultipleSuggestions),handler:function(e){return e.selectPrevPageSuggestion()},kbOpts:{ +weight:190,kbExpr:h.EditorContextKeys.textInputFocus,primary:11,secondary:[2059]}})),p.registerEditorCommand(new x({id:"selectFirstSuggestion",precondition:d.ContextKeyExpr.and(y.Context.Visible,y.Context.MultipleSuggestions),handler:function(e){return e.selectFirstSuggestion()}})),p.registerEditorCommand(new x({id:"toggleSuggestionDetails",precondition:y.Context.Visible,handler:function(e){return e.toggleSuggestionDetails()},kbOpts:{weight:190,kbExpr:h.EditorContextKeys.textInputFocus,primary:2058,mac:{primary:266}}})),p.registerEditorCommand(new x({id:"toggleSuggestionFocus",precondition:y.Context.Visible,handler:function(e){return e.toggleSuggestionFocus()},kbOpts:{weight:190,kbExpr:h.EditorContextKeys.textInputFocus,primary:2570,mac:{primary:778}}}))}),define(t[533],n([1,0,343,14,10,3,11,17,2,22,16,54,29,19,20,25,24,40]),function(e,t,n,i,r,s,l,d,c,h,p,f,g,m,v,_,y,C){"use strict";function b(e,t,n){var o=d.DocumentHighlightProviderRegistry.ordered(e);return i.first2(o.map(function(i){return function(){ +return Promise.resolve(i.provideDocumentHighlights(e,t,n)).then(void 0,r.onUnexpectedExternalError)}}),function(e){return!_.isFalsyOrEmpty(e)})}Object.defineProperty(t,"__esModule",{value:!0}),t.editorWordHighlight=h.registerColor("editor.wordHighlightBackground",{dark:"#575757B8",light:"#57575740",hc:null},n.localize(0,null),!0),t.editorWordHighlightStrong=h.registerColor("editor.wordHighlightStrongBackground",{dark:"#004972B8",light:"#0e639c40",hc:null},n.localize(1,null),!0),t.editorWordHighlightBorder=h.registerColor("editor.wordHighlightBorder",{light:null,dark:null,hc:h.activeContrastBorder},n.localize(2,null)),t.editorWordHighlightStrongBorder=h.registerColor("editor.wordHighlightStrongBorder",{light:null,dark:null,hc:h.activeContrastBorder},n.localize(3,null)),t.overviewRulerWordHighlightForeground=h.registerColor("editorOverviewRuler.wordHighlightForeground",{dark:"#A0A0A0CC",light:"#A0A0A0CC",hc:"#A0A0A0CC"},n.localize(4,null),!0), +t.overviewRulerWordHighlightStrongForeground=h.registerColor("editorOverviewRuler.wordHighlightStrongForeground",{dark:"#C0A0C0CC",light:"#C0A0C0CC",hc:"#C0A0C0CC"},n.localize(5,null),!0),t.ctxHasWordHighlights=new m.RawContextKey("hasWordHighlights",!1),t.getOccurrencesAtPosition=b,l.registerDefaultLanguageCommand("_executeDocumentHighlights",function(e,t){return b(e,t,C.CancellationToken.None)});var S=function(){function e(e,n){var i=this;this.workerRequestTokenId=0,this.workerRequest=null,this.workerRequestCompleted=!1,this.workerRequestValue=[],this.lastCursorPositionChangeTime=0,this.renderDecorationsTimer=-1,this.editor=e,this._hasWordHighlights=t.ctxHasWordHighlights.bindTo(n),this._ignorePositionChangeEvent=!1,this.occurrencesHighlight=this.editor.getConfiguration().contribInfo.occurrencesHighlight,this.model=this.editor.getModel(),this.toUnhook=[],this.toUnhook.push(e.onDidChangeCursorPosition(function(e){i._ignorePositionChangeEvent||i.occurrencesHighlight&&i._onPositionChanged(e)})), +this.toUnhook.push(e.onDidChangeModel(function(e){i._stopAll(),i.model=i.editor.getModel()})),this.toUnhook.push(e.onDidChangeModelContent(function(e){i._stopAll()})),this.toUnhook.push(e.onDidChangeConfiguration(function(e){var t=i.editor.getConfiguration().contribInfo.occurrencesHighlight;i.occurrencesHighlight!==t&&(i.occurrencesHighlight=t,i._stopAll())})),this._lastWordRange=null,this._decorationIds=[],this.workerRequestTokenId=0,this.workerRequest=null,this.workerRequestCompleted=!1,this.lastCursorPositionChangeTime=0,this.renderDecorationsTimer=-1}return e.prototype.hasDecorations=function(){return this._decorationIds.length>0},e.prototype.restore=function(){this.occurrencesHighlight&&this._run()},e.prototype._getSortedHighlights=function(){var e=this;return this._decorationIds.map(function(t){return e.model.getDecorationRange(t)}).sort(s.Range.compareRangesUsingStarts)},e.prototype.moveNext=function(){var e=this,t=this._getSortedHighlights(),n=t[(_.firstIndex(t,function(t){ +return t.containsPosition(e.editor.getPosition())})+1)%t.length];try{this._ignorePositionChangeEvent=!0,this.editor.setPosition(n.getStartPosition()),this.editor.revealRangeInCenterIfOutsideViewport(n)}finally{this._ignorePositionChangeEvent=!1}},e.prototype.moveBack=function(){var e=this,t=this._getSortedHighlights(),n=t[(_.firstIndex(t,function(t){return t.containsPosition(e.editor.getPosition())})-1+t.length)%t.length];try{this._ignorePositionChangeEvent=!0,this.editor.setPosition(n.getStartPosition()),this.editor.revealRangeInCenterIfOutsideViewport(n)}finally{this._ignorePositionChangeEvent=!1}},e.prototype._removeDecorations=function(){this._decorationIds.length>0&&(this._decorationIds=this.editor.deltaDecorations(this._decorationIds,[]),this._hasWordHighlights.set(!1))},e.prototype._stopAll=function(){this._lastWordRange=null,this._removeDecorations(),-1!==this.renderDecorationsTimer&&(clearTimeout(this.renderDecorationsTimer),this.renderDecorationsTimer=-1), +null!==this.workerRequest&&(this.workerRequest.cancel(),this.workerRequest=null),this.workerRequestCompleted||(this.workerRequestTokenId++,this.workerRequestCompleted=!0)},e.prototype._onPositionChanged=function(e){this.occurrencesHighlight&&e.reason===f.CursorChangeReason.Explicit?this._run():this._stopAll()},e.prototype._run=function(){var e=this;if(d.DocumentHighlightProviderRegistry.has(this.model)){var t=this.editor.getSelection();if(t.startLineNumber===t.endLineNumber){var n=t.startLineNumber,o=t.startColumn,a=t.endColumn,l=this.model.getWordAtPosition({lineNumber:n,column:o});if(!l||l.startColumn>o||l.endColumn=a&&(c=!0)}if(this.lastCursorPositionChangeTime=(new Date).getTime(), +c)this.workerRequestCompleted&&-1!==this.renderDecorationsTimer&&(clearTimeout(this.renderDecorationsTimer),this.renderDecorationsTimer=-1,this._beginRenderDecorations());else{this._stopAll();var g=++this.workerRequestTokenId;this.workerRequestCompleted=!1,this.workerRequest=i.createCancelablePromise(function(t){return b(e.model,e.editor.getPosition(),t)}),this.workerRequest.then(function(t){g===e.workerRequestTokenId&&(e.workerRequestCompleted=!0,e.workerRequestValue=t||[],e._beginRenderDecorations())},r.onUnexpectedError)}this._lastWordRange=u}}else this._stopAll()}else this._stopAll()},e.prototype._beginRenderDecorations=function(){var e=this,t=(new Date).getTime(),n=this.lastCursorPositionChangeTime+250;t>=n?(this.renderDecorationsTimer=-1,this.renderDecorations()):this.renderDecorationsTimer=setTimeout(function(){e.renderDecorations()},n-t)},e.prototype.renderDecorations=function(){this.renderDecorationsTimer=-1;for(var t=[],n=0,i=this.workerRequestValue.length;n0?r.format(T,e.length):null:N}(t,i);switch(e.wrappingInfo.inDiffEditor?e.readOnly?s+=n.localize(7,null):s+=n.localize(8,null):e.readOnly?s+=n.localize(9,null):s+=n.localize(10,null),e.accessibilitySupport){case 0:var a=C.isMacintosh?n.localize(11,null):n.localize(12,null);s+="\n\n - "+a;break;case 2:s+="\n\n - "+n.localize(13,null);break;case 1:s+="\n\n - "+n.localize(14,null),s+=" "+a}var u=n.localize(15,null),d=n.localize(16,null),c=n.localize(17,null),h=n.localize(18,null);e.tabFocusMode?s+="\n\n - "+this._descriptionForCommand(v.ToggleTabFocusModeAction.ID,u,d):s+="\n\n - "+this._descriptionForCommand(v.ToggleTabFocusModeAction.ID,c,h);s+="\n\n - "+(C.isMacintosh?n.localize(19,null):n.localize(20,null)), +s+="\n\n"+n.localize(21,null),this._contentDomNode.domNode.appendChild(l.renderFormattedText(s)),this._contentDomNode.domNode.setAttribute("aria-label",s)},t.prototype.hide=function(){this._isVisible&&(this._isVisible=!1,this._isVisibleKey.reset(),this._domNode.setDisplay("none"),this._domNode.setAttribute("aria-hidden","true"),this._contentDomNode.domNode.tabIndex=-1,s.clearNode(this._contentDomNode.domNode),this._editor.focus())},t.prototype._layout=function(){var e=this._editor.getLayoutInfo(),n=Math.max(5,Math.min(t.WIDTH,e.width-40)),i=Math.max(5,Math.min(t.HEIGHT,e.height-40));this._domNode.setWidth(n),this._domNode.setHeight(i);var o=Math.round((e.height-i)/2);this._domNode.setTop(o);var r=Math.round((e.width-n)/2);this._domNode.setLeft(r)},t.ID="editor.contrib.accessibilityHelpWidget",t.WIDTH=500,t.HEIGHT=300,t=a([u(1,f.IContextKeyService),u(2,p.IKeybindingService),u(3,S.IOpenerService)],t)}(c.Widget),R=function(e){function t(){return e.call(this,{id:"editor.action.showAccessibilityHelp", +label:n.localize(22,null),alias:"Show Accessibility Help",precondition:null,kbOpts:{kbExpr:g.EditorContextKeys.focus,primary:E.isIE?2107:571,weight:100}})||this}return o(t,e),t.prototype.run=function(e,t){var n=x.get(t);n&&n.show()},t}(m.EditorAction);m.registerEditorContribution(x),m.registerEditorAction(R);var O=m.EditorCommand.bindToContribution(x.get);m.registerEditorCommand(new O({id:"closeAccessibilityHelp",precondition:L,handler:function(e){return e.hide()},kbOpts:{weight:200,kbExpr:g.EditorContextKeys.focus,primary:9,secondary:[1033]}})),_.registerThemingParticipant(function(e,t){var n=e.getColor(y.editorWidgetBackground);n&&t.addRule(".monaco-editor .accessibilityHelpWidget { background-color: "+n+"; }");var i=e.getColor(y.widgetShadow);i&&t.addRule(".monaco-editor .accessibilityHelpWidget { box-shadow: 0 2px 8px "+i+"; }");var o=e.getColor(y.contrastBorder);o&&t.addRule(".monaco-editor .accessibilityHelpWidget { border: 2px solid "+o+"; }")})}), +define(t[535],n([1,0,345,2,6,11,23,64,17,84,60,27,16,22,406]),function(e,t,n,i,r,s,l,d,c,h,p,f,g,m){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var v=function(e){function t(t,n,i){var o=e.call(this)||this;return o._editor=t,o._standaloneThemeService=n,o._modeService=i,o._widget=null,o._register(o._editor.onDidChangeModel(function(e){return o.stop()})),o._register(o._editor.onDidChangeModelLanguage(function(e){return o.stop()})),o._register(c.TokenizationRegistry.onDidChange(function(e){return o.stop()})),o}return o(t,e),t.get=function(e){return e.getContribution(t.ID)},t.prototype.getId=function(){return t.ID},t.prototype.dispose=function(){this.stop(),e.prototype.dispose.call(this)},t.prototype.launch=function(){this._widget||this._editor.getModel()&&(this._widget=new y(this._editor,this._standaloneThemeService,this._modeService))},t.prototype.stop=function(){this._widget&&(this._widget.dispose(),this._widget=null)},t.ID="editor.contrib.inspectTokens", +t=a([u(1,h.IStandaloneThemeService),u(2,d.IModeService)],t)}(i.Disposable),_=function(e){function t(){return e.call(this,{id:"editor.action.inspectTokens",label:n.localize(0,null),alias:"Developer: Inspect Tokens",precondition:null})||this}return o(t,e),t.prototype.run=function(e,t){var n=v.get(t);n&&n.launch()},t}(s.EditorAction),y=function(e){function t(t,n,i){var o=e.call(this)||this;return o.allowEditorOverflow=!0,o._editor=t,o._modeService=i,o._model=o._editor.getModel(),o._domNode=document.createElement("div"),o._domNode.className="tokens-inspect-widget",o._tokenizationSupport=function(e){var t=c.TokenizationRegistry.get(e.language);return t||{getInitialState:function(){return p.NULL_STATE},tokenize:function(t,n,i){return p.nullTokenize(e.language,t,n,i)},tokenize2:function(t,n,i){return p.nullTokenize2(e.id,t,n,i)}}}(o._model.getLanguageIdentifier()),o._compute(o._editor.getPosition()),o._register(o._editor.onDidChangeCursorPosition(function(e){return o._compute(o._editor.getPosition())})), +o._editor.addContentWidget(o),o}return o(t,e),t.prototype.dispose=function(){this._editor.removeContentWidget(this),e.prototype.dispose.call(this)},t.prototype.getId=function(){return t._ID},t.prototype._compute=function(e){for(var t=this._getTokensAtLine(e.lineNumber),n=0,i=t.tokens1.length-1;i>=0;i--){var o=t.tokens1[i];if(e.column-1>=o.offset){n=i;break}}for(var s=0,i=t.tokens2.length>>>1;i>=0;i--)if(e.column-1>=t.tokens2[i<<1]){s=i;break}var a="",l=this._model.getLineContent(e.lineNumber),u="";if(n'+function(e){for(var t="",n=0,i=e.length;n('+u.length+" "+(1===u.length?"char":"chars")+")", +a+='
                                      ';var h=this._decodeMetadata(t.tokens2[1+(s<<1)]);a+='',a+='",a+='",a+='",a+='",a+='",a+="",a+='
                                      ',n'+r.escape(t.tokens1[n].type)+""),this._domNode.innerHTML=a, +this._editor.layoutContentWidget(this)},t.prototype._decodeMetadata=function(e){var t=c.TokenizationRegistry.getColorMap(),n=c.TokenMetadata.getLanguageId(e),i=c.TokenMetadata.getTokenType(e),o=c.TokenMetadata.getFontStyle(e),r=c.TokenMetadata.getForeground(e),s=c.TokenMetadata.getBackground(e);return{languageIdentifier:this._modeService.getLanguageIdentifier(n),tokenType:i,fontStyle:o,foreground:t[r],background:t[s]}},t.prototype._tokenTypeToString=function(e){switch(e){case 0:return"Other";case 1:return"Comment";case 2:return"String";case 4:return"RegEx"}return"??"},t.prototype._fontStyleToString=function(e){var t="";return 1&e&&(t+="italic "),2&e&&(t+="bold "),4&e&&(t+="underline "),0===t.length&&(t="---"),t},t.prototype._getTokensAtLine=function(e){var t=this._getStateBeforeLine(e),n=this._tokenizationSupport.tokenize(this._model.getLineContent(e),t,0),i=this._tokenizationSupport.tokenize2(this._model.getLineContent(e),t,0);return{startState:t,tokens1:n.tokens,tokens2:i.tokens,endState:n.endState}}, +t.prototype._getStateBeforeLine=function(e){for(var t=this._tokenizationSupport.getInitialState(),n=1;n1?n.localize(0,null,t.lineNumber,t.column):n.localize(1,null,t.lineNumber,t.column):t.lineNumber<1||t.lineNumber>o.getLineCount()?n.localize(2,null,o.getLineCount()):n.localize(3,null,o.getLineMaxColumn(t.lineNumber)),{position:t,isValid:s,label:r}}, +t.prototype.getLabel=function(){return this._parseResult.label},t.prototype.getAriaLabel=function(){return n.localize(4,null,this._parseResult.label)},t.prototype.run=function(e,t){return e===r.Mode.OPEN?this.runOpen():this.runPreview()},t.prototype.runOpen=function(){if(!this._parseResult.isValid)return!1;var e=this.toSelection();return this.editor.setSelection(e),this.editor.revealRangeInCenter(e,0),this.editor.focus(),!0},t.prototype.runPreview=function(){if(!this._parseResult.isValid)return this.decorator.clearDecorations(),!1;var e=this.toSelection();return this.editor.revealRangeInCenter(e,0),this.decorator.decorateLine(e,this.editor),!1},t.prototype.toSelection=function(){return new c.Range(this._parseResult.position.lineNumber,this._parseResult.position.column,this._parseResult.position.lineNumber,this._parseResult.position.column)},t}(i.QuickOpenEntry);t.GotoLineEntry=h;var p=function(e){function t(){return e.call(this,n.localize(5,null),{id:"editor.action.gotoLine",label:n.localize(6,null), +alias:"Go to Line...",precondition:null,kbOpts:{kbExpr:s.EditorContextKeys.focus,primary:2085,mac:{primary:293},weight:100}})||this}return o(t,e),t.prototype.run=function(e,t){var n=this;this._show(this.getController(t),{getModel:function(e){return new i.QuickOpenModel([new h(e,t,n.getController(t))])},getAutoFocus:function(e){return{autoFocusFirstEntry:e.length>0}}})},t}(l.BaseEditorQuickOpenAction);t.GotoLineAction=p,u.registerEditorAction(p)}),define(t[538],n([1,0,347,10,102,13,119,93,49,20,145,11,30]),function(e,t,n,i,r,s,a,l,u,d,c,h,p){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var f=function(e){function t(t,n,i,o){var r=e.call(this)||this;return r.key=t,r.setHighlights(n),r.action=i,r.editor=o,r}return o(t,e),t.prototype.getLabel=function(){return this.action.label},t.prototype.getAriaLabel=function(){return n.localize(0,null,this.getLabel())},t.prototype.getGroupLabel=function(){return this.key},t.prototype.run=function(e,t){var n=this +;return e===l.Mode.OPEN&&(s.TPromise.timeout(50).done(function(){n.editor.focus();try{(n.action.run()||s.TPromise.as(null)).done(null,i.onUnexpectedError)}catch(e){i.onUnexpectedError(e)}},i.onUnexpectedError),!0)},t}(a.QuickOpenEntryGroup);t.EditorActionCommandEntry=f;var g=function(e){function t(){return e.call(this,n.localize(1,null),{id:"editor.action.quickCommand",label:n.localize(2,null),alias:"Command Palette",precondition:null,kbOpts:{kbExpr:d.EditorContextKeys.focus,primary:p.isIE?571:59,weight:100},menuOpts:{group:"z_commands",order:1}})||this}return o(t,e),t.prototype.run=function(e,t){var n=this,i=e.get(u.IKeybindingService);this._show(this.getController(t),{getModel:function(e){return new a.QuickOpenModel(n._editorActionsToEntries(i,t,e))},getAutoFocus:function(e){return{autoFocusFirstEntry:!0,autoFocusPrefixMatch:e}}})},t.prototype._sort=function(e,t){var n=e.getLabel().toLowerCase(),i=t.getLabel().toLowerCase();return n.localeCompare(i)},t.prototype._editorActionsToEntries=function(e,t,n){ +for(var i=t.getSupportedActions(),o=[],s=0;s0&&0===o.indexOf(":")){ +for(var f=null,g=null,m=0,v=0;v0)):m++}g&&g.setGroupLabel(this.typeToLabel(f,m))}else a.length>0&&a[0].setGroupLabel(n.localize(3,null,a.length));return a},t.prototype.typeToLabel=function(e,t){switch(e){case"module":return n.localize(4,null,t);case"class":return n.localize(5,null,t);case"interface":return n.localize(6,null,t);case"method":return n.localize(7,null,t);case"function":return n.localize(8,null,t);case"property":return n.localize(9,null,t);case"variable":return n.localize(10,null,t);case"var":return n.localize(11,null,t);case"constructor":return n.localize(12,null,t);case"call":return n.localize(13,null,t)}return e},t.prototype.sortNormal=function(e,t,n){var i=t.getLabel().toLowerCase(),o=n.getLabel().toLowerCase(),r=i.localeCompare(o);if(0!==r)return r;var s=t.getRange(),a=n.getRange();return s.startLineNumber-a.startLineNumber},t.prototype.sortScoped=function(e,t,n){ +e=e.substr(":".length);var i=t.getType(),o=n.getType(),r=i.localeCompare(o);if(0!==r)return r;if(e){var s=t.getLabel().toLowerCase(),a=n.getLabel().toLowerCase(),l=s.localeCompare(a);if(0!==l)return l}var u=t.getRange(),d=n.getRange();return u.startLineNumber-d.startLineNumber},t}(d.BaseEditorQuickOpenAction);t.QuickOutlineAction=g,h.registerEditorAction(g)}),define(t[540],n([1,0,13,484,7,61]),function(e,t,n,i,r,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype.getActiveCodeEditor=function(){return null},t.prototype.openCodeEditor=function(e,t,i){return t?n.TPromise.as(this.doOpenEditor(t,e)):n.TPromise.as(null)},t.prototype.doOpenEditor=function(e,t){if(!this.findModel(e,t.resource)){if(t.resource){var n=t.resource.scheme;if(n===s.Schemas.http||n===s.Schemas.https)return r.windowOpenNoOpener(t.resource.toString()),e}return null}var i=t.options.selection +;if(i)if("number"==typeof i.endLineNumber&&"number"==typeof i.endColumn)e.setSelection(i),e.revealRangeInCenter(i,1);else{var o={lineNumber:i.startLineNumber,column:i.startColumn};e.setPosition(o),e.revealPositionInCenter(o,1)}return e},t.prototype.findModel=function(e,t){var n=e.getModel();return n.uri.toString()!==t.toString()?null:n},t}(i.CodeEditorServiceImpl);t.StandaloneCodeEditorServiceImpl=a}),define(t[541],n([1,0,22,35]),function(e,t,n,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o,r,s;t.vs={base:"vs",inherit:!1,rules:[{token:"",foreground:"000000",background:"fffffe"},{token:"invalid",foreground:"cd3131"},{token:"emphasis",fontStyle:"italic"},{token:"strong",fontStyle:"bold"},{token:"variable",foreground:"001188"},{token:"variable.predefined",foreground:"4864AA"},{token:"constant",foreground:"dd0000"},{token:"comment",foreground:"008000"},{token:"number",foreground:"09885A"},{token:"number.hex",foreground:"3030c0"},{token:"regexp",foreground:"800000"},{token:"annotation", +foreground:"808080"},{token:"type",foreground:"008080"},{token:"delimiter",foreground:"000000"},{token:"delimiter.html",foreground:"383838"},{token:"delimiter.xml",foreground:"0000FF"},{token:"tag",foreground:"800000"},{token:"tag.id.pug",foreground:"4F76AC"},{token:"tag.class.pug",foreground:"4F76AC"},{token:"meta.scss",foreground:"800000"},{token:"metatag",foreground:"e00000"},{token:"metatag.content.html",foreground:"FF0000"},{token:"metatag.html",foreground:"808080"},{token:"metatag.xml",foreground:"808080"},{token:"metatag.php",fontStyle:"bold"},{token:"key",foreground:"863B00"},{token:"string.key.json",foreground:"A31515"},{token:"string.value.json",foreground:"0451A5"},{token:"attribute.name",foreground:"FF0000"},{token:"attribute.value",foreground:"0451A5"},{token:"attribute.value.number",foreground:"09885A"},{token:"attribute.value.unit",foreground:"09885A"},{token:"attribute.value.html",foreground:"0000FF"},{token:"attribute.value.xml",foreground:"0000FF"},{token:"string",foreground:"A31515"},{ +token:"string.html",foreground:"0000FF"},{token:"string.sql",foreground:"FF0000"},{token:"string.yaml",foreground:"0451A5"},{token:"keyword",foreground:"0000FF"},{token:"keyword.json",foreground:"0451A5"},{token:"keyword.flow",foreground:"AF00DB"},{token:"keyword.flow.scss",foreground:"0000FF"},{token:"operator.scss",foreground:"666666"},{token:"operator.sql",foreground:"778899"},{token:"operator.swift",foreground:"666666"},{token:"predefined.sql",foreground:"FF00FF"}],colors:(o={},o[n.editorBackground]="#FFFFFE",o[n.editorForeground]="#000000",o[n.editorInactiveSelection]="#E5EBF1",o[i.editorIndentGuides]="#D3D3D3",o[i.editorActiveIndentGuides]="#939393",o[n.editorSelectionHighlight]="#ADD6FF4D",o)},t.vs_dark={base:"vs-dark",inherit:!1,rules:[{token:"",foreground:"D4D4D4",background:"1E1E1E"},{token:"invalid",foreground:"f44747"},{token:"emphasis",fontStyle:"italic"},{token:"strong",fontStyle:"bold"},{token:"variable",foreground:"74B0DF"},{token:"variable.predefined",foreground:"4864AA"},{ +token:"variable.parameter",foreground:"9CDCFE"},{token:"constant",foreground:"569CD6"},{token:"comment",foreground:"608B4E"},{token:"number",foreground:"B5CEA8"},{token:"number.hex",foreground:"5BB498"},{token:"regexp",foreground:"B46695"},{token:"annotation",foreground:"cc6666"},{token:"type",foreground:"3DC9B0"},{token:"delimiter",foreground:"DCDCDC"},{token:"delimiter.html",foreground:"808080"},{token:"delimiter.xml",foreground:"808080"},{token:"tag",foreground:"569CD6"},{token:"tag.id.pug",foreground:"4F76AC"},{token:"tag.class.pug",foreground:"4F76AC"},{token:"meta.scss",foreground:"A79873"},{token:"meta.tag",foreground:"CE9178"},{token:"metatag",foreground:"DD6A6F"},{token:"metatag.content.html",foreground:"9CDCFE"},{token:"metatag.html",foreground:"569CD6"},{token:"metatag.xml",foreground:"569CD6"},{token:"metatag.php",fontStyle:"bold"},{token:"key",foreground:"9CDCFE"},{token:"string.key.json",foreground:"9CDCFE"},{token:"string.value.json",foreground:"CE9178"},{token:"attribute.name", +foreground:"9CDCFE"},{token:"attribute.value",foreground:"CE9178"},{token:"attribute.value.number.css",foreground:"B5CEA8"},{token:"attribute.value.unit.css",foreground:"B5CEA8"},{token:"attribute.value.hex.css",foreground:"D4D4D4"},{token:"string",foreground:"CE9178"},{token:"string.sql",foreground:"FF0000"},{token:"keyword",foreground:"569CD6"},{token:"keyword.flow",foreground:"C586C0"},{token:"keyword.json",foreground:"CE9178"},{token:"keyword.flow.scss",foreground:"569CD6"},{token:"operator.scss",foreground:"909090"},{token:"operator.sql",foreground:"778899"},{token:"operator.swift",foreground:"909090"},{token:"predefined.sql",foreground:"FF00FF"}],colors:(r={},r[n.editorBackground]="#1E1E1E",r[n.editorForeground]="#D4D4D4",r[n.editorInactiveSelection]="#3A3D41",r[i.editorIndentGuides]="#404040",r[i.editorActiveIndentGuides]="#707070",r[n.editorSelectionHighlight]="#ADD6FF26",r)},t.hc_black={base:"hc-black",inherit:!1,rules:[{token:"",foreground:"FFFFFF",background:"000000"},{token:"invalid", +foreground:"f44747"},{token:"emphasis",fontStyle:"italic"},{token:"strong",fontStyle:"bold"},{token:"variable",foreground:"1AEBFF"},{token:"variable.parameter",foreground:"9CDCFE"},{token:"constant",foreground:"569CD6"},{token:"comment",foreground:"608B4E"},{token:"number",foreground:"FFFFFF"},{token:"regexp",foreground:"C0C0C0"},{token:"annotation",foreground:"569CD6"},{token:"type",foreground:"3DC9B0"},{token:"delimiter",foreground:"FFFF00"},{token:"delimiter.html",foreground:"FFFF00"},{token:"tag",foreground:"569CD6"},{token:"tag.id.pug",foreground:"4F76AC"},{token:"tag.class.pug",foreground:"4F76AC"},{token:"meta",foreground:"D4D4D4"},{token:"meta.tag",foreground:"CE9178"},{token:"metatag",foreground:"569CD6"},{token:"metatag.content.html",foreground:"1AEBFF"},{token:"metatag.html",foreground:"569CD6"},{token:"metatag.xml",foreground:"569CD6"},{token:"metatag.php",fontStyle:"bold"},{token:"key",foreground:"9CDCFE"},{token:"string.key",foreground:"9CDCFE"},{token:"string.value",foreground:"CE9178"},{ +token:"attribute.name",foreground:"569CD6"},{token:"attribute.value",foreground:"3FF23F"},{token:"string",foreground:"CE9178"},{token:"string.sql",foreground:"FF0000"},{token:"keyword",foreground:"569CD6"},{token:"keyword.flow",foreground:"C586C0"},{token:"operator.sql",foreground:"778899"},{token:"operator.swift",foreground:"909090"},{token:"predefined.sql",foreground:"FF00FF"}],colors:(s={},s[n.editorBackground]="#000000",s[n.editorForeground]="#FFFFFF",s[i.editorIndentGuides]="#FFFFFF",s[i.editorActiveIndentGuides]="#FFFFFF",s)}}),define(t[542],n([1,0,204,541,7,17,27,22,16,45,9]),function(e,t,n,i,o,r,s,a,l,u,d){"use strict";function c(e){return e===f||e===g||e===m}function h(e){switch(e){case f:return i.vs;case g:return i.vs_dark;case m:return i.hc_black}}function p(e){var t=h(e);return new y(e,t)}Object.defineProperty(t,"__esModule",{value:!0});var f="vs",g="vs-dark",m="hc-black",v=u.Registry.as(a.Extensions.ColorContribution),_=u.Registry.as(l.Extensions.ThemingContribution),y=function(){function e(e,t){ +this.themeData=t;var n=t.base;e.length>0?(this.id=n+" "+e,this.themeName=e):(this.id=n,this.themeName=n),this.colors=null,this.defaultColors=Object.create(null),this._tokenTheme=null}return Object.defineProperty(e.prototype,"base",{get:function(){return this.themeData.base},enumerable:!0,configurable:!0}),e.prototype.notifyBaseUpdated=function(){this.themeData.inherit&&(this.colors=null,this._tokenTheme=null)},e.prototype.getColors=function(){if(!this.colors){var e=Object.create(null);for(var t in this.themeData.colors)e[t]=s.Color.fromHex(this.themeData.colors[t]);if(this.themeData.inherit){var n=h(this.themeData.base);for(var t in n.colors)e[t]||(e[t]=s.Color.fromHex(n.colors[t]))}this.colors=e}return this.colors},e.prototype.getColor=function(e,t){var n=this.getColors()[e];return n||(!1!==t?this.getDefault(e):null)},e.prototype.getDefault=function(e){var t=this.defaultColors[e];return t||(t=v.resolveDefaultColor(e,this),this.defaultColors[e]=t,t)},e.prototype.defines=function(e){ +return Object.prototype.hasOwnProperty.call(this.getColors(),e)},Object.defineProperty(e.prototype,"type",{get:function(){switch(this.base){case f:return"light";case m:return"hc";default:return"dark"}},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"tokenTheme",{get:function(){if(!this._tokenTheme){var e=[],t=[];if(this.themeData.inherit){var i=h(this.themeData.base);e=i.rules,i.encodedTokensColors&&(t=i.encodedTokensColors)}e=e.concat(this.themeData.rules),this.themeData.encodedTokensColors&&(t=this.themeData.encodedTokensColors),this._tokenTheme=n.TokenTheme.createFromRawTokenTheme(e,t)}return this._tokenTheme},enumerable:!0,configurable:!0}),e}(),C=function(){function e(){this.environment=Object.create(null),this._onThemeChange=new d.Emitter,this._knownThemes=new Map,this._knownThemes.set(f,p(f)),this._knownThemes.set(g,p(g)),this._knownThemes.set(m,p(m)),this._styleElement=o.createStyleSheet(),this._styleElement.className="monaco-colors",this.setTheme(f)} +return Object.defineProperty(e.prototype,"onThemeChange",{get:function(){return this._onThemeChange.event},enumerable:!0,configurable:!0}),e.prototype.defineTheme=function(e,t){if(!/^[a-z0-9\-]+$/i.test(e))throw new Error("Illegal theme name!");if(!c(t.base)&&!c(e))throw new Error("Illegal theme base!");this._knownThemes.set(e,new y(e,t)),c(e)&&this._knownThemes.forEach(function(t){t.base===e&&t.notifyBaseUpdated()}),this._theme&&this._theme.themeName===e&&this.setTheme(e)},e.prototype.getTheme=function(){return this._theme},e.prototype.setTheme=function(e){var t,i=this;t=this._knownThemes.has(e)?this._knownThemes.get(e):this._knownThemes.get(f),this._theme=t;var o=[],s={},a={addRule:function(e){s[e]||(o.push(e),s[e]=!0)}};_.getThemingParticipants().forEach(function(e){return e(t,a,i.environment)});var l=t.tokenTheme.getColorMap();return a.addRule(n.generateTokensCSSForColorMap(l)),this._styleElement.innerHTML=o.join("\n"),r.TokenizationRegistry.setColorMap(l),this._onThemeChange.fire(t),t.id},e}() +;t.StandaloneThemeServiceImpl=C}),define(t[146],n([1,0,15,2,19,155,103,16,51,354,45,82,81,33,7,43]),function(e,t,n,i,r,s,d,c,h,p,f,g,m,v,_,y){"use strict";function C(e){return"alt"===e.getValue(t.multiSelectModifierSettingKey)}function b(e){return"doubleClick"!==e.getValue(t.openModeSettingKey)}function S(e,t){return e.controller||(e.controller=t.createInstance(I,{})),e.styler||(e.styler=new m.DefaultTreestyler((x||(x=_.createStyleSheet()),x))),e}Object.defineProperty(t,"__esModule",{value:!0});var w;t.IListService=n.createDecorator("listService");var E=function(){function e(e){this.lists=[],this._lastFocusedWidget=void 0}return Object.defineProperty(e.prototype,"lastFocusedList",{get:function(){return this._lastFocusedWidget},enumerable:!0,configurable:!0}),e.prototype.register=function(e,t){var n=this;if(this.lists.some(function(t){return t.widget===e}))throw new Error("Cannot register the same widget multiple times");var o={widget:e,extraContextKeys:t};this.lists.push(o), +e.isDOMFocused()&&(this._lastFocusedWidget=e);return i.combinedDisposable([e.onDidFocus(function(){return n._lastFocusedWidget=e}),i.toDisposable(function(){return n.lists.splice(n.lists.indexOf(o),1)}),e.onDidDispose(function(){n.lists=n.lists.filter(function(e){return e!==o}),n._lastFocusedWidget===e&&(n._lastFocusedWidget=void 0)})])},e=a([u(0,r.IContextKeyService)],e)}();t.ListService=E;var L=new r.RawContextKey("listFocus",!0);t.WorkbenchListSupportsMultiSelectContextKey=new r.RawContextKey("listSupportsMultiselect",!0),t.WorkbenchListHasSelectionOrFocus=new r.RawContextKey("listHasSelectionOrFocus",!1),t.WorkbenchListDoubleSelection=new r.RawContextKey("listDoubleSelection",!1),t.WorkbenchListMultiSelection=new r.RawContextKey("listMultiSelection",!1),t.multiSelectModifierSettingKey="workbench.list.multiSelectModifier",t.openModeSettingKey="workbench.list.openMode",t.horizontalScrollingKey="workbench.tree.horizontalScrolling";var x,N=function(e){function s(n,i,o,r,s,a,u,c){ +var h=this,p=S(i,u),f=c.getValue(t.horizontalScrollingKey)?y.ScrollbarVisibility.Auto:y.ScrollbarVisibility.Hidden,g=l({horizontalScrollMode:f,keyboardSupport:!1},d.computeStyles(a.getTheme(),d.defaultListStyles),o);return h=e.call(this,n,p,g)||this,h.disposables=[],h.contextKeyService=function(e,t){var n=e.createScoped(t.getHTMLElement());return L.bindTo(n),n}(r,h),t.WorkbenchListSupportsMultiSelectContextKey.bindTo(h.contextKeyService),h.listHasSelectionOrFocus=t.WorkbenchListHasSelectionOrFocus.bindTo(h.contextKeyService),h.listDoubleSelection=t.WorkbenchListDoubleSelection.bindTo(h.contextKeyService),h.listMultiSelection=t.WorkbenchListMultiSelection.bindTo(h.contextKeyService),h._openOnSingleClick=b(c),h._useAltAsMultipleSelectionModifier=C(c),h.disposables.push(h.contextKeyService,s.register(h),d.attachListStyler(h,a)),h.disposables.push(h.onDidChangeSelection(function(){var e=h.getSelection(),t=h.getFocus();h.listHasSelectionOrFocus.set(e&&e.length>0||!!t),h.listDoubleSelection.set(e&&2===e.length), +h.listMultiSelection.set(e&&e.length>1)})),h.disposables.push(h.onDidChangeFocus(function(){var e=h.getSelection(),t=h.getFocus();h.listHasSelectionOrFocus.set(e&&e.length>0||!!t)})),h.disposables.push(c.onDidChangeConfiguration(function(e){e.affectsConfiguration(t.openModeSettingKey)&&(h._openOnSingleClick=b(c)),e.affectsConfiguration(t.multiSelectModifierSettingKey)&&(h._useAltAsMultipleSelectionModifier=C(c))})),h}return o(s,e),s.prototype.dispose=function(){e.prototype.dispose.call(this),this.disposables=i.dispose(this.disposables)},s=a([u(3,r.IContextKeyService),u(4,t.IListService),u(5,c.IThemeService),u(6,n.IInstantiationService),u(7,h.IConfigurationService)],s)}(s.Tree);t.WorkbenchTree=N;var I=function(e){function n(t,n){var i=e.call(this,function(e){return"boolean"!=typeof e.keyboardSupport&&(e.keyboardSupport=!1),"number"!=typeof e.clickBehavior&&(e.clickBehavior=m.ClickBehavior.ON_MOUSE_DOWN),e}(t))||this;return i.configurationService=n,i.disposables=[], +v.isUndefinedOrNull(t.openMode)&&(i.setOpenMode(i.getOpenModeSetting()),i.registerListeners()),i}return o(n,e),n.prototype.registerListeners=function(){var e=this;this.disposables.push(this.configurationService.onDidChangeConfiguration(function(n){n.affectsConfiguration(t.openModeSettingKey)&&e.setOpenMode(e.getOpenModeSetting())}))},n.prototype.getOpenModeSetting=function(){return b(this.configurationService)?m.OpenMode.SINGLE_CLICK:m.OpenMode.DOUBLE_CLICK},n.prototype.dispose=function(){this.disposables=i.dispose(this.disposables)},n=a([u(1,h.IConfigurationService)],n)}(m.DefaultController);t.WorkbenchTreeController=I;f.Registry.as(g.Extensions.Configuration).registerConfiguration({id:"workbench",order:7,title:p.localize(0,null),type:"object",properties:(w={},w[t.multiSelectModifierSettingKey]={type:"string",enum:["ctrlCmd","alt"],enumDescriptions:[p.localize(1,null),p.localize(2,null)],default:"ctrlCmd",description:p.localize(3,null)},w[t.openModeSettingKey]={type:"string", +enum:["singleClick","doubleClick"],default:"singleClick",description:p.localize(4,null)},w[t.horizontalScrollingKey]={type:"boolean",default:!1,description:p.localize(5,null)},w)})}),define(t[195],n([1,0,15]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});t.IUriDisplayService=n.createDecorator("uriDisplay")}),define(t[545],n([1,0,19]),function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.bindContextScopedWidget=function(e,t,i){new n.RawContextKey(i,t).bindTo(e)},t.createWidgetScopedContextKeyService=function(e,t){return e.createScoped(t.target)},t.getContextScopedWidget=function(e,t){return e.getContext(document.activeElement).getValue(t)}}),define(t[546],n([1,0,19,115,276,545,97]),function(e,t,n,i,r,s,l){"use strict";function d(e,i){var o=s.createWidgetScopedContextKeyService(e,i);s.bindContextScopedWidget(o,i,t.HistoryNavigationWidgetContext);return{scopedContextKeyService:o, +historyNavigationEnablement:new n.RawContextKey(t.HistoryNavigationEnablementContext,!0).bindTo(o)}}Object.defineProperty(t,"__esModule",{value:!0}),t.HistoryNavigationWidgetContext="historyNavigationWidget",t.HistoryNavigationEnablementContext="historyNavigationEnabled",t.createAndBindHistoryNavigationWidgetScopedContextKeyService=d;var c=function(e){function t(t,n,i,o){var r=e.call(this,t,n,i)||this;return r._register(d(o,{target:r.element,historyNavigator:r}).scopedContextKeyService),r}return o(t,e),t=a([u(3,n.IContextKeyService)],t)}(i.HistoryInputBox);t.ContextScopedHistoryInputBox=c;var h=function(e){function t(t,n,i,o){var r=e.call(this,t,n,i)||this;return r._register(d(o,{target:r.inputBox.element,historyNavigator:r.inputBox}).scopedContextKeyService),r}return o(t,e),t=a([u(3,n.IContextKeyService)],t)}(r.FindInput);t.ContextScopedFindInput=h,l.KeybindingsRegistry.registerCommandAndKeybindingRule({id:"history.showPrevious",weight:200, +when:n.ContextKeyExpr.and(new n.ContextKeyDefinedExpr(t.HistoryNavigationWidgetContext),new n.ContextKeyEqualsExpr(t.HistoryNavigationEnablementContext,!0)),primary:16,secondary:[528],handler:function(e,i){s.getContextScopedWidget(e.get(n.IContextKeyService),t.HistoryNavigationWidgetContext).historyNavigator.showPreviousValue()}}),l.KeybindingsRegistry.registerCommandAndKeybindingRule({id:"history.showNext",weight:200,when:new n.ContextKeyAndExpr([new n.ContextKeyDefinedExpr(t.HistoryNavigationWidgetContext),new n.ContextKeyEqualsExpr(t.HistoryNavigationEnablementContext,!0)]),primary:18,secondary:[530],handler:function(e,i){s.getContextScopedWidget(e.get(n.IContextKeyService),t.HistoryNavigationWidgetContext).historyNavigator.showNextValue()}})}),define(t[547],n([1,0,312,10,18,6,14,7,46,90,23,142,3,16,22,546,373]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m){"use strict";Object.defineProperty(t,"__esModule",{value:!0}) +;var v=n.localize(0,null),_=n.localize(1,null),y=n.localize(2,null),C=n.localize(3,null),b=n.localize(4,null),S=n.localize(5,null),w=n.localize(6,null),E=n.localize(7,null),L=n.localize(8,null),x=n.localize(9,null),N=n.localize(10,null),I=n.localize(11,null,h.MATCHES_LIMIT),M=n.localize(12,null),D=n.localize(13,null),T=69,k=17+(T+3+1)+92+2,R=34,O=function(){return function(e){this.afterLineNumber=e,this.heightInPx=R,this.suppressMouseDown=!1,this.domNode=document.createElement("div"),this.domNode.className="dock-find-viewzone"}}();t.FindWidgetViewZone=O;var P=function(e){function t(t,n,i,o,r,s,u){var d=e.call(this)||this;return d._codeEditor=t,d._controller=n,d._state=i,d._contextViewProvider=o,d._keybindingService=r,d._contextKeyService=s,d._isVisible=!1,d._isReplaceVisible=!1,d._updateHistoryDelayer=new a.Delayer(500),d._register(d._state.onFindReplaceStateChange(function(e){return d._onStateChanged(e)})),d._buildDomNode(),d._updateButtons(),d._tryUpdateWidgetWidth(), +d._register(d._codeEditor.onDidChangeConfiguration(function(e){e.readOnly&&(d._codeEditor.getConfiguration().readOnly&&d._state.change({isReplaceRevealed:!1},!1),d._updateButtons()),e.layoutInfo&&d._tryUpdateWidgetWidth()})),d._register(d._codeEditor.onDidChangeCursorSelection(function(){d._isVisible&&d._updateToggleSelectionFindButton()})),d._register(d._codeEditor.onDidFocusEditorWidget(function(){if(d._isVisible){var e=d._controller.getGlobalBufferTerm();e&&e!==d._state.searchString&&(d._state.change({searchString:e},!0),d._findInput.select())}})),d._findInputFocused=h.CONTEXT_FIND_INPUT_FOCUSED.bindTo(s),d._findFocusTracker=d._register(l.trackFocus(d._findInput.inputBox.inputElement)),d._register(d._findFocusTracker.onDidFocus(function(){d._findInputFocused.set(!0),d._updateSearchScope()})),d._register(d._findFocusTracker.onDidBlur(function(){d._findInputFocused.set(!1)})),d._replaceInputFocused=h.CONTEXT_REPLACE_INPUT_FOCUSED.bindTo(s), +d._replaceFocusTracker=d._register(l.trackFocus(d._replaceInputBox.inputElement)),d._register(d._replaceFocusTracker.onDidFocus(function(){d._replaceInputFocused.set(!0),d._updateSearchScope()})),d._register(d._replaceFocusTracker.onDidBlur(function(){d._replaceInputFocused.set(!1)})),d._codeEditor.addOverlayWidget(d),d._viewZone=new O(0),d._applyTheme(u.getTheme()),d._register(u.onThemeChange(d._applyTheme.bind(d))),d._register(d._codeEditor.onDidChangeModel(function(e){d._isVisible&&void 0!==d._viewZoneId&&d._codeEditor.changeViewZones(function(e){e.removeZone(d._viewZoneId),d._viewZoneId=void 0})})),d._register(d._codeEditor.onDidScrollChange(function(e){e.scrollTopChanged?d._layoutViewZone():setTimeout(function(){d._layoutViewZone()},0)})),d}return o(t,e),t.prototype.getId=function(){return t.ID},t.prototype.getDomNode=function(){return this._domNode},t.prototype.getPosition=function(){return this._isVisible?{preference:c.OverlayWidgetPositionPreference.TOP_RIGHT_CORNER}:null}, +t.prototype._onStateChanged=function(e){if(e.searchString&&(this._findInput.setValue(this._state.searchString),this._updateButtons()),e.replaceString&&(this._replaceInputBox.value=this._state.replaceString),e.isRevealed&&(this._state.isRevealed?this._reveal(!0):this._hide(!0)),e.isReplaceRevealed&&(this._state.isReplaceRevealed?this._codeEditor.getConfiguration().readOnly||this._isReplaceVisible||(this._isReplaceVisible=!0,this._replaceInputBox.width=this._findInput.inputBox.width,this._updateButtons()):this._isReplaceVisible&&(this._isReplaceVisible=!1,this._updateButtons())),e.isRegex&&this._findInput.setRegex(this._state.isRegex),e.wholeWord&&this._findInput.setWholeWords(this._state.wholeWord),e.matchCase&&this._findInput.setCaseSensitive(this._state.matchCase),e.searchScope&&(this._state.searchScope?this._toggleSelectionFind.checked=!0:this._toggleSelectionFind.checked=!1,this._updateToggleSelectionFindButton()),e.searchString||e.matchesCount||e.matchesPosition){ +var t=this._state.searchString.length>0&&0===this._state.matchesCount;l.toggleClass(this._domNode,"no-results",t),this._updateMatchesCount()}(e.searchString||e.currentMatch)&&this._layoutViewZone(),e.updateHistory&&this._delayedUpdateHistory()},t.prototype._delayedUpdateHistory=function(){this._updateHistoryDelayer.trigger(this._updateHistory.bind(this))},t.prototype._updateHistory=function(){this._state.searchString&&this._findInput.inputBox.addToHistory(),this._state.replaceString&&this._replaceInputBox.addToHistory()},t.prototype._updateMatchesCount=function(){this._matchesCount.style.minWidth=T+"px",this._state.matchesCount>=h.MATCHES_LIMIT?this._matchesCount.title=I:this._matchesCount.title="",this._matchesCount.firstChild&&this._matchesCount.removeChild(this._matchesCount.firstChild);var e;if(this._state.matchesCount>0){var t=String(this._state.matchesCount);this._state.matchesCount>=h.MATCHES_LIMIT&&(t+="+");var n=String(this._state.matchesPosition);"0"===n&&(n="?"),e=s.format(M,n,t)}else e=D +;this._matchesCount.appendChild(document.createTextNode(e)),T=Math.max(T,this._matchesCount.clientWidth)},t.prototype._updateToggleSelectionFindButton=function(){var e=this._codeEditor.getSelection(),t=!!e&&(e.startLineNumber!==e.endLineNumber||e.startColumn!==e.endColumn),n=this._toggleSelectionFind.checked;this._toggleSelectionFind.setEnabled(this._isVisible&&(n||t))},t.prototype._updateButtons=function(){this._findInput.setEnabled(this._isVisible),this._replaceInputBox.setEnabled(this._isVisible&&this._isReplaceVisible),this._updateToggleSelectionFindButton(),this._closeBtn.setEnabled(this._isVisible);var e=this._state.searchString.length>0;this._prevBtn.setEnabled(this._isVisible&&e),this._nextBtn.setEnabled(this._isVisible&&e),this._replaceBtn.setEnabled(this._isVisible&&this._isReplaceVisible&&e),this._replaceAllBtn.setEnabled(this._isVisible&&this._isReplaceVisible&&e),l.toggleClass(this._domNode,"replaceToggled",this._isReplaceVisible), +this._toggleReplaceBtn.toggleClass("collapse",!this._isReplaceVisible),this._toggleReplaceBtn.toggleClass("expand",this._isReplaceVisible),this._toggleReplaceBtn.setExpanded(this._isReplaceVisible);var t=!this._codeEditor.getConfiguration().readOnly;this._toggleReplaceBtn.setEnabled(this._isVisible&&t)},t.prototype._reveal=function(e){var t=this;if(!this._isVisible){this._isVisible=!0;var n=this._codeEditor.getSelection();!!n&&(n.startLineNumber!==n.endLineNumber||n.startColumn!==n.endColumn)&&this._codeEditor.getConfiguration().contribInfo.find.autoFindInSelection?this._toggleSelectionFind.checked=!0:this._toggleSelectionFind.checked=!1,this._tryUpdateWidgetWidth(),this._updateButtons(),setTimeout(function(){l.addClass(t._domNode,"visible"),t._domNode.setAttribute("aria-hidden","false")},0),this._codeEditor.layoutOverlayWidget(this);var i=!0;if(this._codeEditor.getConfiguration().contribInfo.find.seedSearchStringFromSelection&&n){ +var o=l.getDomNodePagePosition(this._codeEditor.getDomNode()),r=this._codeEditor.getScrolledVisiblePosition(n.getStartPosition()),s=o.left+r.left;if(r.topn.startLineNumber&&(i=!1);var a=l.getTopLeftOffset(this._domNode).left;s>a&&(i=!1);var u=this._codeEditor.getScrolledVisiblePosition(n.getEndPosition());o.left+u.left>a&&(i=!1)}}this._showViewZone(i)}},t.prototype._hide=function(e){var t=this;this._isVisible&&(this._isVisible=!1,this._updateButtons(),l.removeClass(this._domNode,"visible"),this._domNode.setAttribute("aria-hidden","true"),e&&this._codeEditor.focus(),this._codeEditor.layoutOverlayWidget(this),this._codeEditor.changeViewZones(function(e){void 0!==t._viewZoneId&&(e.removeZone(t._viewZoneId),t._viewZoneId=void 0,t._codeEditor.setScrollTop(t._codeEditor.getScrollTop()-t._viewZone.heightInPx))}))},t.prototype._layoutViewZone=function(){var e=this;this._isVisible&&void 0===this._viewZoneId&&this._codeEditor.changeViewZones(function(t){ +e._state.isReplaceRevealed?e._viewZone.heightInPx=64:e._viewZone.heightInPx=R,e._viewZoneId=t.addZone(e._viewZone),e._codeEditor.setScrollTop(e._codeEditor.getScrollTop()+e._viewZone.heightInPx)})},t.prototype._showViewZone=function(e){var t=this;void 0===e&&(e=!0),this._isVisible&&this._codeEditor.changeViewZones(function(n){var i=R;void 0!==t._viewZoneId?(t._state.isReplaceRevealed?(t._viewZone.heightInPx=64,i=64-R):(t._viewZone.heightInPx=R,i=R-64),n.removeZone(t._viewZoneId)):t._viewZone.heightInPx=R,t._viewZoneId=n.addZone(t._viewZone),e&&t._codeEditor.setScrollTop(t._codeEditor.getScrollTop()+i)})},t.prototype._applyTheme=function(e){var t={inputActiveOptionBorder:e.getColor(g.inputActiveOptionBorder),inputBackground:e.getColor(g.inputBackground),inputForeground:e.getColor(g.inputForeground),inputBorder:e.getColor(g.inputBorder),inputValidationInfoBackground:e.getColor(g.inputValidationInfoBackground),inputValidationInfoBorder:e.getColor(g.inputValidationInfoBorder), +inputValidationWarningBackground:e.getColor(g.inputValidationWarningBackground),inputValidationWarningBorder:e.getColor(g.inputValidationWarningBorder),inputValidationErrorBackground:e.getColor(g.inputValidationErrorBackground),inputValidationErrorBorder:e.getColor(g.inputValidationErrorBorder)};this._findInput.style(t),this._replaceInputBox.style(t)},t.prototype._tryUpdateWidgetWidth=function(){if(this._isVisible){var e=this._codeEditor.getConfiguration().layoutInfo.width,t=this._codeEditor.getConfiguration().layoutInfo.minimapWidth,n=!1,i=!1,o=!1;if(this._resized){if(l.getTotalWidth(this._domNode)>411)return this._domNode.style.maxWidth=e-28-t-15+"px",void(this._replaceInputBox.inputElement.style.width=l.getTotalWidth(this._findInput.inputBox.inputElement)+"px")}if(439+t>=e&&(i=!0),439+t-T>=e&&(o=!0),439+t-T>=e+50&&(n=!0),l.toggleClass(this._domNode,"collapsed-find-widget",n),l.toggleClass(this._domNode,"narrow-find-widget",o),l.toggleClass(this._domNode,"reduced-find-widget",i), +o||n||(this._domNode.style.maxWidth=e-28-t-15+"px"),this._resized){var r=l.getTotalWidth(this._findInput.inputBox.inputElement);r>0&&(this._replaceInputBox.inputElement.style.width=r+"px")}}},t.prototype.focusFindInput=function(){this._findInput.select(),this._findInput.focus()},t.prototype.focusReplaceInput=function(){this._replaceInputBox.select(),this._replaceInputBox.focus()},t.prototype.highlightFindOptions=function(){this._findInput.highlightFindOptions()},t.prototype._updateSearchScope=function(){if(this._toggleSelectionFind.checked){var e=this._codeEditor.getSelection();1===e.endColumn&&e.endLineNumber>e.startLineNumber&&(e=e.setEndPosition(e.endLineNumber-1,1));var t=this._state.currentMatch;e.startLineNumber!==e.endLineNumber&&(p.Range.equalsRange(e,t)||this._state.change({searchScope:e},!0))}},t.prototype._onFindInputMouseDown=function(e){e.middleButton&&e.stopPropagation()},t.prototype._onFindInputKeyDown=function(e){ +return e.equals(3)?(this._codeEditor.getAction(h.FIND_IDS.NextMatchFindAction).run().done(null,i.onUnexpectedError),void e.preventDefault()):e.equals(1027)?(this._codeEditor.getAction(h.FIND_IDS.PreviousMatchFindAction).run().done(null,i.onUnexpectedError),void e.preventDefault()):e.equals(2)?(this._isReplaceVisible?this._replaceInputBox.focus():this._findInput.focusOnCaseSensitive(),void e.preventDefault()):e.equals(2066)?(this._codeEditor.focus(),void e.preventDefault()):void 0},t.prototype._onReplaceInputKeyDown=function(e){return e.equals(3)?(this._controller.replace(),void e.preventDefault()):e.equals(2051)?(this._controller.replaceAll(),void e.preventDefault()):e.equals(2)?(this._findInput.focusOnCaseSensitive(),void e.preventDefault()):e.equals(1026)?(this._findInput.focus(),void e.preventDefault()):e.equals(2066)?(this._codeEditor.focus(),void e.preventDefault()):void 0},t.prototype.getHorizontalSashTop=function(e){return 0},t.prototype.getHorizontalSashLeft=function(e){return 0}, +t.prototype.getHorizontalSashWidth=function(e){return 500},t.prototype._keybindingLabelFor=function(e){var t=this._keybindingService.lookupKeybinding(e);return t?" ("+t.getLabel()+")":""},t.prototype._buildFindPart=function(){var e=this;this._findInput=this._register(new m.ContextScopedFindInput(null,this._contextViewProvider,{width:221,label:v,placeholder:_,appendCaseSensitiveLabel:this._keybindingLabelFor(h.FIND_IDS.ToggleCaseSensitiveCommand),appendWholeWordsLabel:this._keybindingLabelFor(h.FIND_IDS.ToggleWholeWordCommand),appendRegexLabel:this._keybindingLabelFor(h.FIND_IDS.ToggleRegexCommand),validation:function(t){if(0===t.length)return null;if(!e._findInput.getRegex())return null;try{return new RegExp(t),null}catch(e){return{content:e.message}}}},this._contextKeyService)),this._findInput.setRegex(!!this._state.isRegex),this._findInput.setCaseSensitive(!!this._state.matchCase),this._findInput.setWholeWords(!!this._state.wholeWord),this._register(this._findInput.onKeyDown(function(t){ +return e._onFindInputKeyDown(t)})),this._register(this._findInput.inputBox.onDidChange(function(){e._state.change({searchString:e._findInput.getValue()},!0)})),this._register(this._findInput.onDidOptionChange(function(){e._state.change({isRegex:e._findInput.getRegex(),wholeWord:e._findInput.getWholeWords(),matchCase:e._findInput.getCaseSensitive()},!0)})),this._register(this._findInput.onCaseSensitiveKeyDown(function(t){t.equals(1026)&&e._isReplaceVisible&&(e._replaceInputBox.focus(),t.preventDefault())})),r.isLinux&&this._register(this._findInput.onMouseDown(function(t){return e._onFindInputMouseDown(t)})),this._matchesCount=document.createElement("div"),this._matchesCount.className="matchesCount",this._updateMatchesCount(),this._prevBtn=this._register(new F({label:y+this._keybindingLabelFor(h.FIND_IDS.PreviousMatchFindAction),className:"previous",onTrigger:function(){e._codeEditor.getAction(h.FIND_IDS.PreviousMatchFindAction).run().done(null,i.onUnexpectedError)}})),this._nextBtn=this._register(new F({ +label:C+this._keybindingLabelFor(h.FIND_IDS.NextMatchFindAction),className:"next",onTrigger:function(){e._codeEditor.getAction(h.FIND_IDS.NextMatchFindAction).run().done(null,i.onUnexpectedError)}}));var t=document.createElement("div");return t.className="find-part",t.appendChild(this._findInput.domNode),t.appendChild(this._matchesCount),t.appendChild(this._prevBtn.domNode),t.appendChild(this._nextBtn.domNode),this._toggleSelectionFind=this._register(new A({parent:t,title:b+this._keybindingLabelFor(h.FIND_IDS.ToggleSearchScopeCommand),onChange:function(){if(e._toggleSelectionFind.checked){var t=e._codeEditor.getSelection();1===t.endColumn&&t.endLineNumber>t.startLineNumber&&(t=t.setEndPosition(t.endLineNumber-1,1)),t.isEmpty()||e._state.change({searchScope:t},!0)}else e._state.change({searchScope:null},!0)}})),this._closeBtn=this._register(new F({label:S+this._keybindingLabelFor(h.FIND_IDS.CloseFindWidgetCommand),className:"close-fw",onTrigger:function(){e._state.change({isRevealed:!1,searchScope:null},!1)}, +onKeyDown:function(t){t.equals(2)&&e._isReplaceVisible&&(e._replaceBtn.isEnabled()?e._replaceBtn.focus():e._codeEditor.focus(),t.preventDefault())}})),t.appendChild(this._closeBtn.domNode),t},t.prototype._buildReplacePart=function(){var e=this,t=document.createElement("div");t.className="replace-input",t.style.width="221px",this._replaceInputBox=this._register(new m.ContextScopedHistoryInputBox(t,null,{ariaLabel:w,placeholder:E,history:[]},this._contextKeyService)),this._register(l.addStandardDisposableListener(this._replaceInputBox.inputElement,"keydown",function(t){return e._onReplaceInputKeyDown(t)})),this._register(l.addStandardDisposableListener(this._replaceInputBox.inputElement,"input",function(t){e._state.change({replaceString:e._replaceInputBox.value},!1)})),this._replaceBtn=this._register(new F({label:L+this._keybindingLabelFor(h.FIND_IDS.ReplaceOneAction),className:"replace",onTrigger:function(){e._controller.replace()},onKeyDown:function(t){t.equals(1026)&&(e._closeBtn.focus(),t.preventDefault())} +})),this._replaceAllBtn=this._register(new F({label:x+this._keybindingLabelFor(h.FIND_IDS.ReplaceAllAction),className:"replace-all",onTrigger:function(){e._controller.replaceAll()}}));var n=document.createElement("div");return n.className="replace-part",n.appendChild(t),n.appendChild(this._replaceBtn.domNode),n.appendChild(this._replaceAllBtn.domNode),n},t.prototype._buildDomNode=function(){var e=this,t=this._buildFindPart(),n=this._buildReplacePart();this._toggleReplaceBtn=this._register(new F({label:N,className:"toggle left",onTrigger:function(){e._state.change({isReplaceRevealed:!e._isReplaceVisible},!1),e._isReplaceVisible&&(e._replaceInputBox.width=e._findInput.inputBox.width),e._showViewZone()}})),this._toggleReplaceBtn.toggleClass("expand",this._isReplaceVisible),this._toggleReplaceBtn.toggleClass("collapse",!this._isReplaceVisible),this._toggleReplaceBtn.setExpanded(this._isReplaceVisible),this._domNode=document.createElement("div"),this._domNode.className="editor-widget find-widget", +this._domNode.setAttribute("aria-hidden","true"),this._domNode.style.width="411px",this._domNode.appendChild(this._toggleReplaceBtn.domNode),this._domNode.appendChild(t),this._domNode.appendChild(n),this._buildSash()},t.prototype._buildSash=function(){var e=this;this._resizeSash=new d.Sash(this._domNode,this,{orientation:d.Orientation.VERTICAL}),this._resized=!1;var t=411;this._register(this._resizeSash.onDidStart(function(n){t=l.getTotalWidth(e._domNode)})),this._register(this._resizeSash.onDidChange(function(n){e._resized=!0;var i=t+n.startX-n.currentX;if(!(i<411)){var o=i-k;i>(parseFloat(l.getComputedStyle(e._domNode).maxWidth)||0)||(e._domNode.style.width=i+"px",e._isReplaceVisible&&(e._replaceInputBox.width=o))}}))},t.ID="editor.contrib.findWidget",t}(u.Widget);t.FindWidget=P;var A=function(e){function t(n){var i=e.call(this)||this;return i._opts=n,i._domNode=document.createElement("div"),i._domNode.className="monaco-checkbox",i._domNode.title=i._opts.title,i._domNode.tabIndex=0, +i._checkbox=document.createElement("input"),i._checkbox.type="checkbox",i._checkbox.className="checkbox",i._checkbox.id="checkbox-"+t._COUNTER++,i._checkbox.tabIndex=-1,i._label=document.createElement("label"),i._label.className="label",i._label.htmlFor=i._checkbox.id,i._label.tabIndex=-1,i._domNode.appendChild(i._checkbox),i._domNode.appendChild(i._label),i._opts.parent.appendChild(i._domNode),i.onchange(i._checkbox,function(e){i._opts.onChange()}),i}return o(t,e),Object.defineProperty(t.prototype,"domNode",{get:function(){return this._domNode},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"checked",{get:function(){return this._checkbox.checked},set:function(e){this._checkbox.checked=e},enumerable:!0,configurable:!0}),t.prototype.enable=function(){this._checkbox.removeAttribute("disabled")},t.prototype.disable=function(){this._checkbox.disabled=!0},t.prototype.setEnabled=function(e){e?(this.enable(),this.domNode.tabIndex=0):(this.disable(),this.domNode.tabIndex=-1)},t._COUNTER=0,t +}(u.Widget),F=function(e){function t(t){var n=e.call(this)||this;return n._opts=t,n._domNode=document.createElement("div"),n._domNode.title=n._opts.label,n._domNode.tabIndex=0,n._domNode.className="button "+n._opts.className,n._domNode.setAttribute("role","button"),n._domNode.setAttribute("aria-label",n._opts.label),n.onclick(n._domNode,function(e){n._opts.onTrigger(),e.preventDefault()}),n.onkeydown(n._domNode,function(e){if(e.equals(10)||e.equals(3))return n._opts.onTrigger(),void e.preventDefault();n._opts.onKeyDown&&n._opts.onKeyDown(e)}),n}return o(t,e),Object.defineProperty(t.prototype,"domNode",{get:function(){return this._domNode},enumerable:!0,configurable:!0}),t.prototype.isEnabled=function(){return this._domNode.tabIndex>=0},t.prototype.focus=function(){this._domNode.focus()},t.prototype.setEnabled=function(e){l.toggleClass(this._domNode,"disabled",!e),this._domNode.setAttribute("aria-disabled",String(!e)),this._domNode.tabIndex=e?0:-1},t.prototype.setExpanded=function(e){ +this._domNode.setAttribute("aria-expanded",String(!!e))},t.prototype.toggleClass=function(e,t){l.toggleClass(this._domNode,e,t)},t}(u.Widget);t.SimpleButton=F,f.registerThemingParticipant(function(e,t){var n=function(e,n){n&&t.addRule(".monaco-editor "+e+" { background-color: "+n+"; }")};n(".findMatch",e.getColor(g.editorFindMatchHighlight)),n(".currentFindMatch",e.getColor(g.editorFindMatch)),n(".findScope",e.getColor(g.editorFindRangeHighlight));n(".find-widget",e.getColor(g.editorWidgetBackground));var i=e.getColor(g.widgetShadow);i&&t.addRule(".monaco-editor .find-widget { box-shadow: 0 2px 8px "+i+"; }");var o=e.getColor(g.editorFindMatchHighlightBorder);o&&t.addRule(".monaco-editor .findMatch { border: 1px "+("hc"===e.type?"dotted":"solid")+" "+o+"; box-sizing: border-box; }");var r=e.getColor(g.editorFindMatchBorder);r&&t.addRule(".monaco-editor .currentFindMatch { border: 2px solid "+r+"; padding: 1px; box-sizing: border-box; }");var s=e.getColor(g.editorFindRangeHighlightBorder) +;s&&t.addRule(".monaco-editor .findScope { border: 1px "+("hc"===e.type?"dashed":"solid")+" "+s+"; }");var a=e.getColor(g.contrastBorder);a&&t.addRule(".monaco-editor .find-widget { border: 2px solid "+a+"; }");var l=e.getColor(g.errorForeground);l&&t.addRule(".monaco-editor .find-widget.no-results .matchesCount { color: "+l+"; }");var u=e.getColor(g.editorWidgetResizeBorder);if(u)t.addRule(".monaco-editor .find-widget .monaco-sash { background-color: "+u+"; width: 3px !important; margin-left: -4px;}");else{var d=e.getColor(g.editorWidgetBorder);d&&t.addRule(".monaco-editor .find-widget .monaco-sash { background-color: "+d+"; width: 3px !important; margin-left: -4px;}")}})}),define(t[196],n([1,0,311,2,19,6,11,142,243,14,20,72,194,77,49,547,516,16,15,44]),function(e,t,n,i,r,s,l,d,c,h,p,f,g,m,v,_,y,C,b,S){"use strict";function w(e){var t=e.getSelection();if(t.startLineNumber===t.endLineNumber){if(!t.isEmpty())return e.getModel().getValueInRange(t);var n=e.getModel().getWordAtPosition(t.getStartPosition()) +;if(n)return n.word}return null}Object.defineProperty(t,"__esModule",{value:!0}),t.getSelectionSearchString=w;var E=function(e){function t(t,n,i,o){var r=e.call(this)||this;return r._editor=t,r._findWidgetVisible=d.CONTEXT_FIND_WIDGET_VISIBLE.bindTo(n),r._storageService=i,r._clipboardService=o,r._updateHistoryDelayer=new h.Delayer(500),r._state=r._register(new c.FindReplaceState),r.loadQueryState(),r._register(r._state.onFindReplaceStateChange(function(e){return r._onStateChanged(e)})),r._model=null,r._register(r._editor.onDidChangeModel(function(){var e=r._editor.getModel()&&r._state.isRevealed;r.disposeModel(),r._state.change({searchScope:null,matchCase:r._storageService.getBoolean("editor.matchCase",f.StorageScope.WORKSPACE,!1),wholeWord:r._storageService.getBoolean("editor.wholeWord",f.StorageScope.WORKSPACE,!1),isRegex:r._storageService.getBoolean("editor.isRegex",f.StorageScope.WORKSPACE,!1)},!1),e&&r._start({forceRevealReplace:!1,seedSearchStringFromSelection:!1,seedSearchStringFromGlobalClipboard:!1, +shouldFocus:0,shouldAnimate:!1})})),r}return o(t,e),t.get=function(e){return e.getContribution(t.ID)},t.prototype.dispose=function(){this.disposeModel(),e.prototype.dispose.call(this)},t.prototype.disposeModel=function(){this._model&&(this._model.dispose(),this._model=null)},t.prototype.getId=function(){return t.ID},t.prototype._onStateChanged=function(e){this.saveQueryState(e),e.isRevealed&&(this._state.isRevealed?this._findWidgetVisible.set(!0):(this._findWidgetVisible.reset(),this.disposeModel())),e.searchString&&this.setGlobalBufferTerm(this._state.searchString)},t.prototype.saveQueryState=function(e){e.isRegex&&this._storageService.store("editor.isRegex",this._state.actualIsRegex,f.StorageScope.WORKSPACE),e.wholeWord&&this._storageService.store("editor.wholeWord",this._state.actualWholeWord,f.StorageScope.WORKSPACE),e.matchCase&&this._storageService.store("editor.matchCase",this._state.actualMatchCase,f.StorageScope.WORKSPACE)},t.prototype.loadQueryState=function(){this._state.change({ +matchCase:this._storageService.getBoolean("editor.matchCase",f.StorageScope.WORKSPACE,this._state.matchCase),wholeWord:this._storageService.getBoolean("editor.wholeWord",f.StorageScope.WORKSPACE,this._state.wholeWord),isRegex:this._storageService.getBoolean("editor.isRegex",f.StorageScope.WORKSPACE,this._state.isRegex)},!1)},t.prototype.getState=function(){return this._state},t.prototype.closeFindWidget=function(){this._state.change({isRevealed:!1,searchScope:null},!1),this._editor.focus()},t.prototype.toggleCaseSensitive=function(){this._state.change({matchCase:!this._state.matchCase},!1)},t.prototype.toggleWholeWords=function(){this._state.change({wholeWord:!this._state.wholeWord},!1)},t.prototype.toggleRegex=function(){this._state.change({isRegex:!this._state.isRegex},!1)},t.prototype.toggleSearchScope=function(){if(this._state.searchScope)this._state.change({searchScope:null},!0);else{var e=this._editor.getSelection() +;1===e.endColumn&&e.endLineNumber>e.startLineNumber&&(e=e.setEndPosition(e.endLineNumber-1,1)),e.isEmpty()||this._state.change({searchScope:e},!0)}},t.prototype.setSearchString=function(e){this._state.isRegex&&(e=s.escapeRegExpCharacters(e)),this._state.change({searchString:e},!1)},t.prototype.highlightFindOptions=function(){},t.prototype._start=function(e){if(this.disposeModel(),this._editor.getModel()){var t={isRevealed:!0};if(e.seedSearchStringFromSelection){(n=w(this._editor))&&(this._state.isRegex?t.searchString=s.escapeRegExpCharacters(n):t.searchString=n)}if(!t.searchString&&e.seedSearchStringFromGlobalClipboard){var n=this.getGlobalBufferTerm();n&&(t.searchString=n)}e.forceRevealReplace?t.isReplaceRevealed=!0:this._findWidgetVisible.get()||(t.isReplaceRevealed=!1),this._state.change(t,!1),this._model||(this._model=new d.FindModelBoundToEditorModel(this._editor,this._state))}},t.prototype.start=function(e){this._start(e)},t.prototype.moveToNextMatch=function(){ +return!!this._model&&(this._model.moveToNextMatch(),!0)},t.prototype.moveToPrevMatch=function(){return!!this._model&&(this._model.moveToPrevMatch(),!0)},t.prototype.replace=function(){return!!this._model&&(this._model.replace(),!0)},t.prototype.replaceAll=function(){return!!this._model&&(this._model.replaceAll(),!0)},t.prototype.selectAllMatches=function(){return!!this._model&&(this._model.selectAllMatches(),this._editor.focus(),!0)},t.prototype.getGlobalBufferTerm=function(){return this._editor.getConfiguration().contribInfo.find.globalFindClipboard&&this._clipboardService&&!this._editor.getModel().isTooLargeForSyncing()?this._clipboardService.readFindText():""},t.prototype.setGlobalBufferTerm=function(e){this._editor.getConfiguration().contribInfo.find.globalFindClipboard&&this._clipboardService&&!this._editor.getModel().isTooLargeForSyncing()&&this._clipboardService.writeFindText(e)},t.ID="editor.contrib.findController",t=a([u(1,r.IContextKeyService),u(2,f.IStorageService),u(3,g.IClipboardService)],t) +}(i.Disposable);t.CommonFindController=E;var L=function(e){function t(t,n,i,o,r,s,a){var l=e.call(this,t,i,s,a)||this;return l._contextViewService=n,l._contextKeyService=i,l._keybindingService=o,l._themeService=r,l}return o(t,e),t.prototype._start=function(t){this._widget||this._createFindWidget(),e.prototype._start.call(this,t),2===t.shouldFocus?this._widget.focusReplaceInput():1===t.shouldFocus&&this._widget.focusFindInput()},t.prototype.highlightFindOptions=function(){this._widget||this._createFindWidget(),this._state.isRevealed?this._widget.highlightFindOptions():this._findOptionsWidget.highlightFindOptions()},t.prototype._createFindWidget=function(){this._widget=this._register(new _.FindWidget(this._editor,this,this._state,this._contextViewService,this._keybindingService,this._contextKeyService,this._themeService)),this._findOptionsWidget=this._register(new y.FindOptionsWidget(this._editor,this._state,this._keybindingService,this._themeService))}, +t=a([u(1,m.IContextViewService),u(2,r.IContextKeyService),u(3,v.IKeybindingService),u(4,C.IThemeService),u(5,f.IStorageService),u(6,b.optional(g.IClipboardService))],t)}(E);t.FindController=L;var x=function(e){function t(){return e.call(this,{id:d.FIND_IDS.StartFindAction,label:n.localize(0,null),alias:"Find",precondition:null,kbOpts:{kbExpr:null,primary:2084,weight:100},menubarOpts:{menuId:S.MenuId.MenubarEditMenu,group:"3_find",title:n.localize(1,null),order:1}})||this}return o(t,e),t.prototype.run=function(e,t){var n=E.get(t);n&&n.start({forceRevealReplace:!1,seedSearchStringFromSelection:t.getConfiguration().contribInfo.find.seedSearchStringFromSelection,seedSearchStringFromGlobalClipboard:t.getConfiguration().contribInfo.find.globalFindClipboard,shouldFocus:1,shouldAnimate:!0})},t}(l.EditorAction);t.StartFindAction=x;var N=function(e){function t(){return e.call(this,{id:d.FIND_IDS.StartFindWithSelection,label:n.localize(2,null),alias:"Find With Selection",precondition:null,kbOpts:{kbExpr:null, +primary:null,mac:{primary:2083},weight:100}})||this}return o(t,e),t.prototype.run=function(e,t){var n=E.get(t);n&&(n.start({forceRevealReplace:!1,seedSearchStringFromSelection:!0,seedSearchStringFromGlobalClipboard:!1,shouldFocus:1,shouldAnimate:!0}),n.setGlobalBufferTerm(n.getState().searchString))},t}(l.EditorAction);t.StartFindWithSelectionAction=N;var I=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype.run=function(e,t){var n=E.get(t);n&&!this._run(n)&&(n.start({forceRevealReplace:!1,seedSearchStringFromSelection:0===n.getState().searchString.length&&t.getConfiguration().contribInfo.find.seedSearchStringFromSelection,seedSearchStringFromGlobalClipboard:!0,shouldFocus:0,shouldAnimate:!0}),this._run(n))},t}(l.EditorAction);t.MatchFindAction=I;var M=function(e){function t(){return e.call(this,{id:d.FIND_IDS.NextMatchFindAction,label:n.localize(3,null),alias:"Find Next",precondition:null,kbOpts:{kbExpr:p.EditorContextKeys.focus,primary:61,mac:{primary:2085, +secondary:[61]},weight:100}})||this}return o(t,e),t.prototype._run=function(e){return e.moveToNextMatch()},t}(I);t.NextMatchFindAction=M;var D=function(e){function t(){return e.call(this,{id:d.FIND_IDS.PreviousMatchFindAction,label:n.localize(4,null),alias:"Find Previous",precondition:null,kbOpts:{kbExpr:p.EditorContextKeys.focus,primary:1085,mac:{primary:3109,secondary:[1085]},weight:100}})||this}return o(t,e),t.prototype._run=function(e){return e.moveToPrevMatch()},t}(I);t.PreviousMatchFindAction=D;var T=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype.run=function(e,t){var n=E.get(t);if(n){var i=w(t);i&&n.setSearchString(i),this._run(n)||(n.start({forceRevealReplace:!1,seedSearchStringFromSelection:t.getConfiguration().contribInfo.find.seedSearchStringFromSelection,seedSearchStringFromGlobalClipboard:!1,shouldFocus:0,shouldAnimate:!0}),this._run(n))}},t}(l.EditorAction);t.SelectionMatchFindAction=T;var k=function(e){function t(){return e.call(this,{ +id:d.FIND_IDS.NextSelectionMatchFindAction,label:n.localize(5,null),alias:"Find Next Selection",precondition:null,kbOpts:{kbExpr:p.EditorContextKeys.focus,primary:2109,weight:100}})||this}return o(t,e),t.prototype._run=function(e){return e.moveToNextMatch()},t}(T);t.NextSelectionMatchFindAction=k;var R=function(e){function t(){return e.call(this,{id:d.FIND_IDS.PreviousSelectionMatchFindAction,label:n.localize(6,null),alias:"Find Previous Selection",precondition:null,kbOpts:{kbExpr:p.EditorContextKeys.focus,primary:3133,weight:100}})||this}return o(t,e),t.prototype._run=function(e){return e.moveToPrevMatch()},t}(T);t.PreviousSelectionMatchFindAction=R;var O=function(e){function t(){return e.call(this,{id:d.FIND_IDS.StartFindReplaceAction,label:n.localize(7,null),alias:"Replace",precondition:null,kbOpts:{kbExpr:null,primary:2086,mac:{primary:2596},weight:100},menubarOpts:{menuId:S.MenuId.MenubarEditMenu,group:"3_find",title:n.localize(8,null),order:2}})||this}return o(t,e),t.prototype.run=function(e,t){ +if(!t.getConfiguration().readOnly){var n=E.get(t),i=t.getSelection(),o=!i.isEmpty()&&i.startLineNumber===i.endLineNumber&&t.getConfiguration().contribInfo.find.seedSearchStringFromSelection,r=n.getState().searchString||o?2:1;n&&n.start({forceRevealReplace:!0,seedSearchStringFromSelection:o,seedSearchStringFromGlobalClipboard:t.getConfiguration().contribInfo.find.seedSearchStringFromSelection,shouldFocus:r,shouldAnimate:!0})}},t}(l.EditorAction);t.StartFindReplaceAction=O,l.registerEditorContribution(L),l.registerEditorAction(x),l.registerEditorAction(N),l.registerEditorAction(M),l.registerEditorAction(D),l.registerEditorAction(k),l.registerEditorAction(R),l.registerEditorAction(O);var P=l.EditorCommand.bindToContribution(E.get);l.registerEditorCommand(new P({id:d.FIND_IDS.CloseFindWidgetCommand,precondition:d.CONTEXT_FIND_WIDGET_VISIBLE,handler:function(e){return e.closeFindWidget()},kbOpts:{weight:105,kbExpr:p.EditorContextKeys.focus,primary:9,secondary:[1033]}})),l.registerEditorCommand(new P({ +id:d.FIND_IDS.ToggleCaseSensitiveCommand,precondition:null,handler:function(e){return e.toggleCaseSensitive()},kbOpts:{weight:105,kbExpr:p.EditorContextKeys.focus,primary:d.ToggleCaseSensitiveKeybinding.primary,mac:d.ToggleCaseSensitiveKeybinding.mac,win:d.ToggleCaseSensitiveKeybinding.win,linux:d.ToggleCaseSensitiveKeybinding.linux}})),l.registerEditorCommand(new P({id:d.FIND_IDS.ToggleWholeWordCommand,precondition:null,handler:function(e){return e.toggleWholeWords()},kbOpts:{weight:105,kbExpr:p.EditorContextKeys.focus,primary:d.ToggleWholeWordKeybinding.primary,mac:d.ToggleWholeWordKeybinding.mac,win:d.ToggleWholeWordKeybinding.win,linux:d.ToggleWholeWordKeybinding.linux}})),l.registerEditorCommand(new P({id:d.FIND_IDS.ToggleRegexCommand,precondition:null,handler:function(e){return e.toggleRegex()},kbOpts:{weight:105,kbExpr:p.EditorContextKeys.focus,primary:d.ToggleRegexKeybinding.primary,mac:d.ToggleRegexKeybinding.mac,win:d.ToggleRegexKeybinding.win,linux:d.ToggleRegexKeybinding.linux}})), +l.registerEditorCommand(new P({id:d.FIND_IDS.ToggleSearchScopeCommand,precondition:null,handler:function(e){return e.toggleSearchScope()},kbOpts:{weight:105,kbExpr:p.EditorContextKeys.focus,primary:d.ToggleSearchScopeKeybinding.primary,mac:d.ToggleSearchScopeKeybinding.mac,win:d.ToggleSearchScopeKeybinding.win,linux:d.ToggleSearchScopeKeybinding.linux}})),l.registerEditorCommand(new P({id:d.FIND_IDS.ReplaceOneAction,precondition:d.CONTEXT_FIND_WIDGET_VISIBLE,handler:function(e){return e.replace()},kbOpts:{weight:105,kbExpr:p.EditorContextKeys.focus,primary:3094}})),l.registerEditorCommand(new P({id:d.FIND_IDS.ReplaceAllAction,precondition:d.CONTEXT_FIND_WIDGET_VISIBLE,handler:function(e){return e.replaceAll()},kbOpts:{weight:105,kbExpr:p.EditorContextKeys.focus,primary:2563}})),l.registerEditorCommand(new P({id:d.FIND_IDS.SelectAllMatchesAction,precondition:d.CONTEXT_FIND_WIDGET_VISIBLE,handler:function(e){return e.selectAllMatches()},kbOpts:{weight:105,kbExpr:p.EditorContextKeys.focus,primary:515}}))}), +define(t[549],n([1,0,326,2,39,14,24,20,11,3,21,54,181,17,196,29,22,16,44]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m,v,_,y){"use strict";function C(e,t,n){for(var i=b(e,t[0],!n),o=1,r=t.length;o1&&n.push(new c.Selection(e.endLineNumber,e.endColumn,e.endLineNumber,e.endColumn))}},t.prototype.run=function(e,t){var n=this,i=t.getModel(),o=[];t.getSelections().forEach(function(e){return n.getCursorsForSelection(e,i,o)}),o.length>0&&t.setSelections(o)},t}(u.EditorAction),L=function(){return function(e,t,n){this.selections=e,this.revealRange=t,this.revealScrollType=n}}();t.MultiCursorSessionResult=L;var x=function(){function e(e,t,n,i,o,r,s){this._editor=e,this.findController=t,this.isDisconnectedFromFindController=n,this.searchText=i,this.wholeWord=o,this.matchCase=r,this.currentMatch=s}return e.create=function(t,n){var i=n.getState() +;if(!t.hasTextFocus()&&i.isRevealed&&i.searchString.length>0)return new e(t,n,!1,i.searchString,i.wholeWord,i.matchCase,null);var o,r,s=!1,a=t.getSelections();1===a.length&&a[0].isEmpty()?(s=!0,o=!0,r=!0):(o=i.wholeWord,r=i.matchCase);var l,u=t.getSelection(),d=null;if(u.isEmpty()){var h=t.getModel().getWordAtPosition(u.getStartPosition());if(!h)return null;l=h.word,d=new c.Selection(u.startLineNumber,h.startColumn,u.startLineNumber,h.endColumn)}else l=t.getModel().getValueInRange(u).replace(/\r\n/g,"\n");return new e(t,n,s,l,o,r,d)},e.prototype.addSelectionToNextFindMatch=function(){var e=this._getNextMatch();if(!e)return null;var t=this._editor.getSelections();return new L(t.concat(e),e,0)},e.prototype.moveSelectionToNextFindMatch=function(){var e=this._getNextMatch();if(!e)return null;var t=this._editor.getSelections();return new L(t.slice(0,t.length-1).concat(e),e,0)},e.prototype._getNextMatch=function(){if(this.currentMatch){var e=this.currentMatch;return this.currentMatch=null,e} +this.findController.highlightFindOptions();var t=this._editor.getSelections(),n=t[t.length-1],i=this._editor.getModel().findNextMatch(this.searchText,n.getEndPosition(),!1,this.matchCase,this.wholeWord?this._editor.getConfiguration().wordSeparators:null,!1);return i?new c.Selection(i.range.startLineNumber,i.range.startColumn,i.range.endLineNumber,i.range.endColumn):null},e.prototype.addSelectionToPreviousFindMatch=function(){var e=this._getPreviousMatch();if(!e)return null;var t=this._editor.getSelections();return new L(t.concat(e),e,0)},e.prototype.moveSelectionToPreviousFindMatch=function(){var e=this._getPreviousMatch();if(!e)return null;var t=this._editor.getSelections();return new L(t.slice(0,t.length-1).concat(e),e,0)},e.prototype._getPreviousMatch=function(){if(this.currentMatch){var e=this.currentMatch;return this.currentMatch=null,e}this.findController.highlightFindOptions() +;var t=this._editor.getSelections(),n=t[t.length-1],i=this._editor.getModel().findPreviousMatch(this.searchText,n.getStartPosition(),!1,this.matchCase,this.wholeWord?this._editor.getConfiguration().wordSeparators:null,!1);return i?new c.Selection(i.range.startLineNumber,i.range.startColumn,i.range.endLineNumber,i.range.endColumn):null},e.prototype.selectAll=function(){return this.findController.highlightFindOptions(),this._editor.getModel().findMatches(this.searchText,!0,!1,this.matchCase,this.wholeWord?this._editor.getConfiguration().wordSeparators:null,!1,1073741824)},e}();t.MultiCursorSession=x;var N=function(e){function t(t){var n=e.call(this)||this;return n._editor=t,n._ignoreSelectionChange=!1,n._session=null,n._sessionDispose=[],n}return o(t,e),t.get=function(e){return e.getContribution(t.ID)},t.prototype.dispose=function(){this._endSession(),e.prototype.dispose.call(this)},t.prototype.getId=function(){return t.ID},t.prototype._beginSessionIfNeeded=function(e){var t=this;if(!this._session){ +var n=x.create(this._editor,e);if(!n)return;this._session=n;var i={searchString:this._session.searchText};this._session.isDisconnectedFromFindController&&(i.wholeWordOverride=1,i.matchCaseOverride=1,i.isRegexOverride=2),e.getState().change(i,!1),this._sessionDispose=[this._editor.onDidChangeCursorSelection(function(e){t._ignoreSelectionChange||t._endSession()}),this._editor.onDidBlurEditorText(function(){t._endSession()}),e.getState().onFindReplaceStateChange(function(e){(e.matchCase||e.wholeWord)&&t._endSession()})]}},t.prototype._endSession=function(){if(this._sessionDispose=i.dispose(this._sessionDispose),this._session&&this._session.isDisconnectedFromFindController){var e={wholeWordOverride:0,matchCaseOverride:0,isRegexOverride:0};this._session.findController.getState().change(e,!1)}this._session=null},t.prototype._setSelections=function(e){this._ignoreSelectionChange=!0,this._editor.setSelections(e),this._ignoreSelectionChange=!1},t.prototype._expandEmptyToWord=function(e,t){if(!t.isEmpty())return t +;var n=e.getWordAtPosition(t.getStartPosition());return n?new c.Selection(t.startLineNumber,n.startColumn,t.startLineNumber,n.endColumn):t},t.prototype._applySessionResult=function(e){e&&(this._setSelections(e.selections),e.revealRange&&this._editor.revealRangeInCenterIfOutsideViewport(e.revealRange,e.revealScrollType))},t.prototype.getSession=function(e){return this._session},t.prototype.addSelectionToNextFindMatch=function(e){if(!this._session){var t=this._editor.getSelections();if(t.length>1){var n=e.getState().matchCase;if(!C(this._editor.getModel(),t,n)){for(var i=this._editor.getModel(),o=[],r=0,s=t.length;r0&&n.isRegex)t=this._editor.getModel().findMatches(n.searchString,!0,n.isRegex,n.matchCase,n.wholeWord?this._editor.getConfiguration().wordSeparators:null,!1,1073741824);else{if(this._beginSessionIfNeeded(e),!this._session)return;t=this._session.selectAll()}if(t.length>0){for(var i=this._editor.getSelection(),o=0,r=t.length;o1){var l=r.getState().matchCase;if(!C(t.getModel(),a,l))return null}s=x.create(t,r)}if(!s)return null;var u=null,d=f.DocumentHighlightProviderRegistry.has(n);if(s.currentMatch){if(d)return null;if(!t.getConfiguration().contribInfo.occurrencesHighlight)return null;u=s.currentMatch}if(/^[ \t]+$/.test(s.searchText))return null;if(s.searchText.length>200)return null;var c=r.getState(),h=c.matchCase;if(c.isRevealed){var p=c.searchString;h||(p=p.toLowerCase());var m=s.searchText;if(h||(m=m.toLowerCase()), +p===m&&s.matchCase===c.matchCase&&s.wholeWord===c.wholeWord&&!c.isRegex)return null}return new P(u,s.searchText,s.matchCase,s.wholeWord?t.getConfiguration().wordSeparators:null)},t.prototype._setState=function(e){if(P.softEquals(this.state,e))this.state=e;else if(this.state=e,this.state){var n=this.editor.getModel();if(!n.isTooLargeForTokenization()){var i=f.DocumentHighlightProviderRegistry.has(n),o=n.findMatches(this.state.searchText,!0,!1,this.state.matchCase,this.state.wordSeparators,!1).map(function(e){return e.range});o.sort(d.Range.compareRangesUsingStarts);var r=this.editor.getSelections();r.sort(d.Range.compareRangesUsingStarts);for(var s=[],a=0,l=0,u=o.length,c=r.length;a=c)s.push(h),a++;else{var p=d.Range.compareRangesUsingStarts(h,r[l]);p<0?(!r[l].isEmpty()&&d.Range.areIntersecting(h,r[l])||s.push(h),a++):p>0?l++:(a++,l++)}}var g=s.map(function(e){return{range:e,options:i?t._SELECTION_HIGHLIGHT:t._SELECTION_HIGHLIGHT_OVERVIEW}}) +;this.decorations=this.editor.deltaDecorations(this.decorations,g)}}else this.decorations=this.editor.deltaDecorations(this.decorations,[])},t.prototype.dispose=function(){this._setState(null),e.prototype.dispose.call(this)},t.ID="editor.contrib.selectionHighlighter",t._SELECTION_HIGHLIGHT_OVERVIEW=m.ModelDecorationOptions.register({stickiness:a.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,className:"selectionHighlight",overviewRuler:{color:_.themeColorFromId(v.overviewRulerSelectionHighlightForeground),darkColor:_.themeColorFromId(v.overviewRulerSelectionHighlightForeground),position:a.OverviewRulerLane.Center}}),t._SELECTION_HIGHLIGHT=m.ModelDecorationOptions.register({stickiness:a.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,className:"selectionHighlight"}),t}(i.Disposable);t.SelectionHighlighter=A,u.registerEditorContribution(N),u.registerEditorContribution(A),u.registerEditorAction(S),u.registerEditorAction(w),u.registerEditorAction(E),u.registerEditorAction(M),u.registerEditorAction(D), +u.registerEditorAction(T),u.registerEditorAction(k),u.registerEditorAction(R),u.registerEditorAction(O)}),define(t[147],n([1,0,31,50,15,70]),function(e,t,n,i,o,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.IWorkspaceContextService=o.createDecorator("contextService");!function(e){e.isIWorkspace=function(e){return e&&"object"==typeof e&&"string"==typeof e.id&&"string"==typeof e.name&&Array.isArray(e.folders)}}(t.IWorkspace||(t.IWorkspace={}));!function(e){e.isIWorkspaceFolder=function(e){return e&&"object"==typeof e&&n.default.isUri(e.uri)&&"string"==typeof e.name&&"function"==typeof e.toResource}}(t.IWorkspaceFolder||(t.IWorkspaceFolder={}));var s=function(){function e(e,t,n,i,o){void 0===t&&(t=""),void 0===n&&(n=[]),void 0===i&&(i=null),this._id=e,this._name=t,this._configuration=i,this._ctime=o,this._foldersMap=r.TernarySearchTree.forPaths(),this.folders=n}return Object.defineProperty(e.prototype,"folders",{get:function(){return this._folders},set:function(e){this._folders=e, +this.updateFoldersMap()},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"id",{get:function(){return this._id},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"name",{get:function(){return this._name},set:function(e){this._name=e},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"configuration",{get:function(){return this._configuration},set:function(e){this._configuration=e},enumerable:!0,configurable:!0}),e.prototype.getFolder=function(e){return e?this._foldersMap.findSubstr(e.toString()):null},e.prototype.updateFoldersMap=function(){this._foldersMap=r.TernarySearchTree.forPaths();for(var e=0,t=this.folders;e1?this.badge.setTitleFormat(n.localize(1,null,t)):this.badge.setTitleFormat(n.localize(2,null,t))},e=a([u(1,b.IWorkspaceContextService),u(2,C.optional(T.IEnvironmentService)),u(3,M.IThemeService)],e)}(),K=function(){function e(e){var t=document.createElement("div");this.before=document.createElement("span"),this.inside=document.createElement("span"),this.after=document.createElement("span"),m.addClass(this.inside,"referenceMatch"),m.addClass(t,"reference"),t.appendChild(this.before),t.appendChild(this.inside),t.appendChild(this.after),e.appendChild(t)}return e.prototype.set=function(e){var t=e.parent.preview.preview(e.range),n=t.before,i=t.inside,o=t.after;this.before.innerHTML=h.escape(n), +this.inside.innerHTML=h.escape(i),this.after.innerHTML=h.escape(o)},e}(),U=function(){function e(e,t,n){this._contextService=e,this._themeService=t,this._environmentService=n}return e.prototype.getHeight=function(e,t){return 23},e.prototype.getTemplateId=function(t,n){if(n instanceof x.FileReferences)return e._ids.FileReferences;if(n instanceof x.OneReference)return e._ids.OneReference;throw n},e.prototype.renderTemplate=function(t,n,i){if(n===e._ids.FileReferences)return new z(i,this._contextService,this._environmentService,this._themeService);if(n===e._ids.OneReference)return new K(i);throw n},e.prototype.renderElement=function(e,t,n,i){if(t instanceof x.FileReferences)i.set(t);else{if(!(t instanceof x.OneReference))throw n;i.set(t)}},e.prototype.disposeTemplate=function(e,t,n){n instanceof z&&n.dispose()},e._ids={FileReferences:"FileReferences",OneReference:"OneReference"},e=a([u(0,b.IWorkspaceContextService),u(1,M.IThemeService),u(2,C.optional(T.IEnvironmentService))],e)}(),j=function(){function e(){} +return e.prototype.getAriaLabel=function(e,t){return t instanceof x.FileReferences?t.getAriaMessage():t instanceof x.OneReference?t.getAriaMessage():void 0},e}(),q=function(){function e(e,t){var n=this;this._disposables=[],this._onDidChangePercentages=new r.Emitter,this._ratio=t,this._sash=new v.Sash(e,{getVerticalSashLeft:function(){return n._width*n._ratio},getVerticalSashHeight:function(){return n._height}});var i;this._disposables.push(this._sash.onDidStart(function(e){i=e.startX-n._width*n.ratio})),this._disposables.push(this._sash.onDidChange(function(e){var t=e.currentX-i;t>20&&t+200?e.children[0]:void 0},h.prototype._revealReference=function(e,t){return d(this,void 0,void 0,function(){var o,r=this;return c(this,function(a){switch(a.label){case 0:return e.uri.scheme!==l.Schemas.inMemory?this.setTitle(W.basenameOrAuthority(e.uri),this._uriDisplay.getLabel(W.dirname(e.uri),!1)):this.setTitle(n.localize(6,null)),o=this._textModelResolverService.createModelReference(e.uri),t?[4,this._tree.reveal(e.parent)]:[3,2];case 1:a.sent(),a.label=2;case 2:return[2,p.TPromise.join([o,this._tree.reveal(e)]).then(function(t){var n=t[0];if(r._model){s.dispose(r._previewModelReference);var i=n.object;if(i){r._previewModelReference=n;var o=r._preview.getModel()===i.textEditorModel;r._preview.setModel(i.textEditorModel) +;var a=S.Range.lift(e.range).collapseToStart();r._preview.setSelection(a),r._preview.revealRangeInCenter(a,o?0:1)}else r._preview.setModel(r._previewNotAvailableMessage),n.dispose()}else n.dispose()},i.onUnexpectedError)]}})})},h=a([u(3,M.IThemeService),u(4,N.ITextModelService),u(5,C.IInstantiationService),u(6,F.IUriDisplayService)],h)}(L.PeekViewWidget);t.ReferenceWidget=G,t.peekViewTitleBackground=I.registerColor("peekViewTitle.background",{dark:"#1E1E1E",light:"#FFFFFF",hc:"#0C141F"},n.localize(7,null)),t.peekViewTitleForeground=I.registerColor("peekViewTitleLabel.foreground",{dark:"#FFFFFF",light:"#333333",hc:"#FFFFFF"},n.localize(8,null)),t.peekViewTitleInfoForeground=I.registerColor("peekViewTitleDescription.foreground",{dark:"#ccccccb3",light:"#6c6c6cb3",hc:"#FFFFFF99"},n.localize(9,null)),t.peekViewBorder=I.registerColor("peekView.border",{dark:"#007acc",light:"#007acc",hc:I.contrastBorder},n.localize(10,null)),t.peekViewResultsBackground=I.registerColor("peekViewResult.background",{dark:"#252526", +light:"#F3F3F3",hc:f.Color.black},n.localize(11,null)),t.peekViewResultsMatchForeground=I.registerColor("peekViewResult.lineForeground",{dark:"#bbbbbb",light:"#646465",hc:f.Color.white},n.localize(12,null)),t.peekViewResultsFileForeground=I.registerColor("peekViewResult.fileForeground",{dark:f.Color.white,light:"#1E1E1E",hc:f.Color.white},n.localize(13,null)),t.peekViewResultsSelectionBackground=I.registerColor("peekViewResult.selectionBackground",{dark:"#3399ff33",light:"#3399ff33",hc:null},n.localize(14,null)),t.peekViewResultsSelectionForeground=I.registerColor("peekViewResult.selectionForeground",{dark:f.Color.white,light:"#6C6C6C",hc:f.Color.white},n.localize(15,null)),t.peekViewEditorBackground=I.registerColor("peekViewEditor.background",{dark:"#001F33",light:"#F2F8FC",hc:f.Color.black},n.localize(16,null)),t.peekViewEditorGutterBackground=I.registerColor("peekViewEditorGutter.background",{dark:t.peekViewEditorBackground,light:t.peekViewEditorBackground,hc:t.peekViewEditorBackground +},n.localize(17,null)),t.peekViewResultsMatchHighlight=I.registerColor("peekViewResult.matchHighlightBackground",{dark:"#ea5c004d",light:"#ea5c004d",hc:null},n.localize(18,null)),t.peekViewEditorMatchHighlight=I.registerColor("peekViewEditor.matchHighlightBackground",{dark:"#ff8f0099",light:"#f5d802de",hc:null},n.localize(19,null)),t.peekViewEditorMatchHighlightBorder=I.registerColor("peekViewEditor.matchHighlightBorder",{dark:null,light:null,hc:I.activeContrastBorder},n.localize(20,null)),M.registerThemingParticipant(function(e,n){var i=e.getColor(t.peekViewResultsMatchHighlight);i&&n.addRule(".monaco-editor .reference-zone-widget .ref-tree .referenceMatch { background-color: "+i+"; }");var o=e.getColor(t.peekViewEditorMatchHighlight);o&&n.addRule(".monaco-editor .reference-zone-widget .preview .reference-decoration { background-color: "+o+"; }");var r=e.getColor(t.peekViewEditorMatchHighlightBorder) +;r&&n.addRule(".monaco-editor .reference-zone-widget .preview .reference-decoration { border: 2px solid "+r+"; box-sizing: border-box; }");var s=e.getColor(I.activeContrastBorder);s&&n.addRule(".monaco-editor .reference-zone-widget .ref-tree .referenceMatch { border: 1px dotted "+s+"; box-sizing: border-box; }");var a=e.getColor(t.peekViewResultsBackground);a&&n.addRule(".monaco-editor .reference-zone-widget .ref-tree { background-color: "+a+"; }");var l=e.getColor(t.peekViewResultsMatchForeground);l&&n.addRule(".monaco-editor .reference-zone-widget .ref-tree { color: "+l+"; }");var u=e.getColor(t.peekViewResultsFileForeground);u&&n.addRule(".monaco-editor .reference-zone-widget .ref-tree .reference-file { color: "+u+"; }");var d=e.getColor(t.peekViewResultsSelectionBackground);d&&n.addRule(".monaco-editor .reference-zone-widget .ref-tree .monaco-tree.focused .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) { background-color: "+d+"; }");var c=e.getColor(t.peekViewResultsSelectionForeground) +;c&&n.addRule(".monaco-editor .reference-zone-widget .ref-tree .monaco-tree.focused .monaco-tree-rows > .monaco-tree-row.selected:not(.highlighted) { color: "+c+" !important; }");var h=e.getColor(t.peekViewEditorBackground);h&&n.addRule(".monaco-editor .reference-zone-widget .preview .monaco-editor .monaco-editor-background,.monaco-editor .reference-zone-widget .preview .monaco-editor .inputarea.ime-input {\tbackground-color: "+h+";}");var p=e.getColor(t.peekViewEditorGutterBackground);p&&n.addRule(".monaco-editor .reference-zone-widget .preview .monaco-editor .margin {\tbackground-color: "+p+";}")})}),define(t[148],n([1,0,331,10,2,32,15,19,51,72,198,3,12,37]),function(e,t,n,i,o,r,s,l,h,p,f,g,m,v){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ctxReferenceSearchVisible=new l.RawContextKey("referenceSearchVisible",!1);var _=function(){function e(e,n,i,o,r,s,a,l){this._defaultTreeKeyboardSupport=e,this._editorService=o,this._notificationService=r,this._instantiationService=s, +this._storageService=a,this._configurationService=l,this._requestIdPool=0,this._disposables=[],this._ignoreModelChangeEvent=!1,this._editor=n,this._referenceSearchVisible=t.ctxReferenceSearchVisible.bindTo(i)}return e.get=function(t){return t.getContribution(e.ID)},e.prototype.getId=function(){return e.ID},e.prototype.dispose=function(){this._referenceSearchVisible.reset(),o.dispose(this._disposables),o.dispose(this._widget),o.dispose(this._model),this._widget=null,this._model=null,this._editor=null},e.prototype.toggleWidget=function(e,t,i){var o,r=this;if(this._widget&&(o=this._widget.position),this.closeWidget(),o&&e.containsPosition(o))return null;this._referenceSearchVisible.set(!0),this._disposables.push(this._editor.onDidChangeModelLanguage(function(){r.closeWidget()})),this._disposables.push(this._editor.onDidChangeModel(function(){r._ignoreModelChangeEvent||r.closeWidget()}));var s=JSON.parse(this._storageService.get("peekViewLayout",void 0,"{}")) +;this._widget=this._instantiationService.createInstance(f.ReferenceWidget,this._editor,this._defaultTreeKeyboardSupport,s),this._widget.setTitle(n.localize(0,null)),this._widget.show(e),this._disposables.push(this._widget.onDidClose(function(){t.cancel(),r._storageService.store("peekViewLayout",JSON.stringify(r._widget.layoutData)),r._widget=null,r.closeWidget()})),this._disposables.push(this._widget.onDidSelectReference(function(e){var t=e.element,n=e.kind;switch(n){case"open":if("editor"===e.source&&r._configurationService.getValue("editor.stablePeek"))break;case"side":r.openReference(t,"side"===n);break;case"goto":i.onGoto?i.onGoto(t):r._gotoReference(t)}}));var a=++this._requestIdPool;t.then(function(t){if(a===r._requestIdPool&&r._widget)return r._model&&r._model.dispose(),r._model=t,r._widget.setModel(r._model).then(function(){if(r._widget){r._widget.setMetaTitle(i.getMetaTitle(r._model));var t=r._editor.getModel().uri,n=new m.Position(e.startLineNumber,e.startColumn),o=r._model.nearestReference(t,n) +;if(o)return r._widget.setSelection(o)}})},function(e){r._notificationService.error(e)})},e.prototype.goToNextOrPreviousReference=function(e){return d(this,void 0,void 0,function(){var t,n,i;return c(this,function(o){switch(o.label){case 0:return this._model?(t=this._model.nearestReference(this._editor.getModel().uri,this._widget.position),n=this._model.nextOrPreviousReference(t,e),i=this._editor.hasTextFocus(),[4,this._widget.setSelection(n)]):[3,3];case 1:return o.sent(),[4,this._gotoReference(n)];case 2:o.sent(),i&&this._editor.focus(),o.label=3;case 3:return[2]}})})},e.prototype.closeWidget=function(){o.dispose(this._widget),this._widget=null,this._referenceSearchVisible.reset(),this._disposables=o.dispose(this._disposables),o.dispose(this._model),this._model=null,this._editor.focus(),this._requestIdPool+=1},e.prototype._gotoReference=function(e){var t=this;this._widget.hide(),this._ignoreModelChangeEvent=!0;var n=g.Range.lift(e.range).collapseToStart();return this._editorService.openCodeEditor({ +resource:e.uri,options:{selection:n}},this._editor).then(function(e){t._ignoreModelChangeEvent=!1,e&&e===t._editor?(t._widget.show(n),t._widget.focus()):t.closeWidget()},function(e){t._ignoreModelChangeEvent=!1,i.onUnexpectedError(e)})},e.prototype.openReference=function(e,t){var n=e.uri,i=e.range;this._editorService.openCodeEditor({resource:n,options:{selection:i}},this._editor,t),t||this.closeWidget()},e.ID="editor.contrib.referencesController",e=a([u(2,l.IContextKeyService),u(3,r.ICodeEditorService),u(4,v.INotificationService),u(5,s.IInstantiationService),u(6,p.IStorageService),u(7,h.IConfigurationService)],e)}();t.ReferencesController=_}),define(t[200],n([1,0,316,52,39,18,32,3,11,174,148,123,144,19,143,20,92,37,14]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m,v,_,y){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var C=function(){return function(e,t,n,i){void 0===e&&(e=!1),void 0===t&&(t=!1),void 0===n&&(n=!0),void 0===i&&(i=!0),this.openToSide=e,this.openInPeek=t,this.filterCurrent=n, +this.showMessage=i}}();t.DefinitionActionConfig=C;var b=function(e){function t(t,n){var i=e.call(this,n)||this;return i._configuration=t,i}return o(t,e),t.prototype.run=function(e,t){var n=this,i=e.get(_.INotificationService),o=e.get(a.ICodeEditorService),r=e.get(v.IProgressService),s=t.getModel(),u=t.getPosition(),d=this._getDeclarationsAtPosition(s,u).then(function(e){if(!s.isDisposed()&&t.getModel()===s){for(var i=-1,r=[],a=0;a1&&n.localize(2,null,e.references.length)},t.prototype._onResult=function(e,t,n){var o=this,r=n.getAriaMessage();if(i.alert(r),this._configuration.openInPeek)this._openInPeek(e,t,n);else{var s=n.nearestReference(t.getModel().uri,t.getPosition());this._openReference(t,e,s,this._configuration.openToSide).then(function(t){t&&n.references.length>1?o._openInPeek(e,t,n):n.dispose()})}},t.prototype._openReference=function(e,t,n,i){var o=n.uri,r=n.range;return t.openCodeEditor({resource:o,options:{selection:l.Range.collapseToStart(r),revealIfOpened:!0,revealInCenterIfOutsideViewport:!0}},e,i)},t.prototype._openInPeek=function(e,t,n){var i=this,o=c.ReferencesController.get(t);o?o.toggleWidget(t.getSelection(),y.createCancelablePromise(function(e){return Promise.resolve(n)}),{getMetaTitle:function(e){ +return i._getMetaTitle(e)},onGoto:function(n){return o.closeWidget(),i._openReference(t,e,n,!1)}}):n.dispose()},t}(u.EditorAction);t.DefinitionAction=b;var S=s.isWeb?2118:70,w=function(e){function t(){return e.call(this,new C,{id:t.ID,label:n.localize(3,null),alias:"Go to Definition",precondition:f.ContextKeyExpr.and(m.EditorContextKeys.hasDefinitionProvider,m.EditorContextKeys.isInEmbeddedEditor.toNegated()),kbOpts:{kbExpr:m.EditorContextKeys.editorTextFocus,primary:S,weight:100},menuOpts:{group:"navigation",order:1.1}})||this}return o(t,e),t.ID="editor.action.goToDeclaration",t}(b);t.GoToDefinitionAction=w;var E=function(e){function t(){return e.call(this,new C(!0),{id:t.ID,label:n.localize(4,null),alias:"Open Definition to the Side",precondition:f.ContextKeyExpr.and(m.EditorContextKeys.hasDefinitionProvider,m.EditorContextKeys.isInEmbeddedEditor.toNegated()),kbOpts:{kbExpr:m.EditorContextKeys.editorTextFocus,primary:r.KeyChord(2089,S),weight:100}})||this}return o(t,e), +t.ID="editor.action.openDeclarationToTheSide",t}(b);t.OpenDefinitionToSideAction=E;var L=function(e){function t(){return e.call(this,new C(void 0,!0,!1),{id:"editor.action.previewDeclaration",label:n.localize(5,null),alias:"Peek Definition",precondition:f.ContextKeyExpr.and(m.EditorContextKeys.hasDefinitionProvider,p.PeekContext.notInPeekEditor,m.EditorContextKeys.isInEmbeddedEditor.toNegated()),kbOpts:{kbExpr:m.EditorContextKeys.editorTextFocus,primary:582,linux:{primary:3140},weight:100},menuOpts:{group:"navigation",order:1.2}})||this}return o(t,e),t}(b);t.PeekDefinitionAction=L;var x=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e),t.prototype._getDeclarationsAtPosition=function(e,t){return d.getImplementationsAtPosition(e,t)},t.prototype._getNoResultFoundMessage=function(e){return e&&e.word?n.localize(6,null,e.word):n.localize(7,null)},t.prototype._getMetaTitle=function(e){return e.references.length>1&&n.localize(8,null,e.references.length)},t}(b) +;t.ImplementationAction=x;var N=function(e){function t(){return e.call(this,new C,{id:t.ID,label:n.localize(9,null),alias:"Go to Implementation",precondition:f.ContextKeyExpr.and(m.EditorContextKeys.hasImplementationProvider,m.EditorContextKeys.isInEmbeddedEditor.toNegated()),kbOpts:{kbExpr:m.EditorContextKeys.editorTextFocus,primary:2118,weight:100}})||this}return o(t,e),t.ID="editor.action.goToImplementation",t}(x);t.GoToImplementationAction=N;var I=function(e){function t(){return e.call(this,new C(!1,!0,!1),{id:t.ID,label:n.localize(10,null),alias:"Peek Implementation",precondition:f.ContextKeyExpr.and(m.EditorContextKeys.hasImplementationProvider,m.EditorContextKeys.isInEmbeddedEditor.toNegated()),kbOpts:{kbExpr:m.EditorContextKeys.editorTextFocus,primary:3142,weight:100}})||this}return o(t,e),t.ID="editor.action.peekImplementation",t}(x);t.PeekImplementationAction=I;var M=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return o(t,e), +t.prototype._getDeclarationsAtPosition=function(e,t){return d.getTypeDefinitionsAtPosition(e,t)},t.prototype._getNoResultFoundMessage=function(e){return e&&e.word?n.localize(11,null,e.word):n.localize(12,null)},t.prototype._getMetaTitle=function(e){return e.references.length>1&&n.localize(13,null,e.references.length)},t}(b);t.TypeDefinitionAction=M;var D=function(e){function t(){return e.call(this,new C,{id:t.ID,label:n.localize(14,null),alias:"Go to Type Definition",precondition:f.ContextKeyExpr.and(m.EditorContextKeys.hasTypeDefinitionProvider,m.EditorContextKeys.isInEmbeddedEditor.toNegated()),kbOpts:{kbExpr:m.EditorContextKeys.editorTextFocus,primary:0,weight:100},menuOpts:{group:"navigation",order:1.4}})||this}return o(t,e),t.ID="editor.action.goToTypeDefinition",t}(M);t.GoToTypeDefinitionAction=D;var T=function(e){function t(){return e.call(this,new C(!1,!0,!1),{id:t.ID,label:n.localize(15,null),alias:"Peek Type Definition", +precondition:f.ContextKeyExpr.and(m.EditorContextKeys.hasTypeDefinitionProvider,m.EditorContextKeys.isInEmbeddedEditor.toNegated()),kbOpts:{kbExpr:m.EditorContextKeys.editorTextFocus,primary:0,weight:100}})||this}return o(t,e),t.ID="editor.action.peekTypeDefinition",t}(M);t.PeekTypeDefinitionAction=T,u.registerEditorAction(w),u.registerEditorAction(E),u.registerEditorAction(L),u.registerEditorAction(N),u.registerEditorAction(I),u.registerEditorAction(D),u.registerEditorAction(T)}),define(t[554],n([1,0,317,14,10,79,13,64,3,17,23,11,174,2,107,16,22,68,200,169,12,156]),function(e,t,n,i,o,r,s,l,d,c,h,p,f,g,m,v,_,y,C,b,S){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var w=function(){function e(e,t,n){var r=this;this.textModelResolverService=t,this.modeService=n,this.toUnhook=[],this.decorations=[],this.editor=e,this.throttler=new i.Throttler;var s=new b.ClickLinkGesture(e);this.toUnhook.push(s),this.toUnhook.push(s.onMouseMoveOrRelevantKeyDown(function(e){var t=e[0],n=e[1] +;r.startFindDefinition(t,n)})),this.toUnhook.push(s.onExecute(function(e){r.isEnabled(e)&&r.gotoDefinition(e.target,e.hasSideBySideModifier).done(function(){r.removeDecorations()},function(e){r.removeDecorations(),o.onUnexpectedError(e)})})),this.toUnhook.push(s.onCancel(function(){r.removeDecorations(),r.currentWordUnderMouse=null}))}return e.prototype.startFindDefinition=function(e,t){var i=this;if(!this.isEnabled(e,t))return this.currentWordUnderMouse=null,void this.removeDecorations();var a=e.target.position,l=a?this.editor.getModel().getWordAtPosition(a):null;if(!l)return this.currentWordUnderMouse=null,void this.removeDecorations();if(!this.currentWordUnderMouse||this.currentWordUnderMouse.startColumn!==l.startColumn||this.currentWordUnderMouse.endColumn!==l.endColumn||this.currentWordUnderMouse.word!==l.word){this.currentWordUnderMouse=l;var u=new y.EditorState(this.editor,15);this.throttler.queue(function(){return u.validate(i.editor)?i.findDefinition(e.target):s.TPromise.wrap(null) +}).then(function(e){if(e&&e.length&&u.validate(i.editor))if(e.length>1)i.addDecoration(new d.Range(a.lineNumber,l.startColumn,a.lineNumber,l.endColumn),(new r.MarkdownString).appendText(n.localize(0,null,e.length)));else{var t=e[0];if(!t.uri)return;i.textModelResolverService.createModelReference(t.uri).then(function(e){if(e.object&&e.object.textEditorModel){var n=e.object.textEditorModel,o=t.range.startLineNumber;if(0!==n.getLineMaxColumn(o)){var s,u=i.getPreviewValue(n,o);s=t.origin?d.Range.lift(t.origin):new d.Range(a.lineNumber,l.startColumn,a.lineNumber,l.endColumn),i.addDecoration(s,(new r.MarkdownString).appendCodeblock(i.modeService.getModeIdByFilenameOrFirstLine(n.uri.fsPath),u)),e.dispose()}else e.dispose()}else e.dispose()})}else i.removeDecorations()}).done(void 0,o.onUnexpectedError)}},e.prototype.getPreviewValue=function(t,n){var i=this.getPreviewRangeBasedOnBrackets(t,n);i.endLineNumber-i.startLineNumber>=e.MAX_SOURCE_PREVIEW_LINES&&(i=this.getPreviewRangeBasedOnIndentation(t,n)) +;return this.stripIndentationFromPreviewRange(t,n,i)},e.prototype.stripIndentationFromPreviewRange=function(e,t,n){for(var i=e.getLineFirstNonWhitespaceColumn(t),o=t+1;oi)return new d.Range(n,1,i+1,1);s=t.findNextBracket(new S.Position(u,c))}return new d.Range(n,1,i+1,1)},e.prototype.addDecoration=function(e,t){var n={range:e,options:{inlineClassName:"goto-definition-link",hoverMessage:t}};this.decorations=this.editor.deltaDecorations(this.decorations,[n])},e.prototype.removeDecorations=function(){this.decorations.length>0&&(this.decorations=this.editor.deltaDecorations(this.decorations,[]))},e.prototype.isEnabled=function(e,t){return this.editor.getModel()&&e.isNoneOrSingleMouseDown&&e.target.type===h.MouseTargetType.CONTENT_TEXT&&(e.hasTriggerModifier||t&&t.keyCodeIsTriggerKey)&&c.DefinitionProviderRegistry.has(this.editor.getModel())},e.prototype.findDefinition=function(e){var t=this.editor.getModel();return t?f.getDefinitionsAtPosition(t,e.position):s.TPromise.as(null)},e.prototype.gotoDefinition=function(e,t){var n=this;this.editor.setPosition(e.position) +;var i=new C.DefinitionAction(new C.DefinitionActionConfig(t,!1,!0,!1),{alias:void 0,label:void 0,id:void 0,precondition:void 0});return this.editor.invokeWithinContext(function(e){return i.run(e,n.editor)})},e.prototype.getId=function(){return e.ID},e.prototype.dispose=function(){this.toUnhook=g.dispose(this.toUnhook)},e.ID="editor.contrib.gotodefinitionwithmouse",e.MAX_SOURCE_PREVIEW_LINES=8,e=a([u(1,m.ITextModelService),u(2,l.IModeService)],e)}();p.registerEditorContribution(w),v.registerThemingParticipant(function(e,t){var n=e.getColor(_.editorActiveLinkForeground);n&&t.addRule(".monaco-editor .goto-definition-link { color: "+n+" !important; }")})}),define(t[555],n([1,0,330,13,19,97,12,11,17,3,144,148,123,14,10,20,141,23,146,198,34,31,32,40]),function(e,t,n,i,r,s,l,d,c,h,p,f,g,m,v,_,y,C,b,S,w,E,L,x){"use strict";function N(e,t){I(e,function(e){return e.closeWidget()})}function I(e,t){var n=p.getOuterEditor(e);if(n){var i=f.ReferencesController.get(n);i&&t(i)}}function M(e,t,n){ +var i=c.ReferenceProviderRegistry.ordered(e).map(function(n){return m.asWinJsPromise(function(i){return n.provideReferences(e,t,{includeDeclaration:!0},i)}).then(function(e){if(Array.isArray(e))return e},function(e){v.onUnexpectedExternalError(e)})});return Promise.all(i).then(function(e){for(var t=[],n=0,i=e;n1&&n.localize(0,null,e.references.length)}};var D=function(){function e(e,t){e instanceof y.EmbeddedCodeEditorWidget&&p.PeekContext.inPeekEditor.bindTo(t)}return e.prototype.dispose=function(){},e.prototype.getId=function(){return e.ID},e.ID="editor.contrib.referenceController",e=a([u(1,r.IContextKeyService)],e)}();t.ReferenceController=D;var T=function(e){function i(){return e.call(this,{id:"editor.action.referenceSearch.trigger",label:n.localize(1,null),alias:"Find All References", +precondition:r.ContextKeyExpr.and(_.EditorContextKeys.hasReferenceProvider,p.PeekContext.notInPeekEditor,_.EditorContextKeys.isInEmbeddedEditor.toNegated()),kbOpts:{kbExpr:_.EditorContextKeys.editorTextFocus,primary:1094,weight:100},menuOpts:{group:"navigation",order:1.5}})||this}return o(i,e),i.prototype.run=function(e,n){var i=f.ReferencesController.get(n);if(i){var o=n.getSelection(),r=n.getModel(),s=m.createCancelablePromise(function(e){return M(r,o.getStartPosition()).then(function(e){return new g.ReferencesModel(e)})});i.toggleWidget(o,s,t.defaultReferenceSearchOptions)}},i}(d.EditorAction);t.ReferenceAction=T,d.registerEditorContribution(D),d.registerEditorAction(T);w.CommandsRegistry.registerCommand({id:"editor.action.findReferences",handler:function(e,n,o){if(!(n instanceof E.default))throw new Error("illegal argument, uri");if(!o)throw new Error("illegal argument, position");var r=e.get(L.ICodeEditorService);return r.openCodeEditor({resource:n},r.getFocusedCodeEditor()).then(function(e){ +if(C.isCodeEditor(e)){var n=f.ReferencesController.get(e);if(n){var r=m.createCancelablePromise(function(t){return M(e.getModel(),l.Position.lift(o)).then(function(e){return new g.ReferencesModel(e)})}),s=new h.Range(o.lineNumber,o.column,o.lineNumber,o.column);return i.TPromise.as(n.toggleWidget(s,r,t.defaultReferenceSearchOptions))}}})}}),w.CommandsRegistry.registerCommand({id:"editor.action.showReferences",handler:function(e,n,o,r){if(!(n instanceof E.default))throw new Error("illegal argument, uri expected");var s=e.get(L.ICodeEditorService);return s.openCodeEditor({resource:n},s.getFocusedCodeEditor()).then(function(e){if(C.isCodeEditor(e)){var n=f.ReferencesController.get(e);if(n)return i.TPromise.as(n.toggleWidget(new h.Range(o.lineNumber,o.column,o.lineNumber,o.column),m.createCancelablePromise(function(e){return Promise.resolve(new g.ReferencesModel(r))}),t.defaultReferenceSearchOptions)).then(function(){return!0})}})},description:{description:"Show references at a position in a file",args:[{ +name:"uri",description:"The text document in which to show references",constraint:E.default},{name:"position",description:"The position at which to show",constraint:l.Position.isIPosition},{name:"locations",description:"An array of locations.",constraint:Array}]}}),s.KeybindingsRegistry.registerCommandAndKeybindingRule({id:"goToNextReference",weight:250,primary:62,when:f.ctxReferenceSearchVisible,handler:function(e){I(e,function(e){e.goToNextOrPreviousReference(!0)})}}),s.KeybindingsRegistry.registerCommandAndKeybindingRule({id:"goToNextReferenceFromEmbeddedEditor",weight:150,primary:62,when:p.PeekContext.inPeekEditor,handler:function(e){I(e,function(e){e.goToNextOrPreviousReference(!0)})}}),s.KeybindingsRegistry.registerCommandAndKeybindingRule({id:"goToPreviousReference",weight:250,primary:1086,when:f.ctxReferenceSearchVisible,handler:function(e){I(e,function(e){e.goToNextOrPreviousReference(!1)})}}),s.KeybindingsRegistry.registerCommandAndKeybindingRule({id:"goToPreviousReferenceFromEmbeddedEditor", +weight:150,primary:1086,when:p.PeekContext.inPeekEditor,handler:function(e){I(e,function(e){e.goToNextOrPreviousReference(!1)})}}),s.KeybindingsRegistry.registerCommandAndKeybindingRule({id:"closeReferenceSearch",weight:250,primary:9,secondary:[1033],when:r.ContextKeyExpr.and(f.ctxReferenceSearchVisible,r.ContextKeyExpr.not("config.editor.stablePeek")),handler:N}),s.KeybindingsRegistry.registerCommandAndKeybindingRule({id:"closeReferenceSearchEditor",weight:-1,primary:9,secondary:[1033],when:r.ContextKeyExpr.and(p.PeekContext.inPeekEditor,r.ContextKeyExpr.not("config.editor.stablePeek")),handler:N}),s.KeybindingsRegistry.registerCommandAndKeybindingRule({id:"openReferenceToSide",weight:100,primary:2051,mac:{primary:259},when:r.ContextKeyExpr.and(f.ctxReferenceSearchVisible,S.ctxReferenceWidgetSearchTreeFocused),handler:function(e,t){var n=e.get(b.IListService),i=n.lastFocusedList&&n.lastFocusedList.getFocus();i instanceof g.OneReference&&I(e,function(e){return e.openReference(i,!0)})}}),t.provideReferences=M, +d.registerDefaultLanguageCommand("_executeReferenceProvider",function(e,t){return M(e,t,x.CancellationToken.None)})}),define(t[556],n([1,0,133,104,188,185,510,447,448,449,512,173,455,456,457,458,196,459,460,462,200,554,518,520,521,465,522,549,527,525,555,530,468,135,532,178,533,179,474]),function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0})}),define(t[557],n([1,0,32,15,19,51,72,11,37,148]),function(e,t,n,i,r,s,l,d,c,h){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var p=function(e){function t(t,n,i,o,r,s,a){return e.call(this,!0,t,n,i,o,r,s,a)||this}return o(t,e),t=a([u(1,r.IContextKeyService),u(2,n.ICodeEditorService),u(3,c.INotificationService),u(4,i.IInstantiationService),u(5,l.IStorageService),u(6,s.IConfigurationService)],t)}(h.ReferencesController);t.StandaloneReferencesController=p,d.registerEditorContribution(p)}), +define(t[128],n([1,0,118,31,13,34,415,419,154,49,147,23,9,438,2,7,57,97,409,39,418,18,3,37,12,126,17,53,349]),function(e,t,n,i,r,s,a,l,u,d,c,h,p,f,g,m,v,_,y,C,b,S,w,E,L,x,N,I,M){"use strict";function D(e){return e&&"object"==typeof e&&(!e.overrideIdentifier||"string"==typeof e.overrideIdentifier)&&(!e.resource||e.resource instanceof i.default)}Object.defineProperty(t,"__esModule",{value:!0});var T=function(){function e(e){this.model=e,this._onDispose=new p.Emitter}return Object.defineProperty(e.prototype,"textEditorModel",{get:function(){return this.model},enumerable:!0,configurable:!0}),e.prototype.dispose=function(){this._onDispose.fire()},e}();t.SimpleModel=T;var k=function(){function e(){}return e.prototype.setEditor=function(e){this.editor=e},e.prototype.createModelReference=function(e){var t,n=this;return(t=function(e,t,n){return h.isCodeEditor(e)?t(e):n(e)}(this.editor,function(t){return n.findModel(t,e)},function(t){return n.findModel(t.getOriginalEditor(),e)||n.findModel(t.getModifiedEditor(),e) +}))?r.TPromise.as(new g.ImmortalReference(new T(t))):r.TPromise.as(new g.ImmortalReference(null))},e.prototype.findModel=function(e,t){var n=e.getModel();return n.uri.toString()!==t.toString()?null:n},e}();t.SimpleEditorModelResolverService=k;var R=function(){function e(){}return e.prototype.showWhile=function(e,t){return null},e}();t.SimpleProgressService=R;var O=function(){return function(){}}();t.SimpleDialogService=O;var P=function(){function e(){}return e.prototype.info=function(e){return this.notify({severity:n.default.Info,message:e})},e.prototype.warn=function(e){return this.notify({severity:n.default.Warning,message:e})},e.prototype.error=function(e){return this.notify({severity:n.default.Error,message:e})},e.prototype.notify=function(t){switch(t.severity){case n.default.Error:console.error(t.message);break;case n.default.Warning:console.warn(t.message);break;default:console.log(t.message)}return e.NO_OP},e.NO_OP=new E.NoOpNotification,e}();t.SimpleNotificationService=P;var A=function(){ +function e(e){this._onWillExecuteCommand=new p.Emitter,this._instantiationService=e,this._dynamicCommands=Object.create(null)}return e.prototype.addCommand=function(e){var t=this,n=e.id;return this._dynamicCommands[n]=e,g.toDisposable(function(){delete t._dynamicCommands[n]})},e.prototype.executeCommand=function(e){for(var t=[],n=1;n0&&o[r-1]===d)){var c=u.startIndex;0===a?c=0:c "console.log", da "log" vor Kurzem vervollständigt wurde.','Vorschläge auf Grundlage vorheriger Präfixe auswählen, die diese Vorschläge vervollständigt haben. Beispiel: "co" -> "console" und "con" -> "const".',"Steuert, wie Vorschläge bei Anzeige der Vorschlagsliste vorab ausgewählt werden.","Schriftgröße für Vorschlagswidget","Zeilenhöhe für Vorschlagswidget","Controls whether filtering and sorting suggestions accounts for small typos.","Control whether an active snippet prevents quick suggestions.","Steuert, ob der Editor der Auswahl ähnelnde Übereinstimmungen hervorheben soll.","Steuert, ob der Editor das Vorkommen semantischer Symbole markieren soll.","Steuert die Anzahl von Dekorationen, die an derselben Position im Übersichtslineal angezeigt werden.","Steuert, ob um das Übersichtslineal ein Rahmen gezeichnet werden soll.","Steuert den Cursoranimationsstil.","Schriftart des Editors vergrößern, wenn das Mausrad verwendet und die STRG-TASTE gedrückt wird",'Steuert den Cursorstil. Gültige Werte sind "block", "block-outline", "line", "line-thin", "underline" und "underline-thin".','Steuert die Breite des Cursors, falls editor.cursorStyle auf "line" gestellt ist.',"Aktiviert Schriftartligaturen.","Steuert die Sichtbarkeit des Cursors im Übersichtslineal.","Render whitespace characters except for single spaces between words.",'Steuert, wie der Editor Leerzeichen rendert. Mögliche Optionen: "none", "boundary" und "all". Die Option "boundary" rendert keine einzelnen Leerzeichen zwischen Wörtern.',"Steuert, ob der Editor Steuerzeichen rendern soll.","Steuert, ob der Editor Einzugsführungslinien rendern soll.","Controls whether the editor should highlight the active indent guide.","Highlights both the gutter and the current line.",'Steuert, wie der Editor die aktuelle Zeilenhervorhebung rendern soll. Mögliche Werte sind "none", "gutter", "line" und "all".',"Steuert, ob der Editor CodeLens anzeigt.","Steuert, ob für den Editor Codefaltung aktiviert ist.",'Steuert die Art und Weise, wie Faltungsbereiche berechnet werden. "auto" verwendet eine sprachspezifische Strategie für die Codefaltung, sofern verfügbar. "indentation" erzwingt eine einrückungsbasierte Strategie zur Codefaltung.',"Steuert, ob die Falt-Steuerelemente an der Leiste automatisch ausgeblendet werden.","Übereinstimmende Klammern hervorheben, wenn eine davon ausgewählt wird.","Steuert, ob der Editor den vertikalen Glyphenrand rendert. Der Glyphenrand wird hauptsächlich zum Debuggen verwendet.","Das Einfügen und Löschen von Leerzeichen folgt auf Tabstopps.","Nachfolgendes automatisch eingefügtes Leerzeichen entfernen","Peek-Editoren geöffnet lassen, auch wenn auf ihren Inhalt doppelgeklickt oder die ESC-TASTE gedrückt wird.","Steuert, ob der Editor das Verschieben einer Auswahl per Drag and Drop zulässt.","Der Editor verwendet Plattform-APIs, um zu erkennen, wenn eine Sprachausgabe angefügt wird.","Der Editor wird durchgehend für die Verwendung mit einer Sprachausgabe optimiert.","Der Editor wird nie für die Verwendung mit einer Sprachausgabe optimiert. ","Steuert, ob der Editor in einem Modus ausgeführt werden soll, in dem er für die Sprachausgabe optimiert wird.","Controls fading out of unused code.","Steuert, ob der Editor Links erkennen und anklickbar machen soll","Steuert, ob der Editor die Inline-Farbdecorators und die Farbauswahl rendern soll.",'Ermöglicht die Code-Aktion "lightbulb"',"Ein Organisieren der Importe beim Speichern ausführen?","Arten von Codeaktionen, die beim Speichern ausgeführt werden sollen.","Timeout für Codeaktionen, die beim Speichern ausgeführt werden.","Steuert, ob die primäre Linux-Zwischenablage unterstützt werden soll.","Steuert, ob der Diff-Editor das Diff nebeneinander oder inline anzeigt.","Steuert, ob der Diff-Editor Änderungen in führenden oder nachgestellten Leerzeichen als Diffs anzeigt.","Spezielle Behandlung für große Dateien zum Deaktivieren bestimmter speicherintensiver Funktionen.",'Steuert, ob der Diff-Editor die Indikatoren "+" und "-" für hinzugefügte/entfernte Änderungen anzeigt.'], +"vs/editor/common/config/editorOptions":["Der Editor ist zurzeit nicht verfügbar. Drücken Sie Alt+F1 für Optionen.","Editor-Inhalt"],"vs/editor/common/controller/cursor":["Unerwartete Ausnahme beim Ausführen des Befehls."],"vs/editor/common/modes/modesRegistry":["Nur-Text"],"vs/editor/common/services/modelServiceImpl":["[{0}]\n{1}","[{0}] {1}"], +"vs/editor/common/view/editorColorRegistry":["Hintergrundfarbe zur Hervorhebung der Zeile an der Cursorposition.","Hintergrundfarbe für den Rahmen um die Zeile an der Cursorposition.","Hintergrundfarbe hervorgehobener Bereiche, beispielsweise durch Features wie Quick Open und Suche. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen. ","Hintergrundfarbe für den Rahmen um hervorgehobene Bereiche.","Farbe des Cursors im Editor.","Hintergrundfarbe vom Editor-Cursor. Erlaubt die Anpassung der Farbe von einem Zeichen, welches von einem Block-Cursor überdeckt wird.","Farbe der Leerzeichen im Editor.","Farbe der Führungslinien für Einzüge im Editor.","Farbe der Führungslinien für Einzüge im aktiven Editor.","Zeilennummernfarbe im Editor.","Zeilennummernfarbe der aktiven Editorzeile.",'ID ist veraltet. Verwenden Sie stattdessen "editorLineNumber.activeForeground".',"Zeilennummernfarbe der aktiven Editorzeile.","Farbe des Editor-Lineals.","Vordergrundfarbe der CodeLens-Links im Editor","Hintergrundfarbe für zusammengehörige Klammern","Farbe für zusammengehörige Klammern","Farbe des Rahmens für das Übersicht-Lineal.","Hintergrundfarbe der Editorleiste. Die Leiste enthält die Glyphenränder und die Zeilennummern.","Vordergrundfarbe von Fehlerunterstreichungen im Editor.","Rahmenfarbe von Fehlerunterstreichungen im Editor.","Vordergrundfarbe von Warnungsunterstreichungen im Editor.","Rahmenfarbe von Warnungsunterstreichungen im Editor.","Vordergrundfarbe von Informationsunterstreichungen im Editor.","Rahmenfarbe von Informationsunterstreichungen im Editor.","Vordergrundfarbe der Hinweisunterstreichungen im Editor.","Rahmenfarbe der Hinweisunterstreichungen im Editor.","Border of unnecessary code in the editor.","Opacity of unnecessary code in the editor.","Übersichtslineal-Markierungsfarbe für Fehler.","Übersichtslineal-Markierungsfarbe für Warnungen.","Übersichtslineal-Markierungsfarbe für Informationen."], +"vs/editor/contrib/bracketMatching/bracketMatching":["Übersichtslineal-Markierungsfarbe für zusammengehörige Klammern.","Gehe zu Klammer","Auswählen bis Klammer"],"vs/editor/contrib/caretOperations/caretOperations":["Caretzeichen nach links verschieben","Caretzeichen nach rechts verschieben"],"vs/editor/contrib/caretOperations/transpose":["Buchstaben austauschen"],"vs/editor/contrib/clipboard/clipboard":["Ausschneiden","Cu&&t","Kopieren","&&Copy","Einfügen","&&Paste","Mit Syntaxhervorhebung kopieren"],"vs/editor/contrib/codeAction/codeActionCommands":["Korrekturen anzeigen ({0})","Korrekturen anzeigen","Schnelle Problembehebung …","Keine Codeaktionen verfügbar","Keine Codeaktionen verfügbar","Refactoring durchführen...","Keine Refactorings verfügbar","Quellaktion…","Keine Quellaktionen verfügbar","Importe organisieren","Keine Aktion zum Organisieren von Importen verfügbar"], +"vs/editor/contrib/comment/comment":["Zeilenkommentar umschalten","&&Toggle Line Comment","Zeilenkommentar hinzufügen","Zeilenkommentar entfernen","Blockkommentar umschalten","Toggle &&Block Comment"],"vs/editor/contrib/contextmenu/contextmenu":["Editor-Kontextmenü anzeigen"],"vs/editor/contrib/cursorUndo/cursorUndo":["Soft Undo"],"vs/editor/contrib/find/findController":["Suchen","&&Find","Mit Auswahl suchen","Nächstes Element suchen","Vorheriges Element suchen","Nächste Auswahl suchen","Vorherige Auswahl suchen","Ersetzen","&&Replace"],"vs/editor/contrib/find/findWidget":["Suchen","Suchen","Vorherige Übereinstimmung","Nächste Übereinstimmung","In Auswahl suchen","Schließen","Ersetzen","Ersetzen","Ersetzen","Alle ersetzen","Ersetzen-Modus wechseln","Nur die ersten {0} Ergebnisse wurden hervorgehoben, aber alle Suchoperationen werden auf dem gesamten Text durchgeführt.","{0} von {1}","Keine Ergebnisse"], +"vs/editor/contrib/folding/folding":["Auffalten","Faltung rekursiv aufheben","Falten","Rekursiv falten","Alle Blockkommentare falten","Alle Regionen falten","Alle Regionen auffalten","Alle falten","Alle auffalten","Faltebene {0}"],"vs/editor/contrib/fontZoom/fontZoom":["Editorschriftart vergrößern","Editorschriftart verkleinern","Editor Schriftart Vergrößerung zurücksetzen"],"vs/editor/contrib/format/formatActions":["1 Formatierung in Zeile {0} vorgenommen","{0} Formatierungen in Zeile {1} vorgenommen","1 Formatierung zwischen Zeilen {0} und {1} vorgenommen","{0} Formatierungen zwischen Zeilen {1} und {2} vorgenommen",'Es ist kein Formatierer für "{0}"-Dateien installiert. ',"Dokument formatieren",'Es ist kein Dokumentformatierer für "{0}"-Dateien installiert.',"Auswahl formatieren",'Es ist kein Auswahl-Formatierer für "{0}"-Dateien installiert. '], +"vs/editor/contrib/goToDefinition/goToDefinitionCommands":['Keine Definition gefunden für "{0}".',"Keine Definition gefunden"," – {0} Definitionen","Gehe zu Definition","Definition an der Seite öffnen","Peek-Definition",'Keine Implementierung gefunden für "{0}"',"Keine Implementierung gefunden","{0} Implementierungen","Zur Implementierung wechseln","Vorschau der Implementierung anzeigen",'Keine Typendefinition gefunden für "{0}"',"Keine Typendefinition gefunden","{0} Typdefinitionen","Zur Typdefinition wechseln","Vorschau der Typdefinition anzeigen"],"vs/editor/contrib/goToDefinition/goToDefinitionMouse":["Klicken Sie, um {0} Definitionen anzuzeigen."],"vs/editor/contrib/gotoError/gotoError":["Gehe zu nächstem Problem (Fehler, Warnung, Information)","Gehe zu vorigem Problem (Fehler, Warnung, Information)","Gehe zu dem nächsten Problem in den Dateien (Fehler, Warnung, Info) ","Gehe zu dem vorherigen Problem in den Dateien (Fehler, Warnung, Info) "], +"vs/editor/contrib/gotoError/gotoErrorWidget":["({0}/{1})","Editormarkierung: Farbe bei Fehler des Navigationswidgets.","Editormarkierung: Farbe bei Warnung des Navigationswidgets.","Editormarkierung: Farbe bei Warnung des Navigationswidgets.","Editormarkierung: Hintergrund des Navigationswidgets."],"vs/editor/contrib/hover/hover":["Hovern anzeigen"],"vs/editor/contrib/hover/modesContentHover":["Wird geladen..."],"vs/editor/contrib/inPlaceReplace/inPlaceReplace":["Durch vorherigen Wert ersetzen","Durch nächsten Wert ersetzen"], +"vs/editor/contrib/linesOperations/linesOperations":["Zeile nach oben kopieren","&&Copy Line Up","Zeile nach unten kopieren","Co&&py Line Down","Zeile nach oben verschieben","Mo&&ve Line Up","Zeile nach unten verschieben","Move &&Line Down","Zeilen aufsteigend sortieren","Zeilen absteigend sortieren","Nachgestelltes Leerzeichen kürzen","Zeile löschen","Zeileneinzug","Zeile ausrücken","Zeile oben einfügen","Zeile unten einfügen","Alle übrigen löschen","Alle rechts löschen","Zeilen verknüpfen","Zeichen um den Cursor herum transponieren","In Großbuchstaben umwandeln","In Kleinbuchstaben umwandeln"], +"vs/editor/contrib/links/links":["BEFEHLSTASTE + Mausklick zum Aufrufen des Links","STRG + Mausklick zum Aufrufen des Links","Cmd + Klick um Befehl auszuführen","Ctrl + Klick um Befehl auszuführen.","WAHLTASTE + Klicken, um Link zu folgen","ALT + Mausklick zum Aufrufen des Links","WAHLTASTE + Klicken, um Befehl auszuführen","Alt + Klick um Befehl auszuführen.","Fehler beim Öffnen dieses Links, weil er nicht wohlgeformt ist: {0}","Fehler beim Öffnen dieses Links, weil das Ziel fehlt.","Link öffnen"],"vs/editor/contrib/message/messageController":["Ein Bearbeiten ist im schreibgeschützten Editor nicht möglich"], +"vs/editor/contrib/multicursor/multicursor":["Cursor oberhalb hinzufügen","&&Add Cursor Above","Cursor unterhalb hinzufügen","A&&dd Cursor Below","Cursor an Zeilenenden hinzufügen","Add C&&ursors to Line Ends","Auswahl zur nächsten Übereinstimmungssuche hinzufügen","Add &&Next Occurrence","Letzte Auswahl zu vorheriger Übereinstimmungssuche hinzufügen","Add P&&revious Occurrence","Letzte Auswahl in nächste Übereinstimmungssuche verschieben","Letzte Auswahl in vorherige Übereinstimmungssuche verschieben","Alle Vorkommen auswählen und Übereinstimmung suchen","Select All &&Occurrences","Alle Vorkommen ändern"],"vs/editor/contrib/parameterHints/parameterHints":["Parameterhinweise auslösen"],"vs/editor/contrib/parameterHints/parameterHintsWidget":["{0}, Hinweis"],"vs/editor/contrib/referenceSearch/peekViewWidget":["Schließen"],"vs/editor/contrib/referenceSearch/referenceSearch":[" – {0} Verweise","Alle Verweise suchen"],"vs/editor/contrib/referenceSearch/referencesController":["Wird geladen..."], +"vs/editor/contrib/referenceSearch/referencesModel":["Symbol in {0} in Zeile {1}, Spalte {2}","1 Symbol in {0}, vollständiger Pfad {1}","{0} Symbole in {1}, vollständiger Pfad {2}","Es wurden keine Ergebnisse gefunden.","1 Symbol in {0} gefunden","{0} Symbole in {1} gefunden","{0} Symbole in {1} Dateien gefunden"], +"vs/editor/contrib/referenceSearch/referencesWidget":["Fehler beim Auflösen der Datei.","{0} Verweise","{0} Verweis","Keine Vorschau verfügbar.","Verweise","Keine Ergebnisse","Verweise","Hintergrundfarbe des Titelbereichs der Peek-Ansicht.","Farbe des Titels in der Peek-Ansicht.","Farbe der Titelinformationen in der Peek-Ansicht.","Farbe der Peek-Ansichtsränder und des Pfeils.","Hintergrundfarbe der Ergebnisliste in der Peek-Ansicht.","Vordergrundfarbe für Zeilenknoten in der Ergebnisliste der Peek-Ansicht.","Vordergrundfarbe für Dateiknoten in der Ergebnisliste der Peek-Ansicht.","Hintergrundfarbe des ausgewählten Eintrags in der Ergebnisliste der Peek-Ansicht.","Vordergrundfarbe des ausgewählten Eintrags in der Ergebnisliste der Peek-Ansicht.","Hintergrundfarbe des Peek-Editors.","Hintergrundfarbe der Leiste im Peek-Editor.","Farbe für Übereinstimmungsmarkierungen in der Ergebnisliste der Peek-Ansicht.","Farbe für Übereinstimmungsmarkierungen im Peek-Editor.","Rahmen für Übereinstimmungsmarkierungen im Peek-Editor."], +"vs/editor/contrib/rename/rename":["Kein Ergebnis.",'"{0}" erfolgreich in "{1}" umbenannt. Zusammenfassung: {2}',"Fehler beim Ausführen der Umbenennung.","Symbol umbenennen"],"vs/editor/contrib/rename/renameInputField":["Benennen Sie die Eingabe um. Geben Sie einen neuen Namen ein, und drücken Sie die EINGABETASTE, um den Commit auszuführen."],"vs/editor/contrib/smartSelect/smartSelect":["Auswahl erweitern","&&Expand Selection","Auswahl verkleinern","&&Shrink Selection"],"vs/editor/contrib/snippet/snippetVariables":["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag","So","Mo","Di","Mi","Do","Fr","Sa","Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember","Jan","Feb","Mar","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],"vs/editor/contrib/suggest/suggestController":['Durch Annahme von "{0}" wurde folgender Text eingefügt: {1}',"Vorschlag auslösen"], +"vs/editor/contrib/suggest/suggestWidget":["Hintergrundfarbe des Vorschlagswidgets.","Rahmenfarbe des Vorschlagswidgets.","Vordergrundfarbe des Vorschlagswidgets.","Hintergrundfarbe des ausgewählten Eintrags im Vorschlagswidget.","Farbe der Trefferhervorhebung im Vorschlagswidget.","Mehr anzeigen...{0}","{0}, Vorschlag, hat Details","{0}, Vorschlag","Weniger anzeigen...{0}","Wird geladen...","Keine Vorschläge.","{0}, angenommen","{0}, Vorschlag, hat Details","{0}, Vorschlag"],"vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode":["TAB-Umschalttaste verschiebt Fokus"], +"vs/editor/contrib/wordHighlighter/wordHighlighter":["Hintergrundfarbe eines Symbols bei Lesezugriff, beispielsweise dem Lesen einer Variable. Die Farbe muss durchsichtig sein, um nicht dahinterliegende Dekorationen zu verbergen.","Hintergrundfarbe eines Symbols bei Schreibzugriff, beispielsweise dem Schreiben einer Variable. Die Farbe muss durchsichtig sein, um nicht dahinterliegende Dekorationen zu verbergen.","Randfarbe eines Symbols beim Lesezugriff, wie etwa beim Lesen einer Variablen.","Randfarbe eines Symbols beim Schreibzugriff, wie etwa beim Schreiben einer Variablen.","Übersichtslineal-Markierungsfarbe für Symbolhervorhebungen. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen.","Übersichtslineal-Markierungsfarbe für Schreibzugriffs-Symbolhervorhebungen. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen.","Gehe zur nächsten Symbolhervorhebungen","Gehe zur vorherigen Symbolhervorhebungen"], +"vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp":["No selection","Line {0}, Column {1} ({2} selected)","Line {0}, Column {1}","{0} selections ({1} characters selected)","{0} selections","Now changing the setting `accessibilitySupport` to 'on'.","Now opening the Editor Accessibility documentation page."," in a read-only pane of a diff editor."," in a pane of a diff editor."," in a read-only code editor"," in a code editor","To configure the editor to be optimized for usage with a Screen Reader press Command+E now.","To configure the editor to be optimized for usage with a Screen Reader press Control+E now.","The editor is configured to be optimized for usage with a Screen Reader.","The editor is configured to never be optimized for usage with a Screen Reader, which is not the case at this time.","Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.","Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.","Press Command+H now to open a browser window with more information related to editor accessibility.","Press Control+H now to open a browser window with more information related to editor accessibility.","You can dismiss this tooltip and return to the editor by pressing Escape or Shift+Escape.","Show Accessibility Help"], +"vs/editor/standalone/browser/inspectTokens/inspectTokens":["Developer: Inspect Tokens"],"vs/editor/standalone/browser/quickOpen/gotoLine":["Go to line {0} and character {1}","Go to line {0}","Type a line number between 1 and {0} to navigate to","Type a character between 1 and {0} to navigate to","Go to line {0}","Type a line number, followed by an optional colon and a character number to navigate to","Go to Line..."],"vs/editor/standalone/browser/quickOpen/quickCommand":["{0}, commands","Type the name of an action you want to execute","Command Palette"],"vs/editor/standalone/browser/quickOpen/quickOutline":["{0}, symbols","Type the name of an identifier you wish to navigate to","Go to Symbol...","symbols ({0})","modules ({0})","classes ({0})","interfaces ({0})","methods ({0})","functions ({0})","properties ({0})","variables ({0})","variables ({0})","constructors ({0})","calls ({0})"],"vs/editor/standalone/browser/simpleServices":["Made {0} edits in {1} files"], +"vs/editor/standalone/browser/standaloneCodeEditor":["Editor content","Press Ctrl+F1 for Accessibility Options.","Press Alt+F1 for Accessibility Options."],"vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast":["Toggle High Contrast Theme"],"vs/platform/configuration/common/configurationRegistry":["Standard-Konfiguration überschreibt","Zu überschreibende Einstellungen für Sprache {0} konfigurieren.","Zu überschreibende Editor-Einstellungen für eine Sprache konfigurieren.",'"{0}" kann nicht registriert werden. Die Eigenschaft stimmt mit dem Eigenschaftsmuster \'\\\\[.*\\\\]$\' zum Beschreiben sprachspezifischer Editor-Einstellungen überein. Verwenden Sie den Beitrag "configurationDefaults".','"{0}" kann nicht registriert werden. Diese Eigenschaft ist bereits registriert.'],"vs/platform/keybinding/common/abstractKeybindingService":["({0}) wurde gedrückt. Es wird auf die zweite Taste der Kombination gewartet...","Die Tastenkombination ({0}, {1}) ist kein Befehl."], +"vs/platform/list/browser/listService":["Workbench",'Ist unter Windows und Linux der Taste "STRG" und unter macOSX der Befehlstaste zugeordnet.','Ist unter Windows und Linux der Taste "Alt" und unter macOSX der Wahltaste zugeordnet. ','Der Modifizierer zum Hinzufügen eines Elements in Bäumen und Listen zu einer Mehrfachauswahl mit der Maus (zum Beispiel im Explorer, in geöffneten Editoren und in der SCM-Ansicht). "ctrlCmd" wird unter Windows und Linux der Taste "STRG" und unter macOSX der Befehlstaste zugeordnet. Die Mausbewegung "Seitlich öffnen" wird – sofern unterstützt – so angepasst, dass kein Konflikt mit dem Modifizierer zur Mehrfachauswahl entsteht.','Steuert, wie Elemente in Bäumen und Listen mithilfe der Maus geöffnet werden (sofern unterstützt). Legen Sie "singleClick" fest, um Elemente mit einem einzelnen Mausklick zu öffnen, und "doubleClick", damit sie nur mit einem doppelten Mausklick geöffnet werden. Bei übergeordneten Elementen, deren untergeordnete Elemente sich in Bäumen befinden, steuert diese Einstellung, ob ein Einfachklick oder ein Doppelklick das übergeordnete Elemente erweitert. Beachten Sie, dass einige Bäume und Listen diese Einstellung ggf. ignorieren, wenn sie nicht zutrifft.',"Steuert, ob Bäume horizontales Scrollen in der Workbench unterstützen."], +"vs/platform/markers/common/markers":["Fehler","Warnung","Info"], +"vs/platform/theme/common/colorRegistry":["In der Workbench verwendete Farben.","Allgemeine Vordergrundfarbe. Diese Farbe wird nur verwendet, wenn sie nicht durch eine Komponente überschrieben wird.","Allgemeine Vordergrundfarbe. Diese Farbe wird nur verwendet, wenn sie nicht durch eine Komponente überschrieben wird.","Allgemeine Rahmenfarbe für fokussierte Elemente. Diese Farbe wird nur verwendet, wenn sie nicht durch eine Komponente überschrieben wird.","Ein zusätzlicher Rahmen um Elemente, mit dem diese von anderen getrennt werden, um einen größeren Kontrast zu erreichen.","Ein zusätzlicher Rahmen um aktive Elemente, mit dem diese von anderen getrennt werden, um einen größeren Kontrast zu erreichen.","Vordergrundfarbe für Links im Text.","Hintergrundfarbe für Code-Blöcke im Text.","Schattenfarbe von Widgets wie zum Beispiel Suchen/Ersetzen innerhalb des Editors.","Hintergrund für Eingabefeld.","Vordergrund für Eingabefeld.","Rahmen für Eingabefeld.","Rahmenfarbe für aktivierte Optionen in Eingabefeldern.","Hintergrundfarbe bei der Eingabevalidierung für den Schweregrad der Information.","Rahmenfarbe bei der Eingabevalidierung für den Schweregrad der Information.","Hintergrundfarbe bei der Eingabevalidierung für den Schweregrad der Warnung.","Rahmenfarbe bei der Eingabevalidierung für den Schweregrad der Warnung.","Hintergrundfarbe bei der Eingabevalidierung für den Schweregrad des Fehlers.","Rahmenfarbe bei der Eingabevalidierung für den Schweregrad des Fehlers.","Hintergrundfarbe der Liste/Struktur für das fokussierte Element, wenn die Liste/Struktur aktiv ist. Eine aktive Liste/Struktur hat Tastaturfokus, eine inaktive hingegen nicht.","Vordergrundfarbe der Liste/Struktur für das fokussierte Element, wenn die Liste/Struktur aktiv ist. Eine aktive Liste/Struktur hat Tastaturfokus, eine inaktive hingegen nicht.","Hintergrundfarbe der Liste/Struktur für das ausgewählte Element, wenn die Liste/Struktur aktiv ist. Eine aktive Liste/Struktur hat Tastaturfokus, eine inaktive hingegen nicht.","Vordergrundfarbe der Liste/Struktur für das ausgewählte Element, wenn die Liste/Struktur aktiv ist. Eine aktive Liste/Struktur hat Tastaturfokus, eine inaktive hingegen nicht.","Hintergrundfarbe der Liste/Struktur für das ausgewählte Element, wenn die Liste/Struktur inaktiv ist. Eine aktive Liste/Struktur hat Tastaturfokus, eine inaktive hingegen nicht.","Liste/Baumstruktur - Vordergrundfarbe für das ausgewählte Element, wenn die Liste/Baumstruktur inaktiv ist. Eine aktive Liste/Baumstruktur hat Tastaturfokus, eine inaktive hingegen nicht.","List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.","Hintergrund der Liste/Struktur, wenn mit der Maus auf Elemente gezeigt wird.","Vordergrund der Liste/Struktur, wenn mit der Maus auf Elemente gezeigt wird.","Drag & Drop-Hintergrund der Liste/Struktur, wenn Elemente mithilfe der Maus verschoben werden.","Vordergrundfarbe der Liste/Struktur zur Trefferhervorhebung beim Suchen innerhalb der Liste/Struktur.","Schnellauswahlfarbe für das Gruppieren von Bezeichnungen.","Schnellauswahlfarbe für das Gruppieren von Rahmen.","Badge - Hintergrundfarbe. Badges sind kurze Info-Texte, z. B. für Anzahl Suchergebnisse.","Badge - Vordergrundfarbe. Badges sind kurze Info-Texte, z. B. für Anzahl Suchergebnisse.","Schatten der Scrollleiste, um anzuzeigen, dass die Ansicht gescrollt wird.","Hintergrundfarbe vom Scrollbar-Schieber","Hintergrundfarbe des Schiebereglers, wenn darauf gezeigt wird.","Hintergrundfarbe des Schiebereglers, wenn darauf geklickt wird.","Hintergrundfarbe des Fortschrittbalkens, der für lang ausgeführte Vorgänge angezeigt werden kann.","Hintergrundfarbe des Editors.","Standardvordergrundfarbe des Editors.","Hintergrundfarbe von Editor-Widgets wie zum Beispiel Suchen/Ersetzen.","Rahmenfarbe von Editorwigdets. Die Farbe wird nur verwendet, wenn für das Widget ein Rahmen verwendet wird und die Farbe nicht von einem Widget überschrieben wird.","Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget.","Farbe der Editor-Auswahl.","Farbe des gewählten Text für einen hohen Kontrast","Farbe der Auswahl in einem inaktiven Editor. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen. ","Farbe für Bereiche, deren Inhalt der Auswahl entspricht. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen.","Randfarbe für Bereiche, deren Inhalt der Auswahl entspricht.","Farbe des aktuellen Suchergebnisses.","Farbe der anderen Suchergebnisse. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen. ","Farbe des Bereichs zur Einschränkung der Suche. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen.","Randfarbe des aktuellen Suchergebnisses.","Randfarbe der anderen Suchtreffer.","Rahmenfarbe des Bereichs zur Einschränkung der Suche. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen.","Hervorhebung eines Worts, unter dem ein Mauszeiger angezeigt wird. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen. ","Background color of the editor hover.","Rahmenfarbe des Editor-Mauszeigers.","Farbe der aktiven Links.","Hintergrundfarbe für eingefügten Text. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen. ","Hintergrundfarbe für entfernten Text. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen. ","Konturfarbe für eingefügten Text.","Konturfarbe für entfernten Text.","Border color between the two text editors.","Übersichtslineal-Markierungsfarbe für Suchübereinstimmungen. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen.","Übersichtslineal-Markierungsfarbe für Auswahlhervorhebungen. Die Farbe muss durchsichtig sein, um dahinterliegende Dekorationen nicht zu verbergen."] +}); +//# sourceMappingURL=../../../min-maps/vs/editor/editor.main.nls.de.js.map \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/editor/editor.main.nls.es.js b/public/react/public/js/monaco/vs/editor/editor.main.nls.es.js new file mode 100755 index 000000000..8a44a8696 --- /dev/null +++ b/public/react/public/js/monaco/vs/editor/editor.main.nls.es.js @@ -0,0 +1,32 @@ +/*!----------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Version: 0.14.6(6c8f02b41db9ae5c4d15df767d47755e5c73b9d5) + * Released under the MIT license + * https://github.com/Microsoft/vscode/blob/master/LICENSE.txt + *-----------------------------------------------------------*/ +define("vs/editor/editor.main.nls.es",{"vs/base/browser/ui/actionbar/actionbar":["{0} ({1})"],"vs/base/browser/ui/aria/aria":["{0} (ocurrió de nuevo)","{0} (occurred {1} times)"],"vs/base/browser/ui/findinput/findInput":["entrada"],"vs/base/browser/ui/findinput/findInputCheckboxes":["Coincidir mayúsculas y minúsculas","Solo palabras completas","Usar expresión regular"],"vs/base/browser/ui/inputbox/inputBox":["Error: {0}","Advertencia: {0}","Información: {0}"],"vs/base/browser/ui/list/listWidget":["{0}. Use the navigation keys to navigate."],"vs/base/browser/ui/menu/menu":["{0} ({1})"],"vs/base/common/keybindingLabels":["Ctrl","Mayús","Alt","Windows","Ctrl","Mayús","Alt","Super","Control","Mayús","Alt","Comando","Control","Mayús","Alt","Windows","Control","Mayús","Alt","Super"],"vs/base/common/severity":["Error","Advertencia","Información"],"vs/base/parts/quickopen/browser/quickOpenModel":["{0}, selector","selector"], +"vs/base/parts/quickopen/browser/quickOpenWidget":["Selector rápido. Escriba para restringir los resultados.","Selector rápido","{0} Results"],"vs/editor/browser/controller/coreCommands":["&&Select All","&&Undo","&&Redo"],"vs/editor/browser/widget/codeEditorWidget":["El número de cursores se ha limitado a {0}."],"vs/editor/browser/widget/diffEditorWidget":["Los archivos no se pueden comparar porque uno de ellos es demasiado grande."],"vs/editor/browser/widget/diffReview":["Cerrar","sin líneas","1 línea","{0} líneas","Diferencia {0} de {1}: original {2}, {3}, modificado {4}, {5}","vacío","original {0}, modificado {1}: {2}","+ modificado {0}: {1}","- original {0}: {1}","Ir a la siguiente diferencia","Ir a la diferencia anterior"], +"vs/editor/common/config/commonEditorConfig":["Editor","Controla la familia de fuentes.","Controla el grosor de la fuente.","Controla el tamaño de fuente en píxeles.","Controla la altura de línea. Utilice 0 para calcular el valor de lineHeight a partir de fontSize.","Controla el espacio entre letras en pixels.","Los números de línea no se muestran.","Los números de línea se muestran como un número absoluto.","Los números de línea se muestran como distancia en líneas a la posición del cursor.","Los números de línea se muestran cada 10 líneas.","Controla la visualización de los números de línea.","Representar reglas verticales después de un cierto número de caracteres monoespacio. Usar multiples valores para multiples reglas. No se dibuja ninguna regla si la matriz esta vacía.","Caracteres que se usarán como separadores de palabras al realizar operaciones o navegaciones relacionadas con palabras.","El número de espacios a los que equivale una tabulación. Este valor se invalida según el contenido del archivo cuando `editor.detectIndentation` está activado.",'Se esperaba "number". Tenga en cuenta que el ajuste "editor.detectIndentation" ha reemplazado al valor "auto".','Insertar espacios al presionar TAB. Este valor se invalida en función del contenido del archivo cuando "editor.detectIndentation" está activado.','Se esperaba "boolean". Tenga en cuenta que el ajuste "editor.detectIndentation" ha reemplazado al valor "auto".',"Al abrir un archivo, se detectarán `editor.tabSize` y `editor.insertSpaces` en función del contenido del archivo.","Controla si las selecciones tienen esquinas redondeadas","Controla si el editor se seguirá desplazando después de la última línea","Controla el número de caracteres adicionales a partir del cual el editor se desplazará horizontalmente","Controla si el editor se desplaza con una animación","Controla si se muestra el minimapa","Controla en qué lado se muestra el minimapa.","Controla si el control deslizante del minimapa es ocultado automáticamente.","Presentar los caracteres reales en una línea (por oposición a bloques de color)","Limitar el ancho del minimapa para presentar como mucho un número de columnas determinado","Controls whether the hover is shown.","Time delay in milliseconds after which to the hover is shown.","Controls whether the hover should remain visible when mouse is moved over it.","Controla si se inicializa la cadena de búsqueda en Buscar widget en la selección del editor","Controla si el indicador Buscar en selección se activa cuando se seleccionan varios caracteres o líneas de texto en el editor","Controla si el widget de búsqueda debería leer o modificar el portapapeles de busqueda compartido en macOS","Las líneas no se ajustarán nunca.","Las líneas se ajustarán en el ancho de la ventanilla.",'Las líneas se ajustarán en "editor.wordWrapColumn".','Las líneas se ajustarán al valor que sea inferior: el tamaño de la ventanilla o el valor de "editor.wordWrapColumn".','Controla cómo se deben ajustar las líneas. Pueden ser:\n - "off" (deshabilitar ajuste),\n - "on" (ajuste de ventanilla),\n - "wordWrapColumn" (ajustar en "editor.wordWrapColumn") o\n - "bounded" (ajustar en la parte mínima de la ventanilla y "editor.wordWrapColumn").',"Controls the wrapping column of the editor when `editor.wordWrap` is 'wordWrapColumn' or 'bounded'.","No indentation. Wrapped lines begin at column 1.","Wrapped lines get the same indentation as the parent.","Wrapped lines get +1 indentation toward the parent.","Wrapped lines get +2 indentation toward the parent.","Controla el sangrado de las líneas ajustadas. Puede ser uno de 'none', ' same ', ' indent' o ' deepIndent '.","Se utilizará un multiplicador en los eventos de desplazamiento de la rueda del mouse `deltaX` y `deltaY`",'Se asigna a "Control" en Windows y Linux y a "Comando" en macOS.','Se asigna a "Alt" en Windows y Linux y a "Opción" en macOS.','El modificador que se usará para agregar varios cursores con el mouse. "ctrlCmd" se asigna a "Control" en Windows y Linux y a "Comando" en macOS. Los gestos del mouse "Ir a la definición" y "Abrir vínculo" se adaptarán de modo que no entren en conflicto con el modificador multicurso',"Combinar varios cursores cuando se solapan.","Habilita sugerencias rápidas en las cadenas.","Habilita sugerencias rápidas en los comentarios.","Habilita sugerencias rápidas fuera de las cadenas y los comentarios.","Controla si las sugerencias deben mostrarse automáticamente mientras se escribe","Controla el retardo en ms tras el cual aparecerán sugerencias rápidas","Habilita el desplegable que muestra documentación de los parámetros e información de los tipos mientras escribe","Controla si el editor debe cerrar automáticamente los corchetes después de abrirlos","Controla si el editor debe dar formato automáticamente a la línea después de escribirla","Controla si el editor debe formatear automáticamente el contenido pegado. Debe haber disponible un formateador capaz de aplicar formato a un intervalo dentro de un documento.","Controla si el editor debería ajustar automáticamente la sangría cuando los usuarios escriben, pegan o mueven líneas. Las reglas de sangría del idioma deben estar disponibles","Controla si las sugerencias deben aparecer de forma automática al escribir caracteres desencadenadores","Only accept a suggestion with `Enter` when it makes a textual change.",'Controla si las sugerencias deben aceptarse en "Entrar" (además de "TAB"). Ayuda a evitar la ambigüedad entre insertar nuevas líneas o aceptar sugerencias. El valor "smart" significa que solo se acepta una sugerencia con Entrar cuando se realiza un cambio textual.','Controla si se deben aceptar sugerencias en los caracteres de confirmación. Por ejemplo, en Javascript, el punto y coma (";") puede ser un carácter de confirmación que acepta una sugerencia y escribe ese carácter.',"Mostrar sugerencias de fragmentos de código por encima de otras sugerencias.","Mostrar sugerencias de fragmentos de código por debajo de otras sugerencias.","Mostrar sugerencias de fragmentos de código con otras sugerencias.","No mostrar sugerencias de fragmentos de código.","Controla si se muestran los fragmentos de código con otras sugerencias y cómo se ordenan.","Controla si al copiar sin selección se copia la línea actual.","Habilita sugerencias basadas en palabras.","Siempre seleccione la primera sugerencia.","Seleccione sugerencias recientes a menos que escriba una nueva opción, por ejemplo ' Console. | -> Console. log ' porque ' log ' se ha completado recientemente.","Seleccione sugerencias basadas en prefijos anteriores que han completado esas sugerencias, por ejemplo, ' Co-> Console ' y ' con-> const '.","Controla cómo se preseleccionan las sugerencias cuando se muestra la lista,","Tamaño de fuente para el widget de sugerencias","Alto de línea para el widget de sugerencias","Controls whether filtering and sorting suggestions accounts for small typos.","Control whether an active snippet prevents quick suggestions.","Controla si el editor debería destacar coincidencias similares a la selección","Controla si el editor debe resaltar los símbolos semánticos.","Controla el número de decoraciones que pueden aparecer en la misma posición en la regla de visión general","Controla si debe dibujarse un borde alrededor de la regla de información general.","Controla el estilo de animación del cursor.","Ampliar la fuente del editor cuando se use la rueda del mouse mientras se presiona Ctrl",'Controla el estilo del cursor. Los valores aceptados son "block", "block-outline", "line", "line-thin", "underline" y "underline-thin"',"Controla el ancho del cursor cuando editor.cursorStyle se establece a 'line'","Habilita las ligaduras tipográficas.","Controla si el cursor debe ocultarse en la regla de visión general.","Render whitespace characters except for single spaces between words.",'Controla cómo debe representar el editor los espacios en blanco. Las posibilidades son "none", "boundary" y "all". La opción "boundary" no representa los espacios individuales entre palabras.',"Controla si el editor debe representar caracteres de control","Controla si el editor debe representar guías de sangría.","Controls whether the editor should highlight the active indent guide.","Highlights both the gutter and the current line.",'Controla cómo el editor debe presentar el resaltado de línea. Las posibilidades son "ninguno", "margen", "línea" y "todo".',"Controla si el editor muestra CodeLens","Controla si el editor tiene habilitado el plegado de código.","Controla la forma en que se calculan las gamas plegables. Las selecciones ' auto' utilizan una estrategia de plegado específica del idioma, si está disponible. 'Sangría' obliga a utilizar la estrategia de plegado con sangría.","Controla cuándo los controles de plegado del margen son ocultados automáticamente.","Resaltar corchetes coincidentes cuando se seleccione uno de ellos.","Controla si el editor debe representar el margen de glifo vertical. El margen de glifo se usa, principalmente, para depuración.","La inserción y eliminación del espacio en blanco sigue a las tabulaciones.","Quitar espacio en blanco final autoinsertado","Mantiene abierto el editor interactivo incluso al hacer doble clic en su contenido o presionar Escape.","Controla si el editor debe permitir mover selecciones mediante arrastrar y colocar.","El editor usará API de plataforma para detectar cuándo está conectado un lector de pantalla.","El editor se optimizará de forma permanente para su uso con un editor de pantalla.","El editor nunca se optimizará para su uso con un lector de pantalla.","Controla si el editor se debe ejecutar en un modo optimizado para lectores de pantalla.","Controls fading out of unused code.","Controla si el editor debe detectar enlaces y hacerlos cliqueables","Controla si el editor debe representar el Selector de colores y los elementos Decorator de color en línea.","Permite que el foco de acción del código","¿organizar importaciones en guardar?","Tipos de acción de código que se ejecutarán en guardar.","Tiempo de espera para ejecutar acciones de código en guardar.","Controla si el portapapeles principal de Linux debe admitirse.","Controla si el editor de diferencias muestra las diferencias en paralelo o alineadas.","Controla si el editor de diferencias muestra los cambios de espacio inicial o espacio final como diferencias.","Manejo especial para archivos grandes para desactivar ciertas funciones de memoria intensiva.","Controla si el editor de diff muestra indicadores +/- para cambios agregados/quitados"], +"vs/editor/common/config/editorOptions":["No se puede acceder al editor en este momento. Presione Alt+F1 para ver opciones.","Contenido del editor"],"vs/editor/common/controller/cursor":["Excepción inesperada al ejecutar el comando."],"vs/editor/common/modes/modesRegistry":["Texto sin formato"],"vs/editor/common/services/modelServiceImpl":["[{0}]\n{1}","[{0}] {1}"], +"vs/editor/common/view/editorColorRegistry":["Color de fondo para la línea resaltada en la posición del cursor.","Color de fondo del borde alrededor de la línea en la posición del cursor.","Color de fondo de los rangos resaltados, como por ejemplo las características de abrir rápidamente y encontrar. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color de fondo del borde alrededor de los intervalos resaltados.","Color del cursor del editor.","Color de fondo del cursor de edición. Permite personalizar el color del caracter solapado por el bloque del cursor.","Color de los caracteres de espacio en blanco del editor.","Color de las guías de sangría del editor.","Color de las guías de sangría activas del editor.","Color de números de línea del editor.","Color del número de línea activa en el editor","ID es obsoleto. Usar en lugar 'editorLineNumber.activeForeground'. ","Color del número de línea activa en el editor","Color de las reglas del editor","Color principal de lentes de código en el editor","Color de fondo tras corchetes coincidentes","Color de bloques con corchetes coincidentes","Color del borde de la regla de visión general.","Color de fondo del margen del editor. Este espacio contiene los márgenes de glifos y los números de línea.","Color de primer plano de squigglies de error en el editor.","Color de borde de squigglies de error en el editor.","Color de primer plano de squigglies de advertencia en el editor.","Color de borde de squigglies de advertencia en el editor.","Color de primer plano de los subrayados ondulados informativos en el editor.","Color del borde de los subrayados ondulados informativos en el editor.","Color de primer plano de pista squigglies en el editor.","Color de borde de pista squigglies en el editor.","Border of unnecessary code in the editor.","Opacity of unnecessary code in the editor.","Color de marcador de regla de información general para errores. ","Color de marcador de regla de información general para advertencias.","Color de marcador de regla de información general para mensajes informativos. "], +"vs/editor/contrib/bracketMatching/bracketMatching":["Resumen color de marcador de regla para corchetes.","Ir al corchete","Seleccione esta opción para soporte"],"vs/editor/contrib/caretOperations/caretOperations":["Mover símbolo de inserción a la izquierda","Mover símbolo de inserción a la derecha"],"vs/editor/contrib/caretOperations/transpose":["Transponer letras"],"vs/editor/contrib/clipboard/clipboard":["Cortar","Cu&&t","Copiar","&&Copy","Pegar","&&Paste","Copiar con resaltado de sintaxis"],"vs/editor/contrib/codeAction/codeActionCommands":["Mostrar correcciones ({0})","Mostrar correcciones","Corrección Rápida","No hay acciones de código disponibles","No hay acciones de código disponibles","Refactorizar...","No hay refactorizaciones disponibles","Acción de Origen...","No hay acciones de origen disponibles","Organizar Importaciones","No hay acciones de importación disponibles"], +"vs/editor/contrib/comment/comment":["Alternar comentario de línea","&&Toggle Line Comment","Agregar comentario de línea","Quitar comentario de línea","Alternar comentario de bloque","Toggle &&Block Comment"],"vs/editor/contrib/contextmenu/contextmenu":["Mostrar menú contextual del editor"],"vs/editor/contrib/cursorUndo/cursorUndo":["Soft Undo"],"vs/editor/contrib/find/findController":["Buscar","&&Find","Buscar con selección","Buscar siguiente","Buscar anterior","Buscar selección siguiente","Buscar selección anterior","Reemplazar","&&Replace"],"vs/editor/contrib/find/findWidget":["Buscar","Buscar","Coincidencia anterior","Coincidencia siguiente","Buscar en selección","Cerrar","Reemplazar","Reemplazar","Reemplazar","Reemplazar todo","Alternar modo de reemplazar","Sólo los primeros {0} resultados son resaltados, pero todas las operaciones de búsqueda trabajan en todo el texto.","{0} de {1}","Sin resultados"], +"vs/editor/contrib/folding/folding":["Desplegar","Desplegar de forma recursiva","Plegar","Plegar de forma recursiva","Cerrar todos los comentarios de bloqueo","Plegar todas las regiones","Desplegar Todas las Regiones","Plegar todo","Desplegar todo","Nivel de plegamiento {0}"],"vs/editor/contrib/fontZoom/fontZoom":["Acercarse a la tipografía del editor","Alejarse de la tipografía del editor","Restablecer alejamiento de la tipografía del editor"],"vs/editor/contrib/format/formatActions":["1 edición de formato en la línea {0}","{0} ediciones de formato en la línea {1}","1 edición de formato entre las líneas {0} y {1}","{0} ediciones de formato entre las líneas {1} y {2}","No hay formateador para los archivos ' {0} ' instalados.","Dar formato al documento","No hay formateador de documentos para los archivos ' {0} ' instalados.","Dar formato a la selección","No hay formateador de selección para los archivos ' {0} ' instalados."], +"vs/editor/contrib/goToDefinition/goToDefinitionCommands":['No se encontró ninguna definición para "{0}"',"No se encontró ninguna definición"," – {0} definiciones","Ir a definición","Abrir definición en el lateral","Ver la definición",'No se encontró ninguna implementación para "{0}"',"No se encontró ninguna implementación","{0} implementaciones","Ir a implementación","Inspeccionar implementación",'No se encontró ninguna definición de tipo para "{0}"',"No se encontró ninguna definición de tipo"," – {0} definiciones de tipo","Ir a la definición de tipo","Inspeccionar definición de tipo"],"vs/editor/contrib/goToDefinition/goToDefinitionMouse":["Haga clic para mostrar {0} definiciones."],"vs/editor/contrib/gotoError/gotoError":["Ir al siguiente problema (Error, Advertencia, Información)","Ir al problema anterior (Error, Advertencia, Información)","Ir al siguiente problema en Archivos (Error, Advertencia, Información)","Ir al problema anterior en Archivos (Error, Advertencia, Información)"], +"vs/editor/contrib/gotoError/gotoErrorWidget":["({0}/{1})","Color de los errores del widget de navegación de marcadores del editor.","Color de las advertencias del widget de navegación de marcadores del editor.","Color del widget informativo marcador de navegación en el editor.","Fondo del widget de navegación de marcadores del editor."],"vs/editor/contrib/hover/hover":["Mostrar al mantener el puntero"],"vs/editor/contrib/hover/modesContentHover":["Cargando..."],"vs/editor/contrib/inPlaceReplace/inPlaceReplace":["Reemplazar con el valor anterior","Reemplazar con el valor siguiente"], +"vs/editor/contrib/linesOperations/linesOperations":["Copiar línea arriba","&&Copy Line Up","Copiar línea abajo","Co&&py Line Down","Mover línea hacia arriba","Mo&&ve Line Up","Mover línea hacia abajo","Move &&Line Down","Ordenar líneas en orden ascendente","Ordenar líneas en orden descendente","Recortar espacio final","Eliminar línea","Sangría de línea","Anular sangría de línea","Insertar línea arriba","Insertar línea debajo","Eliminar todo a la izquierda","Eliminar todo lo que está a la derecha","Unir líneas","Transponer caracteres alrededor del cursor","Transformar a mayúsculas","Transformar a minúsculas"], +"vs/editor/contrib/links/links":["Cmd + clic para abrir el vínculo","Ctrl + clic para abrir el vínculo","Cmd + click para ejecutar el comando","Ctrl + click para ejecutar el comando","Opción + clic para seguir el enlace","Alt + clic para seguir el vínculo","Opción + click para ejecutar el comando","Alt + clic para ejecutar el comando","No se pudo abrir este vínculo porque no tiene un formato correcto: {0}","No se pudo abrir este vínculo porque falta el destino.","Abrir vínculo"],"vs/editor/contrib/message/messageController":["No se puede editar en un editor de sólo lectura"], +"vs/editor/contrib/multicursor/multicursor":["Agregar cursor arriba","&&Add Cursor Above","Agregar cursor debajo","A&&dd Cursor Below","Añadir cursores a finales de línea","Add C&&ursors to Line Ends","Agregar selección hasta la siguiente coincidencia de búsqueda","Add &&Next Occurrence","Agregar selección hasta la anterior coincidencia de búsqueda","Add P&&revious Occurrence","Mover última selección hasta la siguiente coincidencia de búsqueda","Mover última selección hasta la anterior coincidencia de búsqueda","Seleccionar todas las repeticiones de coincidencia de búsqueda","Select All &&Occurrences","Cambiar todas las ocurrencias"],"vs/editor/contrib/parameterHints/parameterHints":["Sugerencias para parámetros Trigger"],"vs/editor/contrib/parameterHints/parameterHintsWidget":["{0}, sugerencia"],"vs/editor/contrib/referenceSearch/peekViewWidget":["Cerrar"],"vs/editor/contrib/referenceSearch/referenceSearch":[" – {0} referencias","Buscar todas las referencias"], +"vs/editor/contrib/referenceSearch/referencesController":["Cargando..."],"vs/editor/contrib/referenceSearch/referencesModel":["símbolo en {0} linea {1} en la columna {2}","1 símbolo en {0}, ruta de acceso completa {1}","{0} símbolos en {1}, ruta de acceso completa {2}","No se encontraron resultados","Encontró 1 símbolo en {0}","Encontró {0} símbolos en {1}","Encontró {0} símbolos en {1} archivos"], +"vs/editor/contrib/referenceSearch/referencesWidget":["Error al resolver el archivo.","{0} referencias","{0} referencia","vista previa no disponible","Referencias","No hay resultados.","Referencias","Color de fondo del área de título de la vista de inspección.","Color del título de la vista de inpección.","Color de la información del título de la vista de inspección.","Color de los bordes y la flecha de la vista de inspección.","Color de fondo de la lista de resultados de vista de inspección.","Color de primer plano de los nodos de inspección en la lista de resultados.","Color de primer plano de los archivos de inspección en la lista de resultados.","Color de fondo de la entrada seleccionada en la lista de resultados de vista de inspección.","Color de primer plano de la entrada seleccionada en la lista de resultados de vista de inspección.","Color de fondo del editor de vista de inspección.","Color de fondo del margen en el editor de vista de inspección.","Buscar coincidencia con el color de resaltado de la lista de resultados de vista de inspección.","Buscar coincidencia del color de resultado del editor de vista de inspección.","Hacer coincidir el borde resaltado en el editor de vista previa."], +"vs/editor/contrib/rename/rename":["No hay ningún resultado.","Nombre cambiado correctamente de '{0}' a '{1}'. Resumen: {2}","No se pudo cambiar el nombre.","Cambiar el nombre del símbolo"],"vs/editor/contrib/rename/renameInputField":["Cambie el nombre de la entrada. Escriba el nuevo nombre y presione Entrar para confirmar."],"vs/editor/contrib/smartSelect/smartSelect":["Expandir selección","&&Expand Selection","Reducir selección","&&Shrink Selection"],"vs/editor/contrib/snippet/snippetVariables":["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado","Dom","Lun","Mar","Mié","Jue","Vie","Sáb","Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre","Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Noviembre","Dic"],"vs/editor/contrib/suggest/suggestController":["Aceptando '{0}' Insertó el siguente texto : {1}","Sugerencias para Trigger"], +"vs/editor/contrib/suggest/suggestWidget":["Color de fondo del widget sugerido.","Color de borde del widget sugerido.","Color de primer plano del widget sugerido.","Color de fondo de la entrada seleccionada del widget sugerido.","Color del resaltado coincidido en el widget sugerido.","Leer más...{0}","{0}, sugerencia, con detalles","{0}, sugerencia","Leer menos...{0}","Cargando...","No hay sugerencias.","{0}, aceptada","{0}, sugerencia, con detalles","{0}, sugerencia"],"vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode":["Alternar tecla de tabulación para mover el punto de atención"], +"vs/editor/contrib/wordHighlighter/wordHighlighter":["Color de fondo de un símbolo durante el acceso de lectura, como leer una variable. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color de fondo de un símbolo durante el acceso de escritura, como escribir en una variable. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color de fondo de un símbolo durante el acceso de lectura; por ejemplo, cuando se lee una variable.","Color de fondo de un símbolo durante el acceso de escritura; por ejemplo, cuando se escribe una variable.","Destaca el color del marcador para los puntos del símbolo. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Destaca el color del marcador de acceso de escritura. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Ir al siguiente símbolo destacado","Ir al símbolo destacado anterior"], +"vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp":["No selection","Line {0}, Column {1} ({2} selected)","Line {0}, Column {1}","{0} selections ({1} characters selected)","{0} selections","Now changing the setting `accessibilitySupport` to 'on'.","Now opening the Editor Accessibility documentation page."," in a read-only pane of a diff editor."," in a pane of a diff editor."," in a read-only code editor"," in a code editor","To configure the editor to be optimized for usage with a Screen Reader press Command+E now.","To configure the editor to be optimized for usage with a Screen Reader press Control+E now.","The editor is configured to be optimized for usage with a Screen Reader.","The editor is configured to never be optimized for usage with a Screen Reader, which is not the case at this time.","Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.","Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.","Press Command+H now to open a browser window with more information related to editor accessibility.","Press Control+H now to open a browser window with more information related to editor accessibility.","You can dismiss this tooltip and return to the editor by pressing Escape or Shift+Escape.","Show Accessibility Help"], +"vs/editor/standalone/browser/inspectTokens/inspectTokens":["Developer: Inspect Tokens"],"vs/editor/standalone/browser/quickOpen/gotoLine":["Go to line {0} and character {1}","Go to line {0}","Type a line number between 1 and {0} to navigate to","Type a character between 1 and {0} to navigate to","Go to line {0}","Type a line number, followed by an optional colon and a character number to navigate to","Go to Line..."],"vs/editor/standalone/browser/quickOpen/quickCommand":["{0}, commands","Type the name of an action you want to execute","Command Palette"],"vs/editor/standalone/browser/quickOpen/quickOutline":["{0}, symbols","Type the name of an identifier you wish to navigate to","Go to Symbol...","symbols ({0})","modules ({0})","classes ({0})","interfaces ({0})","methods ({0})","functions ({0})","properties ({0})","variables ({0})","variables ({0})","constructors ({0})","calls ({0})"],"vs/editor/standalone/browser/simpleServices":["Made {0} edits in {1} files"], +"vs/editor/standalone/browser/standaloneCodeEditor":["Editor content","Press Ctrl+F1 for Accessibility Options.","Press Alt+F1 for Accessibility Options."],"vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast":["Toggle High Contrast Theme"],"vs/platform/configuration/common/configurationRegistry":["La configuración predeterminada se reemplaza","Establecer los valores de configuración que se reemplazarán para el lenguaje {0}.","Establecer los valores de configuración que se reemplazarán para un lenguaje.",'No se puede registrar "{0}". Coincide con el patrón de propiedad \'\\\\[.*\\\\]$\' para describir la configuración del editor específica del lenguaje. Utilice la contribución "configurationDefaults".','No se puede registrar "{0}". Esta propiedad ya está registrada.'],"vs/platform/keybinding/common/abstractKeybindingService":["Se presionó ({0}). Esperando la siguiente tecla...","La combinación de teclas ({0}, {1}) no es ningún comando."], +"vs/platform/list/browser/listService":["Área de trabajo",'Se asigna a "Control" en Windows y Linux y a "Comando" en macOS.','Se asigna a "Alt" en Windows y Linux y a "Opción" en macOS.',"El modificador que se usará para agregar un elemento en árboles y listas a una selección múltiple con el mouse (por ejemplo en el explorador, los editores abiertos y la vista SCM). ' ctrlCmd ' se asigna a ' control ' en Windows y Linux y a ' Command ' en macOS. Los gestos de ratón \"abrir a lado\", si se admiten, se adaptarán de tal manera que no estén en conflicto con el modificador multiselección.","Controla cómo abrir elementos en árboles y listas con el ratón (si está soportado). Establecer en ' singleClick ' para abrir elementos con un solo clic del ratón y ' DoubleClick ' para abrir sólo a través del doble clic del ratón. Para los elementos padres con hijos en los árboles, este ajuste controlará si un solo clic expande el padre o un doble clic. Tenga en cuenta que algunos árboles y listas pueden optar por ignorar esta configuración si no es aplicable","Controla el esplazamiento horizontal de los árboles en la mesa de trabajo."], +"vs/platform/markers/common/markers":["Error","Advertencia","Información"], +"vs/platform/theme/common/colorRegistry":["Colores usados en el área de trabajo.","Color de primer plano general. Este color solo se usa si un componente no lo invalida.","Color de primer plano general para los mensajes de erroe. Este color solo se usa si un componente no lo invalida.","Color de borde de los elementos con foco. Este color solo se usa si un componente no lo invalida.","Un borde adicional alrededor de los elementos para separarlos unos de otros y así mejorar el contraste.","Un borde adicional alrededor de los elementos activos para separarlos unos de otros y así mejorar el contraste.","Color de primer plano para los vínculos en el texto.","Color de fondo para los bloques de código en el texto.","Color de sombra de los widgets dentro del editor, como buscar/reemplazar","Fondo de cuadro de entrada.","Primer plano de cuadro de entrada.","Borde de cuadro de entrada.","Color de borde de opciones activadas en campos de entrada.","Color de fondo de validación de entrada para gravedad de información.","Color de borde de validación de entrada para gravedad de información.","Color de fondo de validación de entrada para gravedad de advertencia.","Color de borde de validación de entrada para gravedad de advertencia.","Color de fondo de validación de entrada para gravedad de error.","Color de borde de valdación de entrada para gravedad de error.","Color de fondo de la lista o el árbol del elemento con el foco cuando la lista o el árbol están activos. Una lista o un árbol tienen el foco del teclado cuando están activos, cuando están inactivos no.","Color de fondo de la lista o el árbol del elemento con el foco cuando la lista o el árbol están activos. Una lista o un árbol tienen el foco del teclado cuando están activos, cuando están inactivos no.","Color de fondo de la lista o el árbol del elemento seleccionado cuando la lista o el árbol están activos. Una lista o un árbol tienen el foco del teclado cuando están activos, cuando están inactivos no.","Color de primer plano de la lista o el árbol del elemento con el foco cuando la lista o el árbol están activos. Una lista o un árbol tienen el foco del teclado cuando están activos, cuando están inactivos no.","Color de fondo de la lista o el árbol del elemento seleccionado cuando la lista o el árbol están inactivos. Una lista o un árbol tienen el foco del teclado cuando están activos, cuando están inactivos no.","Color de primer plano de la lista o el árbol del elemento con el foco cuando la lista o el árbol esta inactiva. Una lista o un árbol tiene el foco del teclado cuando está activo, cuando esta inactiva no.","List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.","Fondo de la lista o el árbol al mantener el mouse sobre los elementos.","Color de primer plano de la lista o el árbol al pasar por encima de los elementos con el ratón.","Fondo de arrastrar y colocar la lista o el árbol al mover los elementos con el mouse.","Color de primer plano de la lista o el árbol de las coincidencias resaltadas al buscar dentro de la lista o el ábol.","Selector de color rápido para la agrupación de etiquetas.","Selector de color rápido para la agrupación de bordes.","Color de fondo de la insignia. Las insignias son pequeñas etiquetas de información, por ejemplo los resultados de un número de resultados.","Color de fondo de la insignia. Las insignias son pequeñas etiquetas de información, por ejemplo los resultados de un número de resultados.","Sombra de la barra de desplazamiento indica que la vista se ha despazado.","Color de fondo de control deslizante de barra de desplazamiento.","Color de fondo de barra de desplazamiento cursor cuando se pasar sobre el control.","Color de fondo de la barra de desplazamiento al hacer clic.","Color de fondo para la barra de progreso que se puede mostrar para las operaciones de larga duración.","Color de fondo del editor.","Color de primer plano predeterminado del editor.","Color de fondo del editor de widgets como buscar/reemplazar","Color de borde de los widgets del editor. El color solo se usa si el widget elige tener un borde y no invalida el color.","Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget.","Color de la selección del editor.","Color del texto seleccionado para alto contraste.","Color de la selección en un editor inactivo. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color para regiones con el mismo contenido que la selección. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color de borde de las regiones con el mismo contenido que la selección.","Color de la coincidencia de búsqueda actual.","Color de las otras coincidencias de búsqueda. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color de la gama que limita la búsqueda. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color de borde de la coincidencia de búsqueda actual.","Color de borde de otra búsqueda que coincide.","Color de borde de la gama que limita la búsqueda. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Resalte debajo de la palabra para la cual se muestra un Hover. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color de fondo al mantener el puntero en el editor.","Color del borde al mantener el puntero en el editor.","Color de los vínculos activos.","Color de fondo del texto que se insertó. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color de fondo del texto que se eliminó. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Color de contorno para el texto insertado.","Color de contorno para el texto quitado.","Border color between the two text editors.","Destaca el color del marcador de regla para las coincidencias de búsqueda. El color no debe ser opaco para no ocultar las decoraciones subyacentes.","Destaca el color del marcador de regla para los puntos de selección . El color no debe ser opaco para no ocultar las decoraciones subyacentes."] +}); +//# sourceMappingURL=../../../min-maps/vs/editor/editor.main.nls.es.js.map \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/editor/editor.main.nls.fr.js b/public/react/public/js/monaco/vs/editor/editor.main.nls.fr.js new file mode 100755 index 000000000..93d01b056 --- /dev/null +++ b/public/react/public/js/monaco/vs/editor/editor.main.nls.fr.js @@ -0,0 +1,33 @@ +/*!----------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Version: 0.14.6(6c8f02b41db9ae5c4d15df767d47755e5c73b9d5) + * Released under the MIT license + * https://github.com/Microsoft/vscode/blob/master/LICENSE.txt + *-----------------------------------------------------------*/ +define("vs/editor/editor.main.nls.fr",{"vs/base/browser/ui/actionbar/actionbar":["{0} ({1})"],"vs/base/browser/ui/aria/aria":["{0} (s'est reproduit)","{0} (occurred {1} times)"],"vs/base/browser/ui/findinput/findInput":["entrée"],"vs/base/browser/ui/findinput/findInputCheckboxes":["Respecter la casse","Mot entier","Utiliser une expression régulière"],"vs/base/browser/ui/inputbox/inputBox":["Erreur : {0}","Avertissement : {0}","Information : {0}"],"vs/base/browser/ui/list/listWidget":["{0}. Use the navigation keys to navigate."],"vs/base/browser/ui/menu/menu":["{0} ({1})"],"vs/base/common/keybindingLabels":["Ctrl","Maj","Alt","Windows","Ctrl","Maj","Alt","Super","Contrôle","Maj","Alt","Commande","Contrôle","Maj","Alt","Windows","Contrôle","Maj","Alt","Super"],"vs/base/common/severity":["Erreur","Avertissement","Informations"],"vs/base/parts/quickopen/browser/quickOpenModel":["{0}, sélecteur","sélecteur"], +"vs/base/parts/quickopen/browser/quickOpenWidget":["Sélecteur rapide. Tapez pour réduire les résultats.","Sélecteur rapide","{0} Results"],"vs/editor/browser/controller/coreCommands":["&&Select All","&&Undo","&&Redo"],"vs/editor/browser/widget/codeEditorWidget":["Le nombre de curseurs a été limité à {0}."],"vs/editor/browser/widget/diffEditorWidget":["Impossible de comparer les fichiers car l'un d'eux est trop volumineux."],"vs/editor/browser/widget/diffReview":["Fermer","aucune ligne","1 ligne","{0} lignes","Différence {0} sur {1} : original {2}, {3}, modifié {4}, {5}","vide","{0} d'origine, {1} modifiées : {2}","+ {0} modifiées : {1}","- {0} d'origine : {1}","Accéder à la différence suivante","Accéder la différence précédente"], +"vs/editor/common/config/commonEditorConfig":["Éditeur","Contrôle la famille de polices.","Contrôle l'épaisseur de police.","Contrôle la taille de police en pixels.","Contrôle la hauteur de ligne. Utilisez 0 pour calculer lineHeight à partir de fontSize.","Définit l'espacement des caractères en pixels.","Les numéros de ligne ne sont pas affichés.","Les numéros de ligne sont affichés en nombre absolu.","Les numéros de ligne sont affichés sous la forme de distance en lignes à la position du curseur.","Les numéros de ligne sont affichés toutes les 10 lignes.","Contrôle l’affichage des numéros de ligne.","Afficher les règles verticales après un certain nombre de caractères à espacement fixe. Utiliser plusieurs valeurs pour plusieurs règles. Aucune règle n'est dessinée si le tableau est vide","Caractères utilisés comme séparateurs de mots durant la navigation ou les opérations basées sur les mots","Le nombre d'espaces correspondant à une tabulation. Ce paramètre est remplacé en fonction du contenu du fichier quand 'editor.detectIndentation' est activé.","'number' attendu. Notez que la valeur \"auto\" a été remplacée par le paramètre 'editor.detectIndentation'.","Espaces insérés quand vous appuyez sur la touche Tab. Ce paramètre est remplacé en fonction du contenu du fichier quand 'editor.detectIndentation' est activé.","'boolean' attendu. Notez que la valeur \"auto\" a été remplacée par le paramètre 'editor.detectIndentation'.","Quand vous ouvrez un fichier, 'editor.tabSize' et 'editor.insertSpaces' sont détectés en fonction du contenu du fichier.","Contrôle si les sélections ont des angles arrondis","Contrôle si l'éditeur défile au-delà de la dernière ligne","Contrôle le nombre de caractères supplémentaires, au-delà duquel l’éditeur défilera horizontalement","Contrôle si l'éditeur défilera en utilisant une animation","Contrôle si la minicarte est affichée","Contrôle le côté où afficher la minicarte.","Contrôle si le curseur de la minicarte est automatiquement masqué","Afficher les caractères réels sur une ligne (par opposition aux blocs de couleurs)","Limiter la largeur de la minicarte pour afficher au maximum un certain nombre de colonnes","Controls whether the hover is shown.","Time delay in milliseconds after which to the hover is shown.","Controls whether the hover should remain visible when mouse is moved over it.","Contrôle si nous remplissons la chaîne à rechercher dans le Widget Recherche à partir de la sélection de l'éditeur","Contrôle si l'indicateur Rechercher dans la sélection est activé quand plusieurs caractères ou lignes de texte sont sélectionnés dans l'éditeur","Contrôle si le Widget Recherche doit lire ou modifier le presse-papiers partagé sur macOS","Le retour automatique à la ligne n'est jamais effectué.","Le retour automatique à la ligne s'effectue en fonction de la largeur de la fenêtre d'affichage.","Le retour automatique à la ligne s'effectue en fonction de 'editor.wordWrapColumn'.","Retour automatique à la ligne au minimum en fonction de la fenêtre d'affichage et de 'editor.wordWrapColumn'.","Contrôle le retour automatique à la ligne. Valeurs possibles :\n - 'off' (désactive le retour automatique à la ligne) ;\n - 'on' (retour automatique à la ligne dans la fenêtre d'affichage) ;\n - 'wordWrapColumn' (retour automatique à la ligne en fonction de 'editor.wordWrapColumn') ou ;\n - 'bounded' (retour automatique à la ligne au minimum en fonction de la fenêtre d'affichage et de 'editor.wordWrapColumn').","Contrôle la colonne de retour automatique à la ligne de l'éditeur quand 'editor.wordWrap' a la valeur 'wordWrapColumn' ou 'bounded'.","No indentation. Wrapped lines begin at column 1.","Wrapped lines get the same indentation as the parent.","Wrapped lines get +1 indentation toward the parent.","Wrapped lines get +2 indentation toward the parent.","Contrôle la mise en retrait des lignes enveloppées. Il peut s’agir de 'none', 'same', 'indent' ou 'deepIndent'.","Multiplicateur à utiliser pour le 'deltaX' et le 'deltaY' des événements de défilement de la roulette de la souris","Mappe vers 'Contrôle' dans Windows et Linux, et vers 'Commande' dans macOS.","Mappe vers 'Alt' dans Windows et Linux, et vers 'Option' dans macOS.","Le modificateur à utiliser pour ajouter plusieurs curseurs avec la souris. 'ctrlCmd' mappe vers 'Contrôle' dans Windows et Linux, et vers 'Commande' dans macOS. Les mouvements de souris Accéder à la définition et Ouvrir le lien s'adaptent pour ne pas entrer en conflit avec le modificateur multicurseur.","Fusionnez plusieurs curseurs quand ils se chevauchent.","Activez les suggestions rapides dans les chaînes.","Activez les suggestions rapides dans les commentaires.","Activez les suggestions rapides en dehors des chaînes et des commentaires.","Contrôle si les suggestions doivent s'afficher automatiquement en cours de frappe","Contrôle le délai en ms au bout duquel les suggestions rapides s'affichent","Active la pop up qui affiche la documentation des paramètres et écrit de l'information pendant que vous écrivez","Contrôle si l'éditeur doit automatiquement fermer les crochets après les avoir ouverts","Contrôle si l'éditeur doit automatiquement mettre en forme la ligne après la saisie","Contrôle si l'éditeur doit automatiquement mettre en forme le contenu collé. Un formateur doit être disponible et doit pouvoir mettre en forme une plage dans un document.","Contrôle si l’éditeur doit ajuster automatiquement la mise en retrait lorsque les utilisateurs tapent, collent ou déplacent des lignes. Les règles de mise en retrait du language doivent être disponibles.","Contrôle si les suggestions doivent s'afficher automatiquement durant la saisie de caractères de déclenchement","Only accept a suggestion with `Enter` when it makes a textual change.","Contrôle si les suggestions doivent être acceptées avec 'Entrée', en plus de 'Tab'. Cela permet d'éviter toute ambiguïté entre l'insertion de nouvelles lignes et l'acceptation de suggestions. La valeur 'smart' signifie que vous acceptez uniquement une suggestion avec Entrée quand elle applique une modification de texte","Contrôle si les suggestions doivent être acceptées avec des caractères de validation. Par exemple, en JavaScript, le point-virgule (';') peut être un caractère de validation qui permet d'accepter une suggestion et de taper ce caractère.","Afficher des suggestions d’extraits au-dessus d’autres suggestions.","Afficher des suggestions d’extraits en-dessous d’autres suggestions.","Afficher des suggestions d’extraits avec d’autres suggestions.","Ne pas afficher de suggestions d’extrait de code.","Contrôle si les extraits de code s'affichent en même temps que d'autres suggestions, ainsi que leur mode de tri.","Contrôle si la copie sans sélection permet de copier la ligne actuelle.","Contrôle si la saisie semi-automatique doit être calculée en fonction des mots présents dans le document.","Sélectionnez toujours la première suggestion.","Sélectionnez les suggestions récentes à moins qu'une saisie ultérieure en sélectionne un, par exemple 'console.| -> console.log' parce que `log` a été complété récemment.","Sélectionnez des suggestions basées sur des préfixes précédents qui ont complété ces suggestions, par exemple `co -> console` et `con -> const`.","Contrôle comment les suggestions sont pré-sélectionnés lors de l’affichage de la liste de suggestion.","Taille de police du widget de suggestion","Hauteur de ligne du widget de suggestion","Controls whether filtering and sorting suggestions accounts for small typos.","Control whether an active snippet prevents quick suggestions.","Détermine si l'éditeur doit surligner les correspondances similaires à la sélection","Contrôle si l'éditeur doit mettre en surbrillance les occurrences de symboles sémantiques","Contrôle le nombre d'ornements pouvant s'afficher à la même position dans la règle d'aperçu","Contrôle si une bordure doit être dessinée autour de la règle d'aperçu.","Contrôler le style d’animation du curseur.","Agrandir ou réduire la police de l'éditeur quand l'utilisateur fait tourner la roulette de la souris tout en maintenant la touche Ctrl enfoncée","Contrôle le style du curseur. Les valeurs acceptées sont 'block', 'block-outline', 'line', 'line-thin', 'underline' et 'underline-thin'","Contrôle la largeur du curseur quand editor.cursorStyle est à 'line'","Active les ligatures de police","Contrôle si le curseur doit être masqué dans la règle d'aperçu.","Render whitespace characters except for single spaces between words.","Contrôle la façon dont l'éditeur affiche les espaces blancs. Il existe trois options possibles : 'none', 'boundary' et 'all'. L'option 'boundary' n'affiche pas les espaces uniques qui séparent les mots.","Contrôle si l'éditeur doit afficher les caractères de contrôle","Contrôle si l'éditeur doit afficher les repères de mise en retrait","Controls whether the editor should highlight the active indent guide.","Highlights both the gutter and the current line.","Contrôle la façon dont l'éditeur doit afficher la surbrillance de la ligne active. Les différentes possibilités sont 'none', 'gutter', 'line' et 'all'.","Contrôle si l’éditeur affiche CodeLens","Contrôle si le pliage de code est activé dans l'éditeur","Contrôle la façon dont les repliages sont calculées. 'auto' utilise une stratégie repliage spécifique au langage, si disponible. 'indentation' force à ce que la stratégie de repliage basée sur l'indentation soit utilisée.","Définit si les contrôles de réduction sur la bordure sont cachés automatiquement","Met en surbrillance les crochets correspondants quand l'un d'eux est sélectionné.","Contrôle si l'éditeur doit afficher la marge de glyphes verticale. La marge de glyphes sert principalement au débogage.","L'insertion et la suppression d'un espace blanc suit les taquets de tabulation","Supprimer l'espace blanc de fin inséré automatiquement","Garder les éditeurs d'aperçu ouverts même si l'utilisateur double-clique sur son contenu ou appuie sur la touche Échap.","Contrôle si l'éditeur autorise le déplacement des sélections par glisser-déplacer.","L'éditeur utilise les API de la plateforme pour détecter si un lecteur d'écran est attaché.","L'éditeur est optimisé en permanence pour une utilisation avec un lecteur d'écran.","L'éditeur n'est jamais optimisé pour une utilisation avec un lecteur d'écran.","Contrôle si l'éditeur doit s'exécuter dans un mode optimisé pour les lecteurs d'écran.","Controls fading out of unused code.","Contrôle si l'éditeur doit détecter les liens et les rendre cliquables","Contrôle si l'éditeur doit afficher les éléments décoratifs de couleurs inline et le sélecteur de couleurs.","Active l'ampoule d'action de code","Exécuter organiser les importations lors de l'enregistrement ?","Types d'action de code à exécuter à l'enregistrement.","Délai d'attente pour les actions de code exécutées lors de l'enregistrement.","Contrôle si le presse-papiers primaire Linux doit être pris en charge.","Contrôle si l'éditeur de différences affiche les différences en mode côte à côte ou inline","Contrôle si l'éditeur de différences affiche les changements liés aux espaces blancs de début ou de fin comme des différences","Traitement spécial des fichiers volumineux pour désactiver certaines fonctionnalités utilisant beaucoup de mémoire.","Contrôle si l'éditeur de différences affiche les indicateurs +/- pour les modifications ajoutées/supprimées"], +"vs/editor/common/config/editorOptions":["L'éditeur n'est pas accessible pour le moment. Appuyez sur Alt+F1 pour connaître les options.","Contenu d'éditeur"],"vs/editor/common/controller/cursor":["Exception inattendue pendant l'exécution de la commande."],"vs/editor/common/modes/modesRegistry":["Texte brut"],"vs/editor/common/services/modelServiceImpl":["[{0}]\n{1}","[{0}] {1}"], +"vs/editor/common/view/editorColorRegistry":["Couleur d'arrière-plan de la mise en surbrillance de la ligne à la position du curseur.","Couleur d'arrière-plan de la bordure autour de la ligne à la position du curseur.","Couleur d'arrière-plan des plages mises en surbrillance, par exemple par les fonctionnalités d'ouverture rapide et de recherche. La couleur ne doit pas être opaque pour ne pas masquer les décorations sous-jacentes.","Couleur d'arrière-plan de la bordure autour des plages mises en surbrillance.","Couleur du curseur de l'éditeur.","La couleur de fond du curseur de l'éditeur. Permet de personnaliser la couleur d'un caractère survolé par un curseur de bloc.","Couleur des espaces blancs dans l'éditeur.","Couleur des repères de retrait de l'éditeur.","Couleur des guides d'indentation de l'éditeur actif","Couleur des numéros de ligne de l'éditeur.","Couleur des numéros de lignes actives de l'éditeur","Id est obsolète. Utilisez à la place 'editorLineNumber.activeForeground'. ","Couleur des numéros de lignes actives de l'éditeur","Couleur des règles de l'éditeur","Couleur pour les indicateurs CodeLens","Couleur d'arrière-plan pour les accolades associées","Couleur pour le contour des accolades associées","Couleur de la bordure de la règle d'apperçu.","Couleur de fond pour la bordure de l'éditeur. La bordure contient les marges pour les symboles et les numéros de ligne.","Couleur de premier plan de la ligne ondulée marquant les erreurs dans l'éditeur.","Couleur de bordure de la ligne ondulée marquant les erreurs dans l'éditeur.","Couleur de premier plan de la ligne ondulée marquant les avertissements dans l'éditeur.","Couleur de bordure de la ligne ondulée marquant les avertissements dans l'éditeur.","Couleur de premier plan de la ligne ondulée marquant les informations dans l'éditeur.","Couleur de bordure de la ligne ondulée marquant les informations dans l'éditeur.","Couleur de premier plan de la ligne ondulée d'indication dans l'éditeur.","Couleur de bordure de la ligne ondulée d'indication dans l'éditeur.","Border of unnecessary code in the editor.","Opacity of unnecessary code in the editor.","Couleur du marqueur de la règle d'aperçu pour les erreurs.","Couleur du marqueur de la règle d'aperçu pour les avertissements.","Couleur du marqueur de la règle d'aperçu pour les informations."], +"vs/editor/contrib/bracketMatching/bracketMatching":["Couleur du marqueur de la règle d'aperçu pour rechercher des parenthèses.","Atteindre le crochet","Select to Bracket"],"vs/editor/contrib/caretOperations/caretOperations":["Déplacer le point d'insertion vers la gauche","Déplacer le point d'insertion vers la droite"],"vs/editor/contrib/caretOperations/transpose":["Transposer les lettres"],"vs/editor/contrib/clipboard/clipboard":["Couper","Cu&&t","Copier","&&Copy","Coller","&&Paste","Copier avec la coloration syntaxique"],"vs/editor/contrib/codeAction/codeActionCommands":["Afficher les correctifs ({0})","Afficher les correctifs","Correction rapide...","Aucune action de code disponible","Aucune action de code disponible","Remanier...","Aucune refactorisation disponible","Action de la source","Aucune action n'est disponible","Organiser les Imports","Aucune action organiser les imports disponible"], +"vs/editor/contrib/comment/comment":["Activer/désactiver le commentaire de ligne","&&Toggle Line Comment","Ajouter le commentaire de ligne","Supprimer le commentaire de ligne","Activer/désactiver le commentaire de bloc","Toggle &&Block Comment"],"vs/editor/contrib/contextmenu/contextmenu":["Afficher le menu contextuel de l'éditeur"],"vs/editor/contrib/cursorUndo/cursorUndo":["Soft Undo"],"vs/editor/contrib/find/findController":["Rechercher","&&Find","Rechercher dans la sélection","Rechercher suivant","Rechercher précédent","Sélection suivante","Sélection précédente","Remplacer","&&Replace"],"vs/editor/contrib/find/findWidget":["Rechercher","Rechercher","Correspondance précédente","Correspondance suivante","Rechercher dans la sélection","Fermer","Remplacer","Remplacer","Remplacer","Tout remplacer","Changer le mode de remplacement","Seuls les {0} premiers résultats sont mis en évidence, mais toutes les opérations de recherche fonctionnent sur l’ensemble du texte.","{0} sur {1}","Aucun résultat"], +"vs/editor/contrib/folding/folding":["Déplier","Déplier de manière récursive","Plier","Plier de manière récursive","Replier tous les commentaires de bloc","Replier toutes les régions","Déplier toutes les régions","Plier tout","Déplier tout","Niveau de pliage {0}"],"vs/editor/contrib/fontZoom/fontZoom":["Agrandissement de l'éditeur de polices de caractères","Rétrécissement de l'éditeur de polices de caractères","Remise à niveau du zoom de l'éditeur de polices de caractères"], +"vs/editor/contrib/format/formatActions":["1 modification de format effectuée à la ligne {0}","{0} modifications de format effectuées à la ligne {1}","1 modification de format effectuée entre les lignes {0} et {1}","{0} modifications de format effectuées entre les lignes {1} et {2}","Il n’y a aucun formateur installé pour les fichiers '{0}'.","Mettre en forme le document","Il n’y a aucun formateur de document installé pour les fichiers '{0}'.","Mettre en forme la sélection","Il n’y a aucun formateur de sélection installé pour les fichiers '{0}'."], +"vs/editor/contrib/goToDefinition/goToDefinitionCommands":["Définition introuvable pour '{0}'","Définition introuvable"," – {0} définitions","Atteindre la définition","Ouvrir la définition sur le côté","Aperçu de définition","Implémentation introuvable pour '{0}'","Implémentation introuvable","– Implémentations {0}","Accéder à l'implémentation","Aperçu de l'implémentation","Définition de type introuvable pour '{0}'","Définition de type introuvable"," – Définitions de type {0}","Atteindre la définition de type","Aperçu de la définition du type"],"vs/editor/contrib/goToDefinition/goToDefinitionMouse":["Cliquez pour afficher {0} définitions."],"vs/editor/contrib/gotoError/gotoError":["Aller au problème suivant (Erreur, Avertissement, Info)","Aller au problème précédent (Erreur, Avertissement, Info)","Aller au problème suivant dans Fichiers (Erreur, Avertissement, Info)","Aller au problème précédent dans Fichiers (Erreur, Avertissement, Info)"], +"vs/editor/contrib/gotoError/gotoErrorWidget":["({0}/{1})","Couleur d'erreur du widget de navigation dans les marqueurs de l'éditeur.","Couleur d'avertissement du widget de navigation dans les marqueurs de l'éditeur.","Couleur d’information du widget de navigation du marqueur de l'éditeur.","Arrière-plan du widget de navigation dans les marqueurs de l'éditeur."],"vs/editor/contrib/hover/hover":["Afficher par pointage"],"vs/editor/contrib/hover/modesContentHover":["Chargement..."],"vs/editor/contrib/inPlaceReplace/inPlaceReplace":["Remplacer par la valeur précédente","Remplacer par la valeur suivante"], +"vs/editor/contrib/linesOperations/linesOperations":["Copier la ligne en haut","&&Copy Line Up","Copier la ligne en bas","Co&&py Line Down","Déplacer la ligne vers le haut","Mo&&ve Line Up","Déplacer la ligne vers le bas","Move &&Line Down","Trier les lignes dans l'ordre croissant","Trier les lignes dans l'ordre décroissant","Découper l'espace blanc de fin","Supprimer la ligne","Mettre en retrait la ligne","Ajouter un retrait négatif à la ligne","Insérer une ligne au-dessus","Insérer une ligne sous","Supprimer tout ce qui est à gauche","Supprimer tout ce qui est à droite","Joindre les lignes","Transposer les caractères autour du curseur","Transformer en majuscule","Transformer en minuscule"], +"vs/editor/contrib/links/links":["Commande + clic pour suivre le lien","Ctrl + clic pour suivre le lien","Cmd + clic pour exécuter la commande","Ctrl + clic pour exécuter la commande","Option + clic pour suivre le lien","Alt + clic pour suivre le lien","Option + clic pour exécuter la commande","Alt + clic pour exécuter la commande","Échec de l'ouverture de ce lien, car il n'est pas bien formé : {0}","Échec de l'ouverture de ce lien, car sa cible est manquante.","Ouvrir le lien"],"vs/editor/contrib/message/messageController":["Impossible de modifier dans l’éditeur en lecture seule"], +"vs/editor/contrib/multicursor/multicursor":["Ajouter un curseur au-dessus","&&Add Cursor Above","Ajouter un curseur en dessous","A&&dd Cursor Below","Ajouter des curseurs à la fin des lignes","Add C&&ursors to Line Ends","Ajouter la sélection à la correspondance de recherche suivante","Add &&Next Occurrence","Ajouter la sélection à la correspondance de recherche précédente","Add P&&revious Occurrence","Déplacer la dernière sélection vers la correspondance de recherche suivante","Déplacer la dernière sélection à la correspondance de recherche précédente","Sélectionner toutes les occurrences des correspondances de la recherche","Select All &&Occurrences","Modifier toutes les occurrences"],"vs/editor/contrib/parameterHints/parameterHints":["Indicateurs des paramètres Trigger"],"vs/editor/contrib/parameterHints/parameterHintsWidget":["{0}, conseil"],"vs/editor/contrib/referenceSearch/peekViewWidget":["Fermer"], +"vs/editor/contrib/referenceSearch/referenceSearch":[" – {0} références","Rechercher toutes les références"],"vs/editor/contrib/referenceSearch/referencesController":["Chargement..."],"vs/editor/contrib/referenceSearch/referencesModel":["symbole dans {0} sur la ligne {1}, colonne {2}","1 symbole dans {0}, chemin complet {1}","{0} symboles dans {1}, chemin complet {2}","Résultats introuvables","1 symbole dans {0}","{0} symboles dans {1}","{0} symboles dans {1} fichiers"], +"vs/editor/contrib/referenceSearch/referencesWidget":["Échec de la résolution du fichier.","{0} références","{0} référence","aperçu non disponible","Références","Aucun résultat","Références","Couleur d'arrière-plan de la zone de titre de l'affichage d'aperçu.","Couleur du titre de l'affichage d'aperçu.","Couleur des informations sur le titre de l'affichage d'aperçu.","Couleur des bordures et de la flèche de l'affichage d'aperçu.","Couleur d'arrière-plan de la liste des résultats de l'affichage d'aperçu.","Couleur de premier plan des noeuds de lignes dans la liste des résultats de l'affichage d'aperçu.","Couleur de premier plan des noeuds de fichiers dans la liste des résultats de l'affichage d'aperçu.","Couleur d'arrière-plan de l'entrée sélectionnée dans la liste des résultats de l'affichage d'aperçu.","Couleur de premier plan de l'entrée sélectionnée dans la liste des résultats de l'affichage d'aperçu.","Couleur d'arrière-plan de l'éditeur d'affichage d'aperçu.","Couleur d'arrière-plan de la bordure de l'éditeur d'affichage d'aperçu.","Couleur de mise en surbrillance d'une correspondance dans la liste des résultats de l'affichage d'aperçu.","Couleur de mise en surbrillance d'une correspondance dans l'éditeur de l'affichage d'aperçu.","Bordure de mise en surbrillance d'une correspondance dans l'éditeur de l'affichage d'aperçu."], +"vs/editor/contrib/rename/rename":["Aucun résultat.","'{0}' renommé en '{1}'. Récapitulatif : {2}","Échec de l'exécution du renommage.","Renommer le symbole"],"vs/editor/contrib/rename/renameInputField":["Renommez l'entrée. Tapez le nouveau nom et appuyez sur Entrée pour valider."],"vs/editor/contrib/smartSelect/smartSelect":["Développer la sélection","&&Expand Selection","Réduire la sélection","&&Shrink Selection"],"vs/editor/contrib/snippet/snippetVariables":["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi","Dim","Lun","Mar","Mer","Jeu","Ven","Sam","Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre","Jan","Fév","Mar","Avr","Mai","Jun","Jul","Aoû","Sep","Oct","Nov","Déc"],"vs/editor/contrib/suggest/suggestController":["L'acceptation de '{0}' a inséré le texte suivant : {1}","Suggestions pour Trigger"], +"vs/editor/contrib/suggest/suggestWidget":["Couleur d'arrière-plan du widget de suggestion.","Couleur de bordure du widget de suggestion.","Couleur de premier plan du widget de suggestion.","Couleur d'arrière-plan de l'entrée sélectionnée dans le widget de suggestion.","Couleur de la surbrillance des correspondances dans le widget de suggestion.","En savoir plus...{0}","{0}, suggestion, avec détails","{0}, suggestion","En savoir moins...{0}","Chargement...","Pas de suggestions.","{0}, accepté","{0}, suggestion, avec détails","{0}, suggestion"],"vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode":["Activer/désactiver l'utilisation de la touche Tab pour déplacer le focus"], +"vs/editor/contrib/wordHighlighter/wordHighlighter":["Couleur d'arrière-plan d'un symbole durant l'accès en lecture, par exemple la lecture d'une variable. La couleur ne doit pas être opaque pour ne pas masquer les décorations sous-jacentes.","Couleur d'arrière-plan d'un symbole durant l'accès en écriture, par exemple l'écriture dans une variable. La couleur ne doit pas être opaque pour ne pas masquer les décorations sous-jacentes.","Couleur de bordure d'un symbole durant l'accès en lecture, par exemple la lecture d'une variable.","Couleur de bordure d'un symbole durant l'accès en écriture, par exemple l'écriture dans une variable.","Couleur du marqueur de la règle d'aperçu pour les mises en surbrillance de symbole. La couleur doit ne pas être opaque pour ne pas masquer les décorations du dessous.","Couleur du marqueur de la règle d'aperçu pour les mises en surbrillance de symbole d'accès en écriture. La couleur doit ne pas être opaque pour ne pas masquer les décorations du dessous.","Aller à la prochaine mise en évidence de symbole","Aller à la mise en évidence de symbole précédente"], +"vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp":["No selection","Line {0}, Column {1} ({2} selected)","Line {0}, Column {1}","{0} selections ({1} characters selected)","{0} selections","Now changing the setting `accessibilitySupport` to 'on'.","Now opening the Editor Accessibility documentation page."," in a read-only pane of a diff editor."," in a pane of a diff editor."," in a read-only code editor"," in a code editor","To configure the editor to be optimized for usage with a Screen Reader press Command+E now.","To configure the editor to be optimized for usage with a Screen Reader press Control+E now.","The editor is configured to be optimized for usage with a Screen Reader.","The editor is configured to never be optimized for usage with a Screen Reader, which is not the case at this time.","Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.","Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.","Press Command+H now to open a browser window with more information related to editor accessibility.","Press Control+H now to open a browser window with more information related to editor accessibility.","You can dismiss this tooltip and return to the editor by pressing Escape or Shift+Escape.","Show Accessibility Help"], +"vs/editor/standalone/browser/inspectTokens/inspectTokens":["Developer: Inspect Tokens"],"vs/editor/standalone/browser/quickOpen/gotoLine":["Go to line {0} and character {1}","Go to line {0}","Type a line number between 1 and {0} to navigate to","Type a character between 1 and {0} to navigate to","Go to line {0}","Type a line number, followed by an optional colon and a character number to navigate to","Go to Line..."],"vs/editor/standalone/browser/quickOpen/quickCommand":["{0}, commands","Type the name of an action you want to execute","Command Palette"],"vs/editor/standalone/browser/quickOpen/quickOutline":["{0}, symbols","Type the name of an identifier you wish to navigate to","Go to Symbol...","symbols ({0})","modules ({0})","classes ({0})","interfaces ({0})","methods ({0})","functions ({0})","properties ({0})","variables ({0})","variables ({0})","constructors ({0})","calls ({0})"],"vs/editor/standalone/browser/simpleServices":["Made {0} edits in {1} files"], +"vs/editor/standalone/browser/standaloneCodeEditor":["Editor content","Press Ctrl+F1 for Accessibility Options.","Press Alt+F1 for Accessibility Options."],"vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast":["Toggle High Contrast Theme"],"vs/platform/configuration/common/configurationRegistry":["Substitutions de configuration par défaut","Configurez les paramètres d'éditeur à remplacer pour le langage {0}.","Configurez les paramètres d'éditeur à remplacer pour un langage.","Impossible d'inscrire '{0}'. Ceci correspond au modèle de propriété '\\\\[.*\\\\]$' permettant de décrire les paramètres d'éditeur spécifiques à un langage. Utilisez la contribution 'configurationDefaults'.","Impossible d'inscrire '{0}'. Cette propriété est déjà inscrite."],"vs/platform/keybinding/common/abstractKeybindingService":["Touche ({0}) utilisée. En attente de la seconde touche pour la pression simultanée...","La combinaison de touches ({0}, {1}) n'est pas une commande."], +"vs/platform/list/browser/listService":["Banc d'essai","Mappe vers 'Contrôle' dans Windows et Linux, et vers 'Commande' dans macOS.","Mappe vers 'Alt' dans Windows et Linux, et vers 'Option' dans macOS.","Le modificateur à utiliser pour ajouter un élément à une multi-sélection avec la souris (par exemple dans l’Explorateur, des éditeurs ouverts et scm view). 'ctrlCmd' mappe vers 'Contrôle' dans Windows et Linux, et vers 'Commande' dans macOS. Les mouvements de souris 'Ouvrir sur le côté', si supportés, s'adaptent pour ne pas entrer en conflit avec le modificateur multiselect.","Contrôle l’ouverture des éléments dans les arbres et listes à l’aide de la souris (si pris en charge). Mettre la valeur `singleClick` pour ouvrir des éléments avec un simple clic de souris et `doubleClick` pour ouvrir uniquement via un double-clic de souris. Pour les parents ayant des enfants dans les arbres, ce paramètre contrôle si un simple clic développe le parent ou un double-clic. Notez que certains arbres et listes peuvent choisir d’ignorer ce paramètre, si ce n’est pas applicable. ","Contrôle si les arborescences prennent en charge le défilement horizontal dans le plan de travail."], +"vs/platform/markers/common/markers":["Erreur","Avertissement","Informations"], +"vs/platform/theme/common/colorRegistry":["Couleurs utilisées dans le banc d'essai.","Couleur de premier plan globale. Cette couleur est utilisée si elle n'est pas remplacée par un composant.","Couleur principale de premier plan pour les messages d'erreur. Cette couleur est utilisée uniquement si elle n'est pas redéfinie par un composant.","Couleur de bordure globale des éléments ayant le focus. Cette couleur est utilisée si elle n'est pas remplacée par un composant.","Bordure supplémentaire autour des éléments pour les séparer des autres et obtenir un meilleur contraste.","Bordure supplémentaire autour des éléments actifs pour les séparer des autres et obtenir un meilleur contraste.","Couleur des liens dans le texte.","Couleur d'arrière-plan des blocs de code dans le texte.","Couleur de l'ombre des widgets, comme rechercher/remplacer, au sein de l'éditeur.","Arrière-plan de la zone d'entrée.","Premier plan de la zone d'entrée.","Bordure de la zone d'entrée.","Couleur de la bordure des options activées dans les champs d'entrée.","Couleur d'arrière-plan de la validation d'entrée pour la gravité des informations.","Couleur de bordure de la validation d'entrée pour la gravité des informations.","Couleur d'arrière-plan de la validation d'entrée pour la gravité de l'avertissement.","Couleur de bordure de la validation d'entrée pour la gravité de l'avertissement.","Couleur d'arrière-plan de la validation d'entrée pour la gravité de l'erreur.","Couleur de bordure de la validation d'entrée pour la gravité de l'erreur. ","Couleur d'arrière-plan de la liste/l'arborescence pour l'élément ayant le focus quand la liste/l'arborescence est active. Une liste/aborescence active peut être sélectionnée au clavier, elle ne l'est pas quand elle est inactive.","Couleur de premier plan de la liste/l'arborescence pour l'élément ayant le focus quand la liste/l'arborescence est active. Une liste/aborescence active peut être sélectionnée au clavier, elle ne l'est pas quand elle est inactive.","Couleur d'arrière-plan de la liste/l'arborescence de l'élément sélectionné quand la liste/l'arborescence est active. Une liste/arborescence active peut être sélectionnée au clavier, elle ne l'est pas quand elle est inactive.","Couleur de premier plan de la liste/l'arborescence pour l'élément sélectionné quand la liste/l'arborescence est active. Une liste/aborescence active peut être sélectionnée au clavier, elle ne l'est pas quand elle est inactive.","Couleur d'arrière-plan de la liste/l'arborescence pour l'élément sélectionné quand la liste/l'arborescence est inactive. Une liste/aborescence active peut être sélectionnée au clavier, elle ne l'est pas quand elle est inactive.","Couleur de premier plan de la liste/l'arborescence pour l'élément sélectionné quand la liste/l'arborescence est active. Une liste/aborescence active peut être sélectionnée au clavier, elle ne l'est pas quand elle est inactive.","List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.","Arrière-plan de la liste/l'arborescence pendant le pointage sur des éléments avec la souris.","Premier plan de la liste/l'arborescence pendant le pointage sur des éléments avec la souris.","Arrière-plan de l'opération de glisser-déplacer dans une liste/arborescence pendant le déplacement d'éléments avec la souris.","Couleur de premier plan dans la liste/l'arborescence pour la surbrillance des correspondances pendant la recherche dans une liste/arborescence.","Couleur du sélecteur rapide pour les étiquettes de regroupement.","Couleur du sélecteur rapide pour les bordures de regroupement.","Couleur de fond des badges. Les badges sont de courts libelés d'information, ex. le nombre de résultats de recherche.","Couleur des badges. Les badges sont de courts libelés d'information, ex. le nombre de résultats de recherche.","Ombre de la barre de défilement pour indiquer que la vue défile.","Couleur de fond du curseur de la barre de défilement.","Couleur de fond du curseur de la barre de défilement lors du survol.","Couleur d’arrière-plan de la barre de défilement lorsqu'on clique dessus.","Couleur de fond pour la barre de progression qui peut s'afficher lors d'opérations longues.","Couleur d'arrière-plan de l'éditeur.","Couleur de premier plan par défaut de l'éditeur.","Couleur d'arrière-plan des gadgets de l'éditeur tels que rechercher/remplacer.","Couleur de bordure des widgets de l'éditeur. La couleur est utilisée uniquement si le widget choisit d'avoir une bordure et si la couleur n'est pas remplacée par un widget.","Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget.","Couleur de la sélection de l'éditeur.","Couleur du texte sélectionné pour le contraste élevé.","Couleur de sélection dans un éditeur inactif. La couleur doit ne pas être opaque afin de ne pas masquer les décorations sous-jacentes.","Couleur des régions avec le même contenu que la sélection. La couleur doit ne pas être opaque afin de ne pas masquer les décorations sous-jacentes.","Couleur de bordure des régions dont le contenu est identique à la sélection.","Couleur du résultat de recherche actif.","Couleur des autres résultats de recherche correspondants. La couleur doit ne pas être opaque afin de ne pas masquer les décorations sous-jacentes.","Couleur de la plage limitant la recherche. La couleur ne doit pas être opaque pour ne pas masquer les décorations sous-jacentes.","Couleur de bordure du résultat de recherche actif.","Couleur de bordure des autres résultats de recherche.","Couleur de la bordure limitant la recherche. La couleur ne doit pas être opaque pour ne pas masquer les décorations sous-jacentes. ","Mettre en surbrillance ci-dessous le mot pour lequel un survol est affiché. La couleur doit ne pas être opaque afin de ne pas masquer les décorations sous-jacentes.","Couleur d'arrière-plan du pointage de l'éditeur.","Couleur de bordure du pointage de l'éditeur.","Couleur des liens actifs.","Couleur de fond pour le texte qui est inséré. La couleur ne doit pas être opaque pour ne pas masquer les décorations du dessous.","Couleur de fond pour le texte qui est retiré. La couleur doit ne pas être opaque pour ne pas masquer les décorations du dessous. ","Couleur de contour du texte inséré.","Couleur de contour du texte supprimé.","Border color between the two text editors.","Couleur du marqueur de la règle d'aperçu pour les correspondances trouvées. La couleur doit ne pas être opaque pour ne pas masquer les décorations du dessous.","Couleur du marqueur de la règle d'aperçu pour les mises en surbrillance de sélection. La couleur doit ne pas être opaque pour ne pas masquer les décorations du dessous."] +}); +//# sourceMappingURL=../../../min-maps/vs/editor/editor.main.nls.fr.js.map \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/editor/editor.main.nls.it.js b/public/react/public/js/monaco/vs/editor/editor.main.nls.it.js new file mode 100755 index 000000000..e039bb130 --- /dev/null +++ b/public/react/public/js/monaco/vs/editor/editor.main.nls.it.js @@ -0,0 +1,32 @@ +/*!----------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Version: 0.14.6(6c8f02b41db9ae5c4d15df767d47755e5c73b9d5) + * Released under the MIT license + * https://github.com/Microsoft/vscode/blob/master/LICENSE.txt + *-----------------------------------------------------------*/ +define("vs/editor/editor.main.nls.it",{"vs/base/browser/ui/actionbar/actionbar":["{0} ({1})"],"vs/base/browser/ui/aria/aria":["{0} (nuova occorrenza)","{0} (occurred {1} times)"],"vs/base/browser/ui/findinput/findInput":["input"],"vs/base/browser/ui/findinput/findInputCheckboxes":["Maiuscole/minuscole","Parola intera","Usa espressione regolare"],"vs/base/browser/ui/inputbox/inputBox":["Errore: {0}","Avviso: {0}","Info: {0}"],"vs/base/browser/ui/list/listWidget":["{0}. Use the navigation keys to navigate."],"vs/base/browser/ui/menu/menu":["{0} ({1})"],"vs/base/common/keybindingLabels":["CTRL","MAIUSC","ALT","Windows","CTRL","MAIUSC","ALT","Super","CTRL","MAIUSC","ALT","Comando","CTRL","MAIUSC","ALT","Windows","CTRL","MAIUSC","ALT","Super"],"vs/base/common/severity":["Errore","Avviso","Informazioni"],"vs/base/parts/quickopen/browser/quickOpenModel":["{0}, selezione","selezione"], +"vs/base/parts/quickopen/browser/quickOpenWidget":["Selezione rapida. Digitare per ridurre il numero di risultati.","Selezione rapida","{0} Results"],"vs/editor/browser/controller/coreCommands":["&&Select All","&&Undo","&&Redo"],"vs/editor/browser/widget/codeEditorWidget":["Il numero di cursori è stato limitato a {0}."],"vs/editor/browser/widget/diffEditorWidget":["Non è possibile confrontare i file perché uno è troppo grande."],"vs/editor/browser/widget/diffReview":["Chiudi","nessuna linea","1 linea","{0} linee","Differenza {0} di {1}: originale {2}, {3}, modificate {4}, {5}","vuota","originali {0}, modificate {1}: {2}","+ modificate {0}: {1}","- originali {0}: {1}","Vai alla differenza successiva","Vai alla differenza precedente"], +"vs/editor/common/config/commonEditorConfig":["Editor","Controlla la famiglia di caratteri.","Controlla lo spessore del carattere.","Controlla le dimensioni del carattere in pixel.","Controlla l'altezza della riga. Usare 0 per calcolare l'altezza della riga dalle dimensioni del carattere.","Controlla la spaziatura tra le lettere in pixel.","I numeri di riga non vengono visualizzati.","I numeri di riga vengono visualizzati come numeri assoluti.","I numeri di riga vengono visualizzati come distanza in linee alla posizione del cursore.","I numeri di riga vengono visualizzati ogni 10 righe.","Controlla la visualizzazione dei numeri di riga.","Mostra righelli verticali dopo un certo numero di caratteri a spaziatura fissa. Utilizza più valori per più righelli. Nessun righello viene disegnati se la matrice è vuota","Caratteri che verranno usati come separatori di parola quando si eseguono operazioni o spostamenti correlati a parole","Il numero di spazi corrispondenti ad un carattere Tab. Questa impostazione viene sottoposta a override in base al contenuto dei file quando 'editor.detectIndentation' è 'on'.","È previsto 'number'. Nota: il valore \"auto\" è stato sostituito dall'impostazione `editor.detectIndentation`.","Inserire spazi quando si preme Tab. Questa impostazione viene sottoposta a override in base al contenuto dei file quando è 'editor.detectIndentation' è 'on'.","È previsto 'boolean'. Nota: il valore \"auto\" è stato sostituito dall'impostazione `editor.detectIndentation`.","All'apertura di un file, `editor.tabSize` e `editor.insertSpaces` verranno rilevati in base al contenuto del file.","Controlla se gli angoli delle selezioni sono arrotondati","Controlla se l'editor scorrerà oltre l'ultima riga","Controlla il numero di caratteri aggiuntivi oltre il quale l'editor scorrerà orizzontalmente","Controlla se per lo scorrimento dell'editor verrà usata un'animazione.","Controlla se la mini mappa è visualizzata","Definisce il lato in cui eseguire il rendering della mini mappa.","Controlla se lo slider della mini mappa viene nascosto automaticamente.","Esegue il rendering dei caratteri effettivi di una riga (in contrapposizione ai blocchi colore)","Limita la larghezza della mini mappa in modo da eseguire il rendering al massimo di un certo numero di colonne","Controls whether the hover is shown.","Time delay in milliseconds after which to the hover is shown.","Controls whether the hover should remain visible when mouse is moved over it.","Controlla se inizializzare la stringa di ricerca nel Widget Trova con il testo selezionato nell'editor","Controlla se l'impostazione Trova nella selezione è attivata quando vengono selezionati più caratteri o righe di testo nell'editor","Controlla se il widget Trova debba leggere o modificare gli appunti ricerche condivise su macOS","Il wrapping delle righe non viene eseguito.","Verrà eseguito il wrapping delle righe in base alla larghezza del viewport.","Verrà eseguito il wrapping delle righe alla posizione corrispondente a `editor.wordWrapColumn`.","Verrà eseguito il wrapping delle righe alla posizione minima del viewport e di `editor.wordWrapColumn`.","Controlla il wrapping delle righe. Valori possibili:\n - 'off' (disabilita il wrapping),\n - 'on' (wrapping del viewport),\n - 'wordWrapColumn' (esegue il wrapping alla posizione corrispondente a `editor.wordWrapColumn`) o\n - 'bounded' (esegue il wrapping alla posizione minima del viewport e di `editor.wordWrapColumn`).","Controlla la colonna di wrapping dell'editor quando il valore di `editor.wordWrap` è 'wordWrapColumn' o 'bounded'.","No indentation. Wrapped lines begin at column 1.","Wrapped lines get the same indentation as the parent.","Wrapped lines get +1 indentation toward the parent.","Wrapped lines get +2 indentation toward the parent.","Controlla il rientro delle righe con ritorno a capo. Può essere uno dei valori seguenti: 'none', 'same', 'indent' o 'deepIndent'.","Moltiplicatore da usare sui valori `deltaX` e `deltaY` degli eventi di scorrimento della rotellina del mouse","Rappresenta il tasto 'Control' (ctrl) su Windows e Linux e il tasto 'Comando' (cmd) su OSX.","Rappresenta il tasto 'Alt' su Windows e Linux e il tasto 'Opzione' su OSX.","Il modificatore da utilizzare per aggiungere molteplici cursori con il mouse. 'ctrlCmd' rappresenta il tasto 'Control' su Windows e Linux e il tasto 'Comando' su OSX. I gesti del mouse Vai a definizione e Apri il Link si adatteranno in modo da non entrare in conflitto con il modificatore multi-cursore.","Unire i cursori multipli se sovrapposti.","Abilita i suggerimenti rapidi all'interno di stringhe.","Abilita i suggerimenti rapidi all'interno di commenti.","Abilita i suggerimenti rapidi all'esterno di stringhe e commenti.","Controlla se visualizzare automaticamente i suggerimenti durante la digitazione","Controlla il ritardo in ms dopo il quale verranno visualizzati i suggerimenti rapidi","Abilita un popup che mostra documentazione sui parametri e informazioni sui tipi mentre si digita","Controlla se l'editor deve chiudere automaticamente le parentesi quadre dopo che sono state aperte","Controlla se l'editor deve formattare automaticamente la riga dopo la digitazione","Controlla se l'editor deve formattare automaticamente il contenuto incollato. Deve essere disponibile un formattatore che deve essere in grado di formattare un intervallo in un documento.","Controlla se l'editor deve correggere automaticamente l'indentazione mentre l'utente digita, incolla o sposta delle righe. Devono essere disponibili le regole di indentazione del linguaggio.","Controlla se i suggerimenti devono essere visualizzati automaticamente durante la digitazione dei caratteri trigger","Only accept a suggestion with `Enter` when it makes a textual change.","Controlla se i suggerimenti devono essere accettati con 'INVIO' in aggiunta a 'TAB'. In questo modo è possibile evitare ambiguità tra l'inserimento di nuove righe e l'accettazione di suggerimenti. Il valore 'smart' indica di accettare un suggerimento con 'INVIO' quando comporta una modifica al testo","Controlla se accettare i suggerimenti con i caratteri di commit. Ad esempio, in JavaScript il punto e virgola (';') può essere un carattere di commit che accetta un suggerimento e digita tale carattere.","Visualizza i suggerimenti dello snippet sopra gli altri suggerimenti.","Visualizza i suggerimenti dello snippet sotto gli altri suggerimenti.","Visualizza i suggerimenti degli snippet insieme agli altri suggerimenti.","Non mostrare i suggerimenti sugli snippet.","Controlla se i frammenti di codice sono visualizzati con altri suggerimenti e il modo in cui sono ordinati.","Consente di controllare se, quando si copia senza aver effettuato una selezione, viene copiata la riga corrente.","Controlla se calcolare i completamenti in base alle parole presenti nel documento.","Consente di selezionare sempre il primo suggerimento.","Consente di selezionare suggerimenti recenti a meno che continuando a digitare non ne venga selezionato uno, ad esempio `console.| -> console.log` perché `log` è stato completato di recente.","Consente di selezionare i suggerimenti in base a prefissi precedenti che hanno completato tali suggerimenti, ad esempio `co -> console` e `con -> const`.","Controlla la modalità di preselezione dei suggerimenti durante la visualizzazione degll'elenco dei suggerimenti.","Dimensioni del carattere per il widget dei suggerimenti","Altezza della riga per il widget dei suggerimenti","Controls whether filtering and sorting suggestions accounts for small typos.","Control whether an active snippet prevents quick suggestions.","Controlla se l'editor deve evidenziare gli elementi corrispondenti simili alla selezione","Controlla se l'editor deve evidenziare le occorrenze di simboli semantici","Controlla il numero di effetti che possono essere visualizzati nella stessa posizione nel righello delle annotazioni","Controlla se deve essere disegnato un bordo intorno al righello delle annotazioni.","Controllo dello stile di animazione del cursore.","Ingrandisce il carattere dell'editor quando si usa la rotellina del mouse e si tiene premuto CTRL","Controlla lo stile del cursore. I valori accettati sono 'block', 'block-outline', 'line', 'line-thin', 'underline' e 'underline-thin'","Controlla la larghezza del cursore quando editor.cursorSyle è impostato a 'line'","Abilita i caratteri legatura","Controlla se il cursore deve essere nascosto nel righello delle annotazioni.","Render whitespace characters except for single spaces between words.","Consente di controllare in che modo l'editor deve eseguire il rendering dei caratteri di spazio vuoto. Le opzioni possibili sono: 'none', 'boundary' e 'all'. Con l'opzione 'boundary' non viene eseguito il rendering di singoli spazi tra le parole.","Controlla se l'editor deve eseguire il rendering dei caratteri di controllo","Controlla se l'editor deve eseguire il rendering delle guide con rientro","Controls whether the editor should highlight the active indent guide.","Highlights both the gutter and the current line.","Consente di controllare in che modo l'editor deve eseguire il rendering dell'evidenziazione di riga corrente. Le opzioni possibili sono 'none', 'gutter', 'line' e 'all'.","Controlla se nell'editor è visualizzato CodeLens","Controlla se per l'editor è abilitata la riduzione del codice","Controlla in che modo vengono calcolati gli intervalli di riduzione. Con 'auto' viene usata l'eventuale strategia di riduzione specifica disponibile. Con 'indentation' viene usata forzatamente la strategia di riduzione basata sui rientri.","Controlla se i controlli di riduzione sul margine della barra di scorrimento sono automaticamente nascosti.","Evidenzia le parentesi corrispondenti quando se ne seleziona una.","Controlla se l'editor deve eseguire il rendering del margine verticale del glifo. Il margine del glifo viene usato principalmente per il debug.","Inserimento ed eliminazione dello spazio vuoto dopo le tabulazioni","Rimuovi lo spazio vuoto finale inserito automaticamente","Mantiene aperti gli editor rapidi anche quando si fa doppio clic sul contenuto o si preme ESC.","Controlla se l'editor consentire lo spostamento di selezioni tramite trascinamento della selezione.","L'editor utilizzerà API della piattaforma per rilevare quando è collegata un'utilità per la lettura dello schermo.","L'editor sarà definitivamente ottimizzato per l'utilizzo con un'utilità per la lettura dello schermo.","L'editor non sarà mai ottimizzato per l'utilizzo con un'utilità per la lettura dello schermo.","Controlla se l'editor deve essere eseguito in una modalità ottimizzata per le utilità per la lettura dello schermo.","Controls fading out of unused code.","Controlla se l'editor deve individuare i collegamenti e renderli cliccabili","Controlla se l'editor deve eseguire il rendering del selettore di colore e degli elementi Decorator di tipo colore inline.","Abilita il codice azione lightbulb","Eseguire l'organizzazione degli Imports durante il salvataggio?","Tipi di azione codice da eseguire durante il salvataggio.","Timeout per le azioni codice eseguite durante il salvataggio.","Controlla se gli appunti primari di Linux devono essere supportati.","Controlla se l'editor diff mostra le differenze affiancate o incorporate","Controlla se l'editor diff mostra come differenze le modifiche relative a spazi vuoti iniziali e finali","Gestione speciale dei file di grandi dimensioni per disabilitare alcune funzionalità che fanno un uso intensivo della memoria.","Consente di controllare se l'editor diff mostra gli indicatori +/- per le modifiche aggiunte/rimosse"], +"vs/editor/common/config/editorOptions":["L'editor non è accessibile in questo momento. Premere Alt+F1 per le opzioni.","Contenuto editor"],"vs/editor/common/controller/cursor":["Eccezione imprevista durante l'esecuzione del comando."],"vs/editor/common/modes/modesRegistry":["Testo normale"],"vs/editor/common/services/modelServiceImpl":["[{0}]\n{1}","[{0}] {1}"], +"vs/editor/common/view/editorColorRegistry":["Colore di sfondo per l'evidenziazione della riga alla posizione del cursore.","Colore di sfondo per il bordo intorno alla riga alla posizione del cursore.","Colore di sfondo degli intervalli evidenziati, ad esempio dalle funzionalità Quick Open e Trova. il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.","Colore di sfondo del bordo intorno agli intervalli selezionati.","Colore del cursore dell'editor.","Colore di sfondo del cursore editor. Permette di personalizzare il colore di un carattere quando sovrapposto da un blocco cursore.","Colore dei caratteri di spazio vuoto nell'editor.","Colore delle guide per i rientri dell'editor.","Colore delle guide di indentazione dell'editor attivo","Colore dei numeri di riga dell'editor.","Colore dei numeri per la riga attiva dell'editor","Id è deprecato. In alternativa utilizzare 'editorLineNumber.activeForeground'.","Colore dei numeri per la riga attiva dell'editor","Colore dei righelli dell'editor.","Colore primo piano delle finestre di CodeLens dell'editor","Colore di sfondo delle parentesi corrispondenti","Colore delle caselle di parentesi corrispondenti","Colore del bordo del righello delle annotazioni.","Colore di sfondo della barra di navigazione dell'editor. La barra contiene i margini di glifo e i numeri di riga.","Colore primo piano degli squiggle di errore nell'editor.","Colore del bordo degli squiggle di errore nell'editor.","Colore primo piano degli squiggle di avviso nell'editor","Colore del bordo degli squggle di avviso nell'editor.","Colore primo piano degli squiggle di informazione nell'editor","Colore del bordo degli squiggle di informazione nell'editor","Colore primo piano degli squiggle di suggerimento nell'editor.","Colore del bordo degli squiggle di suggerimento nell'editor.","Border of unnecessary code in the editor.","Opacity of unnecessary code in the editor.","Colore del marcatore del righello delle annotazioni per gli errori.","Colore del marcatore del righello delle annotazioni per gli avvisi.","Colore del marcatore del righello delle annotazioni per i messaggi di tipo informativo."], +"vs/editor/contrib/bracketMatching/bracketMatching":["Colore del marcatore del righello delle annotazioni per la corrispondenza delle parentesi.","Vai alla parentesi","Seleziona fino alla parentesi"],"vs/editor/contrib/caretOperations/caretOperations":["Sposta il punto di inserimento a sinistra","Sposta il punto di inserimento a destra"],"vs/editor/contrib/caretOperations/transpose":["Trasponi lettere"],"vs/editor/contrib/clipboard/clipboard":["Taglia","Cu&&t","Copia","&&Copy","Incolla","&&Paste","Copia con evidenziazione sintassi"],"vs/editor/contrib/codeAction/codeActionCommands":["Mostra correzioni ({0})","Mostra correzioni","Correzione rapida...","Azioni codice non disponibili","Azioni codice non disponibili","Effettua refactoring...","Refactoring non disponibili","Azione origine...","Azioni origine non disponibili","Organizza gli Imports","Azioni di organizzazione Imports non disponibili"], +"vs/editor/contrib/comment/comment":["Attiva/Disattiva commento per la riga","&&Toggle Line Comment","Aggiungi commento per la riga","Rimuovi commento per la riga","Attiva/Disattiva commento per il blocco","Toggle &&Block Comment"],"vs/editor/contrib/contextmenu/contextmenu":["Mostra il menu di scelta rapida editor"],"vs/editor/contrib/cursorUndo/cursorUndo":["Soft Undo"],"vs/editor/contrib/find/findController":["Trova","&&Find","Trova nella selezione","Trova successivo","Trova precedente","Trova selezione successiva","Trova selezione precedente","Sostituisci","&&Replace"],"vs/editor/contrib/find/findWidget":["Trova","Trova","Risultato precedente","Risultato successivo","Trova nella selezione","Chiudi","Sostituisci","Sostituisci","Sostituisci","Sostituisci tutto","Attiva/Disattiva modalità sostituzione","Solo i primi {0} risultati vengono evidenziati, ma tutte le operazioni di ricerca funzionano su tutto il testo.","{0} di {1}","Nessun risultato"], +"vs/editor/contrib/folding/folding":["Espandi","Espandi in modo ricorsivo","Riduci","Riduci in modo ricorsivo","Riduci tutti i blocchi commento","Riduci tutte le regioni","Espandi tutte le regioni","Riduci tutto","Espandi tutto","Livello riduzione {0}"],"vs/editor/contrib/fontZoom/fontZoom":["Zoom In del Font Editor","Zoom Reset del Font Editor","Reset dello Zoom del Font Editor"],"vs/editor/contrib/format/formatActions":["È stata apportata 1 modifica di formattazione a riga {0}","Sono state apportate {0} modifiche di formattazione a riga {1}","È stata apportata 1 modifica di formattazione tra le righe {0} e {1}","Sono state apportate {0} modifiche di formattazione tra le righe {1} e {2}","Non c'è alcun formattatore installato per i file '{0}'.","Formatta documento","Non è installato alcun formattatore di documenti per i file '{0}'.","Formatta selezione","Non è installato alcun formattatore di selezione per i file '{0}'."], +"vs/editor/contrib/goToDefinition/goToDefinitionCommands":["Non è stata trovata alcuna definizione per '{0}'","Non è stata trovata alcuna definizione"," - Definizioni di {0}","Vai alla definizione","Apri definizione lateralmente","Visualizza la definizione","Non sono state trovate implementazioni per '{0}'","Non sono state trovate implementazioni","- {0} implementazioni","Vai all'implementazione","Anteprima implementazione","Non sono state trovate definizioni di tipi per '{0}'","Non sono state trovate definizioni di tipi"," - {0} definizioni di tipo","Vai alla definizione di tipo","Anteprima definizione di tipo"],"vs/editor/contrib/goToDefinition/goToDefinitionMouse":["Fare clic per visualizzare {0} definizioni."],"vs/editor/contrib/gotoError/gotoError":["Vai al problema successivo (Errore, Avviso, Informazioni)","Vai al problema precedente (Errore, Avviso, Info)","Vai al Problema Successivo nei File (Error, Warning, Info)","Vai al Problema Precedente nei File (Error, Warning, Info) "], +"vs/editor/contrib/gotoError/gotoErrorWidget":["({0}/{1})","Colore per gli errori del widget di spostamento tra marcatori dell'editor.","Colore per gli avvisi del widget di spostamento tra marcatori dell'editor.","Colore delle informazioni del widget di navigazione marcatori dell'editor.","Sfondo del widget di spostamento tra marcatori dell'editor."],"vs/editor/contrib/hover/hover":["Visualizza passaggio del mouse"],"vs/editor/contrib/hover/modesContentHover":["Caricamento..."],"vs/editor/contrib/inPlaceReplace/inPlaceReplace":["Sostituisci con il valore precedente","Sostituisci con il valore successivo"], +"vs/editor/contrib/linesOperations/linesOperations":["Copia la riga in alto","&&Copy Line Up","Copia la riga in basso","Co&&py Line Down","Sposta la riga in alto","Mo&&ve Line Up","Sposta la riga in basso","Move &&Line Down","Ordinamento righe crescente","Ordinamento righe decrescente","Taglia spazio vuoto finale","Elimina la riga","Imposta un rientro per la riga","Riduci il rientro per la riga","Inserisci la riga sopra","Inserisci la riga sotto","Elimina tutto a sinistra","Elimina tutto a destra","Unisci righe","Trasponi caratteri intorno al cursore","Converti in maiuscolo","Converti in minuscolo"], +"vs/editor/contrib/links/links":["Cmd + clic per seguire il collegamento","CTRL + clic per seguire il collegamento","Cmd + click per eseguire il comando","Ctrl + clic per eseguire il comando","Opzione + clic per seguire il collegamento","Alt + clic per seguire il collegamento","Opzione + clic per eseguire il comando","Alt + clic per eseguire il comando","Non è stato possibile aprire questo collegamento perché il formato non è valido: {0}","Non è stato possibile aprire questo collegamento perché manca la destinazione.","Apri il collegamento"],"vs/editor/contrib/message/messageController":["Impossibile modificare nell'editor di sola lettura"], +"vs/editor/contrib/multicursor/multicursor":["Aggiungi cursore sopra","&&Add Cursor Above","Aggiungi cursore sotto","A&&dd Cursor Below","Aggiungi cursore alla fine delle righe","Add C&&ursors to Line Ends","Aggiungi selezione a risultato ricerca successivo","Add &&Next Occurrence","Aggiungi selezione a risultato ricerca precedente","Add P&&revious Occurrence","Sposta ultima selezione a risultato ricerca successivo","Sposta ultima selezione a risultato ricerca precedente","Seleziona tutte le occorrenze del risultato ricerca","Select All &&Occurrences","Cambia tutte le occorrenze"],"vs/editor/contrib/parameterHints/parameterHints":["Attiva i suggerimenti per i parametri"],"vs/editor/contrib/parameterHints/parameterHintsWidget":["{0}, suggerimento"],"vs/editor/contrib/referenceSearch/peekViewWidget":["Chiudi"],"vs/editor/contrib/referenceSearch/referenceSearch":[" - Riferimenti di {0}","Trova tutti i riferimenti"],"vs/editor/contrib/referenceSearch/referencesController":["Caricamento..."], +"vs/editor/contrib/referenceSearch/referencesModel":["simbolo in {0} alla riga {1} colonna {2}","1 simbolo in {0}, percorso completo {1}","{0} simboli in {1}, percorso completo {2}","Non sono stati trovati risultati","Trovato 1 simbolo in {0}","Trovati {0} simboli in {1}","Trovati {0} simboli in {1} file"], +"vs/editor/contrib/referenceSearch/referencesWidget":["Non è stato possibile risolvere il file.","{0} riferimenti","{0} riferimento","anteprima non disponibile","Riferimenti","Nessun risultato","Riferimenti","Colore di sfondo dell'area del titolo della visualizzazione rapida.","Colore del titolo della visualizzazione rapida.","Colore delle informazioni del titolo della visualizzazione rapida.","Colore dei bordi e della freccia della visualizzazione rapida.","Colore di sfondo dell'elenco risultati della visualizzazione rapida.","Colore primo piano dei nodi riga nell'elenco risultati della visualizzazione rapida.","Colore primo piano dei nodi file nell'elenco risultati della visualizzazione rapida.","Colore di sfondo della voce selezionata nell'elenco risultati della visualizzazione rapida.","Colore primo piano della voce selezionata nell'elenco risultati della visualizzazione rapida.","Colore di sfondo dell'editor di visualizzazioni rapide.","Colore di sfondo della barra di navigazione nell'editor visualizzazione rapida.","Colore dell'evidenziazione delle corrispondenze nell'elenco risultati della visualizzazione rapida.","Colore dell'evidenziazione delle corrispondenze nell'editor di visualizzazioni rapide.","Bordo dell'evidenziazione delle corrispondenze nell'editor di visualizzazioni rapide."], +"vs/editor/contrib/rename/rename":["Nessun risultato.","Correttamente rinominato '{0}' in '{1}'. Sommario: {2}","L'esecuzione dell'operazione di ridenominazione non è riuscita.","Rinomina simbolo"],"vs/editor/contrib/rename/renameInputField":["Consente di rinominare l'input. Digitare il nuovo nome e premere INVIO per eseguire il commit."],"vs/editor/contrib/smartSelect/smartSelect":["Espandi SELECT","&&Expand Selection","Comprimi SELECT","&&Shrink Selection"],"vs/editor/contrib/snippet/snippetVariables":["Domenica","Lunedì","Martedì","Mercoledì","Giovedì","Venerdì","Sabato","Dom","Lun","Mar","Mer","Gio","Ven","Sab","Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre","Gen","Feb","Mar","Apr","Mag","Giu","Lug","Ago","Set","Ott","Nov","Dic"],"vs/editor/contrib/suggest/suggestController":["L'accettazione di '{0}' ha inserito il seguente testo: {1}","Attiva suggerimento"], +"vs/editor/contrib/suggest/suggestWidget":["Colore di sfondo del widget dei suggerimenti.","Colore del bordo del widget dei suggerimenti.","Colore primo piano del widget dei suggerimenti.","Colore di sfondo della voce selezionata del widget dei suggerimenti.","Colore delle evidenziazioni corrispondenze nel widget dei suggerimenti.","Altre informazioni...{0}","{0}, suggerimento, con dettagli","{0}, suggerimento","Meno informazioni... {0}","Caricamento...","Non ci sono suggerimenti.","{0}, accettato","{0}, suggerimento, con dettagli","{0}, suggerimento"],"vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode":["Attiva/Disattiva l'uso di TAB per spostare lo stato attivo"], +"vs/editor/contrib/wordHighlighter/wordHighlighter":["Colore di sfondo di un simbolo durante l'accesso in lettura, ad esempio durante la lettura di una variabile. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.","Colore di sfondo di un simbolo durante l'accesso in scrittura, per esempio durante la scrittura di una variabile. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.","Colore del bordo di un simbolo durante l'accesso in lettura, ad esempio durante la lettura di una variabile.","Colore del bordo di un simbolo durante l'accesso in scrittura, ad esempio durante la scrittura in una variabile.","Colore del marcatore righello panoramica per evidenziazione simboli. Il colore non deve essere opaco per non nascondere decorazioni sottostanti.","Colore del marcatore righello panoramica per evidenziazione simboli con accesso in scrittura. Il colore non deve essere opaco per non nascondere decorazioni sottostanti.","Vai al prossimo simbolo evidenziato","Vai al precedente simbolo evidenziato"], +"vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp":["No selection","Line {0}, Column {1} ({2} selected)","Line {0}, Column {1}","{0} selections ({1} characters selected)","{0} selections","Now changing the setting `accessibilitySupport` to 'on'.","Now opening the Editor Accessibility documentation page."," in a read-only pane of a diff editor."," in a pane of a diff editor."," in a read-only code editor"," in a code editor","To configure the editor to be optimized for usage with a Screen Reader press Command+E now.","To configure the editor to be optimized for usage with a Screen Reader press Control+E now.","The editor is configured to be optimized for usage with a Screen Reader.","The editor is configured to never be optimized for usage with a Screen Reader, which is not the case at this time.","Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.","Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.","Press Command+H now to open a browser window with more information related to editor accessibility.","Press Control+H now to open a browser window with more information related to editor accessibility.","You can dismiss this tooltip and return to the editor by pressing Escape or Shift+Escape.","Show Accessibility Help"], +"vs/editor/standalone/browser/inspectTokens/inspectTokens":["Developer: Inspect Tokens"],"vs/editor/standalone/browser/quickOpen/gotoLine":["Go to line {0} and character {1}","Go to line {0}","Type a line number between 1 and {0} to navigate to","Type a character between 1 and {0} to navigate to","Go to line {0}","Type a line number, followed by an optional colon and a character number to navigate to","Go to Line..."],"vs/editor/standalone/browser/quickOpen/quickCommand":["{0}, commands","Type the name of an action you want to execute","Command Palette"],"vs/editor/standalone/browser/quickOpen/quickOutline":["{0}, symbols","Type the name of an identifier you wish to navigate to","Go to Symbol...","symbols ({0})","modules ({0})","classes ({0})","interfaces ({0})","methods ({0})","functions ({0})","properties ({0})","variables ({0})","variables ({0})","constructors ({0})","calls ({0})"],"vs/editor/standalone/browser/simpleServices":["Made {0} edits in {1} files"], +"vs/editor/standalone/browser/standaloneCodeEditor":["Editor content","Press Ctrl+F1 for Accessibility Options.","Press Alt+F1 for Accessibility Options."],"vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast":["Toggle High Contrast Theme"],"vs/platform/configuration/common/configurationRegistry":["Override configurazione predefinita","Consente di configurare le impostazioni dell'editor di cui eseguire l'override per il linguaggio {0}.","Consente di configurare le impostazioni dell'editor di cui eseguire l'override per un linguaggio.","Non è possibile registrare '{0}'. Corrisponde al criterio di proprietà '\\\\[.*\\\\]$' per la descrizione delle impostazioni dell'editor specifiche del linguaggio. Usare il contributo 'configurationDefaults'.","Non è possibile registrare '{0}'. Questa proprietà è già registrata."],"vs/platform/keybinding/common/abstractKeybindingService":["È stato premuto ({0}). In attesa del secondo tasto...","La combinazione di tasti ({0}, {1}) non è un comando."], +"vs/platform/list/browser/listService":["Area di lavoro","Rappresenta il tasto 'Control' (ctrl) su Windows e Linux e il tasto 'Comando' (cmd) su OSX.","Rappresenta il tasto 'Alt' su Windows e Linux e il tasto 'Opzione' su OSX.","Modificatore da usare per aggiungere un elemento in alberi ed elenchi a una selezione multipla con il mouse (ad esempio editor aperti e visualizzazione Gestione controllo servizi in Esplora risorse). 'ctrlCmd' rappresenta il tasto 'CTRL' in Windows e Linux e il tasto 'Cmd' in OSX. I gesti del mouse Apri lateralmente, se supportati, si adatteranno in modo da non entrare in conflitto con il modificatore di selezione multipla.","Controlla la modalità di apertura degli elementi in alberi ed elenchi con il mouse, se supportata. Impostare su `singleClick` per aprire gli elementi con un unico clic del mouse e `doubleClick` per aprirli solo se viene fatto doppio clic. Per gli elementi padre con elementi figlio negli alberi, questa impostazione controllerà se per espandere l'elemento padre è necessario fare clic una sola volta o fare doppio clic. Tenere presente che alcuni alberi ed elenchi potrebbero scegliere di ignorare questa impostazione se non è applicabile. ","Controlla se gli alberi supportano lo scorrimento orizzontale in workbench."], +"vs/platform/markers/common/markers":["Errore","Avviso","Informazioni"], +"vs/platform/theme/common/colorRegistry":["Colori usati nell'area di lavoro.","Colore primo piano. Questo colore è utilizzato solo se non viene sovrascritto da un componente.","Colore primo piano globale per i messaggi di errore. Questo colore è utilizzato solamente se non viene sottoposto a override da un componente.","Colore dei bordi degli elementi evidenziati. Questo colore è utilizzato solo se non viene sovrascritto da un componente.","Un bordo supplementare attorno agli elementi per contrastarli maggiormente rispetto agli altri.","Un bordo supplementare intorno agli elementi attivi per contrastarli maggiormente rispetto agli altri.","Colore primo piano dei link nel testo.","Colore sfondo per blocchi di codice nel testo.","Colore ombreggiatura dei widget, ad es. Trova/Sostituisci all'interno dell'editor.","Sfondo della casella di input.","Primo piano della casella di input.","Bordo della casella di input.","Colore del bordo di opzioni attivate nei campi di input.","Colore di sfondo di convalida dell'input di tipo Informazione.","Colore bordo di convalida dell'input di tipo Informazione.","Colore di sfondo di convalida dell'input di tipo Avviso.","Colore bordo di convalida dell'input di tipo Avviso.","Colore di sfondo di convalida dell'input di tipo Errore.","Colore bordo di convalida dell'input di tipo Errore.","Colore sfondo Elenco/Struttura ad albero per l'elemento evidenziato quando l'Elenco/Struttura ad albero è attivo. Un Elenco/Struttura ad albero attivo\nha il focus della tastiera, uno inattivo no.","Colore primo piano Elenco/Struttura ad albero per l'elemento con stato attivo quando l'Elenco/Struttura ad albero è attivo. Un Elenco/Struttura ad albero attivo\nha il focus della tastiera, uno inattivo no.","Colore sfondo Elenco/Struttura ad albero per l'elemento selezionato quando l'Elenco/Struttura ad albero è attivo. Un Elenco/Struttura ad albero attivo\nha il focus della tastiera, uno inattivo no.","Colore primo piano Elenco/Struttura ad albero per l'elemento selezionato quando l'Elenco/Struttura ad albero è attivo. Un Elenco/Struttura ad albero attivo\nha il focus della tastiera, uno inattivo no.","Colore sfondo Elenco/Struttura ad albero per l'elemento selezionato quando l'Elenco/Struttura ad albero è inattivo. Un Elenco/Struttura ad albero attivo\nha il focus della tastiera, uno inattivo no.","Colore primo piano Elenco/Struttura ad albero per l'elemento selezionato quando l'Elenco/Struttura ad albero è inattivo. Un Elenco/Struttura ad albero attivo\nha il focus della tastiera, uno inattivo no.","List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.","Sfondo Elenco/Struttura ad albero al passaggio del mouse sugli elementi.","Primo piano Elenco/Struttura ad albero al passaggio del mouse sugli elementi.","Sfondo Elenco/Struttura ad albero durante il trascinamento degli elementi selezionati.","Colore primo piano Elenco/Struttura ad albero delle occorrenze trovate durante la ricerca nell'Elenco/Struttura ad albero.","Colore di selezione rapida per il raggruppamento delle etichette.","Colore di selezione rapida per il raggruppamento dei bordi.","Colore di sfondo del badge. I badge sono piccole etichette informative, ad esempio per mostrare il conteggio dei risultati di una ricerca.","Colore primo piano del badge. I badge sono piccole etichette informative, ad esempio per mostrare il conteggio dei risultati di una ricerca.","Ombra di ScrollBar per indicare lo scorrimento della visualizzazione.","Colore di sfondo dello slider della barra di scorrimento.","Colore di sfondo dello Slider della Barra di scorrimento al passaggio del mouse.","Colore di sfondo del cursore della barra di scorrimento quando cliccata.","Colore di sfondo dell'indicatore di stato che può essere mostrato durante l'esecuzione di operazioni lunghe.","Colore di sfondo dell'editor.","Colore primo piano predefinito dell'editor.","Colore di sfondo dei widget dell'editor, ad esempio Trova/Sostituisci.","Colore bordo dei widget dell'editor. Il colore viene utilizzato solo se il widget sceglie di avere un bordo e se il colore non è sottoposto a override da un widget.","Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget.","Colore della selezione dell'editor.","Colore del testo selezionato per il contrasto elevato.","Colore della selezione in un editor non attivo. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.","Colore delle aree con lo stesso contenuto della selezione. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.","Colore del bordo delle regioni con lo stesso contenuto della selezione.","Colore della corrispondenza di ricerca corrente.","Colore degli altri risultati della ricerca. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.","Colore dell'intervallo di limite della ricerca. Il colore non deve essere opaco per non nascondere decorazioni sottostanti.","Colore del bordo della corrispondenza della ricerca corrente.","Colore del bordo delle altre corrispondenze della ricerca.","Colore del bordo dell'intervallo di limite della ricerca. Il colore non deve essere opaco per non nascondere decorazioni sottostanti.","Evidenziazione sotto la parola per cui è visualizzata un'area sensibile al passaggio del mouse. Il colore non deve essere opaco per evitare di nascondere le decorazioni sottostanti.","Colore di sfondo dell'area sensibile al passaggio del mouse dell'editor.","Colore del bordo dell'area sensibile al passaggio del mouse dell'editor.","Colore dei collegamenti attivi.","Colore di sfondo per il testo che è stato inserito. Il colore non deve essere opaco per non nascondere le decorazioni sottostanti.","Colore di sfondo per il testo che è stato rimosso. Il colore non deve essere opaco per non nascondere le decorazioni sottostanti.","Colore del contorno del testo che è stato inserito.","Colore del contorno del testo che è stato rimosso.","Border color between the two text editors.","Colore del marcatore righello panoramica per trovare corrispondenze. Il colore non deve essere opaco per non nascondere decorazioni sottostanti.","Colore del marcatore righello panoramica per evidenziazione selezioni. Il colore non deve essere opaco per non nascondere decorazioni sottostanti."] +}); +//# sourceMappingURL=../../../min-maps/vs/editor/editor.main.nls.it.js.map \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/editor/editor.main.nls.ja.js b/public/react/public/js/monaco/vs/editor/editor.main.nls.ja.js new file mode 100755 index 000000000..3f7b98c80 --- /dev/null +++ b/public/react/public/js/monaco/vs/editor/editor.main.nls.ja.js @@ -0,0 +1,25 @@ +/*!----------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Version: 0.14.6(6c8f02b41db9ae5c4d15df767d47755e5c73b9d5) + * Released under the MIT license + * https://github.com/Microsoft/vscode/blob/master/LICENSE.txt + *-----------------------------------------------------------*/ +define("vs/editor/editor.main.nls.ja",{"vs/base/browser/ui/actionbar/actionbar":["{0} ({1})"],"vs/base/browser/ui/aria/aria":["{0} (再発)","{0} (occurred {1} times)"],"vs/base/browser/ui/findinput/findInput":["入力"],"vs/base/browser/ui/findinput/findInputCheckboxes":["大文字と小文字を区別する","単語単位で検索する","正規表現を使用する"],"vs/base/browser/ui/inputbox/inputBox":["エラー: {0}","警告: {0}","情報: {0}"],"vs/base/browser/ui/list/listWidget":["{0}. Use the navigation keys to navigate."],"vs/base/browser/ui/menu/menu":["{0} ({1})"],"vs/base/common/keybindingLabels":["Ctrl","Shift","Alt","Windows","Ctrl","Shift","Alt","Super","Control","Shift","Alt","コマンド","Control","Shift","Alt","Windows","Control","Shift","Alt","Super"],"vs/base/common/severity":["エラー","警告","情報"],"vs/base/parts/quickopen/browser/quickOpenModel":["{0}, ピッカー","選択"],"vs/base/parts/quickopen/browser/quickOpenWidget":["クイック選択。入力すると結果が絞り込まれます。","クイック選択","{0} Results"],"vs/editor/browser/controller/coreCommands":["&&Select All","&&Undo","&&Redo"], +"vs/editor/browser/widget/codeEditorWidget":["カーソルの数は {0} 個に制限されています。"],"vs/editor/browser/widget/diffEditorWidget":["一方のファイルが大きすぎるため、ファイルを比較できません。"],"vs/editor/browser/widget/diffReview":["閉じる","行なし","1 行","{0} 行","{1} の差異 {0}: 変更前 {2}, {3}, 変更後 {4}, {5}","空白","変更前の {0}、変更後の {1}: {2}","+ 変更後の {0}: {1}","- 変更前の {0}: {1}","次の差分に移動","前の差分に移動"], +"vs/editor/common/config/commonEditorConfig":["エディター","フォント ファミリを制御します。","フォントの太さを制御します。","フォント サイズをピクセル単位で制御します。","行の高さを制御します。fontSize に基づいて lineHeight を計算する場合には、0 を使用します。","文字の間隔をピクセル単位で制御します。","行番号は表示されません。","行番号は、絶対数として表示されます。","行番号は、カーソル位置までの行数として表示されます。","行番号は 10 行ごとに表示されます。","行番号の表示を制御します。","等幅フォントの特定番号の後ろに垂直ルーラーを表示します。複数のルーラーには複数の値を使用します。配列が空の場合はルーラーを表示しません。","単語に関連したナビゲーションまたは操作を実行するときに、単語の区切り文字として使用される文字","1 つのタブに相当するスペースの数。`editor.detectIndentation` がオンの場合、この設定はファイル コンテンツに基づいて上書きされます。","'number' が必要です。`editor.detectIndentation` 設定によって値 \"auto\" が置き換えられていることに注意してください。","Tab キーを押すとスペースが挿入されます。`editor.detectIndentation` がオンの場合、この設定はファイル コンテンツに基づいて上書きされます。","'boolean' が必要です。`editor.detectIndentation` 設定によって値 \"auto\" が置き換えられていることに注意してください。","ファイルを開くと、そのファイルの内容に基づいて `editor.tabSize` と `editor.insertSpaces` が検出されます。","選択範囲の角を丸くするかどうかを制御します","エディターで最後の行を越えてスクロールするかどうかを制御します","エディターが水平方向に余分にスクロールする文字数を制御します","アニメーションでエディターをスクロールするかどうかを制御します","ミニマップを表示するかどうかを制御します","ミニマップを表示する場所を制御します。","ミニマップのスライダーを自動的に非表示にするかどうかを制御します。","行に (カラー ブロックではなく) 実際の文字を表示します","表示するミニマップの最大幅を特定の桁数に制限します","Controls whether the hover is shown.","Time delay in milliseconds after which to the hover is shown.","Controls whether the hover should remain visible when mouse is moved over it.","エディターの選択から検索ウィジェット内の検索文字列を与えるかどうかを制御します","エディター内で複数の文字もしくは行が選択されているときに選択範囲を検索するフラグを有効にするかどうかを制御します","macOS で検索ウィジェットが共有の検索クリップボードを読み取りまたは変更するかどうかを制御します","行を折り返しません。","行をビューポートの幅で折り返します。","行を 'editor.wordWrapColumn' で折り返します。","ビューポートと 'editor.wordWrapColumn' の最小値で行を折り返します。","行の折り返し方法を制御します。次の値を指定できます。\n - 'off' (折り返さない),\n - 'on' (ビューポート折り返し),\n - 'wordWrapColumn' ('editor.wordWrapColumn' で折り返し) or\n - 'bounded' (ビューポートと 'editor.wordWrapColumn' の最小値で折り返し).","'editor.wordWrap' が 'wordWrapColumn' または 'bounded' の場合に、エディターの折り返し桁を制御します。","No indentation. Wrapped lines begin at column 1.","Wrapped lines get the same indentation as the parent.","Wrapped lines get +1 indentation toward the parent.","Wrapped lines get +2 indentation toward the parent.","折り返し行のインデントを制御します。'none'、'same'、'indent' または 'deepIndent' のいずれかを指定できます。","マウス ホイール スクロール イベントの `deltaX` と `deltaY` で使用される乗数","Windows および Linux 上の `Control` キーと macOS 上の `Command` キーに割り当てます。","Windows および Linux 上の `Alt` キーと macOS 上の `Option` キーに割り当てます。","マウスを使用して複数のカーソルを追加するときに使用する修飾キーです。`ctrlCmd` は Windows および Linux 上の `Control` キーと macOS 上の `Command` キーに割り当てます。「定義に移動」や「リンクを開く」のマウス操作は、マルチカーソルの修飾キーと競合しないように適用されます。","複数のカーソルが重なっているときは、マージします。","文字列内でクイック候補を有効にします。","コメント内でクイック候補を有効にします。","文字列およびコメント外でクイック候補を有効にします。","入力中に候補を自動的に表示するかどうかを制御します","クイック候補が表示されるまでの待ち時間 (ミリ秒) を制御します","入力時にパラメーター ドキュメントと型情報を表示するポップアップを有効にする","エディターで左角かっこの後に自動的に右角かっこを挿入するかどうかを制御します","エディターで入力後に自動的に行の書式設定を行うかどうかを制御します","貼り付けた内容がエディターにより自動的にフォーマットされるかどうかを制御します。フォーマッタを使用可能にする必要があります。また、フォーマッタがドキュメント内の範囲をフォーマットできなければなりません。","ユーザーが入力や貼り付け、行の移動をしたとき、エディターがインデントを自動的に調整するかどうかを制御します。言語のインデント ルールを使用できる必要があります。","トリガー文字の入力時に候補が自動的に表示されるようにするかどうかを制御します","Only accept a suggestion with `Enter` when it makes a textual change.","'Tab' キーに加えて 'Enter' キーで候補を受け入れるかどうかを制御します。改行の挿入や候補の反映の間であいまいさを解消するのに役立ちます。'smart' 値は文字を変更するときに、Enter キーを押すだけで提案を反映することを意味します。","コミット文字で候補を受け入れるかどうかを制御します。たとえば、JavaScript ではセミコロン (';') をコミット文字にして、候補を受け入れてその文字を入力することができます。","他の候補の上にスニペットの候補を表示します。","他の候補の下にスニペットの候補を表示します。","他の候補と一緒にスニペットの候補を表示します。","スニペットの候補を表示しません。","他の修正候補と一緒にスニペットを表示するかどうか、およびその並び替えの方法を制御します。","選択範囲を指定しないでコピーする場合に現在の行をコピーするかどうかを制御します。","ドキュメント内の単語に基づいて入力候補を計算するかどうかを制御します。","常に最初の候補を選択します。","追加入力によって選択されたものがなければ、最近の候補を選択します。例: `console.| -> console.log` (`log` は最近入力されたため)。","これらの候補を入力した前のプレフィックスに基づいて候補を選択します。例: `co -> console`、`con -> const`。","候補リストを表示するときに候補を事前に選択する方法を制御します。","候補のウィジェットのフォント サイズ","候補のウィジェットの行の高さ","Controls whether filtering and sorting suggestions accounts for small typos.","Control whether an active snippet prevents quick suggestions.","エディターで選択範囲に類似する一致箇所を強調表示するかどうかを制御します","エディターでセマンティック シンボルの出現箇所を強調表示するかどうかを制御します","概要ルーラーの同じ位置に表示できる装飾の数を制御します","概要ルーラーの周囲に境界線が描画されるかどうかを制御します。","カーソルのアニメーション方式を制御します。","Ctrl キーを押しながらマウス ホイールを使用してエディターのフォントをズームします","カーソルのスタイルを制御します。指定できる値は 'block'、'block-outline'、'line'、'line-thin'、'underline'、'underline-thin' です","editor.cursorStyle が 'line' に設定されている場合、カーソルの幅を制御する","フォントの合字を使用します","概要ルーラーでカーソルを非表示にするかどうかを制御します。","Render whitespace characters except for single spaces between words.","エディターで空白文字を表示する方法を制御します。'none'、'boundary' および 'all' が使用可能です。'boundary' オプションでは、単語間の単一スペースは表示されません。","エディターで制御文字を表示する必要があるかどうかを制御します","エディターでインデントのガイドを表示する必要があるかどうかを制御します","Controls whether the editor should highlight the active indent guide.","Highlights both the gutter and the current line.","エディターが現在の行をどのように強調表示するかを制御します。考えられる値は 'none'、'gutter'、'line'、'all' です。","エディターが CodeLens を表示するかどうかを制御します","エディターでコードの折りたたみを有効にするかどうかを制御します","折りたたみ範囲の計算方法を制御します。'auto' は利用可能であれば言語固有の折りたたみ方式を使用します。'indentation' は常にインデントに基づく折りたたみ方式を使用します。","余白上の折りたたみコントロールを自動的に非表示にするかどうかを制御します 。","かっこを選択すると、対応するかっこを強調表示します。","エディターで縦のグリフ余白が表示されるかどうかを制御します。ほとんどの場合、グリフ余白はデバッグに使用されます。","空白の挿入や削除はタブ位置に従って行われます","自動挿入された末尾の空白を削除する","エディターのコンテンツをダブルクリックするか、Esc キーを押しても、ピーク エディターを開いたままにします。","ドラッグ アンド ドロップによる選択範囲の移動をエディターが許可する必要があるかどうかを制御します。","エディターはスクリーン リーダーがいつ接続されたかを検出するためにプラットフォーム API を使用します。","エディターは永続的にスクリーン リーダー向けに最適化されます。","エディターはスクリーン リーダー向けに最適化されません。","エディターをスクリーン リーダーに最適化されたモードで実行するかどうかを制御します。","Controls fading out of unused code.","エディターがリンクを検出してクリック可能な状態にするかどうかを制御します","エディターでインライン カラー デコレーターと色の選択を表示する必要があるかどうかを制御します。","コード アクション (lightbulb) を有効にする","保存時にインポートの整理を実行しますか?","保存時に実行されるコードアクションの種類。","保存時に実行されるコード アクションのタイムアウト値。","Linux の PRIMARY クリップボードをサポートするかどうかを制御します。","差分エディターが差分を横に並べて表示するか、行内に表示するかを制御します","差分エディターが、先頭または末尾の空白の変更を差分として表示するかどうかを制御します。","大きなファイルでメモリが集中する特定の機能を無効にするための特別な処理。","差分エディターが追加/削除された変更に +/- インジケーターを示すかどうかを制御します"], +"vs/editor/common/config/editorOptions":["現在エディターにアクセスすることはできません。 Alt + F1 キーを押してオプションを選択します。","エディターのコンテンツ"],"vs/editor/common/controller/cursor":["コマンドの実行中に予期しない例外が発生しました。"],"vs/editor/common/modes/modesRegistry":["プレーンテキスト"],"vs/editor/common/services/modelServiceImpl":["[{0}]\n{1}","[{0}] {1}"], +"vs/editor/common/view/editorColorRegistry":["カーソル位置の行を強調表示する背景色。","カーソル位置の行の境界線を強調表示する背景色。","Quick Open 機能や検索機能などによって強調表示された範囲の背景色。下にある装飾を隠さないために、色は不透過であってはなりません。","強調表示された範囲の境界線の背景色。","エディターのカーソルの色。","選択された文字列の背景色です。選択された文字列の背景色をカスタマイズ出来ます。","エディターのスペース文字の色。","エディター インデント ガイドの色。","アクティブなエディターのインデント ガイドの色。","エディターの行番号の色。","エディターのアクティブ行番号の色","id は使用しないでください。代わりに 'EditorLineNumber.activeForeground' を使用してください。","エディターのアクティブ行番号の色","エディター ルーラーの色。","CodeLens エディターの前景色。","一致するかっこの背景色","一致するかっこ内のボックスの色","概要ルーラーの境界色。","エディターの余白の背景色。余白にはグリフ マージンと行番号が含まれます。","エディターでエラーを示す波線の前景色。","エディターでエラーを示す波線の境界線の色。","エディターで警告を示す波線の前景色。","エディターで警告を示す波線の境界線の色。","エディターで情報を示す波線の前景色。","エディターで情報を示す波線の境界線の色。","エディターでヒントを示す波線の前景色。","エディターでヒントを示す波線の境界線の色。","Border of unnecessary code in the editor.","Opacity of unnecessary code in the editor.","エラーを示す概要ルーラーのマーカー色。","警告を示す概要ルーラーのマーカー色。","情報を示す概要ルーラーのマーカー色。"],"vs/editor/contrib/bracketMatching/bracketMatching":["一致するブラケットを示す概要ルーラーのマーカー色。","ブラケットへ移動","ブラケットに選択"], +"vs/editor/contrib/caretOperations/caretOperations":["キャレットを左に移動","キャレットを右に移動"],"vs/editor/contrib/caretOperations/transpose":["文字の入れ替え"],"vs/editor/contrib/clipboard/clipboard":["切り取り","Cu&&t","コピー","&&Copy","貼り付け","&&Paste","構文を強調表示してコピー"],"vs/editor/contrib/codeAction/codeActionCommands":["修正プログラム ({0}) を表示する","修正プログラムを表示する","クイック フィックス...","利用可能なコード アクションはありません","利用可能なコード アクションはありません","リファクター...","利用可能なリファクタリングはありません","ソース アクション...","利用可能なソース アクションはありません","インポートを整理","利用可能なインポートの整理アクションはありません"],"vs/editor/contrib/comment/comment":["行コメントの切り替え","&&Toggle Line Comment","行コメントの追加","行コメントの削除","ブロック コメントの切り替え","Toggle &&Block Comment"],"vs/editor/contrib/contextmenu/contextmenu":["エディターのコンテキスト メニューの表示"],"vs/editor/contrib/cursorUndo/cursorUndo":["Soft Undo"],"vs/editor/contrib/find/findController":["検索","&&Find","選択範囲を検索","次を検索","前を検索","次の選択項目を検索","前の選択項目を検索","置換","&&Replace"], +"vs/editor/contrib/find/findWidget":["検索","検索","前の一致項目","次の一致項目","選択範囲を検索","閉じる","置換","置換","置換","すべて置換","置換モードの切り替え","最初の {0} 件の結果だけが強調表示されますが、すべての検索操作はテキスト全体で機能します。","{0} / {1} 件","結果なし"],"vs/editor/contrib/folding/folding":["展開","再帰的に展開","折りたたみ","再帰的に折りたたむ","すべてのブロック コメントの折りたたみ","すべての領域を折りたたむ","すべての領域を展開","すべて折りたたみ","すべて展開","レベル {0} で折りたたむ"],"vs/editor/contrib/fontZoom/fontZoom":["エディターのフォントを拡大","エディターのフォントを縮小","エディターのフォントのズームをリセット"],"vs/editor/contrib/format/formatActions":["行 {0} で 1 つの書式設定を編集","行 {1} で {0} 個の書式設定を編集","行 {0} と {1} の間で 1 つの書式設定を編集","行 {1} と {2} の間で {0} 個の書式設定を編集","インストールされた '{0}'ファイル用のフォーマッターが存在しません。","ドキュメントのフォーマット","インストールされた '{0}'ファイル用のドキュメント フォーマッターが存在しません。","選択範囲のフォーマット","インストールされた '{0}' ファイル用の選択範囲フォーマッターが存在しません。"],"vs/editor/contrib/goToDefinition/goToDefinitionCommands":["'{0}' の定義は見つかりません","定義が見つかりません"," – {0} 個の定義","定義へ移動","定義を横に開く","定義をここに表示","'{0}' の実装が見つかりません","実装が見つかりません","– {0} 個の実装","実装に移動","実装のプレビュー","'{0}' の型定義が見つかりません","型定義が見つかりません"," – {0} 個の型定義","型定義へ移動","型定義を表示"], +"vs/editor/contrib/goToDefinition/goToDefinitionMouse":["クリックして、{0} の定義を表示します。"],"vs/editor/contrib/gotoError/gotoError":["次の問題 (エラー、警告、情報) へ移動","前の問題 (エラー、警告、情報) へ移動","ファイル内の次の問題 (エラー、警告、情報) へ移動","ファイル内の前の問題 (エラー、警告、情報) へ移動"],"vs/editor/contrib/gotoError/gotoErrorWidget":["({0}/{1})","エディターのマーカー ナビゲーション ウィジェットのエラーの色。","エディターのマーカー ナビゲーション ウィジェットの警告の色。","エディターのマーカー ナビゲーション ウィジェットの情報の色。","エディターのマーカー ナビゲーション ウィジェットの背景。"],"vs/editor/contrib/hover/hover":["ホバーの表示"],"vs/editor/contrib/hover/modesContentHover":["読み込んでいます..."],"vs/editor/contrib/inPlaceReplace/inPlaceReplace":["前の値に置換","次の値に置換"],"vs/editor/contrib/linesOperations/linesOperations":["行を上へコピー","&&Copy Line Up","行を下へコピー","Co&&py Line Down","行を上へ移動","Mo&&ve Line Up","行を下へ移動","Move &&Line Down","行を昇順に並べ替え","行を降順に並べ替え","末尾の空白のトリミング","行の削除","行のインデント","行のインデント解除","行を上に挿入","行を下に挿入","左側をすべて削除","右側をすべて削除","行をつなげる","カーソルの周囲の文字を入れ替える","大文字に変換","小文字に変換"], +"vs/editor/contrib/links/links":["command キーを押しながらクリックしてリンク先を表示","Ctrl キーを押しながらクリックしてリンク先を表示","command キーを押しながらクリックしてコマンドを実行","Ctrl キーを押しながらクリックしてコマンドを実行","Option キーを押しながらクリックしてリンク先を表示","Altl キーを押しながらクリックしてリンク先を表示","Option キーを押しながらクリックしてコマンドを実行","Alt キーを押しながらクリックしてコマンドを実行","このリンクは形式が正しくないため開くことができませんでした: {0}","このリンクはターゲットが存在しないため開くことができませんでした。","リンクを開く"],"vs/editor/contrib/message/messageController":["読み取り専用のエディターは編集できません"],"vs/editor/contrib/multicursor/multicursor":["カーソルを上に挿入","&&Add Cursor Above","カーソルを下に挿入","A&&dd Cursor Below","カーソルを行末に挿入","Add C&&ursors to Line Ends","選択項目を次の一致項目に追加","Add &&Next Occurrence","選択項目を次の一致項目に追加","Add P&&revious Occurrence","最後に選択した項目を次の一致項目に移動","最後に選択した項目を前の一致項目に移動","一致するすべての出現箇所を選択","Select All &&Occurrences","すべての出現箇所を変更"],"vs/editor/contrib/parameterHints/parameterHints":["パラメーター ヒントをトリガー"],"vs/editor/contrib/parameterHints/parameterHintsWidget":["{0}、ヒント"],"vs/editor/contrib/referenceSearch/peekViewWidget":["閉じる"], +"vs/editor/contrib/referenceSearch/referenceSearch":["– {0} 個の参照","すべての参照の検索"],"vs/editor/contrib/referenceSearch/referencesController":["読み込んでいます..."],"vs/editor/contrib/referenceSearch/referencesModel":["列 {2} の {1} 行目に {0} つのシンボル","{0} に 1 個のシンボル、完全なパス {1}","{1} に {0} 個のシンボル、完全なパス {2}","一致する項目はありません","{0} に 1 個のシンボルが見つかりました","{1} に {0} 個のシンボルが見つかりました","{1} 個のファイルに {0} 個のシンボルが見つかりました"],"vs/editor/contrib/referenceSearch/referencesWidget":["ファイルを解決できませんでした。","{0} 個の参照","{0} 個の参照","プレビューを表示できません","参照","結果がありません","参照","ピーク ビューのタイトル領域の背景色。","ピーク ビュー タイトルの色。","ピーク ビューのタイトル情報の色。","ピーク ビューの境界と矢印の色。","ピーク ビュー結果リストの背景色。","ピーク ビュー結果リストのライン ノードの前景色。","ピーク ビュー結果リストのファイル ノードの前景色。","ピーク ビュー結果リストの選択済みエントリの背景色。","ピーク ビュー結果リストの選択済みエントリの前景色。","ピーク ビュー エディターの背景色。","ピーク ビュー エディターの余白の背景色。","ピーク ビュー結果リストの一致した強調表示色。","ピーク ビュー エディターの一致した強調表示色。","ピーク ビュー エディターの一致した強調境界色。"],"vs/editor/contrib/rename/rename":["結果がありません。","'{0}' から '{1}' への名前変更が正常に完了しました。概要: {2}","名前の変更を実行できませんでした。","シンボルの名前を変更"], +"vs/editor/contrib/rename/renameInputField":["名前変更入力。新しい名前を入力し、Enter キーを押してコミットしてください。"],"vs/editor/contrib/smartSelect/smartSelect":["選択範囲を拡大","&&Expand Selection","選択範囲を縮小","&&Shrink Selection"],"vs/editor/contrib/snippet/snippetVariables":["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日","日","月","火","水","木","金","土","1 月","2 月","3 月","4 月","5 月","6 月","7 月","8 月","9 月","10 月","11 月","12 月","1 月","2 月","3 月","4 月","5 月","6 月","7 月","8 月","9 月","10 月","11 月","12 月"],"vs/editor/contrib/suggest/suggestController":["'{0}' が次のテキストを挿入したことを承認しています: {1}","候補をトリガー"],"vs/editor/contrib/suggest/suggestWidget":["候補のウィジェットの背景色。","候補ウィジェットの境界線色。","候補ウィジェットの前景色。","候補ウィジェット内で選択済みエントリの背景色。","候補のウィジェット内で一致したハイライトの色。","詳細を表示...{0}","{0}、候補、詳細あり","{0}、候補","詳細を隠す...{0}","読み込んでいます...","候補はありません。","{0}、受け入れ済み","{0}、候補、詳細あり","{0}、候補"],"vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode":["TAB キーのフォーカス移動を切り替え"], +"vs/editor/contrib/wordHighlighter/wordHighlighter":["変数の読み取りなど読み取りアクセス中のシンボルの背景色。下にある装飾を隠さないために、色は不透過であってはなりません。","変数への書き込みなど書き込みアクセス中のシンボルの背景色。下にある装飾を隠さないために、色は不透過であってはなりません。","変数の読み取りなど読み取りアクセス中のシンボルの境界線の色。","変数への書き込みなど書き込みアクセス中のシンボルの境界線の色。","シンボルを強調表示するときの概要ルーラーのマーカー色。この色は下地の色に紛れないよう不明瞭であってはいけません。","書き込みアクセス シンボルを強調表示するときの概要ルーラーのマーカー色。この色は下地の色に紛れないよう不明瞭であってはいけません。","次のシンボル ハイライトに移動","前のシンボル ハイライトに移動"], +"vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp":["No selection","Line {0}, Column {1} ({2} selected)","Line {0}, Column {1}","{0} selections ({1} characters selected)","{0} selections","Now changing the setting `accessibilitySupport` to 'on'.","Now opening the Editor Accessibility documentation page."," in a read-only pane of a diff editor."," in a pane of a diff editor."," in a read-only code editor"," in a code editor","To configure the editor to be optimized for usage with a Screen Reader press Command+E now.","To configure the editor to be optimized for usage with a Screen Reader press Control+E now.","The editor is configured to be optimized for usage with a Screen Reader.","The editor is configured to never be optimized for usage with a Screen Reader, which is not the case at this time.","Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.","Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.","Press Command+H now to open a browser window with more information related to editor accessibility.","Press Control+H now to open a browser window with more information related to editor accessibility.","You can dismiss this tooltip and return to the editor by pressing Escape or Shift+Escape.","Show Accessibility Help"], +"vs/editor/standalone/browser/inspectTokens/inspectTokens":["Developer: Inspect Tokens"],"vs/editor/standalone/browser/quickOpen/gotoLine":["Go to line {0} and character {1}","Go to line {0}","Type a line number between 1 and {0} to navigate to","Type a character between 1 and {0} to navigate to","Go to line {0}","Type a line number, followed by an optional colon and a character number to navigate to","Go to Line..."],"vs/editor/standalone/browser/quickOpen/quickCommand":["{0}, commands","Type the name of an action you want to execute","Command Palette"],"vs/editor/standalone/browser/quickOpen/quickOutline":["{0}, symbols","Type the name of an identifier you wish to navigate to","Go to Symbol...","symbols ({0})","modules ({0})","classes ({0})","interfaces ({0})","methods ({0})","functions ({0})","properties ({0})","variables ({0})","variables ({0})","constructors ({0})","calls ({0})"],"vs/editor/standalone/browser/simpleServices":["Made {0} edits in {1} files"], +"vs/editor/standalone/browser/standaloneCodeEditor":["Editor content","Press Ctrl+F1 for Accessibility Options.","Press Alt+F1 for Accessibility Options."],"vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast":["Toggle High Contrast Theme"],"vs/platform/configuration/common/configurationRegistry":["既定の構成オーバーライド","{0} 言語に対して上書きされるエディター設定を構成します。","言語に対して上書きされるエディター設定を構成します。","'{0}' を登録できません。これは、言語固有のエディター設定を記述するプロパティ パターン '\\\\[.*\\\\]$' に一致しています。'configurationDefaults' コントリビューションを使用してください。","'{0}' を登録できません。このプロパティは既に登録されています。"],"vs/platform/keybinding/common/abstractKeybindingService":["({0}) が押されました。2 番目のキーを待っています...","キーの組み合わせ ({0}、{1}) はコマンドではありません。"], +"vs/platform/list/browser/listService":["ワークベンチ","Windows および Linux 上の `Control` キーと macOS 上の `Command` キーに割り当てます。","Windows および Linux 上の `Alt` キーと macOS 上の `Option` キーに割り当てます。","マウスで複数の選択肢にツリーおよびリストの項目を追加するために使用される修飾子 (たとえば、エクスプローラーでエディターと scm ビューを開くなど)。`ctrlCmd` は、Windows と Linux では `Control` にマップされ、macOS では `Command` にマップされます。'横に並べて開く' マウス ジェスチャー (サポートされている場合) は、複数選択修飾子と競合しないように調整されます。","マウスを使用して、ツリーとリストで項目を開く方法を制御します (サポートされている場合)。'SingleClick' に設定すると、項目をマウスのシングル クリックで開き、'doubleClick' に設定すると、ダブル クリックでのみ開きます。ツリーで子を持つ親の場合、この設定で、親をシングル クリックで展開するか、ダブル クリックで展開するかを制御します。該当しない場合、一部のツリーとリストでは、この設定が無視される場合があることに注意してください。","ワークベンチでツリーが水平スクロールをサポートするかどうかを制御します。"],"vs/platform/markers/common/markers":["エラー","警告","情報"], +"vs/platform/theme/common/colorRegistry":["ワークベンチで使用する色。","全体の前景色。この色は、コンポーネントによってオーバーライドされていない場合にのみ使用されます。","エラー メッセージ全体の前景色。この色は、コンポーネントによって上書きされていない場合にのみ使用されます。","フォーカスされた要素の境界線全体の色。この色はコンポーネントによって上書きされていない場合にのみ使用されます。","コントラストを強めるために、他の要素と隔てる追加の境界線。","コントラストを強めるために、アクティブな他要素と隔てる追加の境界線。","テキスト内のリンクの前景色。","テキスト内のコード ブロックの背景色。","エディター内の検索/置換窓など、エディター ウィジェットの影の色。","入力ボックスの背景。","入力ボックスの前景。","入力ボックスの境界線。","入力フィールドのアクティブ オプションの境界線の色。","情報の重大度を示す入力検証の背景色。","情報の重大度を示す入力検証の境界線色。","警告の重大度を示す入力検証の背景色。","警告の重大度を示す入力検証の境界線色。","エラーの重大度を示す入力検証の背景色。","エラーの重大度を示す入力検証の境界線色。","ツリーリストがアクティブのとき、フォーカスされた項目のツリーリスト背景色。アクティブなツリーリストはキーボード フォーカスがあり、非アクティブではこれがありません。","ツリーリストがアクティブのとき、フォーカスされた項目のツリーリスト前景色。アクティブなツリーリストはキーボード フォーカスがあり、非アクティブではこれがありません。","ツリーリストがアクティブのとき、選択された項目のツリーリスト背景色。アクティブなツリーリストはキーボード フォーカスがあり、非アクティブではこれがありません。","ツリーリストがアクティブのとき、選択された項目のツリーリスト前景色。アクティブなツリーリストはキーボード フォーカスがあり、非アクティブではこれがありません。","ツリーリストが非アクティブのとき、フォーカスされた項目のツリーリスト背景色。アクティブなツリーリストはキーボード フォーカスがあり、非アクティブではこれがありません。","ツリーリストが非アクティブのとき、選択された項目のツリーリスト前景色。アクティブなツリーリストはキーボード フォーカスがあり、非アクティブではこれがありません。","List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.","マウス操作で項目をホバーするときのツリーリスト背景。","マウス操作で項目をホバーするときのツリーリスト前景。","マウス操作で項目を移動するときのツリーリスト ドラッグ アンド ドロップの背景。","ツリーリスト内を検索しているとき、一致した強調のツリーリスト前景色。","ラベルをグループ化するためのクリック選択の色。","境界線をグループ化するためのクイック選択の色。","バッジの背景色。バッジとは小さな情報ラベルのことです。例:検索結果の数","バッジの前景色。バッジとは小さな情報ラベルのことです。例:検索結果の数","ビューがスクロールされたことを示すスクロール バーの影。","スクロール バーのスライダーの背景色。","ホバー時のスクロール バー スライダー背景色。","クリック時のスクロール バー スライダー背景色。","時間のかかる操作で表示するプログレス バーの背景色。","エディターの背景色。","エディターの既定の前景色。","検索/置換窓など、エディター ウィジェットの背景色。","エディター ウィジェットの境界線色。ウィジェットに境界線があり、ウィジェットによって配色を上書きされていない場合でのみこの配色は使用されます。","Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget.","エディターの選択範囲の色。","ハイ コントラストの選択済みテキストの色。","非アクティブなエディターの選択範囲の色。下にある装飾を隠さないために、色は不透過であってはなりません。","選択範囲と同じコンテンツの領域の色。下にある装飾を隠さないために、色は不透過であってはなりません。","選択範囲と同じコンテンツの境界線の色。","現在の検索一致項目の色。","他の検索一致項目の色。下にある装飾を隠さないために、色は不透過であってはなりません。","検索を制限する範囲の色。下にある装飾を隠さないために、色は不透過であってはなりません。","現在の検索一致項目の境界線の色。","他の検索一致項目の境界線の色。","検索を制限する範囲の境界線の色。下にある装飾を隠さないために、色は不透過であってはなりません。","ホバーが表示されているワードの下を強調表示します。下にある装飾を隠さないために、色は不透過であってはなりません。","エディター ホバーの背景色。","エディター ホバーの境界線の色。","アクティブなリンクの色。","挿入されたテキストの境界線の色。下にある装飾を隠さないために、色は不透過であってはなりません。","削除されたテキストの境界線の色。下にある装飾を隠さないために、色は不透過であってはなりません。","挿入されたテキストの輪郭の色。","削除されたテキストの輪郭の色。","Border color between the two text editors.","検索一致項目を示す概要ルーラーのマーカー色。この色は下地の色に紛れないよう不明瞭であってはいけません。","選択範囲を強調表示するときの概要ルーラーのマーカー色。この色は下地の色に紛れないよう不明瞭であってはいけません。"] +}); +//# sourceMappingURL=../../../min-maps/vs/editor/editor.main.nls.ja.js.map \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/editor/editor.main.nls.js b/public/react/public/js/monaco/vs/editor/editor.main.nls.js new file mode 100755 index 000000000..c42ac0085 --- /dev/null +++ b/public/react/public/js/monaco/vs/editor/editor.main.nls.js @@ -0,0 +1,29 @@ +/*!----------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Version: 0.14.6(6c8f02b41db9ae5c4d15df767d47755e5c73b9d5) + * Released under the MIT license + * https://github.com/Microsoft/vscode/blob/master/LICENSE.txt + *-----------------------------------------------------------*/ +define("vs/editor/editor.main.nls",{"vs/base/browser/ui/actionbar/actionbar":["{0} ({1})"],"vs/base/browser/ui/aria/aria":["{0} (occurred again)","{0} (occurred {1} times)"],"vs/base/browser/ui/findinput/findInput":["input"],"vs/base/browser/ui/findinput/findInputCheckboxes":["Match Case","Match Whole Word","Use Regular Expression"],"vs/base/browser/ui/inputbox/inputBox":["Error: {0}","Warning: {0}","Info: {0}"],"vs/base/browser/ui/list/listWidget":["{0}. Use the navigation keys to navigate."],"vs/base/browser/ui/menu/menu":["{0} ({1})"],"vs/base/common/keybindingLabels":["Ctrl","Shift","Alt","Windows","Ctrl","Shift","Alt","Super","Control","Shift","Alt","Command","Control","Shift","Alt","Windows","Control","Shift","Alt","Super"],"vs/base/common/severity":["Error","Warning","Info"],"vs/base/parts/quickopen/browser/quickOpenModel":["{0}, picker","picker"],"vs/base/parts/quickopen/browser/quickOpenWidget":["Quick picker. Type to narrow down results.","Quick Picker","{0} Results"], +"vs/editor/browser/controller/coreCommands":["&&Select All","&&Undo","&&Redo"],"vs/editor/browser/widget/codeEditorWidget":["The number of cursors has been limited to {0}."],"vs/editor/browser/widget/diffEditorWidget":["Cannot compare files because one file is too large."],"vs/editor/browser/widget/diffReview":["Close","no lines","1 line","{0} lines","Difference {0} of {1}: original {2}, {3}, modified {4}, {5}","blank","original {0}, modified {1}: {2}","+ modified {0}: {1}","- original {0}: {1}","Go to Next Difference","Go to Previous Difference"], +"vs/editor/common/config/commonEditorConfig":["Editor","Controls the font family.","Controls the font weight.","Controls the font size in pixels.","Controls the line height. Use 0 to compute the line height from the font size.","Controls the letter spacing in pixels.","Line numbers are not rendered.","Line numbers are rendered as absolute number.","Line numbers are rendered as distance in lines to cursor position.","Line numbers are rendered every 10 lines.","Controls the display of line numbers.","Render vertical rulers after a certain number of monospace characters. Use multiple values for multiple rulers. No rulers are drawn if array is empty.","Characters that will be used as word separators when doing word related navigations or operations.","The number of spaces a tab is equal to. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.","Expected 'number'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.","Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.","Expected 'boolean'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.","Controls whether `#editor.tabSize#` and `#editor.insertSpaces#` will be automatically detected when a file is opened based on the file contents.","Controls whether selections should have rounded corners.","Controls whether the editor will scroll beyond the last line.","Controls the number of extra characters beyond which the editor will scroll horizontally.","Controls whether the editor will scroll using an animation.","Controls whether the minimap is shown.","Controls the side where to render the minimap.","Controls whether the minimap slider is automatically hidden.","Render the actual characters on a line as opposed to color blocks.","Limit the width of the minimap to render at most a certain number of columns.","Controls whether the hover is shown.","Time delay in milliseconds after which to the hover is shown.","Controls whether the hover should remain visible when mouse is moved over it.","Controls whether the search string in the Find Widget is seeded from the editor selection.","Controls whether the find operation is carried on selected text or the entire file in the editor.","Controls whether the Find Widget should read or modify the shared find clipboard on macOS.","Lines will never wrap.","Lines will wrap at the viewport width.","Lines will wrap at `#editor.wordWrapColumn#`.","Lines will wrap at the minimum of viewport and `#editor.wordWrapColumn#`.","Controls how lines should wrap.","Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.","No indentation. Wrapped lines begin at column 1.","Wrapped lines get the same indentation as the parent.","Wrapped lines get +1 indentation toward the parent.","Wrapped lines get +2 indentation toward the parent.","Controls the indentation of wrapped lines.","A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.","Maps to `Control` on Windows and Linux and to `Command` on macOS.","Maps to `Alt` on Windows and Linux and to `Option` on macOS.","The modifier to be used to add multiple cursors with the mouse. The Go To Definition and Open Link mouse gestures will adapt such that they do not conflict with the multicursor modifier. [Read more](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).","Merge multiple cursors when they are overlapping.","Enable quick suggestions inside strings.","Enable quick suggestions inside comments.","Enable quick suggestions outside of strings and comments.","Controls whether suggestions should automatically show up while typing.","Controls the delay in milliseconds after which quick suggestions will show up.","Enables a pop-up that shows parameter documentation and type information as you type.","Controls whether the editor should automatically close brackets after the user adds an opening bracket.","Controls whether the editor should automatically format the line after typing.","Controls whether the editor should automatically format the pasted content. A formatter must be available and the formatter should be able to format a range in a document.","Controls whether the editor should automatically adjust the indentation when users type, paste or move lines. Extensions with indentation rules of the language must be available.","Controls whether suggestions should automatically show up when typing trigger characters.","Only accept a suggestion with `Enter` when it makes a textual change.","Controls whether suggestions should be accepted on `Enter`, in addition to `Tab`. Helps to avoid ambiguity between inserting new lines or accepting suggestions.","Controls whether suggestions should be accepted on commit characters. For example, in JavaScript, the semi-colon (`;`) can be a commit character that accepts a suggestion and types that character.","Show snippet suggestions on top of other suggestions.","Show snippet suggestions below other suggestions.","Show snippets suggestions with other suggestions.","Do not show snippet suggestions.","Controls whether snippets are shown with other suggestions and how they are sorted.","Controls whether copying without a selection copies the current line.","Controls whether completions should be computed based on words in the document.","Always select the first suggestion.","Select recent suggestions unless further typing selects one, e.g. `console.| -> console.log` because `log` has been completed recently.","Select suggestions based on previous prefixes that have completed those suggestions, e.g. `co -> console` and `con -> const`.","Controls how suggestions are pre-selected when showing the suggest list.","Font size for the suggest widget.","Line height for the suggest widget.","Controls whether filtering and sorting suggestions accounts for small typos.","Control whether an active snippet prevents quick suggestions.","Controls whether the editor should highlight matches similar to the selection","Controls whether the editor should highlight semantic symbol occurrences.","Controls the number of decorations that can show up at the same position in the overview ruler.","Controls whether a border should be drawn around the overview ruler.","Control the cursor animation style.","Zoom the font of the editor when using mouse wheel and holding `Ctrl`.","Controls the cursor style.","Controls the width of the cursor when `#editor.cursorStyle#` is set to `line`.","Enables/Disables font ligatures.","Controls whether the cursor should be hidden in the overview ruler.","Render whitespace characters except for single spaces between words.","Controls how the editor should render whitespace characters.","Controls whether the editor should render control characters.","Controls whether the editor should render indent guides.","Controls whether the editor should highlight the active indent guide.","Highlights both the gutter and the current line.","Controls how the editor should render the current line highlight.","Controls whether the editor shows CodeLens","Controls whether the editor has code folding enabled","Controls the strategy for computing folding ranges. `auto` uses a language specific folding strategy, if available. `indentation` uses the indentation based folding strategy.","Controls whether the fold controls on the gutter are automatically hidden.","Highlight matching brackets when one of them is selected.","Controls whether the editor should render the vertical glyph margin. Glyph margin is mostly used for debugging.","Inserting and deleting whitespace follows tab stops.","Remove trailing auto inserted whitespace.","Keep peek editors open even when double clicking their content or when hitting `Escape`.","Controls whether the editor should allow moving selections via drag and drop.","The editor will use platform APIs to detect when a Screen Reader is attached.","The editor will be permanently optimized for usage with a Screen Reader.","The editor will never be optimized for usage with a Screen Reader.","Controls whether the editor should run in a mode where it is optimized for screen readers.","Controls fading out of unused code.","Controls whether the editor should detect links and make them clickable.","Controls whether the editor should render the inline color decorators and color picker.","Enables the code action lightbulb in the editor.","Controls whether organize imports action should be run on file save.","Code action kinds to be run on save.","Timeout in milliseconds after which the code actions that are run on save are cancelled.","Controls whether the Linux primary clipboard should be supported.","Controls whether the diff editor shows the diff side by side or inline.","Controls whether the diff editor shows changes in leading or trailing whitespace as diffs.","Special handling for large files to disable certain memory intensive features.","Controls whether the diff editor shows +/- indicators for added/removed changes."], +"vs/editor/common/config/editorOptions":["The editor is not accessible at this time. Press Alt+F1 for options.","Editor content"],"vs/editor/common/controller/cursor":["Unexpected exception while executing command."],"vs/editor/common/modes/modesRegistry":["Plain Text"],"vs/editor/common/services/modelServiceImpl":["[{0}]\n{1}","[{0}] {1}"], +"vs/editor/common/view/editorColorRegistry":["Background color for the highlight of line at the cursor position.","Background color for the border around the line at the cursor position.","Background color of highlighted ranges, like by quick open and find features. The color must not be opaque to not hide underlying decorations.","Background color of the border around highlighted ranges.","Color of the editor cursor.","The background color of the editor cursor. Allows customizing the color of a character overlapped by a block cursor.","Color of whitespace characters in the editor.","Color of the editor indentation guides.","Color of the active editor indentation guides.","Color of editor line numbers.","Color of editor active line number","Id is deprecated. Use 'editorLineNumber.activeForeground' instead.","Color of editor active line number","Color of the editor rulers.","Foreground color of editor code lenses","Background color behind matching brackets","Color for matching brackets boxes","Color of the overview ruler border.","Background color of the editor gutter. The gutter contains the glyph margins and the line numbers.","Foreground color of error squigglies in the editor.","Border color of error squigglies in the editor.","Foreground color of warning squigglies in the editor.","Border color of warning squigglies in the editor.","Foreground color of info squigglies in the editor.","Border color of info squigglies in the editor.","Foreground color of hint squigglies in the editor.","Border color of hint squigglies in the editor.","Border of unnecessary code in the editor.","Opacity of unnecessary code in the editor.","Overview ruler marker color for errors.","Overview ruler marker color for warnings.","Overview ruler marker color for infos."], +"vs/editor/contrib/bracketMatching/bracketMatching":["Overview ruler marker color for matching brackets.","Go to Bracket","Select to Bracket"],"vs/editor/contrib/caretOperations/caretOperations":["Move Caret Left","Move Caret Right"],"vs/editor/contrib/caretOperations/transpose":["Transpose Letters"],"vs/editor/contrib/clipboard/clipboard":["Cut","Cu&&t","Copy","&&Copy","Paste","&&Paste","Copy With Syntax Highlighting"],"vs/editor/contrib/codeAction/codeActionCommands":["Show Fixes ({0})","Show Fixes","Quick Fix...","No code actions available","No code actions available","Refactor...","No refactorings available","Source Action...","No source actions available","Organize Imports","No organize imports action available"],"vs/editor/contrib/comment/comment":["Toggle Line Comment","&&Toggle Line Comment","Add Line Comment","Remove Line Comment","Toggle Block Comment","Toggle &&Block Comment"],"vs/editor/contrib/contextmenu/contextmenu":["Show Editor Context Menu"], +"vs/editor/contrib/cursorUndo/cursorUndo":["Soft Undo"],"vs/editor/contrib/find/findController":["Find","&&Find","Find With Selection","Find Next","Find Previous","Find Next Selection","Find Previous Selection","Replace","&&Replace"],"vs/editor/contrib/find/findWidget":["Find","Find","Previous match","Next match","Find in selection","Close","Replace","Replace","Replace","Replace All","Toggle Replace mode","Only the first {0} results are highlighted, but all find operations work on the entire text.","{0} of {1}","No Results"],"vs/editor/contrib/folding/folding":["Unfold","Unfold Recursively","Fold","Fold Recursively","Fold All Block Comments","Fold All Regions","Unfold All Regions","Fold All","Unfold All","Fold Level {0}"],"vs/editor/contrib/fontZoom/fontZoom":["Editor Font Zoom In","Editor Font Zoom Out","Editor Font Zoom Reset"], +"vs/editor/contrib/format/formatActions":["Made 1 formatting edit on line {0}","Made {0} formatting edits on line {1}","Made 1 formatting edit between lines {0} and {1}","Made {0} formatting edits between lines {1} and {2}","There is no formatter for '{0}'-files installed.","Format Document","There is no document formatter for '{0}'-files installed.","Format Selection","There is no selection formatter for '{0}'-files installed."],"vs/editor/contrib/goToDefinition/goToDefinitionCommands":["No definition found for '{0}'","No definition found"," – {0} definitions","Go to Definition","Open Definition to the Side","Peek Definition","No implementation found for '{0}'","No implementation found"," – {0} implementations","Go to Implementation","Peek Implementation","No type definition found for '{0}'","No type definition found"," – {0} type definitions","Go to Type Definition","Peek Type Definition"],"vs/editor/contrib/goToDefinition/goToDefinitionMouse":["Click to show {0} definitions."], +"vs/editor/contrib/gotoError/gotoError":["Go to Next Problem (Error, Warning, Info)","Go to Previous Problem (Error, Warning, Info)","Go to Next Problem in Files (Error, Warning, Info)","Go to Previous Problem in Files (Error, Warning, Info)"],"vs/editor/contrib/gotoError/gotoErrorWidget":["({0}/{1})","Editor marker navigation widget error color.","Editor marker navigation widget warning color.","Editor marker navigation widget info color.","Editor marker navigation widget background."],"vs/editor/contrib/hover/hover":["Show Hover"],"vs/editor/contrib/hover/modesContentHover":["Loading..."],"vs/editor/contrib/inPlaceReplace/inPlaceReplace":["Replace with Previous Value","Replace with Next Value"], +"vs/editor/contrib/linesOperations/linesOperations":["Copy Line Up","&&Copy Line Up","Copy Line Down","Co&&py Line Down","Move Line Up","Mo&&ve Line Up","Move Line Down","Move &&Line Down","Sort Lines Ascending","Sort Lines Descending","Trim Trailing Whitespace","Delete Line","Indent Line","Outdent Line","Insert Line Above","Insert Line Below","Delete All Left","Delete All Right","Join Lines","Transpose characters around the cursor","Transform to Uppercase","Transform to Lowercase"],"vs/editor/contrib/links/links":["Cmd + click to follow link","Ctrl + click to follow link","Cmd + click to execute command","Ctrl + click to execute command","Option + click to follow link","Alt + click to follow link","Option + click to execute command","Alt + click to execute command","Failed to open this link because it is not well-formed: {0}","Failed to open this link because its target is missing.","Open Link"],"vs/editor/contrib/message/messageController":["Cannot edit in read-only editor"], +"vs/editor/contrib/multicursor/multicursor":["Add Cursor Above","&&Add Cursor Above","Add Cursor Below","A&&dd Cursor Below","Add Cursors to Line Ends","Add C&&ursors to Line Ends","Add Selection To Next Find Match","Add &&Next Occurrence","Add Selection To Previous Find Match","Add P&&revious Occurrence","Move Last Selection To Next Find Match","Move Last Selection To Previous Find Match","Select All Occurrences of Find Match","Select All &&Occurrences","Change All Occurrences"],"vs/editor/contrib/parameterHints/parameterHints":["Trigger Parameter Hints"],"vs/editor/contrib/parameterHints/parameterHintsWidget":["{0}, hint"],"vs/editor/contrib/referenceSearch/peekViewWidget":["Close"],"vs/editor/contrib/referenceSearch/referenceSearch":[" – {0} references","Find All References"],"vs/editor/contrib/referenceSearch/referencesController":["Loading..."], +"vs/editor/contrib/referenceSearch/referencesModel":["symbol in {0} on line {1} at column {2}","1 symbol in {0}, full path {1}","{0} symbols in {1}, full path {2}","No results found","Found 1 symbol in {0}","Found {0} symbols in {1}","Found {0} symbols in {1} files"], +"vs/editor/contrib/referenceSearch/referencesWidget":["Failed to resolve file.","{0} references","{0} reference","no preview available","References","No results","References","Background color of the peek view title area.","Color of the peek view title.","Color of the peek view title info.","Color of the peek view borders and arrow.","Background color of the peek view result list.","Foreground color for line nodes in the peek view result list.","Foreground color for file nodes in the peek view result list.","Background color of the selected entry in the peek view result list.","Foreground color of the selected entry in the peek view result list.","Background color of the peek view editor.","Background color of the gutter in the peek view editor.","Match highlight color in the peek view result list.","Match highlight color in the peek view editor.","Match highlight border in the peek view editor."], +"vs/editor/contrib/rename/rename":["No result.","Successfully renamed '{0}' to '{1}'. Summary: {2}","Rename failed to execute.","Rename Symbol"],"vs/editor/contrib/rename/renameInputField":["Rename input. Type new name and press Enter to commit."],"vs/editor/contrib/smartSelect/smartSelect":["Expand Select","&&Expand Selection","Shrink Select","&&Shrink Selection"],"vs/editor/contrib/snippet/snippetVariables":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sun","Mon","Tue","Wed","Thu","Fri","Sat","January","February","March","April","May","June","July","August","September","October","November","December","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"vs/editor/contrib/suggest/suggestController":["Accepting '{0}' did insert the following text: {1}","Trigger Suggest"], +"vs/editor/contrib/suggest/suggestWidget":["Background color of the suggest widget.","Border color of the suggest widget.","Foreground color of the suggest widget.","Background color of the selected entry in the suggest widget.","Color of the match highlights in the suggest widget.","Read More...{0}","{0}, suggestion, has details","{0}, suggestion","Read less...{0}","Loading...","No suggestions.","{0}, accepted","{0}, suggestion, has details","{0}, suggestion"],"vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode":["Toggle Tab Key Moves Focus"], +"vs/editor/contrib/wordHighlighter/wordHighlighter":["Background color of a symbol during read-access, like reading a variable. The color must not be opaque to not hide underlying decorations.","Background color of a symbol during write-access, like writing to a variable. The color must not be opaque to not hide underlying decorations.","Border color of a symbol during read-access, like reading a variable.","Border color of a symbol during write-access, like writing to a variable.","Overview ruler marker color for symbol highlights. The color must not be opaque to not hide underlying decorations.","Overview ruler marker color for write-access symbol highlights. The color must not be opaque to not hide underlying decorations.","Go to Next Symbol Highlight","Go to Previous Symbol Highlight"], +"vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp":["No selection","Line {0}, Column {1} ({2} selected)","Line {0}, Column {1}","{0} selections ({1} characters selected)","{0} selections","Now changing the setting `accessibilitySupport` to 'on'.","Now opening the Editor Accessibility documentation page."," in a read-only pane of a diff editor."," in a pane of a diff editor."," in a read-only code editor"," in a code editor","To configure the editor to be optimized for usage with a Screen Reader press Command+E now.","To configure the editor to be optimized for usage with a Screen Reader press Control+E now.","The editor is configured to be optimized for usage with a Screen Reader.","The editor is configured to never be optimized for usage with a Screen Reader, which is not the case at this time.","Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.","Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}.","Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.","Press Command+H now to open a browser window with more information related to editor accessibility.","Press Control+H now to open a browser window with more information related to editor accessibility.","You can dismiss this tooltip and return to the editor by pressing Escape or Shift+Escape.","Show Accessibility Help"], +"vs/editor/standalone/browser/inspectTokens/inspectTokens":["Developer: Inspect Tokens"],"vs/editor/standalone/browser/quickOpen/gotoLine":["Go to line {0} and character {1}","Go to line {0}","Type a line number between 1 and {0} to navigate to","Type a character between 1 and {0} to navigate to","Go to line {0}","Type a line number, followed by an optional colon and a character number to navigate to","Go to Line..."],"vs/editor/standalone/browser/quickOpen/quickCommand":["{0}, commands","Type the name of an action you want to execute","Command Palette"],"vs/editor/standalone/browser/quickOpen/quickOutline":["{0}, symbols","Type the name of an identifier you wish to navigate to","Go to Symbol...","symbols ({0})","modules ({0})","classes ({0})","interfaces ({0})","methods ({0})","functions ({0})","properties ({0})","variables ({0})","variables ({0})","constructors ({0})","calls ({0})"],"vs/editor/standalone/browser/simpleServices":["Made {0} edits in {1} files"], +"vs/editor/standalone/browser/standaloneCodeEditor":["Editor content","Press Ctrl+F1 for Accessibility Options.","Press Alt+F1 for Accessibility Options."],"vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast":["Toggle High Contrast Theme"],"vs/platform/configuration/common/configurationRegistry":["Default Configuration Overrides","Configure editor settings to be overridden for {0} language.","Configure editor settings to be overridden for a language.","Cannot register '{0}'. This matches property pattern '\\\\[.*\\\\]$' for describing language specific editor settings. Use 'configurationDefaults' contribution.","Cannot register '{0}'. This property is already registered."],"vs/platform/keybinding/common/abstractKeybindingService":["({0}) was pressed. Waiting for second key of chord...","The key combination ({0}, {1}) is not a command."], +"vs/platform/list/browser/listService":["Workbench","Maps to `Control` on Windows and Linux and to `Command` on macOS.","Maps to `Alt` on Windows and Linux and to `Option` on macOS.","The modifier to be used to add an item in trees and lists to a multi-selection with the mouse (for example in the explorer, open editors and scm view). The 'Open to Side' mouse gestures - if supported - will adapt such that they do not conflict with the multiselect modifier.","Controls how to open items in trees and lists using the mouse (if supported). For parents with children in trees, this setting will control if a single click expands the parent or a double click. Note that some trees and lists might choose to ignore this setting if it is not applicable. ","Controls whether trees support horizontal scrolling in the workbench."],"vs/platform/markers/common/markers":["Error","Warning","Info"], +"vs/platform/theme/common/colorRegistry":["Colors used in the workbench.","Overall foreground color. This color is only used if not overridden by a component.","Overall foreground color for error messages. This color is only used if not overridden by a component.","Overall border color for focused elements. This color is only used if not overridden by a component.","An extra border around elements to separate them from others for greater contrast.","An extra border around active elements to separate them from others for greater contrast.","Foreground color for links in text.","Background color for code blocks in text.","Shadow color of widgets such as find/replace inside the editor.","Input box background.","Input box foreground.","Input box border.","Border color of activated options in input fields.","Input validation background color for information severity.","Input validation border color for information severity.","Input validation background color for warning severity.","Input validation border color for warning severity.","Input validation background color for error severity.","Input validation border color for error severity.","List/Tree background color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.","List/Tree foreground color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.","List/Tree background color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.","List/Tree foreground color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.","List/Tree background color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.","List/Tree foreground color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.","List/Tree background color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.","List/Tree background when hovering over items using the mouse.","List/Tree foreground when hovering over items using the mouse.","List/Tree drag and drop background when moving items around using the mouse.","List/Tree foreground color of the match highlights when searching inside the list/tree.","Quick picker color for grouping labels.","Quick picker color for grouping borders.","Badge background color. Badges are small information labels, e.g. for search results count.","Badge foreground color. Badges are small information labels, e.g. for search results count.","Scrollbar shadow to indicate that the view is scrolled.","Scrollbar slider background color.","Scrollbar slider background color when hovering.","Scrollbar slider background color when clicked on.","Background color of the progress bar that can show for long running operations.","Editor background color.","Editor default foreground color.","Background color of editor widgets, such as find/replace.","Border color of editor widgets. The color is only used if the widget chooses to have a border and if the color is not overridden by a widget.","Border color of the resize bar of editor widgets. The color is only used if the widget chooses to have a resize border and if the color is not overridden by a widget.","Color of the editor selection.","Color of the selected text for high contrast.","Color of the selection in an inactive editor. The color must not be opaque to not hide underlying decorations.","Color for regions with the same content as the selection. The color must not be opaque to not hide underlying decorations.","Border color for regions with the same content as the selection.","Color of the current search match.","Color of the other search matches. The color must not be opaque to not hide underlying decorations.","Color of the range limiting the search. The color must not be opaque to not hide underlying decorations.","Border color of the current search match.","Border color of the other search matches.","Border color of the range limiting the search. The color must not be opaque to not hide underlying decorations.","Highlight below the word for which a hover is shown. The color must not be opaque to not hide underlying decorations.","Background color of the editor hover.","Border color of the editor hover.","Color of active links.","Background color for text that got inserted. The color must not be opaque to not hide underlying decorations.","Background color for text that got removed. The color must not be opaque to not hide underlying decorations.","Outline color for the text that got inserted.","Outline color for text that got removed.","Border color between the two text editors.","Overview ruler marker color for find matches. The color must not be opaque to not hide underlying decorations.","Overview ruler marker color for selection highlights. The color must not be opaque to not hide underlying decorations."] +}); +//# sourceMappingURL=../../../min-maps/vs/editor/editor.main.nls.js.map \ No newline at end of file diff --git a/public/react/public/js/monaco/vs/editor/editor.main.nls.ko.js b/public/react/public/js/monaco/vs/editor/editor.main.nls.ko.js new file mode 100755 index 000000000..12afb80f1 --- /dev/null +++ b/public/react/public/js/monaco/vs/editor/editor.main.nls.ko.js @@ -0,0 +1,26 @@ +/*!----------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Version: 0.14.6(6c8f02b41db9ae5c4d15df767d47755e5c73b9d5) + * Released under the MIT license + * https://github.com/Microsoft/vscode/blob/master/LICENSE.txt + *-----------------------------------------------------------*/ +define("vs/editor/editor.main.nls.ko",{"vs/base/browser/ui/actionbar/actionbar":["{0}({1})"],"vs/base/browser/ui/aria/aria":["{0}(다시 발생함)","{0} (occurred {1} times)"],"vs/base/browser/ui/findinput/findInput":["입력"],"vs/base/browser/ui/findinput/findInputCheckboxes":["대/소문자 구분","단어 단위로","정규식 사용"],"vs/base/browser/ui/inputbox/inputBox":["오류: {0}","경고: {0}","정보: {0}"],"vs/base/browser/ui/list/listWidget":["{0}. Use the navigation keys to navigate."],"vs/base/browser/ui/menu/menu":["{0} ({1})"],"vs/base/common/keybindingLabels":["Ctrl","","Alt","Windows","Ctrl","","Alt","Super","컨트롤","","Alt","명령","컨트롤","","Alt","Windows","컨트롤","","Alt","Super"],"vs/base/common/severity":["오류","경고","정보"],"vs/base/parts/quickopen/browser/quickOpenModel":["{0}, 선택기","선택기"],"vs/base/parts/quickopen/browser/quickOpenWidget":["빠른 선택기입니다. 결과의 범위를 축소하려면 입력합니다.","빠른 선택기","{0} Results"],"vs/editor/browser/controller/coreCommands":["&&Select All","&&Undo","&&Redo"], +"vs/editor/browser/widget/codeEditorWidget":["커서 수는 {0}(으)로 제한되었습니다."],"vs/editor/browser/widget/diffEditorWidget":["파일 1개가 너무 커서 파일을 비교할 수 없습니다."],"vs/editor/browser/widget/diffReview":["닫기","줄 없음","1줄","{0}줄","차이 {0}/{1}개: 원본 {2}, {3}, 수정 {4}, {5}","비어 있음","원본 {0}, 수정 {1}: {2}","+ 수정됨 {0}: {1}","- 원본 {0}: {1}","다음 다른 항목으로 이동","다음 다른 항목으로 이동"], +"vs/editor/common/config/commonEditorConfig":["편집기","글꼴 패밀리를 제어합니다.","글꼴 두께를 제어합니다.","글꼴 크기(픽셀)를 제어합니다.","줄 높이를 제어합니다. fontSize의 lineHeight를 계산하려면 0을 사용합니다.","글자 간격을 픽셀 단위로 조정합니다.","줄 번호는 렌더링 되지 않습니다.","줄 번호는 절대값으로 렌더링 됩니다.","줄 번호는 커서 위치에서 줄 간격 거리로 렌더링 됩니다.","줄 번호는 매 10 줄마다 렌더링이 이루어집니다.","줄 번호의 표시 여부를 제어합니다.","특정 수의 고정 폭 문자 뒤에 세로 눈금자를 렌더링합니다. 여러 눈금자의 경우 여러 값을 사용합니다. 배열이 비어 있는 경우 눈금자가 그려져 있지 않습니다.","단어 관련 탐색 또는 작업을 수행할 때 단어 구분 기호로 사용되는 문자입니다.","탭 한 개에 해당하는 공백 수입니다. `editor.detectIndentation`이 켜져 있는 경우 이 설정은 파일 콘텐츠에 따라 재정의됩니다.","'number'가 필요합니다. 값 \"auto\"는 `editor.detectIndentation` 설정에 의해 바뀌었습니다.","탭 키를 누를 때 공백을 삽입합니다. `editor.detectIndentation`이 켜져 있는 경우 이 설정은 파일 콘텐츠에 따라 재정의됩니다.","'boolean'이 필요합니다. 값 \"auto\"는 `editor.detectIndentation` 설정에 의해 바뀌었습니다.","파일을 열면 파일 콘텐츠를 기반으로 하여 'editor.tabSize'와 'editor.insertSpaces'가 검색됩니다.","선택 항목의 모서리를 둥글게 할지 여부를 제어합니다.","편집기에서 마지막 줄 이후로 스크롤할지 여부를 제어합니다.","편집기에서 가로로 스크롤되는 범위를 벗어나는 추가 문자의 수를 제어합니다.","편집기에서 애니메이션을 사용하여 스크롤할지 여부를 제어합니다.","미니맵 표시 여부를 제어합니다.","미니맵을 렌더링할 측면을 제어합니다.","미니맵 슬라이더를 자동으로 숨길지 결정합니다.","줄의 실제 문자(색 블록 아님) 렌더링","최대 특정 수의 열을 렌더링하도록 미니맵의 너비를 제한합니다.","Controls whether the hover is shown.","Time delay in milliseconds after which to the hover is shown.","Controls whether the hover should remain visible when mouse is moved over it.","편집기 선택에서 Find Widget의 검색 문자열을 시딩할지 설정합니다.","편집기에서 여러 글자 또는 행을 선택했을 때 Find in Selection 플래그를 켤지 설정합니다.","macOS에서 Find Widget이 공유 클립보드 찾기를 읽거나 수정해야 할지 설정합니다.","줄이 바뀌지 않습니다.","뷰포트 너비에서 줄이 바뀝니다.","`editor.wordWrapColumn`에서 줄이 바뀝니다.","뷰포트의 최소값 및 `editor.wordWrapColumn`에서 줄이 바뀝니다.","줄 바꿈 여부를 제어합니다. 다음 중 하나일 수 있습니다.\n - 'off' (줄 바꿈 사용 안 함),\n - 'on' (뷰포트 줄 바꿈),\n - 'wordWrapColumn' (`editor.wordWrapColumn`에서 줄 바꿈) 또는\n - 'bounded' (뷰포트의 최소값 및 `editor.wordWrapColumn`에서 줄 바꿈).","`editor.wordWrap`이 'wordWrapColumn' 또는 'bounded'인 경우 편집기의 열 줄 바꿈을 제어합니다.","No indentation. Wrapped lines begin at column 1.","Wrapped lines get the same indentation as the parent.","Wrapped lines get +1 indentation toward the parent.","Wrapped lines get +2 indentation toward the parent.","줄 바꿈 행의 들여쓰기를 제어합니다. 'none', 'same', 'indent' 또는 'deepIndent' 중 하나일 수 있습니다.","마우스 휠 스크롤 이벤트의 `deltaX` 및 `deltaY`에서 사용할 승수","Windows와 Linux의 'Control'을 macOS의 'Command'로 매핑합니다.","Windows와 Linux의 'Alt'를 macOS의 'Option'으로 매핑합니다.","마우스로 여러 커서를 추가할 때 사용할 수정자입니다. `ctrlCmd`는 Windows와 Linux에서 `Control`로 매핑되고 macOS에서 `Command`로 매핑됩니다. Go To Definition 및 Open Link 마우스 제스처가 멀티커서 수정자와 충돌하지 않도록 조정됩니다.","여러 커서가 겹치는 경우 커서를 병합합니다.","문자열 내에서 빠른 제안을 사용합니다.","주석 내에서 빠른 제안을 사용합니다.","문자열 및 주석 외부에서 빠른 제안을 사용합니다.","입력하는 동안 제안을 자동으로 표시할지 여부를 제어합니다.","빠른 제안을 표시할 지연 시간(ms)을 제어합니다.","입력과 동시에 매개변수 문서와 유형 정보를 표시하는 팝업을 사용","괄호를 연 다음에 편집기에서 괄호를 자동으로 닫을지 여부를 제어합니다.","입력 후 편집기에서 자동으로 줄의 서식을 지정할지 여부를 제어합니다.","붙여넣은 콘텐츠의 서식을 편집기에서 자동으로 지정할지 여부를 제어합니다. 포맷터는 반드시 사용할 수 있어야 하며 문서에서 범위의 서식을 지정할 수 있어야 합니다.","사용자가 입력하고 라인을 붙여넣거나 이동할 때 편집기가 자동으로 들여쓰기를 적용할지 결정합니다. 해당 언어의 들여쓰기 규칙을 사용할 수 있어야 합니다.","트리거 문자를 입력할 때 제안을 자동으로 표시할지 여부를 제어합니다.","Only accept a suggestion with `Enter` when it makes a textual change.","'Tab' 키 외에 'Enter' 키에 대한 제안도 허용할지를 제어합니다. 새 줄을 삽입하는 동작과 제안을 허용하는 동작 간의 모호함을 없앨 수 있습니다.","커밋 문자에 대한 제안을 허용할지를 제어합니다. 예를 들어 JavaScript에서는 세미콜론(';')이 제안을 허용하고 해당 문자를 입력하는 커밋 문자일 수 있습니다.","다른 제안 위에 조각 제안을 표시합니다.","다른 제안 아래에 조각 제안을 표시합니다.","다른 제안과 함께 조각 제안을 표시합니다.","코드 조각 제안을 표시하지 않습니다.\n","코드 조각이 다른 추천과 함께 표시되는지 여부 및 정렬 방법을 제어합니다.","선택 영역 없이 현재 줄 복사 여부를 제어합니다.","문서 내 단어를 기반으로 완성을 계산할지 여부를 제어합니다.","항상 첫 번째 제안을 선택합니다.","추가로 입력되지 않는 경우, 최근 제안을 선택합니다. 예를 들어 'log'가 최근에 완료되었으므로 'console.| -> console.log'로 전개되는 것을 선택합니다.","제안을 완료한 이전 접두사를 기준으로 제안을 선택합니다. 예를 들어 'co-> console'로, 'con->const'로 전개됩니다.","제안 목록을 표시할 때 제한이 미리 선택되는 방식을 제어합니다.","제안 위젯의 글꼴 크기","제안 위젯의 줄 높이","Controls whether filtering and sorting suggestions accounts for small typos.","Control whether an active snippet prevents quick suggestions.","편집기에서 선택 항목과 유사한 일치 항목을 강조 표시할지 여부를 제어합니다.","편집기에서 의미 체계 기호 항목을 강조 표시할지 여부를 제어합니다.","개요 눈금자에서 동일한 위치에 표시될 수 있는 장식 수를 제어합니다.","개요 눈금자 주위에 테두리를 그릴지 여부를 제어합니다.","커서 애니메이션 스타일을 제어합니다.","마우스 휠을 사용할 때 Ctrl 키를 누르고 있으면 편집기의 글꼴 확대/축소","커서 스타일을 제어합니다. 허용되는 값은 '블록', '블록-윤곽', '줄', '줄-가늘게', '밑줄' 및 '밑줄-가늘게'입니다.","editor.cursorStyle 설정이 'line'으로 설정되어 있을 때 커서의 넓이를 조절합니다.","글꼴 합자 사용","커서가 개요 눈금자에서 가려져야 하는지 여부를 제어합니다.","Render whitespace characters except for single spaces between words.","편집기에서 공백 문자를 렌더링하는 방법을 제어합니다. 가능한 값은 'none', 'boundary' 및 'all'입니다. 'boundary' 옵션은 단어 사이의 한 칸 공백을 렌더링하지 않습니다.","편집기에서 제어 문자를 렌더링할지를 제어합니다.","편집기에서 들여쓰기 가이드를 렌더링할지를 제어합니다.","Controls whether the editor should highlight the active indent guide.","Highlights both the gutter and the current line.","편집기가 현재 줄 강조 표시를 렌더링하는 방식을 제어합니다. 가능한 값은 'none', 'gutter', 'line' 및 'all'입니다.","편집기에서 CodeLens를 표시하는지 여부를 제어합니다.","편집기에서 코드 접기를 사용할지 여부를 제어합니다.","접기 범위를 계산하는 방식을 제어합니다. '자동' 선택이면 사용 가능한 경우 언어 관련 접기 전략을 사용합니다. '들여쓰기'이면 들여쓰기 기반 접기 전략이 사용됩니다.","거터의 폴드 컨트롤을 자동으로 숨길지 결정합니다.","대괄호 중 하나를 선택할 때 일치하는 대괄호를 강조 표시합니다.","편집기에서 세로 문자 모양 여백을 렌더링할지 여부를 제어합니다. 문자 모양 여백은 주로 디버깅에 사용됩니다.","탭 정지 뒤에 공백 삽입 및 삭제","끝에 자동 삽입된 공백 제거","해당 콘텐츠를 두 번 클릭하거나 키를 누르더라도 Peek 편집기를 열린 상태로 유지합니다.","편집기에서 끌어서 놓기로 선택 영역을 이동할 수 있는지 여부를 제어합니다.","편집기가 스크린 리더가 연결되면 플랫폼 API를 사용하여 감지합니다.","편집기가 스크린 리더 사용을 위해 영구적으로 최적화됩니다.","편집기가 스크린 리더 사용을 위해 최적화되지 않습니다.","편집기를 스크린 리더를 위해 최적화된 모드로 실행할지 결정합니다.","Controls fading out of unused code.","편집기에서 링크를 감지하고 클릭할 수 있게 만들지 결정합니다.","편집기에서 인라인 색 데코레이터 및 색 선택을 렌더링할지를 제어합니다.","코드 동작 전구를 사용합니다.","저장할 때 가져오기 구성을 실행하시겠습니까?","저장할 때 실행되는 코드 동작 종류입니다.","저장할 때 실행되는 코드 동작에 대한 시간 제한입니다.","Linux 주 클립보드의 지원 여부를 제어합니다.","diff 편집기에서 diff를 나란히 표시할지 인라인으로 표시할지 여부를 제어합니다.","diff 편집기에서 선행 공백 또는 후행 공백 변경을 diffs로 표시할지 여부를 제어합니다.","큰 파일에 대한 특수 처리로, 메모리를 많이 사용하는 특정 기능을 사용하지 않도록 설정합니다.","diff 편집기에서 추가/제거된 변경 내용에 대해 +/- 표시기를 표시하는지 여부를 제어합니다."], +"vs/editor/common/config/editorOptions":["지금은 편집기를 사용할 수 없습니다. Alt+F1을 눌러 옵션을 보세요.","편집기 콘텐츠"],"vs/editor/common/controller/cursor":["명령을 실행하는 동안 예기치 않은 예외가 발생했습니다."],"vs/editor/common/modes/modesRegistry":["일반 텍스트"],"vs/editor/common/services/modelServiceImpl":["[{0}]\n{1}","[{0}] {1}"], +"vs/editor/common/view/editorColorRegistry":["커서 위치의 줄 강조 표시에 대한 배경색입니다.","커서 위치의 줄 테두리에 대한 배경색입니다.","빠른 열기 및 찾기 기능 등을 통해 강조 표시된 영역의 배경색입니다. 색은 밑에 깔린 꾸밈을 가리지 않도록 반드시 불투명이 아니어야 합니다.","강조 영역 주변의 테두리에 대한 배경색입니다","편집기 커서 색입니다.","편집기 커서의 배경색입니다. 블록 커서와 겹치는 글자의 색상을 사용자 정의할 수 있습니다.","편집기의 공백 문자 색입니다.","편집기 들여쓰기 안내선 색입니다.","활성 편집기 들여쓰기 안내선 색입니다.","편집기 줄 번호 색입니다.","편집기 활성 영역 줄번호 색상","ID는 사용되지 않습니다. 대신 'editorLineNumber.activeForeground'를 사용하세요.","편집기 활성 영역 줄번호 색상","편집기 눈금의 색상입니다.","편집기 코드 렌즈의 전경색입니다.","일치하는 괄호 뒤의 배경색","일치하는 브래킷 박스의 색상","개요 눈금 경계의 색상입니다.","편집기 거터의 배경색입니다. 거터에는 글리프 여백과 행 수가 있습니다.","편집기 내 오류 표시선의 전경색입니다.","편집기 내 오류 표시선의 테두리 색입니다.","편집기 내 경고 표시선의 전경색입니다.","편집기 내 경고 표시선의 테두리 색입니다.","편집기 내 정보 표시선의 전경색입니다.","편집기 내 정보 표시선의 테두리 색입니다.","편집기에서 힌트 표시선의 전경색입니다.","편집기에서 힌트 표시선의 테두리 색입니다.","Border of unnecessary code in the editor.","Opacity of unnecessary code in the editor.","오류의 개요 눈금자 마커 색입니다.","경고의 개요 눈금자 마커 색입니다.","정보의 개요 눈금자 마커 색입니다."], +"vs/editor/contrib/bracketMatching/bracketMatching":["괄호에 해당하는 영역을 표시자에 채색하여 표시합니다.","대괄호로 이동","괄호까지 선택"],"vs/editor/contrib/caretOperations/caretOperations":["캐럿을 왼쪽으로 이동","캐럿을 오른쪽으로 이동"],"vs/editor/contrib/caretOperations/transpose":["문자 바꾸기"],"vs/editor/contrib/clipboard/clipboard":["잘라내기","Cu&&t","복사","&&Copy","붙여넣기","&&Paste","구문을 강조 표시하여 복사"],"vs/editor/contrib/codeAction/codeActionCommands":["수정 사항 표시({0})","수정 사항 표시","빠른 수정...","사용 가능한 코드 동작이 없습니다.","사용 가능한 코드 동작이 없습니다.","리팩터링...","사용 가능한 리펙터링이 없습니다.","소스 작업...","사용 가능한 소스 작업이 없습니다.","가져오기 구성","사용 가능한 가져오기 구성 작업이 없습니다."],"vs/editor/contrib/comment/comment":["줄 주석 설정/해제","&&Toggle Line Comment","줄 주석 추가","줄 주석 제거","블록 주석 설정/해제","Toggle &&Block Comment"],"vs/editor/contrib/contextmenu/contextmenu":["편집기 상황에 맞는 메뉴 표시"],"vs/editor/contrib/cursorUndo/cursorUndo":["Soft Undo"],"vs/editor/contrib/find/findController":["찾기","&&Find","선택 영역에서 찾기","다음 찾기","이전 찾기","다음 선택 찾기","이전 선택 찾기","바꾸기","&&Replace"], +"vs/editor/contrib/find/findWidget":["찾기","찾기","이전 검색 결과","다음 검색 결과","선택 항목에서 찾기","닫기","바꾸기","바꾸기","바꾸기","모두 바꾸기","바꾸기 모드 설정/해제","처음 {0}개의 결과가 강조 표시되지만 모든 찾기 작업은 전체 텍스트에 대해 수행됩니다.","{0}/{1}","결과 없음"],"vs/editor/contrib/folding/folding":["펼치기","재귀적으로 펼치기","접기","재귀적으로 접기","모든 블록 코멘트를 접기","모든 영역 접기","모든 영역 펼치기","모두 접기","모두 펼치기","수준 {0} 접기"],"vs/editor/contrib/fontZoom/fontZoom":["편집기 글꼴 확대","편집기 글꼴 축소","편집기 글꼴 확대/축소 다시 설정"],"vs/editor/contrib/format/formatActions":["줄 {0}에서 1개 서식 편집을 수행했습니다.","줄 {1}에서 {0}개 서식 편집을 수행했습니다.","줄 {0}과(와) {1} 사이에서 1개 서식 편집을 수행했습니다.","줄 {1}과(와) {2} 사이에서 {0}개 서식 편집을 수행했습니다."," '{0}'-파일에 대한 설치된 형식기가 없습니다.","문서 서식"," '{0}'-파일에 대한 문서 포맷터가 설치되어 있지 않습니다.","선택 영역 서식","'{0}'-파일에 대한 선택 영역 포맷터가 설치되어 있지 않습니다."], +"vs/editor/contrib/goToDefinition/goToDefinitionCommands":["'{0}'에 대한 정의를 찾을 수 없습니다.","정의를 찾을 수 없음","– {0} 정의","정의로 이동","측면에서 정의 열기","정의 피킹(Peeking)","'{0}'에 대한 구현을 찾을 수 없습니다.","구현을 찾을 수 없습니다."," – {0} 개 구현","구현으로 이동","구현 미리 보기","'{0}'에 대한 형식 정의를 찾을 수 없습니다.","형식 정의를 찾을 수 없습니다.","– {0} 형식 정의","형식 정의로 이동","형식 정의 미리 보기"],"vs/editor/contrib/goToDefinition/goToDefinitionMouse":["{0}개 정의를 표시하려면 클릭하세요."],"vs/editor/contrib/gotoError/gotoError":["다음 문제로 이동 (오류, 경고, 정보)","이전 문제로 이동 (오류, 경고, 정보)","파일의 다음 문제로 이동 (오류, 경고, 정보)","파일의 이전 문제로 이동 (오류, 경고, 정보)"],"vs/editor/contrib/gotoError/gotoErrorWidget":["({0}/{1})","편집기 표식 탐색 위젯 오류 색입니다.","편집기 표식 탐색 위젯 경고 색입니다.","편집기 표식 탐색 위젯 정보 색입니다.","편집기 표식 탐색 위젯 배경입니다."],"vs/editor/contrib/hover/hover":["가리키기 표시"],"vs/editor/contrib/hover/modesContentHover":["로드 중..."],"vs/editor/contrib/inPlaceReplace/inPlaceReplace":["이전 값으로 바꾸기","다음 값으로 바꾸기"], +"vs/editor/contrib/linesOperations/linesOperations":["위에 줄 복사","&&Copy Line Up","아래에 줄 복사","Co&&py Line Down","줄 위로 이동","Mo&&ve Line Up","줄 아래로 이동","Move &&Line Down","줄을 오름차순 정렬","줄을 내림차순으로 정렬","후행 공백 자르기","줄 삭제","줄 들여쓰기","줄 내어쓰기","위에 줄 삽입","아래에 줄 삽입","왼쪽 모두 삭제","우측에 있는 항목 삭제","줄 연결","커서 주위 문자 바꾸기","대문자로 변환","소문자로 변환"],"vs/editor/contrib/links/links":["Cmd 키를 누르고 클릭하여 링크로 이동","Ctrl 키를 누르고 클릭하여 링크로 이동","명령을 실행하려면 Cmd+클릭","명령을 실행하려면 Ctrl+클릭","