diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000000000000000000000000000000000000..354028db57092b3c34725bb22b496690b46a2565 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,57 @@ +--- +engines: + brakeman: + enabled: true + bundler-audit: + enabled: true + csslint: + enabled: true + coffeelint: + enabled: true + duplication: + enabled: true + config: + languages: + ruby: + mass_threshold: 24 + javascript: + python: + php: + eslint: + enabled: true + fixme: + enabled: true + rubocop: + enabled: true +ratings: + paths: + - Gemfile.lock + - "**.erb" + - "**.haml" + - "**.rb" + - "**.rhtml" + - "**.slim" + - "**.css" + - "**.coffee" + - "**.inc" + - "**.js" + - "**.jsx" + - "**.module" + - "**.php" + - "**.py" +exclude_paths: +- ./config/ +- ./node_modules/ +- ./spec/ +- ./test/ +- ./vendor/ +- ./dtu-core/ +- ./bin/ +- ./public/ +- ./pdfjs/ +- ./app/assets/javascripts/mathjax.js +- ./app/assets/javascripts/mathjax-editing.js +- ./app/assets/javascripts/json-stringify-safe.js +- ./app/assets/javascripts/edit-page.js +- ./app/assets/stylesheets/base.css + diff --git a/.csslintrc b/.csslintrc new file mode 100644 index 0000000000000000000000000000000000000000..aacba956e5bbede1c195ce554fcad3e200b24ff8 --- /dev/null +++ b/.csslintrc @@ -0,0 +1,2 @@ +--exclude-exts=.min.css +--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..f8f5b51e032aca388ddee9c3e2a4da525879b7d3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,20 @@ +README.md +README.rdoc +**/.git +**/.gitignore +**/.idea +**/node_modules +LICENSE +tmp/ +log/ +**/*.sqlite3 +vendor/assets/components/ +public/assets/ +**/.codeclimate.yml +**/.csslintrc +**/.rubocop.yml +**/.eslintrc.yml +**/.eslintignore +**/coffeelint.json + + diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000000000000000000000000000000000..5adcb91f79c55186e70972e8fd45714dd3fca5c7 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +**/*{.,-}min.js +node_modules/ +deps/**/* +assets/**/* +public/**/* +/*.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000000000000000000000000000000000..1aef201e5e31349ffffac6c309dc7ebf43757df2 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,18 @@ +module.exports = { + "extends": ["eslint:recommended", "airbnb-base"], + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "jquery": true + }, + "globals": { + }, + rules: { + 'no-console': 'off', + "no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "WithStatement"], + "class-methods-use-this": 'off', + "no-param-reassign": 'off', + "max-len": ["error", 120, 2], + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..694df0d8f2afcea81447784942cd390763c9fd67 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +pdf.js +.idea +node_modules +log +*.log +**/*.log +tmp +db/*.sqlite3 +/external.env +vendor/assets/components +public/assets/ +public/vendor/ +public/assets/Exercise*.md +public/assets/parse-errors.html +public/assets/podcasts_static.html +public/assets/Agendas.md + +spec/files/data +spec/files/test_file*.json + +/public/packs +/public/packs-test +/node_modules +/yarn-error.log +yarn-debug.log* +.yarn-integrity diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 74df558a20e2a41624dfb282afcf2765c6b51006..53e6a2fe6794bdcd9979920b98506e802412cfe4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,20 +1,95 @@ +image: docker:stable +services: +- docker:dind + stages: - - test - - build - - deploy +- build +- test +- release +- deploy + +variables: + DOCKER_DRIVER: overlay2 + CONTAINER_IMAGE: lab.compute.dtu.dk:5005/$CI_PROJECT_PATH + CONTAINER_TEST_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA + CONTAINER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME + GIT_SUBMODULE_STRATEGY: recursive + +before_script: +- echo docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY +- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY test: + tags: + - enote-shell stage: test - script: echo "Running tests" + script: + - echo "Running tests" + - echo docker run $CONTAINER_TEST_IMAGE ./scripts/run-tests.sh + - docker pull $CONTAINER_TEST_IMAGE + - docker run $CONTAINER_TEST_IMAGE ./scripts/run-tests.sh build: + tags: + - enote-shell stage: build script: - echo "Building the app" - - ls -als + - echo docker build --tag $CONTAINER_TEST_IMAGE . + - docker build --tag $CONTAINER_TEST_IMAGE . + - docker push $CONTAINER_TEST_IMAGE +release-image: + tags: + - enote-shell + stage: release + script: + - echo "Releasing image ${CONTAINER_TEST_IMAGE} as ${CONTAINER_RELEASE_IMAGE}" + - docker pull $CONTAINER_TEST_IMAGE + - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE + - docker images | grep ${CI_PROJECT_PATH} + - docker push $CONTAINER_RELEASE_IMAGE -deploy: +deploy_devel: + tags: + - deploy-devel stage: deploy - script: echo "deploying" - \ No newline at end of file + script: + - echo "Deploy to development server" + - cd /enote/src/dtu-enote + - echo docker stop course_website + - ../../gen/docker-stop.sh + - docker-compose -f ../../gen/docker-compose-enote.yml pull + - ../../gen/docker-start.sh + - docker ps -q -f status=exited | xargs -I '{}' docker rm -f '{}' + - docker ps -q -f status=dead | xargs -I '{}' docker rm -f '{}' + - echo docker pull $CONTAINER_RELEASE_IMAGE + - docker images | grep ${CI_PROJECT_PATH} + - echo bundle exec rake deploy:redeploy[dtu-enote-website] + - docker image prune -f + environment: + name: develop + url: https://enote-devel3.compute.dtu.dk + only: + - develop + +deploy_production: + tags: + - deploy-prod-2019 + stage: deploy + script: + - echo "Deploy to ${CI_BUILD_REF_SLUG} server" + - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY + - cd /enote/src/dtu-enote + - ../../gen/docker-stop.sh + - docker-compose -f ../../gen/docker-compose-enote.yml pull + - docker images | grep ${CI_PROJECT_PATH} + - ../../gen/docker-start.sh + - docker ps -q -f status=exited | xargs -I '{}' docker rm -f '{}' + - docker ps -q -f status=dead | xargs -I '{}' docker rm -f '{}' + - docker image prune -f + environment: + name: production + url: https://quiz.compute.dtu.dk + only: + - release-2019.0 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..3ad6fc37f34a1c4952195bbf8b35a2956032c845 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "deps/dtu-core"] + path = deps/dtu-core + url = https://lab.compute.dtu.dk/enote/dtu-enote-core.git +[submodule "deps/dtu-quiz-parser"] + path = deps/dtu-quiz-parser + url = https://lab.compute.dtu.dk/enote/dtu-quiz-parser.git +[submodule "deps/pdfjs"] + path = deps/pdfjs + url = https://lab.compute.dtu.dk/enote/dtu-enote-pdfjs.git +[submodule "deps/feedbackjs"] + path = deps/feedbackjs + url = https://lab.compute.dtu.dk/enote/feedback.git diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 0000000000000000000000000000000000000000..6ec30bb5cd40da83856e24685b4af68393b3824e --- /dev/null +++ b/.jshintignore @@ -0,0 +1,5 @@ +**/*{.,-}min.js +node_modules/**/* +deps/**/* +assets/**/* +public/**/* diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000000000000000000000000000000000000..a7a08a349e0d58fc4a8b94e87157b82708ff694d --- /dev/null +++ b/.jshintrc @@ -0,0 +1,62 @@ +{ + /* + * ENVIRONMENTS + * ================= + */ + + // Define globals exposed by modern browsers. + "browser": true, + + // Define globals exposed by jQuery. + "jquery": true, + + // Define globals exposed by Node.js. + "node": true, + + // Allow ES6. + "esversion": 6, + + /* + * ENFORCING OPTIONS + * ================= + */ + + // Force all variable names to use either camelCase style or UPPER_CASE + // with underscores. + "camelcase": true, + + // Prohibit use of == and != in favor of === and !==. + "eqeqeq": true, + + // Enforce tab width of 2 spaces. + "indent": 2, + + // Prohibit use of a variable before it is defined. + "latedef": true, + + // Enforce line length to 100 characters + "maxlen": 100, + + // Require capitalized names for constructor functions. + "newcap": true, + + // Enforce use of single quotation marks for strings. + "quotmark": "single", + + // Enforce placing 'use strict' at the top function scope + "strict": true, + + // Prohibit use of explicitly undeclared variables. + "undef": true, + + // Warn when variables are defined but never used. + "unused": true, + + /* + * RELAXING OPTIONS + * ================= + */ + + // Suppress warnings about == null comparisons. + "eqnull": true +} diff --git a/.rspec b/.rspec new file mode 100644 index 0000000000000000000000000000000000000000..83e16f80447460c937aeaa44a64d743b27863077 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000000000000000000000000000000000000..07c72b3b2f19a6c5409fcbab0684cf8b25a96270 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,33 @@ +GlobalVars: + AllowedVariables: + - $redis + - $worker_redis + - $redis_course_website +Metrics/LineLength: + Max: 160 +Metrics/CyclomaticComplexity: + Max: 11 +Metrics/PerceivedComplexity: + Max: 11 +Metrics/ClassLength: + Max: 300 +Metrics/MethodLength: + Max: 60 +Metrics/AbcSize: + Max: 60 +Metrics/BlockLength: + Max: 60 +Style/AsciiComments: + Enabled: false +Metrics/ParameterLists: + CountKeywordArgs: false +AllCops: + DisplayCopNames: true + Exclude: + - '**/*.yml' + - 'db/**/*' + - 'config/**/*' + - 'test/**/*' + - 'doc/**/*' + - 'bin/**/*' + - 'node_modules/**/*' diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..e89d2cc29a44b65d3ac41e4c0728908829234b9c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,92 @@ +FROM dtucompute/enote-base-ubuntu1804:v2019 + +ARG DEPENDENCY_HASH=1 +ARG TZ=Europe/Copenhagen + +ARG UID=1000 +ARG GID=1000 + +EXPOSE 3000 + +ENV APP_ROOT /app +WORKDIR ${APP_ROOT}/ +USER dtuuser + +ENV CHOWN=dtuuser:dtugroup + +# +# COURSE +# + +LABEL "github"="https://github.com/dtu-compute/dtu-course-website" +LABEL version="2019" +LABEL description="This Dockerfile builds the container \ +to house the DTU course website." + +RUN sudo apt update +RUN sudo apt-get -y install redis +RUN sudo apt-get -y install imagemagick +RUN sudo apt-get -y install libsqlite3-dev + +# https://github.com/yarnpkg/yarn/issues/3189 +#RUN sudo apt-get remove cmdinstall +RUN sudo apt update +RUN sudo apt remove -y cmdtest +RUN sudo apt remove -y yarn +RUN sudo npm install -g yarn +RUN yarn --version + +# Install the necessary gems +COPY deps ${APP_ROOT}/deps +COPY Gemfile ${APP_ROOT}/Gemfile +COPY Rakefile ${APP_ROOT}/Rakefile +COPY Gemfile ${APP_ROOT}/Gemfile.lock +RUN sudo chown ${CHOWN} Gemfile* +RUN sudo chown -R ${CHOWN} ${APP_ROOT}/deps + +RUN bundle install --without development --binstubs + +# Install client-side components +COPY package.json ${APP_ROOT}/package.json +COPY yarn.lock ${APP_ROOT}/yarn.lock +RUN sudo chown -R ${CHOWN} ~/.npm +RUN sudo chown -R ${CHOWN} ~/.config +RUN cd deps/feedbackjs && npm install && npm install gulp +RUN cd deps/feedbackjs && npm run build +RUN yarn install + +# Add PDF.JS +RUN cd deps/pdfjs && \ + npm install && \ + npm install gulp && \ + sudo npm install -g gulp && \ + gulp generic && \ + cd ${APP_ROOT} + +# Copy application code to container +COPY ./app ${APP_ROOT}/app +COPY ./scripts ${APP_ROOT}/scripts +COPY ./deps ${APP_ROOT}/deps +COPY ./config ${APP_ROOT}/config +COPY ./db ${APP_ROOT}/db +COPY ./lib ${APP_ROOT}/lib +COPY ./bin ${APP_ROOT}/bin +COPY ./public-maintenance ${APP_ROOT}/public-maintenance +COPY ./spec ${APP_ROOT}/spec +COPY ./test ${APP_ROOT}/test +COPY maintenance.ru config.ru .rspec Procfile Rakefile postcss.config.js ${APP_ROOT}/ +RUN sudo chown -R ${CHOWN} ${APP_ROOT}/spec/files +RUN sudo chown -R ${CHOWN} ${APP_ROOT}/db +RUN sudo chown -R ${CHOWN} ${APP_ROOT}/scripts +RUN mkdir -p ${APP_ROOT}/tmp +RUN mkdir -p ${APP_ROOT}/log + +# Generate cookie key +RUN RAILS_ENV=production PRECOMPILE=1 bundle exec rake secret > ~/secret-key-base.txt + +# RUN NODE_ENV=development yarn run webpack --config config/webpack/development.js +# RUN NODE_ENV=production yarn run webpack --config config/webpack/production.js +RUN RAILS_ENV=production PRECOMPILE=1 bundle exec rake assets:precompile --trace + +CMD ["/bin/bash", "-l", "-c", "./scripts/run-server.sh 2>&1 | tee ${APP_ROOT}/log/run-server.log"] + diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000000000000000000000000000000000..b390b83e79003120e15cf4c5360664dd6263c37a --- /dev/null +++ b/Gemfile @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +ruby '2.5.1' + +# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' +gem 'rails', '~> 5.1.4' +# gem 'sprockets', '3.6.3' # https://github.com/rails/sass-rails/issues/381 +# gem 'sprockets', '~> 3.7' +gem 'sprockets','~> 4.0.0.beta8' + +gem 'webpacker', '~> 4.x' + +# Use SCSS for stylesheets +gem 'sass-rails', '~> 5.0' +# Use less for stackedit stylesheets +gem 'less-rails' +gem 'therubyracer' +# Use Uglifier as compressor for JavaScript assets +gem 'uglifier', '>= 1.3.0' +# Use CoffeeScript for .coffee assets and views +gem 'coffee-rails', '~> 4.2.2' + +gem 'listen', '= 3.1.1' + +gem 'bower-rails' + +# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks +# it also causes mysterious problems with MathJax +# gem 'turbolinks' +# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder +gem 'jbuilder', '~> 2.0' +# bundle exec rake doc:rails generates the API under doc/api. +gem 'sdoc', '~> 0.4.0', group: :doc + +group :development do + # Access an IRB console on exception pages or by using <%= console %> in views + gem 'web-console', '~> 3.5.1' + + # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring + gem 'spring' +end + +gem 'activemodel', '~> 5.1.4' +gem 'activerecord', '~> 5.1.4' +gem 'sqlite3', '~> 1.3.0' + +gem 'dtu-core', path: 'deps/dtu-core' +gem 'quiz', path: 'deps/dtu-quiz-parser' + +gem 'awesome_print', '~> 1.6', '>= 1.6.1' + +# Web Stack +gem 'foreman', '~> 0.84.0' +gem 'rack-rewrite', '~> 1.5.1' +gem 'thin', '~> 1.7.2' + +group :development, :test do + gem 'capybara' + gem 'guard-rspec' + gem 'pry' + gem 'rails-controller-testing' + gem 'rspec-core' + gem 'rspec-html-matchers' + gem 'rspec-rails', '~> 3.0' + gem 'rubocop', require: false +end + +group :test do + gem 'database_cleaner' + #gem 'fakefs', git: '/Users/iain/Projects/enote/dtu-enote-installer/src/fakefs', branch: 'fix', require: 'fakefs/safe' + #gem 'fakefs', '~> 0.2', require: 'fakefs/safe' + gem 'fakefs', git: 'https://github.com/iainbryson/fakefs', branch: 'fix', require: 'fakefs/safe' + gem 'fakeredis', '~> 0.7', require: 'fakeredis/rspec' +end + +gem 'rubycas-client', '~> 2.3.8', git: 'https://github.com/rubycas/rubycas-client' + +gem 'nokogiri', '~> 1.8.5' + +# redis +gem 'redis', '~> 3.2' +gem 'redis-namespace' +gem 'redis-rack-cache' +gem 'redis-rails' + +# git for file manager +gem 'git', '>= 1.2.2' + +gem 'responders', '~> 2.0' + +gem 'font-awesome-rails', '~> 4.7.0.3' + +gem 'lograge', '~> 0.4' +gem 'logstash-event' + +gem 'datagrid', '~> 1.5' +gem 'kaminari' + +gem 'addressable' + +gem 'rest-client', '~> 2.0' + +# Added at 2018-04-23 09:29:09 -0700 by iainbryson: +gem 'micro_magick', '~> 1.1' + +# Added at 2018-06-09 09:16:14 +0200 by iainbryson: +gem 'i18n', '~> 0.9.5' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000000000000000000000000000000000..75b787c9189175dc28c9e6b37df86b7dc2e262ce --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,423 @@ +GIT + remote: https://github.com/iainbryson/fakefs + revision: a95feb1a38661fb388077e8a65f92670fe76366e + branch: fix + specs: + fakefs (0.20.0) + +GIT + remote: https://github.com/rubycas/rubycas-client + revision: 7b67c8f1b5515ee4e28479d640d2da0a5aadfbe0 + specs: + rubycas-client (2.3.10.rc1) + activesupport + +PATH + remote: deps/dtu-core + specs: + dtu-auth2 (0.2018.01) + dtu-core (0.2019.01) + dtu-auth2 (~> 0.2018) + dtu-file-management (~> 0.2018) + rails (~> 5.1) + dtu-file-management (0.2018.01) + +PATH + remote: deps/dtu-quiz-parser + specs: + quiz (0.2.0) + +GEM + remote: https://rubygems.org/ + specs: + actioncable (5.1.7) + actionpack (= 5.1.7) + nio4r (~> 2.0) + websocket-driver (~> 0.6.1) + actionmailer (5.1.7) + actionpack (= 5.1.7) + actionview (= 5.1.7) + activejob (= 5.1.7) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (5.1.7) + actionview (= 5.1.7) + activesupport (= 5.1.7) + rack (~> 2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (5.1.7) + activesupport (= 5.1.7) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (5.1.7) + activesupport (= 5.1.7) + globalid (>= 0.3.6) + activemodel (5.1.7) + activesupport (= 5.1.7) + activerecord (5.1.7) + activemodel (= 5.1.7) + activesupport (= 5.1.7) + arel (~> 8.0) + activesupport (5.1.7) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + addressable (2.6.0) + public_suffix (>= 2.0.2, < 4.0) + arel (8.0.0) + ast (2.4.0) + awesome_print (1.8.0) + bindex (0.7.0) + bower-rails (0.11.0) + builder (3.2.3) + capybara (3.18.0) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (~> 1.2) + xpath (~> 3.2) + coderay (1.1.2) + coffee-rails (4.2.2) + coffee-script (>= 2.2.0) + railties (>= 4.0.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + commonjs (0.2.7) + concurrent-ruby (1.1.5) + crass (1.0.4) + daemons (1.3.1) + database_cleaner (1.7.0) + datagrid (1.5.8) + rails (>= 4.0) + diff-lcs (1.3) + domain_name (0.5.20180417) + unf (>= 0.0.5, < 1.0.0) + erubi (1.8.0) + eventmachine (1.2.7) + execjs (2.7.0) + fakeredis (0.7.0) + redis (>= 3.2, < 5.0) + ffi (1.10.0) + font-awesome-rails (4.7.0.5) + railties (>= 3.2, < 6.1) + foreman (0.84.0) + thor (~> 0.19.1) + formatador (0.2.5) + git (1.5.0) + globalid (0.4.2) + activesupport (>= 4.2.0) + guard (2.15.0) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + lumberjack (>= 1.0.12, < 2.0) + nenv (~> 0.1) + notiffany (~> 0.0) + pry (>= 0.9.12) + shellany (~> 0.0) + thor (>= 0.18.1) + guard-compat (1.2.1) + guard-rspec (4.7.3) + guard (~> 2.1) + guard-compat (~> 1.1) + rspec (>= 2.99.0, < 4.0) + http-cookie (1.0.3) + domain_name (~> 0.5) + i18n (0.9.5) + concurrent-ruby (~> 1.0) + jaro_winkler (1.5.2) + jbuilder (2.8.0) + activesupport (>= 4.2.0) + multi_json (>= 1.2) + json (1.8.6) + 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) + less (2.6.0) + commonjs (~> 0.2.7) + less-rails (4.0.0) + actionpack (>= 4) + less (~> 2.6.0) + sprockets (>= 2) + libv8 (3.16.14.19) + listen (3.1.1) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9.7) + lograge (0.11.0) + actionpack (>= 4) + activesupport (>= 4) + railties (>= 4) + request_store (~> 1.0) + logstash-event (1.2.02) + loofah (2.2.3) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + lumberjack (1.0.13) + mail (2.7.1) + mini_mime (>= 0.1.1) + method_source (0.9.2) + micro_magick (1.1.0) + mime-types (3.2.2) + mime-types-data (~> 3.2015) + mime-types-data (3.2019.0331) + mini_mime (1.0.1) + mini_portile2 (2.3.0) + minitest (5.11.3) + multi_json (1.13.1) + nenv (0.3.0) + netrc (0.11.0) + nio4r (2.3.1) + nokogiri (1.8.5) + mini_portile2 (~> 2.3.0) + notiffany (0.1.1) + nenv (~> 0.1) + shellany (~> 0.0) + parallel (1.17.0) + parser (2.6.3.0) + ast (~> 2.4.0) + pry (0.12.2) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + public_suffix (3.0.3) + rack (2.0.7) + rack-cache (1.9.0) + rack (>= 0.4) + rack-proxy (0.6.5) + rack + rack-rewrite (1.5.1) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (5.1.7) + actioncable (= 5.1.7) + actionmailer (= 5.1.7) + actionpack (= 5.1.7) + actionview (= 5.1.7) + activejob (= 5.1.7) + activemodel (= 5.1.7) + activerecord (= 5.1.7) + activesupport (= 5.1.7) + bundler (>= 1.3.0) + railties (= 5.1.7) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.4) + actionpack (>= 5.0.1.x) + actionview (>= 5.0.1.x) + activesupport (>= 5.0.1.x) + 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) + railties (5.1.7) + actionpack (= 5.1.7) + activesupport (= 5.1.7) + method_source + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rainbow (3.0.0) + rake (12.3.2) + rb-fsevent (0.10.3) + rb-inotify (0.10.0) + ffi (~> 1.0) + rdoc (4.3.0) + redis (3.3.5) + 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-namespace (1.6.0) + redis (>= 3.0.4) + redis-rack (2.0.5) + rack (>= 1.5, < 3) + redis-store (>= 1.2, < 2) + redis-rack-cache (2.0.2) + rack-cache (>= 1.6, < 2) + 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) + ref (2.0.0) + regexp_parser (1.4.0) + request_store (1.4.1) + rack (>= 1.4) + responders (2.4.1) + actionpack (>= 4.2.0, < 6.0) + railties (>= 4.2.0, < 6.0) + rest-client (2.0.2) + http-cookie (>= 1.0.2, < 2.0) + mime-types (>= 1.16, < 4.0) + netrc (~> 0.8) + rspec (3.8.0) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-core (3.8.0) + rspec-support (~> 3.8.0) + rspec-expectations (3.8.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-html-matchers (0.9.1) + nokogiri (~> 1) + rspec (>= 3.0.0.a, < 4) + rspec-mocks (3.8.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-rails (3.8.2) + 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) + rubocop (0.68.1) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + parser (>= 2.5, != 2.5.1.1) + rainbow (>= 2.2.2, < 4.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 1.6) + ruby-progressbar (1.10.0) + sass (3.7.4) + 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) + sdoc (0.4.2) + json (~> 1.7, >= 1.7.7) + rdoc (~> 4.0) + shellany (0.0.1) + spring (2.0.2) + activesupport (>= 4.2) + sprockets (4.0.0.beta8) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.3.13) + therubyracer (0.12.3) + libv8 (~> 3.16.14.15) + ref + thin (1.7.2) + daemons (~> 1.0, >= 1.0.9) + eventmachine (~> 1.0, >= 1.0.4) + rack (>= 1, < 3) + thor (0.19.4) + thread_safe (0.3.6) + tilt (2.0.9) + tzinfo (1.2.5) + thread_safe (~> 0.1) + uglifier (4.1.20) + execjs (>= 0.3.0, < 3) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.6) + unicode-display_width (1.5.0) + web-console (3.5.1) + actionview (>= 5.0) + activemodel (>= 5.0) + bindex (>= 0.4.0) + railties (>= 5.0) + webpacker (4.0.2) + activesupport (>= 4.2) + rack-proxy (>= 0.6.1) + railties (>= 4.2) + websocket-driver (0.6.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.3) + xpath (3.2.0) + nokogiri (~> 1.8) + +PLATFORMS + ruby + +DEPENDENCIES + activemodel (~> 5.1.4) + activerecord (~> 5.1.4) + addressable + awesome_print (~> 1.6, >= 1.6.1) + bower-rails + capybara + coffee-rails (~> 4.2.2) + database_cleaner + datagrid (~> 1.5) + dtu-core! + fakefs! + fakeredis (~> 0.7) + font-awesome-rails (~> 4.7.0.3) + foreman (~> 0.84.0) + git (>= 1.2.2) + guard-rspec + i18n (~> 0.9.5) + jbuilder (~> 2.0) + kaminari + less-rails + listen (= 3.1.1) + lograge (~> 0.4) + logstash-event + micro_magick (~> 1.1) + nokogiri (~> 1.8.5) + pry + quiz! + rack-rewrite (~> 1.5.1) + rails (~> 5.1.4) + rails-controller-testing + redis (~> 3.2) + redis-namespace + redis-rack-cache + redis-rails + responders (~> 2.0) + rest-client (~> 2.0) + rspec-core + rspec-html-matchers + rspec-rails (~> 3.0) + rubocop + rubycas-client (~> 2.3.8)! + sass-rails (~> 5.0) + sdoc (~> 0.4.0) + spring + sprockets (~> 4.0.0.beta8) + sqlite3 (~> 1.3.0) + therubyracer + thin (~> 1.7.2) + uglifier (>= 1.3.0) + web-console (~> 3.5.1) + webpacker (~> 4.x) + +RUBY VERSION + ruby 2.5.1p57 + +BUNDLED WITH + 1.16.6 diff --git a/Procfile b/Procfile new file mode 100644 index 0000000000000000000000000000000000000000..ceced79c85ff79e8b1138e9c7cffbde1baabd186 --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +web: bundle exec thin start -p $PORT + diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..75e547a43c072b3063d9562c398f334374131326 --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# Running the app with Docker + + +Hard restart/rebuild of the containers: + +``` +docker-compose -f docker-compose.prod.yml kill +docker-compose -f docker-compose.prod.yml build +docker-compose -f docker-compose.prod.yml kill +docker-compose -f docker-compose.prod.yml up -d +``` + +## Get the logs + +Logs can be found either in the primary location: + +``` +docker cp coursewebsite_course_1:/dtu-course/app/log/production.log production.log +docker cp coursewebsite_course_1:/dtu-course/app/log/run-server.log run-server.log +``` + +Or in the shared volume location: +``` +docker cp coursewebsite_course_1:/data/log/production.log production.log +docker cp coursewebsite_course_1:/data/log/run-server.log run-server.log +``` + +Or you can get the container logs: + +### Rails app +``` +docker logs coursewebsite_course_1 > course_container.log 2>&1 +tail course_container.log +``` + +### Webserver +``` +docker logs coursewebsite_nginx_1 > nginx_container.log 2>&1 +tail nginx_container.log +``` + +Access Log: + +``` +docker cp coursewebsite_nginx_1:/var/log/nginx_access2.log nginx_access2.log +``` + +Error logs: +``` +docker cp coursewebsite_nginx_1:/var/log/nginx_error2.log nginx_error2.log +``` + + +## Simple errors checks: + +Check for rake errors: + +``` +docker logs course_website | grep -A 5 -B 5 aborted! +``` + +``` +docker logs course_website | grep -A 5 -B 5 ERROR +docker logs course_website | grep -A 5 -B 5 FATAL +``` + diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000000000000000000000000000000000000..ba6b733dd2358d858f00445ebd91c214f0f5d2e5 --- /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 File.expand_path('../config/application', __FILE__) + +Rails.application.load_tasks diff --git a/app/.codeclimate.yml b/app/.codeclimate.yml new file mode 100644 index 0000000000000000000000000000000000000000..93053a20340bbc9d071eb8e6e188ead653d2d879 --- /dev/null +++ b/app/.codeclimate.yml @@ -0,0 +1,42 @@ +--- +engines: + csslint: + enabled: true + coffeelint: + enabled: true + duplication: + enabled: true + config: + languages: + ruby: + javascript: + exclude_paths: + - "./assets/javascripts/mathjax.js" + - "./assets/javascripts/edit-page.js" + - "**.js" + eslint: + enabled: true + exclude_paths: + - "assets/javascripts/mathjax.js" + - "assets/javascripts/edit-page.js" + - "**.js" + - "assets/javascripts/" + fixme: + enabled: true + rubocop: + enabled: true +ratings: + paths: + - "**.css" + - "**.coffee" + - "**.inc" + - "**.js" + - "**.jsx" + - "**.module" + - "**.php" + - "**.py" + - "**.rb" +exclude_paths: +- "assets/javascripts/mathjax.js" +- "assets/javascripts/edit-page.js" +- "**.js" \ No newline at end of file diff --git a/app/.csslintrc b/app/.csslintrc new file mode 100644 index 0000000000000000000000000000000000000000..1bc44069a4adc530182522559ea14e3ca78a61e4 --- /dev/null +++ b/app/.csslintrc @@ -0,0 +1,3 @@ +--exclude-exts=.min.css +--exclude=base.css +--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes diff --git a/app/.eslintignore b/app/.eslintignore new file mode 100644 index 0000000000000000000000000000000000000000..140a7504d100e3ee06e6af80fbff4905595663f4 --- /dev/null +++ b/app/.eslintignore @@ -0,0 +1,2 @@ +**/*{.,-}min.js +mathjax.js diff --git a/app/.eslintrc.yml b/app/.eslintrc.yml new file mode 100644 index 0000000000000000000000000000000000000000..a6a0ce9c44238e06ff55ca335a66a4e16810da38 --- /dev/null +++ b/app/.eslintrc.yml @@ -0,0 +1,277 @@ +--- +parserOptions: + sourceType: module + ecmaFeatures: + jsx: true + +env: + amd: true + browser: true + es6: true + jquery: true + node: true + +# http://eslint.org/docs/rules/ +rules: + # Possible Errors + no-await-in-loop: off + no-cond-assign: error + no-console: off + no-constant-condition: error + no-control-regex: error + no-debugger: error + no-dupe-args: error + no-dupe-keys: error + no-duplicate-case: error + no-empty-character-class: error + no-empty: error + no-ex-assign: error + no-extra-boolean-cast: error + no-extra-parens: off + no-extra-semi: error + no-func-assign: error + no-inner-declarations: + - error + - functions + no-invalid-regexp: error + no-irregular-whitespace: error + no-negated-in-lhs: error + no-obj-calls: error + no-prototype-builtins: off + no-regex-spaces: error + no-sparse-arrays: error + no-template-curly-in-string: off + no-unexpected-multiline: error + no-unreachable: error + no-unsafe-finally: off + no-unsafe-negation: off + use-isnan: error + valid-jsdoc: off + valid-typeof: error + + # Best Practices + accessor-pairs: error + array-callback-return: off + block-scoped-var: off + class-methods-use-this: off + complexity: + - error + - 6 + consistent-return: off + curly: off + default-case: off + dot-location: off + dot-notation: off + eqeqeq: error + guard-for-in: error + no-alert: error + no-caller: error + no-case-declarations: error + no-div-regex: error + no-else-return: off + no-empty-function: off + no-empty-pattern: error + no-eq-null: error + no-eval: error + no-extend-native: error + no-extra-bind: error + no-extra-label: off + no-fallthrough: error + no-floating-decimal: off + no-global-assign: off + no-implicit-coercion: off + no-implied-eval: error + no-invalid-this: off + no-iterator: error + no-labels: + - error + - allowLoop: true + allowSwitch: true + no-lone-blocks: error + no-loop-func: error + no-magic-number: off + no-multi-spaces: off + no-multi-str: off + no-native-reassign: error + no-new-func: error + no-new-wrappers: error + no-new: error + no-octal-escape: error + no-octal: error + no-param-reassign: off + no-proto: error + no-redeclare: error + no-restricted-properties: off + no-return-assign: error + no-return-await: off + no-script-url: error + no-self-assign: off + no-self-compare: error + no-sequences: off + no-throw-literal: off + no-unmodified-loop-condition: off + no-unused-expressions: error + no-unused-labels: off + no-useless-call: error + no-useless-concat: error + no-useless-escape: off + no-useless-return: off + no-void: error + no-warning-comments: off + no-with: error + prefer-promise-reject-errors: off + radix: error + require-await: off + vars-on-top: off + wrap-iife: error + yoda: off + + # Strict + strict: off + + # Variables + init-declarations: off + no-catch-shadow: error + no-delete-var: error + no-label-var: error + no-restricted-globals: off + no-shadow-restricted-names: error + no-shadow: off + no-undef-init: error + no-undef: off + no-undefined: off + no-unused-vars: off + no-use-before-define: off + + # Node.js and CommonJS + callback-return: error + global-require: error + handle-callback-err: error + no-mixed-requires: off + no-new-require: off + no-path-concat: error + no-process-env: off + no-process-exit: error + no-restricted-modules: off + no-sync: off + + # Stylistic Issues + array-bracket-spacing: off + block-spacing: off + brace-style: off + camelcase: off + capitalized-comments: off + comma-dangle: + - error + - never + comma-spacing: off + comma-style: off + computed-property-spacing: off + consistent-this: off + eol-last: off + func-call-spacing: off + func-name-matching: off + func-names: off + func-style: off + id-length: off + id-match: off + indent: off + jsx-quotes: off + key-spacing: off + keyword-spacing: off + line-comment-position: off + linebreak-style: off + lines-around-comment: off + lines-around-directive: off + max-depth: off + max-len: off + max-nested-callbacks: off + max-params: off + max-statements-per-line: off + max-statements: + - error + - 30 + multiline-ternary: off + new-cap: off + new-parens: off + newline-after-var: off + newline-before-return: off + newline-per-chained-call: off + no-array-constructor: off + no-bitwise: off + no-continue: off + no-inline-comments: off + no-lonely-if: off + no-mixed-operators: off + no-mixed-spaces-and-tabs: off + no-multi-assign: off + no-multiple-empty-lines: off + no-negated-condition: off + no-nested-ternary: off + no-new-object: off + no-plusplus: off + no-restricted-syntax: off + no-spaced-func: off + no-tabs: off + no-ternary: off + no-trailing-spaces: off + no-underscore-dangle: off + no-unneeded-ternary: off + object-curly-newline: off + object-curly-spacing: off + object-property-newline: off + one-var-declaration-per-line: off + one-var: off + operator-assignment: off + operator-linebreak: off + padded-blocks: off + quote-props: off + quotes: off + require-jsdoc: off + semi-spacing: off + semi: off + sort-keys: off + sort-vars: off + space-before-blocks: off + space-before-function-paren: off + space-in-parens: off + space-infix-ops: off + space-unary-ops: off + spaced-comment: off + template-tag-spacing: off + unicode-bom: off + wrap-regex: off + + # ECMAScript 6 + arrow-body-style: off + arrow-parens: off + arrow-spacing: off + constructor-super: off + generator-star-spacing: off + no-class-assign: off + no-confusing-arrow: off + no-const-assign: off + no-dupe-class-members: off + no-duplicate-imports: off + no-new-symbol: off + no-restricted-imports: off + no-this-before-super: off + no-useless-computed-key: off + no-useless-constructor: off + no-useless-rename: off + no-var: off + object-shorthand: off + prefer-arrow-callback: off + prefer-const: off + prefer-destructuring: off + prefer-numeric-literals: off + prefer-rest-params: off + prefer-reflect: off + prefer-spread: off + prefer-template: off + require-yield: off + rest-spread-spacing: off + sort-imports: off + symbol-description: off + template-curly-spacing: off + yield-star-spacing: off diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 0000000000000000000000000000000000000000..cfe863c2a0b0475a95c7ef517abf59a8aa27e8e4 --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,5 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link application.css +//= link dtu_core_app/application.css +//= link dtu_core_app/application.js diff --git a/app/assets/images/.keep b/app/assets/images/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/assets/images/dtulogo.svg b/app/assets/images/dtulogo.svg new file mode 100644 index 0000000000000000000000000000000000000000..cafd65237441a572b488e69399aae39b570dc513 --- /dev/null +++ b/app/assets/images/dtulogo.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + viewBox="0 0 51.785331 75.5428" + height="75.542801" + width="51.785332" + xml:space="preserve" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="dtulogo.svg"><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1313" + inkscape:window-height="924" + id="namedview14" + showgrid="true" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:zoom="3.3638598" + inkscape:cx="39.711236" + inkscape:cy="-34.847759" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:current-layer="svg2"><inkscape:grid + type="xygrid" + id="grid3342" + originx="-0.40638376" + originy="-1166.8806" /></sodipodi:namedview><metadata + id="metadata8"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs6"><clipPath + id="clipPath18" + clipPathUnits="userSpaceOnUse"><path + id="path16" + d="m 0,841.89 595.276,0 L 595.276,0 0,0 Z" + inkscape:connector-curvature="0" /></clipPath></defs><g + transform="matrix(1.3333333,0,0,-1.3333333,-457.91652,597.92572)" + id="g10"><g + id="g12"><g + clip-path="url(#clipPath18)" + id="g14"><g + transform="translate(345.9375,448.4443)" + id="g20"><path + id="path22" + style="fill:#848282;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 0,0 c -0.154,0 -0.249,-0.047 -0.318,-0.114 -0.069,-0.07 -0.114,-0.162 -0.114,-0.318 l 0,-19.712 c 0,-0.154 0.045,-0.248 0.114,-0.316 0.069,-0.068 0.164,-0.114 0.318,-0.114 l 5.156,0 c 2.003,0 3.225,0.455 3.965,1.414 1.093,1.308 1.128,3.422 1.128,6.661 l 0,4.423 c 0,3.24 -0.035,5.352 -1.128,6.661 C 8.381,-0.455 7.159,0 5.156,0 Z m 2.84,-2.405 1.818,0 c 0.803,0 1.282,-0.131 1.654,-0.576 0.572,-0.687 0.621,-2.074 0.621,-4.869 l 0,-4.875 c 0,-2.796 -0.049,-4.181 -0.621,-4.869 -0.372,-0.445 -0.851,-0.575 -1.654,-0.575 l -1.818,0 z m 31.317,1.973 c 0,0.156 -0.047,0.248 -0.115,0.318 C 33.975,-0.047 33.879,0 33.726,0 l -2.411,0 c -0.154,0 -0.248,-0.047 -0.316,-0.114 -0.069,-0.07 -0.115,-0.162 -0.115,-0.318 l 0,-14.552 c 0,-1.519 -0.115,-2.421 -0.608,-2.963 -0.335,-0.367 -0.809,-0.547 -1.471,-0.547 -0.604,0 -1.059,0.167 -1.407,0.55 -0.466,0.513 -0.608,1.386 -0.608,2.96 l 0,14.552 c 0,0.156 -0.048,0.248 -0.117,0.318 C 26.606,-0.047 26.512,0 26.356,0 l -2.408,0 c -0.155,0 -0.25,-0.047 -0.316,-0.114 -0.07,-0.07 -0.115,-0.162 -0.115,-0.318 l 0,-14.556 c 0,-2.119 0.288,-3.448 1.129,-4.374 0.875,-0.962 2.198,-1.473 4.201,-1.473 2.026,0 3.331,0.543 4.133,1.476 0.944,1.095 1.177,2.403 1.177,4.371 z M 18.599,-20.144 c 0,-0.154 -0.045,-0.248 -0.114,-0.316 -0.069,-0.068 -0.163,-0.114 -0.316,-0.114 l -2.638,0 c -0.153,0 -0.249,0.046 -0.316,0.114 -0.07,0.068 -0.115,0.162 -0.115,0.316 l 0,17.543 -3.095,0 c -0.155,0 -0.248,0.046 -0.318,0.115 -0.069,0.068 -0.116,0.163 -0.116,0.317 l 0,1.737 c 0,0.156 0.047,0.248 0.116,0.318 C 11.757,-0.047 11.85,0 12.005,0 l 9.689,0 c 0.156,0 0.25,-0.047 0.32,-0.114 0.065,-0.07 0.113,-0.162 0.113,-0.318 l 0,-1.737 c 0,-0.154 -0.048,-0.249 -0.113,-0.317 -0.07,-0.069 -0.164,-0.115 -0.32,-0.115 l -3.095,0 z" + inkscape:connector-curvature="0" /></g><g + transform="translate(382.2764,417.5732)" + id="g24"><path + id="path26" + style="fill:#bf2033;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 0,0 -8.266,-4.337 c -10.701,4.162 -11.604,4.162 -22.309,0 L -38.839,0 l 8.264,4.341 c 10.705,-4.164 11.608,-4.164 22.309,0 z m 0,-10.724 -8.266,-4.339 c -10.701,4.165 -11.604,4.165 -22.309,0 l -8.264,4.339 8.264,4.339 c 10.705,-4.163 11.608,-4.163 22.309,0 z m 0,-10.723 -8.266,-4.339 c -10.701,4.162 -11.604,4.162 -22.309,0 l -8.264,4.339 8.264,4.337 c 10.705,-4.163 11.608,-4.163 22.309,0 L 0,-21.447" + inkscape:connector-curvature="0" /></g></g></g></g></svg> \ No newline at end of file diff --git a/app/assets/images/kunlogo.png b/app/assets/images/kunlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..45991ffd89c5e2347301095b2618f1bb4038282e Binary files /dev/null and b/app/assets/images/kunlogo.png differ diff --git a/app/assets/images/wmd-buttons.png b/app/assets/images/wmd-buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..50b37090363e6757e7bd0ba75cd1e0dfaabd13d2 Binary files /dev/null and b/app/assets/images/wmd-buttons.png differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 0000000000000000000000000000000000000000..c9bbee9f5d0fafb233bc3001073e831581ce43f7 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1 @@ +console.error('Moved to webpack!'); diff --git a/app/assets/javascripts/md-page.coffee b/app/assets/javascripts/md-page.coffee new file mode 100644 index 0000000000000000000000000000000000000000..cb1f1e24d0c08a4e3d2a407eb62e06480a807e5e --- /dev/null +++ b/app/assets/javascripts/md-page.coffee @@ -0,0 +1,118 @@ +class MdPage + constructor: (config) -> + self = this + self.config = config + + if (MdPage.instance) + console.error "Multiple MdPage" + return + + MdPage.instance = this + + if config.allow_chat + setupChat = () => + self.chat = new Chat(config.user_info, "https://"+config.chat_server_domain) + setTimeout(setupChat, 2000) + + console?.log "Markdown page" + console.dir config + + if config.allow_feedback + require(['index'], (fallback) => (new fallback.Feedback({ajaxURL: '/feedbacks'})).open() ) + + # c.f. page_compiler_service.rb + @VERBATIM_HTML_START: "<div class='verbatim-html'>" + @VERBATIM_HTML_END : "</div><!-- verbatim-html -->" + + @preConvertMarkdown: (page) -> + output = [] + block_no = 0 + in_non_md_block = false + non_md_block = [] + emitBlock = () -> + $("<div id='pcm#{block_no}'>#{non_md_block.join('\n')}</div>").appendTo(pcm) + pcm = $("<div id='preConvertMarkdown'></div>").hide().appendTo("body") + for line in page.split(/\n/) + if in_non_md_block + if line == MdPage.VERBATIM_HTML_END + in_non_md_block = false + emitBlock() + non_md_block = [] + else + non_md_block.push(line) + else + if line == MdPage.VERBATIM_HTML_START + in_non_md_block = true + output.push("<div class='pcm-paceholder' data-pcmid='pcm#{block_no}'></div>") + else + output.push(line) + + emitBlock() if in_non_md_block + + new_page = output.join("\n") + new_page + + @postConvertMarkdown: (page) -> + lineMapper = (line) -> + m = line.match(/<div class='pcm-paceholder' data-pcmid='(pcm\d+)'><\/div>/) + if (m) + e = $("#"+m[1]) + console.dir(e) + h = e.html() + e.remove() + h + else + line + page.split(/\n/).map(lineMapper).join('\n') + + @showFullFeedbackImage: (event, url) -> + $(".full-feedback-image").attr('src', url) + $("#full-feedback-image-modal").modal('show') +# + # Init + # + + @isMyPage: () -> + return (typeof renderCoursePage is 'function') + + @initPage: () -> + + # if !window.MD_PAGE_CONFIG? + # console?.log "reloading because page was accessed\ + # via turbolink and page isn't configured" + # window.location.reload() + # return + + if MdPage.instance? + MdPage.instance = null + + window.md_page = new MdPage(window.MD_PAGE_CONFIG) + + if typeof window.Markdown is 'object' + ClientDebug.send('info', { + type: 'rendering-info', + message: "MD Rendering starting. ", + location: window.location.href + }) + + window.renderPage() + + ClientDebug.send('info', { + type: 'rendering-info', + message: "MD Rendering complete. ", + location: window.location.href + }) + else + # if Markdown hasn't been loaded then we must reload the entire page -- + # we're turbolinking from a non-MD page to a MD page + console?.log('Markdown is not loaded; forcing full reload') + location.reload() + + # + # Data + # + + @instance: null + + +window.MdPage = MdPage diff --git a/app/assets/javascripts/require-config.coffee.erb b/app/assets/javascripts/require-config.coffee.erb new file mode 100644 index 0000000000000000000000000000000000000000..5da58416f02de77ebdbd76c295b47f2c10ac7ed6 --- /dev/null +++ b/app/assets/javascripts/require-config.coffee.erb @@ -0,0 +1,14 @@ +<% + def rjs_asset_path(path) + asset = asset_path(path) + File.join(File.dirname(asset), File.basename(asset, ".*")) + end +%> +@require = + baseUrl: "/assets", + paths: + "html2canvas": "<%= rjs_asset_path 'html2canvas/dist/html2canvas.js' %>" + "index": "<%= rjs_asset_path('feedback/feedback.js')%>" + onError: () -> console.log('ERROR'), + +console.dir(@require) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/coffeelint.json b/app/coffeelint.json new file mode 100644 index 0000000000000000000000000000000000000000..86422e323d1f407c05c048bb35d67e433101e758 --- /dev/null +++ b/app/coffeelint.json @@ -0,0 +1,129 @@ +{ + "arrow_spacing": { + "level": "ignore" + }, + "braces_spacing": { + "level": "ignore", + "spaces": 0, + "empty_object_spaces": 0 + }, + "camel_case_classes": { + "level": "error" + }, + "coffeescript_error": { + "level": "error" + }, + "colon_assignment_spacing": { + "level": "ignore", + "spacing": { + "left": 0, + "right": 0 + } + }, + "cyclomatic_complexity": { + "value": 10, + "level": "ignore" + }, + "duplicate_key": { + "level": "error" + }, + "empty_constructor_needs_parens": { + "level": "ignore" + }, + "ensure_comprehensions": { + "level": "warn" + }, + "eol_last": { + "level": "ignore" + }, + "indentation": { + "value": 2, + "level": "error" + }, + "line_endings": { + "level": "ignore", + "value": "unix" + }, + "max_line_length": { + "value": 80, + "level": "error", + "limitComments": true + }, + "missing_fat_arrows": { + "level": "ignore", + "is_strict": false + }, + "newlines_after_classes": { + "value": 3, + "level": "ignore" + }, + "no_backticks": { + "level": "error" + }, + "no_debugger": { + "level": "warn", + "console": false + }, + "no_empty_functions": { + "level": "ignore" + }, + "no_empty_param_list": { + "level": "ignore" + }, + "no_implicit_braces": { + "level": "ignore", + "strict": true + }, + "no_implicit_parens": { + "strict": true, + "level": "ignore" + }, + "no_interpolation_in_single_quotes": { + "level": "ignore" + }, + "no_plusplus": { + "level": "ignore" + }, + "no_stand_alone_at": { + "level": "ignore" + }, + "no_tabs": { + "level": "error" + }, + "no_this": { + "level": "ignore" + }, + "no_throwing_strings": { + "level": "error" + }, + "no_trailing_semicolons": { + "level": "error" + }, + "no_trailing_whitespace": { + "level": "error", + "allowed_in_comments": false, + "allowed_in_empty_lines": true + }, + "no_unnecessary_double_quotes": { + "level": "ignore" + }, + "no_unnecessary_fat_arrows": { + "level": "warn" + }, + "non_empty_constructor_needs_parens": { + "level": "ignore" + }, + "prefer_english_operator": { + "level": "ignore", + "doubleNotLevel": "ignore" + }, + "space_operators": { + "level": "ignore" + }, + "spacing_after_comma": { + "level": "ignore" + }, + "transform_messes_up_line_numbers": { + "level": "warn" + } +} diff --git a/app/controllers/admin/admin_controller.rb b/app/controllers/admin/admin_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..58e42171457c2a4088b89ce0be83d689ddec100d --- /dev/null +++ b/app/controllers/admin/admin_controller.rb @@ -0,0 +1,30 @@ +class Admin::AdminController < ApplicationController + include AdminHelper + include CourseUrlHelper + + before_action EnoteCas::Filter, if: proc { Rails.env.production? } + + before_action :require_login # , :if => proc { Rails.env.production? } + + before_action :require_admin # , :if => proc { Rails.env.production? } + + before_action :retrieve_taught_courses + + attr_accessor(:taught_courses) + + def index + end + + # TODO: cleanup? + def retrieve_taught_courses + @taught_courses = current_user_courses_for_acl :administrator || [] + end + +# def first_course +# if @course +# redirect_to home_path(course: my_course_id) +# else +# render 'no_admin' +# end +# end +end diff --git a/app/controllers/admin/admin_course_controller.rb b/app/controllers/admin/admin_course_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..cd1a5c83e6a84df2398ad960d70cf11bac69b44b --- /dev/null +++ b/app/controllers/admin/admin_course_controller.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'pathname' +require 'yaml' + +## +# Controller for the course view of the administrative console of the website. +class Admin::AdminCourseController < Admin::AdminController + + def index + @admin_tab = "course" + + load_course_config + end + + def change_course_number + load_course_config + + success, msg = process_submit({number: params[:number]}) + if success + render json: { message: msg}, status: :ok + else + render json: {}, status: :unprocessable_entity + end + end + + private + + def process_submit(details) + return false unless details and details.has_key? :number + return false unless @cn_dumper_config + + @cn_dumper_config[my_course_id]['element'] = details[:number] + File.open(@cn_dumper_path, 'w') {|f| f.write @cn_dumper_config.to_yaml } + + msg = "Course Number Updated to #{details[:number]}" + Rails.logger.info msg + return true, msg + end + + def load_course_config + Rails.logger.info "load_course_config" + + users_path = File.join(WebsiteConfig.data_root, 'user_config', "#{my_course_id}-users.yaml") + groups_path = File.join(WebsiteConfig.data_root, 'user_config', "#{my_course_id}-groups.yaml") + title_path = File.join(WebsiteConfig.data_root, 'user_config', "#{my_course_id}-title.yaml") + + @cn_dumper_path = File.join(WebsiteConfig.config_root, 'cn-dumper.yaml') + + @cn_dumper_config = YAML::load_file @cn_dumper_path + + Rails.logger.info "cndumper: #{@cn_dumper_config.ai}" + + @course_name = "unknown" + if File.exist? title_path + @course_title = YAML::load_file title_path + @course_name = @course_title['title'] + end + Rails.logger.info "name: #{title_path} #{@course_name}" + + @course_element = "0" + if @cn_dumper_config.has_key? my_course_id + @course_element = @cn_dumper_config[my_course_id]['element'] + #@course_name = @cn_dumper_config[my_course_id]['name'] + end + + if File.exist?(users_path) and File.exist?(groups_path) + @users_stat = File.stat(users_path) + @groups_stat = File.stat(groups_path) + @course_members_updated = @users_stat.mtime.in_time_zone.to_s :quiz + @users = File.read users_path + @groups = File.read groups_path + else + @course_members_updated = "unknown" + end + end +end + diff --git a/app/controllers/admin/admin_enotes_controller.rb b/app/controllers/admin/admin_enotes_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..5b9769c828e81af1af6c0a7a516b53e0aab3ff4d --- /dev/null +++ b/app/controllers/admin/admin_enotes_controller.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'pathname' +require 'ostruct' + +## +# Controller for the administrative console of the website. +class Admin::AdminEnotesController < Admin::AdminController + attr_accessor(:running_getpdf, + :latest_getpdf_job) + + def index + @admin_tab = "enotes" + + # Maybe create another singleton for Uploads and have it share a common subclass? + @course_enotes_files = Enotes.instance.get(my_course_id)[:enote_files] + @course_enotes_viewmodel = @course_enotes_files.map do |file| + { + friendly_name: File.basename(file), + mtime: File.exist?(file) ? File.mtime(file).to_s(:quiz) : nil + } + end + + # + # Sharelatex/GetPDF + # + js = EnotesService.new(my_course_id).getpdf_jobs + + # sometimes the getpdf server doesn't report completed jobs as complete. + js = js.map do |job| + if job.lastFinishedAt + if job.status.eql?("running") + if job.failReason + job.status = 'failed' + else + job.status = 'completed' + end + end + end + Rails.logger.info "getPDF job: #{job.status} #{job.lastFinishedAt} #{job.failResaon}" + job + end + + @latest_getpdf_job = nil + @latest_getpdf_job = js[0] if js.length > 0 + #Rails.logger.info "latest getPDF job: #{@latest_getpdf_job}" + + @running_getpdf = js.select { |x| x.status.eql? 'running' } + getpdf_jobs_grid_defaults = { + order: :status, + descending: true, + course_id: my_course_id + } + options = getpdf_jobs_grid_defaults.merge(params[:getpdf_jobs] || {}) + @getpdf_jobs_grid = GetpdfJobsGrid.new(options) + @getpdf_jobs_grid.scope { js } + end + + def update_enotes + update_svc = UpdateService.new(my_course_id) + + update_svc.update_enotes + + render json: {} + end + + def build_enotes + update_svc = UpdateService.new(my_course_id) + + js = update_svc.launch_compile_enotes + + render json: js + end + + def publish_enotes + update_svc = UpdateService.new my_course_id + + js = update_svc.publish_enotes + + render json: js + end + + ## + # GETPDF Jobs API + ## + def getpdf_jobs + render json: EnotesService.new(my_course_id).getpdf_jobs + end + + def getpdf_job + render json: EnotesService.new(my_course_id).getpdf_job(params[:job_id]) + end + + def cancel_getpdf_job + render json: EnotesService.new(my_course_id).cancel_getpdf_job(params[:job_id]) + end + + private +end diff --git a/app/controllers/admin/admin_feedback_controller.rb b/app/controllers/admin/admin_feedback_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..c0636378e9fab6d8f75f98dce2542c7b3df03633 --- /dev/null +++ b/app/controllers/admin/admin_feedback_controller.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Admin + ## + # Controller for the feedback view of the administrative console of the website. + class AdminFeedbackController < Admin::AdminController + def index + @admin_tab = 'feedback' + + feedback_grid_defaults = { + order: :created_at, + descending: true, + course_id: my_course_id + } + options = feedback_grid_defaults.merge(params[:feedback_grid] || {}) + @feedback_grid = FeedbackGrid.new(options) do |scope| + scope.where(course_id: my_course_id).page(params[:page]).per(20) + end + end + + def set_allowed + new_value = parse_json_object + config = WebsiteConfig.get + config.courses[my_course_id].allow_feedback = new_value['allow_feedback'] + config.to_yml + end + end +end diff --git a/app/controllers/admin/admin_files_controller.rb b/app/controllers/admin/admin_files_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..9e6e476c88afd2e93bbb9980f5d91aaf4b1d5827 --- /dev/null +++ b/app/controllers/admin/admin_files_controller.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'pathname' +require 'ostruct' + +## +# Controller for the administrative console of the website. +class Admin::AdminFilesController < Admin::AdminController + attr_accessor(:course_uploads_files, + :course_enotes_files, + :filemanager_tree) + + def index + @admin_tab = "files" + + # Maybe create another singleton for Uploads and have it share a common subclass? + @course_enotes_files = Enotes.instance.get(my_course_id)[:enote_files] + @course_enotes_viewmodel = @course_enotes_files.map do |file| + { + friendly_name: File.basename(file), + mtime: File.exist?(file) ? File.mtime(file).to_s(:quiz) : nil + } + end + @course_uploads_files = DTUFileManagement::FileManager.instance.uploads_files[my_course_id] || [] + + # + # File Manager Tab + # + @filemanager_tree = list_uploads + end + + def update + update_svc = UpdateService.new(my_course_id) + + update_svc.compile_pages + + render json: {} + end + + def update_filemanager + update_svc = UpdateService.new(my_course_id) + + update_svc.update_filemanager current_user + + render json: {} + end + + def upload + uploaded_io = params[:new_upload_file] + uploads_folder = DTUFileManagement::FileManager.instance.uploads_folder(my_course_id) + new_path = File.join(uploads_folder, + sanitize_filename(uploaded_io.original_filename)) + Rails.logger.info("Uploading #{uploaded_io.original_filename} to #{new_path}") + File.open(new_path, 'wb') do |file| + file.write(uploaded_io.read) + end + DTUFileManagement::FileManager.instance.update + redirect_to admin_path(anchor: 'filemanager') + end + + private + + def get_file(file) + File.exist?(file) ? File.read(file) : '<div></div>' + end + + def list_uploads + root = File.join(DTUFileManagement::FileManager.instance.uploads_folder(my_course_id)) + uploads_root_path = Pathname.new(File.expand_path(root)) + + directory_hash = lambda do |root_path, path, name = nil| + data = { text: (name || path) } + data[:nodes] = children = [] + Dir.foreach(path) do |entry| + next if ['..', '.'].include? entry + full_path = File.join(path, entry) + rel = Pathname.new(full_path).relative_path_from(root_path) + if File.directory?(full_path) + children << directory_hash.call(root_path, full_path, entry) + else + tags = [File.mtime(full_path.to_s).to_s(:quiz)] + url = url_for_file(:uploads, my_course_id, rel.to_s) + children << { text: rel.to_s, tags: tags, href: url } + end + end + return data + end + + directory_hash.call(uploads_root_path, uploads_root_path.to_s) + end +end diff --git a/app/controllers/admin/admin_pages_controller.rb b/app/controllers/admin/admin_pages_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..000b9a8d1bf2ec400b35dfeeb92f5be36a77ca75 --- /dev/null +++ b/app/controllers/admin/admin_pages_controller.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require 'pathname' +require 'ostruct' + +## +# Controller for the pages view of the administrative console of the website. +class Admin::AdminPagesController < Admin::AdminController + + def index + @admin_tab = "pages" + + process_commit params[:commit] + + # + # Pages Tab + # + page_grid_defaults = { + order: :modified_time, + descending: true, + course_id: my_course_id + } + options = page_grid_defaults.merge(params[:page_grid] || {}) + @page_grid = PageGrid.new(options) + @page_grid.scope { Pages.get(my_course_id).pages } + + page_errors_grid_defaults = { course_id: my_course_id } + options = page_errors_grid_defaults.merge(params[:page_errors_grid] || {}) + @page_errors_grid = PageErrorsGrid.new(options) + @page_errors_grid.scope { Errors.get(my_course_id).error_list } + end + + def update + update_svc = UpdateService.new(my_course_id) + + update_svc.compile_pages + + render json: {} + end + + def recompile_all_pages + update_svc = UpdateService.new(my_course_id) + + update_svc.compile_pages + + render json: {} + end + + private + + def process_commit(commit) + Rails.logger.info("Processing commit #{commit}") + case commit + when 'Rename File' + flash[:alert] = 'File Renamed' + from = params[:course_enotes_rename]['rename_from'] + to = params[:course_enotes_rename]['rename_to'] + Rails.logger.info("#{my_course_id} #{from} #{to}") + DTUFileManagement::FileManager.instance.rename_upload(my_course_id, from, to) + redirect_to admin_path(anchor: 'filemanager') + when 'Delete' + flash[:alert] = 'Files Deleted' + Rails.logger.info("Removing Files #{params[:files]}") + DTUFileManagement::FileManager.instance.remove_uploads(params[:files]) + redirect_to admin_path(anchor: 'filemanager') + when 'Update Files' + Rails.logger.info('Updating Files') + DTUFileManagement::FileManager.instance.update + Enotes.instance.refresh(my_course_id) + Rails.logger.info(DTUFileManagement::FileManager.instance.enotes_files) + redirect_to admin_path(anchor: 'filemanager') + end + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..6720acfe677729ec32fddce6a59c0d0d2ba1950a --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +## +# Base controller class for the course website project +class ApplicationController < ActionController::Base + include ApplicationHelper + include CourseUrlHelper + + # include MultiParameterAttributes + + # Prevent CSRF attacks by raising an exception. + # For APIs, you may want to use :null_session instead. + protect_from_forgery with: :exception + + skip_before_action :verify_authenticity_token, if: :json_request? + + before_action :refresh_config + + before_action :require_valid_course + + def respond_modal_with(*args, &blk) + options = args.extract_options! + options[:responder] = ModalResponder + respond_with(*args, options, &blk) + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/controllers/enotes_controller.rb b/app/controllers/enotes_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..f1a281975282a94fe898466f698debf43ba37f53 --- /dev/null +++ b/app/controllers/enotes_controller.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +## +# Controller for enotes (displaying them, querying them) +class EnotesController < ApplicationController + include OptionalAuthHelper + + respond_to :json, :html + + before_action EnoteCas::GatewayFilter, if: proc { allow_unauthed? } + + attr_accessor(:enotes, + :pdf_url, + :kind_query) + + def index + kind = params[:kind] + + get_enotes(kind) + + Rails.logger.debug @enotes.ai + + respond_to do |format| + format.html { render layout: false } + format.json { respond_with json: @enotes.to_json } + end + end + + def show + kind = params[:kind] + + enote_path = 'sharelatex-public' + enote_path = 'sharelatex-private' if kind.eql? 'staging' + + @pdf_url = File.join('/filemanager', my_course_id, enote_path, params[:enote] + '.pdf') + + render :show, layout: 'enote' + end + + private + + def get_enotes(kind) + if kind.eql? 'staging' + EnotesStaging.instance.refresh my_course_id + @enotes = EnotesStaging.instance.get(my_course_id) + @kind_query = '?kind=staging' + else + Enotes.instance.refresh my_course_id + @enotes = Enotes.instance.get(my_course_id) + @kind_query = '' + end + end +end diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..0c2c3db95527a61b2c783fd2c2bc5ef59f41f2d3 --- /dev/null +++ b/app/controllers/errors_controller.rb @@ -0,0 +1,31 @@ +class ErrorsController < ApplicationController + + respond_to :json, :html + + include OptionalAuthHelper + include ServiceHelper + + before_action EnoteCas::GatewayFilter, :if => proc {allow_unauthed?} + + attr_accessor(:page_errors_grid) + + def index + errors = Errors.get(my_course_id) + + defaults = {} + options = defaults.merge(params[:page_errors_grid] || {}) + @page_errors_grid = PageErrorsGrid.new(options) do #|scope| + errors.error_list + end + + if request.xhr? + render json: {table: view_context.datagrid_table(@page_errors_grid)} + return + end + + respond_to do |format| + format.html { @page_errors_grid } + format.json { respond_with json: errors.error_list.to_json } + end + end +end diff --git a/app/controllers/feedback_controller.rb b/app/controllers/feedback_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..040b5e6f7f478a345d48acfd20e82bec4eb68978 --- /dev/null +++ b/app/controllers/feedback_controller.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +def valid_ids(ids) + ids.each do |id| + return false unless id.is_a?(Integer) && id.positive? + end + true +end + +## +# Controller for feedback resource +class FeedbackController < ActionController::Base + respond_to :json, :html + + include ApplicationHelper + include DtuCoreApp::SessionsHelper + include OptionalAuthHelper + include HomeHelper + include CourseUrlHelper + + protect_from_forgery with: :exception + + skip_before_action :verify_authenticity_token # , if: :json_request? + + before_action :refresh_config + + # before_action EnoteCas::GatewayFilter, if: proc {allow_unauthed?} + + attr_accessor(:page_name, + :course_id, + :user_id) + + def show + @feedback = Feedback.find(params[:feedback_id]) + render json: @feedback.to_json, status: :ok + end + + def index + feedback_grid_defaults = { + order: :created_at, + descending: true, + course_id: my_course_id + } + options = feedback_grid_defaults.merge(params[:feedback_grid] || {}) + @feedback_grid = FeedbackGrid.new(options) + + if request.xhr? + render json: { table: view_context.datagrid_table(@feedback_grid) } + return + end + + respond_to do |format| + format.html { @feedback_grid } + format.json { respond_with json: Feedback.where(course_id: p[:course_id]).to_json } + end + end + + def create + feedback_params = params.require('feedback').permit(:description, :url, :screenshot) + additional_params = { + user_id: current_user_id, + user_name: current_user ? current_user.full_name : 'Anonymous', + course_id: my_course_id + } + feedback = Feedback.build_from_post_params feedback_params.merge(additional_params) + + if feedback + render json: {}, status: :created + else + render json: { error: { message: 'Cannot save feedback' } }, status: :unprocessable_entity + end + end + + def destroy + Feedback.destroy params[:feedback_id] + render json: { message: 'Feedback deleted.' }, status: :ok + end + + def destroy_multiple + args = parse_json_object + + if args.key?('ids') && valid_ids(args['ids']) + @feedbacks = Feedback.find(args['ids']).delete_all + render json: { message: "#{"Feedback".pluralize(@feedbacks.size)} deleted." }, status: :ok + else + render json: { message: 'Malformed request.' }, status: :unprocessable_entity + end + end + + def update + new_value = parse_json_object + @feedback = Feedback.find(params[:feedback_id]) + @feedback.status = new_value['status'] if new_value.key? 'status' + @feedback.reply = new_value['reply'] if new_value.key? 'reply' + @feedback.save! + render json: { message: 'Feedback updated.' }, status: :ok + end + + def view_feedbacks + p = params.permit(:course_id, :page_name) + @feedbacks = Feedback.where(page: p[:page_name], course_id: p[:course_id]) + respond_modal_with @feedbacks, location: root_path + end + + def view_full_image + @feedback = Feedback.find(params[:feedback_id]) + respond_modal_with @feedback, location: root_path, dialog_class: 'modal-lg' + end + + def respond_modal_with(*args, &blk) + options = args.extract_options! + options[:responder] = ModalResponder + respond_with(*args, options, &blk) + end +end diff --git a/app/controllers/md_single_page_controller.rb b/app/controllers/md_single_page_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..bf9f98a0cb095565bfb8aee34307debac419f549 --- /dev/null +++ b/app/controllers/md_single_page_controller.rb @@ -0,0 +1,218 @@ +# frozen_string_literal: true + +## +# Controller for a page of markdown. In general it consists of a central page and a left rail page +# TODO: Split this into viewer and editor controllers +class MdSinglePageController < ApplicationController + respond_to :json, :html + + include OptionalAuthHelper + include ApplicationHelper + include HomeHelper + + before_action EnoteCas::GatewayFilter, if: proc { allow_unauthed? } + + attr_accessor(:page, + :left_md, + :right_md, + :edit_md, + :macros_tex, + :error_message, + :editor_config, + :quick_buttons, + :page_feedbacks, + :groups, + :mode, + :user_id, + :mdpage_config) + + def show + @page = params[:page] || page_default + @user_id = current_user_id + @groups = my_groups + @mode = params[:mode] || 'view' + @quick_buttons = [] + @page_feedbacks = [] + @mdpage_config = { + user_info: { username: @user_id || 'Anonymous' }, + logged_in: logged_in?, + allow_feedback: (WebsiteConfig.get.courses[my_course_id].allow_feedback && !admin?) && logged_in? + } + + ap @mdpage_config + + return show_edit if @mode.eql? 'edit' + + show_static + end + + def show_editing + @editing = PagesService.new(my_course_id).who_is_editing? @page + + if @editing.nil? + PagesService.new(my_course_id).edit_page @page, current_user + else + unless @editing.eql? current_user_id + render action: 'edit_locked', layout: 'edit_page' + return + end + end + + @edit_md_path = Pages.get_file_name(PagesService.new(my_course_id).raw_md_folder, page) + + Rails.logger.info "Editing #{@edit_md_path}" + + if File.exist? @edit_md_path + @edit_md = File.read(@edit_md_path) + else + @error_message = 'Page does not exist!' + end + + @editor_config = { + page: @page, + edit_md: @edit_md, + macros_tex: @macros_tex + } + + # when the page has a .tex to it, we need to make sure to still serve the html + Rails.logger.info request.format + request.format = 'html' unless request.format == 'json' + + respond_to do |format| + format.html { render action: 'edit', layout: 'edit_page' } + format.json { render partial: 'md_single_page/editor_config.json', object: @editor_config } + end + end + + def update + # TODO: check if locks exist + @page = params[:page] + + message = parse_json_object + new_content = message['content'] + + pages_svc = PagesService.new(my_course_id) + + @edit_md_path = Pages.get_file_name(pages_svc.raw_md_folder, @page) + + Rails.logger.info "Saving page #{@page}" + + File.write(@edit_md_path, new_content) + + Rails.logger.info "Rebuilding page #{@page}" + + if Pages.macros_page? @page + Rails.logger.info "Updating macro #{@page}" + IncludedPages.get(my_course_id).refresh @page + pages_svc.compile_all_pages + else + pages_svc.rebuild_all_pages([@edit_md_path], false) + end + + render json: {} + end + + def stop_editing + @page = params[:page_name] + + unless current_user + render json: { message: 'Must be logged-in in order to stop editing.' }, status: :unauthorized + return + end + + roles = my_roles + if roles.include?('author') || roles.include?('administrator') + Rails.logger.info "Attempting to edit page #{@page}" + + success = PagesService.new(my_course_id).edit_page @page, nil + + render json: { message: success ? 'Successfully stopped editing' : 'Could not stop editing' }, status: :ok + + else + Rails.logger.error "Cannot stop editing page; user is not an author or admin #{roles}" + render json: { message: 'Must be author or admin in order to stop editing.' }, status: :unauthorized + end + end + + def can_edit? + return false, 'You must be logged in to edit' unless current_user + + unless my_roles.include?('author') || my_roles.include?('administrator') + return false, 'You must be an author or an administrator to edits' + end + + [true, nil] + end + + def right_suffix + '-right' + end + + def page_default + 'Frontpage' + end + + private + + def show_static + get_sub_pages @page, right_suffix + + if @mode.eql? 'view' + show_view + elsif @mode.eql? 'print' + render_page @page, right_suffix, @groups, 'print_page' + end + end + + def show_edit + @can_edit, @error_message = can_edit? + + @macros_tex = IncludedPages.get(my_course_id).pages['macros.tex'] + + unless @can_edit + # redirect_to show_page_path(:page => @page) + render action: 'edit', layout: 'edit_page' + return + end + + show_editing + end + + def show_view + if admin? + # editing = PagesService.new(my_course_id).who_is_editing? @page + @quick_buttons << button_for_page(@left_sub_page, :left) if @left_sub_page + @quick_buttons << button_for_page(@right_sub_page, :right) if @right_sub_page + else + @page_feedbacks = Feedback.where({course_id: my_course_id, page: @page}).order(created_at: 'desc') + @quick_buttons << new_feedback_button_for_page(@page, :left) + @quick_buttons << view_feedback_button_for_page(@page, :left) unless @page_feedbacks.empty? + end + render_page @page, right_suffix, @groups + end + + def button_for_page(page, placement = :left) + return { kind: :none, text: nil } if page.blank? + + editing = PagesService.new(my_course_id).who_is_editing? page + if editing.nil? + { kind: :edit, text: 'Edit', page: page, placement: placement } + elsif editing.eql? current_user_id + { kind: :edit, text: 'Continue Edit', page: page, placement: placement } + else + { kind: :revoke, text: "Revoke #{editing}", page: page, placement: placement } + end + end + + def new_feedback_button_for_page(page, placement = :left) + return { kind: :none, text: nil } if page.blank? + + { kind: :new_feedback, text: 'Feedback', page: page, placement: placement } + end + + def view_feedback_button_for_page(page, placement = :left) + return { kind: :none, text: nil } if page.blank? + + { kind: :view_feedback, text: "Feedbacks #{page_feedbacks.length}", page: page, placement: placement } + end +end diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..3bd0fb3febbeb4f29d63527854dd182c2cd75a42 --- /dev/null +++ b/app/controllers/pages_controller.rb @@ -0,0 +1,61 @@ +class PagesController < ApplicationController + + respond_to :json, :html + + include OptionalAuthHelper + include ServiceHelper + include ApplicationHelper + + before_action EnoteCas::GatewayFilter, :if => proc {allow_unauthed?} + + attr_accessor(:grid) + + def index + defaults = {:order => :modified_time, :descending => true} + options = defaults.merge(params[:page_grid] || {}) + @grid = PageGrid.new(options) do #|scope| + Pages.get(my_course_id).pages + end + + if request.xhr? + render json: {table: view_context.datagrid_table(@grid)} + return + end + + respond_to do |format| + format.html { @grid } + format.json { respond_with json: Pages.get(my_course_id).to_json } + end + end + + def new_page + page_name = params[:page_name] + Rails.logger.info "new_page #{page_name}" + json_response(PagesService.new(my_course_id).new_page(page_name)) + end + + def delete_page + page_name = params[:page_name] + Rails.logger.info "delete_page #{page_name}" + json_response(PagesService.new(my_course_id).delete_page(page_name)) + end + + def rename_page + page_name = params[:page_name] + to_name = params[:to_name] + Rails.logger.info "rename_page #{page_name} to #{to_name}" + json_response(PagesService.new(my_course_id).rename_page(page_name, to_name)) + end + + private + + def get_target_page(name) + pages = Pages.get(my_course_id).pages.select{ |p| p.pretty_name.eql? name } + if pages.empty? + render json: {message: "#{name} doesn't exist"}, status: :not_found + return nil + end + return pages.first + end + +end diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..1e44fec578ffb04ec000ca5b20f6f91213c16eb9 --- /dev/null +++ b/app/controllers/root_controller.rb @@ -0,0 +1,10 @@ +class RootController < ApplicationController + + include OptionalAuthHelper + include HomeHelper + + before_action EnoteCas::GatewayFilter, :if => proc {allow_unauthed?} + + def index + end +end diff --git a/app/controllers/site_errors_controller.rb b/app/controllers/site_errors_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..dbe12df3deffc03d49bbc1f1139da76396ae5d36 --- /dev/null +++ b/app/controllers/site_errors_controller.rb @@ -0,0 +1,6 @@ +class SiteErrorsController < ApplicationController + #http://rubyjunky.com/cleaning-up-rails-4-production-logging.html + def error_404 + render file: "public/404.html", status: :not_found + end +end \ No newline at end of file diff --git a/app/controllers/sitemap_controller.rb b/app/controllers/sitemap_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..3be7779dcf13f7122d1b8282d5742e597cd58478 --- /dev/null +++ b/app/controllers/sitemap_controller.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +## +# Controller to generate a search engine sitemap +# https://www.sitemaps.org/protocol.html +class SitemapController < ApplicationController + layout nil + + def index + # Start with pages + @pages = page_sitemap + + # add aliases for pages + @pages.concat page_alias_sitemap + + # eNotes + @pages.concat enote_sitemap + + @pages = @pages.map do |page| + if !page[:lastmod].methods.include? :strftime + begin + page[:lastmod] = Date.parse(page[:lastmod].to_s) + rescue ArgumentError + Rails.logger.error "Invalid :lastmod for #{page.ai}" # handle invalid date + page[:lastmod] = Date.today + end + end + page + end + + headers['Content-Type'] = 'application/xml' + respond_to do |format| + format.xml { @pages } + end + end + + private + + def page_alias_sitemap + aliases = [] + home = @pages.detect { |p| p[:name].eql? 'Frontpage' } + unless home.nil? + home[:priority] = '0.9' + aliases << home.merge(loc: WebsiteConfig.get.courses[my_course_id].page_external_url('home')) + aliases << home.merge(loc: WebsiteConfig.get.courses[my_course_id].page_external_url('')) + end + + podcast = @pages.detect { |p| p[:name].eql? 'Podcast' } + aliases << podcast.merge(loc: WebsiteConfig.get.courses[my_course_id].page_external_url('podcast')) unless home.nil? + + aliases + end + + def page_sitemap + Pages.get(my_course_id).pages.map do |page| + name = page.pretty_name + name = name[0..-7] if name.downcase.ends_with? '-right' + next if name.downcase.ends_with? '-left' + { + name: name, + loc: WebsiteConfig.get.courses[my_course_id].page_external_url(name), + lastmod: page.mtime, + changefreq: 'monthly', + priority: '0.4' + } + end.reject(&:nil?) + end + + def enote_sitemap + enotes = Enotes.instance.get(my_course_id) + enote_stats = enotes[:enote_stats] + enotes[:enotes].each_with_index.map do |enote, idx| + lastmod = enote_stats[idx]&.[](:mtime) + + [ + { + name: enote, + loc: WebsiteConfig.get.courses[my_course_id].enote_external_url(enote), + lastmod: lastmod, + changefreq: 'monthly', + priority: '0.4' + }, + { + name: enote + '-file', + loc: WebsiteConfig.get.courses[my_course_id].enote_file_external_url(enotes[:enote_files][idx]), + lastmod: lastmod, + changefreq: 'monthly', + priority: '0.4' + } + ] + end.flatten.to_a + end +end diff --git a/app/grids/feedback_grid.rb b/app/grids/feedback_grid.rb new file mode 100644 index 0000000000000000000000000000000000000000..e7c86c4f2dfb45e70dce7cae79d93ae261d48ab8 --- /dev/null +++ b/app/grids/feedback_grid.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +# Grid displaying all the pages +# +class FeedbackGrid + include Datagrid + include ActionView::Helpers::FormOptionsHelper + + attr_accessor :course_id + + scope { Feedback } + + column(:select, header: '') do |model| + format(model) do + content_tag('input class="select-feedback-checkbox" ' \ + 'data-feedback-id="' + model.id.to_s + '"' \ + "onchange='AdminPage.selectFeedback(event);'" \ + ' type="checkbox"') + end + end + + column(:created_at, header: 'Date', order: 'created_at', descending: true) do |model| + 'Date: ' + model.created_at.in_time_zone.to_s(:quiz) + end + + column(:feedback_user, header: 'User') do |model| + "User: #{model.user_name}" + end + + column(:feedback_url, header: 'URL') do |model| + path = URI.parse(model.url).path + "URL: <a href='#{model.url}'>#{path}</a>".html_safe + end + + column(:thumbnail_image, header: 'Thumbnail') do |model| + "<a href='#{Rails.application.routes.url_helpers.view_full_image_path(model.id)}' \ +data-modal='true'><img src='#{model.image_thumb_url}' onerror='AdminPage.thumbnailNotFound(this);'></img></a>".html_safe + end + + column(:feedback_text, header: 'Text', class: 'feedback-text') do |model| + %(<div class="comment-form-group" data-feedback-id='#{model.id}'> + <label for="feedback-text">Text:</label> + <textarea readonly class="form-control"rows="5" id="feedback-text"> + #{model.text} + </textarea> + </div>).html_safe + end + + column(:feedback_reply, header: 'Reply', class: 'feedback-reply') do |model| + textarea_action = model.reply.blank? ? + %{onchange="AdminPage.setFeedbackComment(event, + '#{Rails.application.routes.url_helpers.feedback_path('FEEDBACK_ID')} %>');" } : + 'readonly' + + %{<div class="comment-form-group" data-feedback-id='#{model.id}'> + <label for="feedback-reply">Reply:</label> + <textarea class="form-control feedback-reply" + rows="5" + id="feedback-reply" + #{textarea_action} + > + #{model.reply} + </textarea> + </div>}.html_safe + end + + column(:delete_feedback, header: 'Delete') do |model| + %{<button class='btn btn-primary' + onclick='AdminPage.deleteFeedback(event, + "#{Rails.application.routes.url_helpers.feedback_path model.id}")'> + <span aria-hidden="true">×</span><span class="sr-only">Close</span> + </button>}.html_safe + end + + column(:feedback_status, header: 'Status') do |model| + feedback_url = Rails.application.routes.url_helpers.feedback_path model.id + options = Feedback.STATUS_OPTIONS.map do |status| + "<option value='#{status}' \ + #{'selected' if status.eql?(model.status)}> #{Feedback.STATUS_FRIENDLY[status]} \ +</option>" + end.join(' ') + "<select class='form-control feedback-status' \ +onchange='AdminPage.changeFeedbackStatus(event, \"#{feedback_url}\");'>\ + #{options}</select>".html_safe + end + + column(:submit, header: 'Submit') do |model| + %{<button class='btn btn-primary btn-submit' + onclick='AdminPage.submitFeedback(event, + "#{Rails.application.routes.url_helpers.feedback_path model.id}")'> + <span aria-hidden="true">Submit</span> + </button>}.html_safe + end +end diff --git a/app/grids/getpdf_jobs_grid.rb b/app/grids/getpdf_jobs_grid.rb new file mode 100644 index 0000000000000000000000000000000000000000..c0716bbef49bff6119d60824f1077fe404cdfdee --- /dev/null +++ b/app/grids/getpdf_jobs_grid.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class GetpdfJobsGrid + include Datagrid + include ActionView::Helpers::FormOptionsHelper + + attr_accessor :course_id + + scope { [] } + + column(:status, header: 'Status', order: 'status', descending: true) do |model| + "<p class='getpdf_status_#{model['_id']}'>#{model['status']}</p>".html_safe + end + + column(:lastFinishedAt, header: 'Finished Time', order: 'lastFinishedAt', descending: false) do |model| + lfa = model.lastFinishedAt.in_time_zone + if lfa + lfa.to_s :quiz + else + '' + end + end + + column(:commands, header: 'Actions', order: false) do |model, grid| + data_path = Rails.application.routes.url_helpers.getpdf_job_path grid.course_id, model._id + cell = %{<button class="btn btn-primary" + id="view-getpdf-job-logs" + onclick='return AdminPage.getGetPDFJobInfo(event, "#{data_path}");'> View Logs </button>} + .html_safe + if model['status'].eql? 'running' + cancel_path = Rails.application.routes.url_helpers.cancel_getpdf_job_path grid.course_id, model._id + cell += %{<button class="btn btn-primary" + id="cancel-getpdf-job" + onclick='return cancelGetPDFJob(event, "#{cancel_path}");'> Cancel Job </button>} + .html_safe + end + + cell + end +end diff --git a/app/grids/page_errors_grid.rb b/app/grids/page_errors_grid.rb new file mode 100644 index 0000000000000000000000000000000000000000..6a10e203e885b03f617b28fe7921b42fd1d1f34e --- /dev/null +++ b/app/grids/page_errors_grid.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# Grid displaying all the page errors +# +class PageErrorsGrid + include Datagrid + include ActionView::Helpers::FormOptionsHelper + + attr_accessor :course_id + + scope { [] } + + column(:page, header: 'Page', order: 'file', descending: false) do |model| + url = Rails.application.routes.url_helpers.show_page_path page: model.page, course_id: model.course_id + "<a href=#{url}>#{model.page}</a>".html_safe + end + + column(:edit_action, header: 'Edit', order: false) do |model| + if model.missing_page? + %{<button class="btn btn-primary new-page-button" + onclick='return PageIndex.new_page(event, "#{model.page}");'> New </button>} + else + %{<button class="btn btn-primary edit-page-button" + onclick='return PageIndex.edit_page(event, "#{model.page}", "#{model.course_id}");'> Edit </button>} + end.html_safe + end + + column(:line, header: 'Line', order: 'line', descending: false, &:line) + + column(:text, header: 'Text', order: false, &:text) +end diff --git a/app/grids/page_grid.rb b/app/grids/page_grid.rb new file mode 100644 index 0000000000000000000000000000000000000000..1cc5b7fd05e79140cdbf6a225cf88a3d9009f418 --- /dev/null +++ b/app/grids/page_grid.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# Grid displaying all the pages +# +class PageGrid + include Datagrid + include ActionView::Helpers::FormOptionsHelper + + attr_accessor :course_id + + scope { [] } + column(:select) do |model| + format(model) do + content_tag('input class="select-page-checkbox" ' \ + 'data-page-name="' + model.pretty_name + + '" type="checkbox"') + end + end + + column(:pretty_name, header: 'Page Name', order: 'pretty_name', descending: false) do |model| + if model.viewable + url = Rails.application.routes.url_helpers.show_page_path page: model.pretty_name, course_id: model.course_id + "<a href=#{url}>#{model.pretty_name}</a>".html_safe + else + "<p >#{model.pretty_name}</p>".html_safe + end + end + + column(:modified_time, header: 'Modified', order: 'mtime', descending: false) do |model| + model.mtime.in_time_zone.to_s :quiz + end + + column(:commands, header: 'Actions', order: false) do |model| + readonly = !model.editable + x = '' + if model.edit_info + revoke_button_text = "Revoke Lock owned by #{model.edit_info[:user]}\ + <br/>\ + from #{model.edit_info[:locked_time].to_s(:quiz)}" + x = %{<button class="btn btn-primary" + id="revoke-lock" #{'disabled' if readonly} + onclick='return PageIndex.stop_editing_page(event, "#{model.pretty_name}", "#{model.course_id}");'> + #{revoke_button_text} + </button> } + end + (x + %{<button class="btn btn-primary edit-enotes-button" + #{'disabled' if readonly} + onclick='return PageIndex.edit_page(event, "#{model.pretty_name}", "#{model.course_id}");'> Edit </button>} + ).html_safe + end +end diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..77c4c27d6e874f0b92881fb04e81afd42be675d0 --- /dev/null +++ b/app/helpers/admin_helper.rb @@ -0,0 +1,20 @@ +module AdminHelper + def url_for_file(kind, course, file) + '/filemanager/' + kind.to_s + '/' + course + '/' + file + end + + def render_getpdf_time(t) + if t.nil? || t.empty? + "N/A" + else + t.in_time_zone.to_s :quiz + end + end + + + def ready_to_publish?(latest_getpdf_job) + update_svc = UpdateService.new my_course_id + + (latest_getpdf_job.status.eql? 'completed') && update_svc.any_staging_enotes_to_publish? + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..df467aeeb589c3b9d0103f719e2f6c8928a347be --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,150 @@ +# frozen_string_literal: true + +## +# Helper class for all controllers +module ApplicationHelper + include DtuCoreApp::SessionsHelper + + attr_accessor(:_course_id) + + def json_request? + request.format.json? + end + + def refresh_config + WebsiteConfig.clear + end + + def require_valid_course + set_course + + @website_course_config = WebsiteConfig.get.courses[@_course_id] + + return unless @website_course_config.nil? + + @error_message = "Course '#{@_course_id}' is not configured" + render 'errors/course_not_configured', layout: 'error' + end + + def set_course + @_course_id = params[:course_id] + Rails.logger.info "set course #{_course_id}" + end + + def require_login + return if current_user + + Rails.logger.warn 'Checking log-in status for access to page: not logged in' + redirect_to core.login_path + end + + def require_admin + unless current_user + Rails.logger.warn 'Checking admin authorization: user not logged in' + redirect_to core.login_path + return + end + unless admin? + Rails.logger.warn "Checking admin authorization for #{current_user_id}: not an admin" + redirect_to course_home_url + return + end + Rails.logger.info "Checking admin authorization for #{current_user_id}: success" + end + + def enotes(course_id = nil) + course_id ||= my_course_id + Enotes.instance.get(course_id) + end + + def my_course_id + _course_id || params[:course_id] + end + + def my_course + DTUAuth2::CachedAuthorizationManager.course_by_id(my_course_id) + end + + def my_roles + roles_for_course my_course_id + end + + def my_groups + return [] unless current_user_id + + DTUAuth2::CachedAuthorizationManager.groups_by_course_and_user my_course_id, current_user_id + end + + def admin? + is_admin my_course_id + end + + def logged_in? + !current_user_id.nil? + end + + def current_class?(test_path) + return 'active' if request.path.starts_with? test_path + '' + end + + def parse_json_object + body = request.body.read + data = nil + begin + data = JSON.parse body + rescue JSON::ParserError => e + logger.debug "Exception parsing options: #{e}" + render json: e.to_json, status: :bad_request if e + return nil + end + + logger.debug data + + data + end + + def simple_json_response(success, message, additional_fields = {}) + result = { success: success, message: message } + result = result.merge(additional_fields) + + logger.info(result) + + result + end + + def message_prefix(message) + Time.zone.now.to_s(:quiz_time) + ' ' + message + end + + def sanitize_filename(filename) + # Bad as defined by wikipedia: https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words + # Also have to escape the backslash + bad_chars = ['/', '\\', '?', '%', '*', ':', '|', '"', '<', '>', '.', ' '] + bad_chars.each do |bad_char| + filename.gsub!(bad_char, '_') + end + filename + end + + # https://gist.github.com/suryart/7418454 + def bootstrap_class_for(flash_type) + { success: 'alert-success', + error: 'alert-danger', + alert: 'alert-warning', + notice: 'alert-info' }[flash_type.to_sym] || flash_type.to_s + end + + def flash_messages(_opts = {}) + flash.each do |msg_type, message| + concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)} fade in") do + concat content_tag(:button, + 'x', + class: 'close', + data: { dismiss: 'alert' }) + concat message + end) + end + nil + end +end diff --git a/app/helpers/course_url_helper.rb b/app/helpers/course_url_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..a1053c612084a3a374de5673b5bc05b29308e6f5 --- /dev/null +++ b/app/helpers/course_url_helper.rb @@ -0,0 +1,29 @@ + + +module CourseUrlHelper + + ## + # Work around for the fact that the reverse proxy + # exists in production but not development + def map_url(params) + raise("Must be called with a block") unless block_given? + + url = yield params + + return url if url.start_with?('http') + + url = '/' + url unless url.start_with? '/' + + course_url_prefix = "/#{params[:course_id]}" + + if ENV['RAILS_ENV'].eql? "production" + # snip off the course info + url = url.slice(course_url_prefix.length, url.length-course_url_prefix.length) if url.start_with? course_url_prefix + elsif ENV['RAILS_ENV'].eql? "development" + # add course if it isn't there... + url = course_url_prefix + url unless url.start_with? course_url_prefix + end + + url + end +end diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..0146a34f6a3354734a5e94ac9bab27079e69c753 --- /dev/null +++ b/app/helpers/home_helper.rb @@ -0,0 +1,54 @@ +module HomeHelper + def render_page(root, right_suffix = '-right', groups = [], layout = "md_rendered_page") + get_sub_pages(root, right_suffix) unless @right_md + + @right_md = enforce_group_permissions(@right_md, groups) + @left_md = enforce_group_permissions(@left_md, groups) + +# render template: "md_single_page/show.html.erb", layout: layout + render layout: layout + end + + + def enforce_group_permissions(md, groups) + return md if md.blank? + + MarkdownService.new(md).enforce_groups(Set.new(groups.map(&:group))) + end + + private + + def get_sub_pages(root, right_suffix = '-right') + @left_sub_page = root + '-left' + @right_sub_page = root + right_suffix + @root_sub_page = root + + @left_path = File.join(PagesService.new(my_course_id).compiled_folder, @left_sub_page + ".md") + @right_path = File.join(PagesService.new(my_course_id).compiled_folder, @right_sub_page + '.md') + @md_path = File.join(PagesService.new(my_course_id).compiled_folder, @root_sub_page + '.md') + + if File.exist? @left_path + Rails.logger.debug "#{@left_path}: left page exists" + @left_md = File.read(@left_path) + else + Rails.logger.warn "#{@left_path}: left page does not exist" + @left_md = nil + @left_sub_page = nil + end + + if File.exist? @right_path + Rails.logger.debug "#{@right_path}: right page exists" + @right_md = File.read(@right_path) + else + Rails.logger.warn "#{@right_path}: right page does not exist" + @right_md = "<h3>No page information. Maybe update from the admin page?</h3>" + if File.exist? @md_path + @right_md = File.read(@md_path) + @right_sub_page = @root_sub_page + else + @right_md = "<h3>Page \"#{root}\" or \"#{root}-right\" does not exist. Maybe update from the admin page?</h3>" + @right_sub_page = nil + end + end + end +end diff --git a/app/helpers/optional_auth_helper.rb b/app/helpers/optional_auth_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..97b62e41461359ff3741a48ab675b8dcccb6e369 --- /dev/null +++ b/app/helpers/optional_auth_helper.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +## +# Module for development to allow pages to be viewed without (CAS) auth. +module OptionalAuthHelper + def allow_unauthed? + # Rails.logger.info("params: ticket -#{params[:ticket]}-") + Rails.env.production? && !params[:ticket].blank? + end +end diff --git a/app/helpers/service_helper.rb b/app/helpers/service_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..d0fc6b51b6fc40028c9a0d804000a17aafb4a3b3 --- /dev/null +++ b/app/helpers/service_helper.rb @@ -0,0 +1,19 @@ +# Helpers for dealing with service object responses +module ServiceHelper + def form_redirect(redirect_path, service_result) + if service_result.success + redirect_to redirect_path, :notice => message_prefix(service_result.message) + else + redirect_to redirect_path, :alert => message_prefix(service_result.message) + end + end + + def json_response(service_result) + if service_result.success + flash.now[:alert] = message_prefix(service_result.message) + else + flash.now[:notice] = message_prefix(service_result.message) + end + render json: simple_json_response(service_result.success, service_result.message, service_result.details || {}), status: service_result.status + end +end diff --git a/app/javascript/css/admin.scss b/app/javascript/css/admin.scss new file mode 100644 index 0000000000000000000000000000000000000000..5d5c45f87ba135a15d6a84187f16b0ad289dda4d --- /dev/null +++ b/app/javascript/css/admin.scss @@ -0,0 +1,256 @@ +// Place all the styles related to the admin controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ + +@import 'base-style'; + +.valid-groups { + text-align: left; +} + +.valid-group { + display: inline-block; + margin-right: 8px; + border: 1px solid black; + background-color: lightblue; + border-radius: 2px; + line-height: 1.5em; + padding: 2px 8px 2px 8px; + margin-bottom: 4px; +} + +.editor-commands { + text-align: left; +} + +.admin-buttons > .btn-group-vertical { + padding-bottom: 20px; + + .btn-xs { + text-align: left; + font-size: 120%; + } +} + +.page-index-grid-form, +.page-errors-index-grid-form, +.getpdf-jobs-grid-form, +.feedback-grid-form, +.datagrid-form { + background-color: $body-bg !important; +} + +.feedback-grid tr:hover, +.getpdf-jobs-grid tr:hover, +.page-errors-grid tr:hover, +.page-index-grid tr:hover { + xbackground-color: $light-yellow-highlight; +} + +tr.page-selected, +tr.page-selected:hover { + xbackground-color: $correct-answer; +} + +.admin-button { + white-space: normal; +} + +.admin-course-grid { + border-bottom: 2em; + margin-bottom: 2em; +} + +.modal-flash { + height: 2.0em; + overflow: hidden; +} + +.flash-container { + margin-top: 1.0em; + height: 5.0em; + overflow: hidden; +} + +.hand-in-list { + max-height: 300px; + overflow: scroll; +} + +.admin-buttons-table { + width: 100%; + tr { + td { + padding-bottom: 10px; + margin-bottom: 10px; + + } + } + margin: 5px; +} + +.datagrid-actions { + display: none; +} + +.admin-buttons-table { + tbody { + tr { + td { + padding-left: 10px; + } + } + } +} + +.feedback-grid-table, +.getpdf-jobs-grid-table, +.page-index-grid-table, +.page-errors-index-grid-table { + tbody { + tr { + td { + text-align: left; + } + } + } + thead { + tr { + th { + div.order { + display: none; + } + } + } + } + th, td { + padding: 8px; + line-height: 20px; + vertical-align: top; + border-top: 1px solid #dddddd; + } + thead:first-child tr:first-child th, thead:first-child tr:first-child td { + border-top: 0; + } +} + +.feedbacks-table { + tbody { + tr { + td { + border: none; + } + } + } +} + +input.feedback-radio { + margin-left: 0px !important; + margin-top: 8px; +} + +.feedback-radio-label { + margin-left: 20px; +} + +input.quiz-meta-checkbox { + margin-left: 0px !important; + margin-top: 8px; +} + +.quiz-meta-checkbox-label { + margin-left: 20px; +} + +tr.parse-error { + text-align: left; + td { + text-align: left; + } +} + +h3 > button { + display: inline; +} + +.admin-feedback-spacer { + margin-top: 20px; + margin-bottom: 20px; + border-bottom: 1px solid grey; +} + +.feedback-actions { + display: flex; + align-items: center; + justify-items: center; +} + +.row.feedback-reply-row { + display: flex; + align-items: center; + justify-items: center; + max-height: 138px; +} + +.enable-feedback, +.enable-chat { + font-size: 26px; + input { + margin-right: 15px; + width: 26px; + height: 26px; + } +} + +.feedback-text, +.feedback-reply { + div { + overflow: hidden; + /*white-space: nowrap;*/ + text-overflow: ellipsis; + } +} + +.feedback-card { + width: 100%; + cursor: pointer; + background-color: white; + border-radius: 20px; + padding: 40px 40px 2px 40px; + margin-bottom: 15px; + filter: drop-shadow(0 0 0.95rem #cCcCcC); + text-align: left; + transition: all .2s ease-in-out; +} + +.admin-feedback-card { + margin: 10px; + + table { + width: 100%; + } + tbody { + padding-top: 20px; + padding-bottom: 20px; + tr { + padding-left: 20px; + padding-right: 20px; + td { + padding: 5px; + } + } + } + + .feedbacks-table tr td { + border: none; + } +} + +.btn-submit { + float: right; +} + + +.chat-log-table { + +} diff --git a/app/javascript/css/agenda.scss b/app/javascript/css/agenda.scss new file mode 100644 index 0000000000000000000000000000000000000000..85ee3c97c103b50f47982848e801f712bff20b37 --- /dev/null +++ b/app/javascript/css/agenda.scss @@ -0,0 +1,17 @@ +// Place all the styles related to the agenda controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ + +.link-error, +.error-directive { + font-weight: bold; + background-color: red; + color: white; +} + +@media (min-width: 768px) { + .modal-xl { + width: 90%; + max-width:1200px; + } +} diff --git a/app/javascript/css/base-style.scss b/app/javascript/css/base-style.scss new file mode 100644 index 0000000000000000000000000000000000000000..5f803f8a4d8717915a36d8d8841a8076c0393371 --- /dev/null +++ b/app/javascript/css/base-style.scss @@ -0,0 +1,39 @@ + +@import '~dtu_core_assets/tango_palette'; + +$body-bg: #fff !global; +$font-size-base: 20px !global; +$light-yellow-highlight: rgba(255,245,125, 0.6); +$answer-selected: rgba(240,235,115, 0.8); +$correct-answer: rgba(115,240,115, 0.8); +$incorrect-answer: rgba(240,115,115, 0.8); +$feedback-answer: rgba(140,140,250, 0.8); +$quiz-question-separation: 5vh; +$header-color : #f0f0f0; +$header-font-size: 16px; + +$light-yellow-highlight: rgba(255,245,125, 0.6); +$answer-selected: rgba(240,235,115, 0.8); +$correct-answer: rgba(115,240,115, 0.8); +$incorrect-answer: rgba(240,115,115, 0.8); +$feedback-answer: rgba(140,140,250, 0.8); + +$header-text: #999999; +$panel-border: #999999; + +$nav-highlight-border: rgba(200, 200, 200, 0.8); +$bgDefault : #707070; +$bgHighlight : lighten( $bgDefault, 10% ); +$colDefault : lighten( $bgHighlight, 10% ); +$colHighlight : lighten( $colDefault, 10% ); +$bgHighlight : #808080; +$colDefault : #909090; +$colHighlight : #A0A0A0; + +$font_name : "Source Sans Pro",sans-serif; +$editor_font_family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; + +$header_height: 99; +$header_height_shrunk: 49; +$header_margin: 15px; + diff --git a/app/javascript/css/base.css b/app/javascript/css/base.css new file mode 100644 index 0000000000000000000000000000000000000000..9af41813b412dddc518222192b7d541e8bc3fe75 --- /dev/null +++ b/app/javascript/css/base.css @@ -0,0 +1,481 @@ +/* // Core variables and mixins +@import "../bower-libs/bootstrap/less/variables.less"; +@import "../bower-libs/bootstrap/less/mixins.less"; + +// Reset +@import "../bower-libs/bootstrap/less/normalize.less"; + +// Core CSS +@import "../bower-libs/bootstrap/less/scaffolding.less"; +@import "../bower-libs/bootstrap/less/type.less"; +@import "../bower-libs/bootstrap/less/code.less"; +@import "../bower-libs/bootstrap/less/grid.less"; +@import "../bower-libs/bootstrap/less/tables.less"; +@import "../bower-libs/bootstrap/less/forms.less"; +@import "../bower-libs/bootstrap/less/buttons.less"; + +// Components +@import "../bower-libs/bootstrap/less/component-animations.less"; +@import "../bower-libs/bootstrap/less/glyphicons.less"; +@import "../bower-libs/bootstrap/less/dropdowns.less"; +@import "../bower-libs/bootstrap/less/button-groups.less"; +@import "../bower-libs/bootstrap/less/input-groups.less"; +@import "../bower-libs/bootstrap/less/navs.less"; +@import "../bower-libs/bootstrap/less/navbar.less"; +@import "../bower-libs/bootstrap/less/breadcrumbs.less"; +@import "../bower-libs/bootstrap/less/pagination.less"; +@import "../bower-libs/bootstrap/less/pager.less"; +@import "../bower-libs/bootstrap/less/labels.less"; +@import "../bower-libs/bootstrap/less/badges.less"; +@import "../bower-libs/bootstrap/less/jumbotron.less"; +@import "../bower-libs/bootstrap/less/thumbnails.less"; +@import "../bower-libs/bootstrap/less/alerts.less"; +@import "../bower-libs/bootstrap/less/progress-bars.less"; +@import "../bower-libs/bootstrap/less/media.less"; +@import "../bower-libs/bootstrap/less/list-group.less"; +@import "../bower-libs/bootstrap/less/panels.less"; +@import "../bower-libs/bootstrap/less/wells.less"; +@import "../bower-libs/bootstrap/less/close.less"; + +// Components w/ JavaScript +@import "../bower-libs/bootstrap/less/modals.less"; +@import "../bower-libs/bootstrap/less/tooltip.less"; +@import "../bower-libs/bootstrap/less/popovers.less"; + +// Utility classes +@import "../bower-libs/bootstrap/less/utilities.less"; + +@import (less) "../libs/highlight/styles/default.css"; +@import (less) "../li/fontello/c/fontello.css"; +*/ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +.pln { + color: #000000; +} +/* plain text */ +.str { + color: #008800; +} +/* string content */ +.kwd { + color: #000088; +} +/* a keyword */ +.com { + color: #880000; +} +/* a comment */ +.typ { + color: #660066; +} +/* a type name */ +.lit { + color: #006666; +} +/* a literal value */ +/* punctuation, lisp open bracket, lisp close bracket */ +.pun, +.opn, +.clo { + color: #666600; +} +.tag { + color: #000088; +} +/* a markup tag name */ +.atn { + color: #660066; +} +/* a markup attribute name */ +.atv { + color: #008800; +} +/* a markup attribute value */ +.dec, +.var { + color: #660066; +} +/* a declaration; a variable name */ +.fun { + color: #ff0000; +} +/* a function name */ +/* Put a border around prettyprinted code snippets. */ +pre.prettyprint { + padding: 2px; + border: 1px solid #888888; +} +/* 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: #eeeeee; +} +@font-face { + font-family: 'fontello'; + src: url('/font/fontello.svg#fontello') format('svg'), url('/font/fontello.woff') format('woff'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url("/font/SourceSansPro-Light-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro'), local('SourceSansPro'), url("/font/SourceSansPro-Regular-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url("/font/SourceSansPro-Bold-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 300; + src: local('Source Sans Pro Light Italic'), local('SourceSansProLight-Italic'), url("/font/SourceSansPro-LightItalic-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 400; + src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url("/font/SourceSansPro-Italic-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 700; + src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldItalic'), url("/font/SourceSansPro-BoldItalic-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Code Pro'), local('SourceCodePro-Regular'), url("/font/SourceCodePro-Regular-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 700; + src: local('Source Code Pro Bold'), local('SourceCodePro-Bold'), url("/font/SourceCodePro-Bold-webfont.woff") format('woff'); +} +.container { + margin-bottom: 180px; + text-align: justify; +} +a code { + color: inherit; +} +h1 { + font-size: 2.6em; +} +h2 { + font-size: 2.15em; +} +h3 { + font-size: 1.7em; +} +h4 { + font-size: 1.25em; +} +h5 { + font-size: 1em; +} +h6 { + font-size: 0.85em; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 1.5em 0; + text-align: start; +} +pre { + word-break: break-word; +} +p, +pre, +pre.prettyprint, +blockquote { + margin: 0 0 1.1em; +} +hr { + margin: 2em 0; +} +img { + max-width: 100%; +} +.sequence-diagram, +.flow-chart { + text-align: center; + margin-bottom: 1.1em; +} +.sequence-diagram text, +.flow-chart text { + font-size: 15px !important; + font-family: "Source Sans Pro", sans-serif !important; +} +.sequence-diagram [fill="#ffffff"], +.flow-chart [fill="#ffffff"] { + fill: #ffffff; +} +.sequence-diagram [stroke="#000000"], +.flow-chart [stroke="#000000"] { + stroke: #000000; +} +.sequence-diagram text[stroke="#000000"], +.flow-chart text[stroke="#000000"] { + stroke: none; +} +.sequence-diagram [fill="#000"], +.flow-chart [fill="#000"], +.sequence-diagram [fill="#000000"], +.flow-chart [fill="#000000"], +.sequence-diagram [fill="black"], +.flow-chart [fill="black"] { + fill: #000000; +} +code, +pre { + font-family: "Source Code Pro", monospace; + font-size: 0.9em; +} +code { + white-space: normal; +} +pre, +pre.prettyprint { + text-align: start; + border: 0; + padding: 10px 20px; + border-radius: 5px; +} +pre code, +pre.prettyprint code { + background-color: transparent !important; +} +/* Definition list */ +dt, +dd { + margin-top: 5px; + margin-bottom: 5px; +} +dd { + margin-left: 40px; +} +/* Table style */ +table { + margin-bottom: 20px; +} +table th, +table td { + padding: 8px; + line-height: 20px; + vertical-align: top; + border-top: 1px solid #dddddd; +} +table th { + font-weight: bold; +} +table thead th { + vertical-align: bottom; +} +table caption + thead tr:first-child th, +table caption + thead tr:first-child td, +table colgroup + thead tr:first-child th, +table colgroup + thead tr:first-child td, +table thead:first-child tr:first-child th, +table thead:first-child tr:first-child td { + border-top: 0; +} +table tbody + tbody { + border-top: 2px solid #dddddd; +} +blockquote { + border-left-width: 10px; + background-color: #f8f8f8; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + padding: 15px 20px; +} +blockquote p { + margin-bottom: 1.1em; + font-size: 1em; + line-height: 1.45; +} +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +ul, +ol { + margin-bottom: 1.1em; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 1.1em; +} +kbd { + padding: 0.1em 0.6em; + border: 1px solid rgba(0, 0, 0, 0.25); + font-size: 0.7em; + font-family: sans-serif; + background-color: #ffffff; + color: #333333; + border-radius: 3px; + display: inline-block; + margin: 0 0.1em; + white-space: nowrap; +} +.toc ul { + list-style-type: none; + margin-bottom: 15px; +} +.footnote { + vertical-align: top; + position: relative; + top: -0.5em; + font-size: 0.8em; +} +/*********************** + * Icons + ***********************/ +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + line-height: 1.35em; + vertical-align: middle; + background-repeat: no-repeat; +} +.icon-code { + font-size: 83%; + line-height: 1.65em; +} +.icon-code:before { + margin-left: 0.1em; + margin-right: 0.6em; +} +.icon-trash { + line-height: 1.50em; +} +.icon-folder-open { + font-size: 80%; +} +.icon-folder-open:before { + margin-right: 0.6em; +} +.icon-chart-bar { + font-size: 95%; +} +.icon-chart-bar:before { + margin-left: 0.3em; + margin-right: 0.3em; +} +.icon-comment-alt, +.icon-chat { + font-size: 92%; +} +.icon-comment-alt:before, +.icon-chat:before { + margin-left: 0.1em; + margin-right: 0.4em; +} +.icon-file { + font-size: 104%; + margin-left: 0; + margin-right: 0; +} +.icon-link { + font-size: 104%; +} +[class^="icon-provider-"], +[class*=" icon-provider-"] { + background-image: url("../img/icons.png"); + width: 18px; + height: 16px; + margin-top: -2px; + margin-left: 2px; +} +@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { + [class^="icon-provider-"], + [class*=" icon-provider-"] { + background-image: url("../img/icons2x.png"); + background-size: 256px 16px; + } +} +.icon-provider-stackedit { + background-position: 0 0; +} +.icon-provider-gdrive, +.icon-provider-gdrivesec, +.icon-provider-gdriveter { + background-position: -18px 0; +} +.icon-provider-dropbox { + background-position: -37px 0; +} +.icon-provider-github, +.icon-provider-gist { + background-position: -54px 0; +} +.icon-provider-blogger, +.icon-provider-bloggerpage { + background-position: -72px 0; +} +.icon-provider-tumblr { + background-position: -90px 0; +} +.icon-provider-wordpress { + background-position: -108px 0; +} +.icon-provider-ssh { + background-position: -126px 0; +} +.icon-provider-gplus { + background-position: -144px 0; +} +.icon-provider-couchdb { + background-position: -162px 0; +} +/******************* + * RTL + *******************/ +body.rtl #wmd-input, +body.rtl #preview-contents, +body.rtl .input-file-title, +body.rtl .search-bar input, +body.rtl .modal-document-manager input, +body.rtl .comments-popover, +body.rtl .container { + direction: rtl; +} diff --git a/app/javascript/css/base.less b/app/javascript/css/base.less new file mode 100644 index 0000000000000000000000000000000000000000..c23c05a259b1777ec209aee861b4a3311121e047 --- /dev/null +++ b/app/javascript/css/base.less @@ -0,0 +1,476 @@ +/* // Core variables and mixins +@import "../bower-libs/bootstrap/less/variables.less"; +@import "../bower-libs/bootstrap/less/mixins.less"; + +// Reset +@import "../bower-libs/bootstrap/less/normalize.less"; + +// Core CSS +@import "../bower-libs/bootstrap/less/scaffolding.less"; +@import "../bower-libs/bootstrap/less/type.less"; +@import "../bower-libs/bootstrap/less/code.less"; +@import "../bower-libs/bootstrap/less/grid.less"; +@import "../bower-libs/bootstrap/less/tables.less"; +@import "../bower-libs/bootstrap/less/forms.less"; +@import "../bower-libs/bootstrap/less/buttons.less"; + +// Components +@import "../bower-libs/bootstrap/less/component-animations.less"; +@import "../bower-libs/bootstrap/less/glyphicons.less"; +@import "../bower-libs/bootstrap/less/dropdowns.less"; +@import "../bower-libs/bootstrap/less/button-groups.less"; +@import "../bower-libs/bootstrap/less/input-groups.less"; +@import "../bower-libs/bootstrap/less/navs.less"; +@import "../bower-libs/bootstrap/less/navbar.less"; +@import "../bower-libs/bootstrap/less/breadcrumbs.less"; +@import "../bower-libs/bootstrap/less/pagination.less"; +@import "../bower-libs/bootstrap/less/pager.less"; +@import "../bower-libs/bootstrap/less/labels.less"; +@import "../bower-libs/bootstrap/less/badges.less"; +@import "../bower-libs/bootstrap/less/jumbotron.less"; +@import "../bower-libs/bootstrap/less/thumbnails.less"; +@import "../bower-libs/bootstrap/less/alerts.less"; +@import "../bower-libs/bootstrap/less/progress-bars.less"; +@import "../bower-libs/bootstrap/less/media.less"; +@import "../bower-libs/bootstrap/less/list-group.less"; +@import "../bower-libs/bootstrap/less/panels.less"; +@import "../bower-libs/bootstrap/less/wells.less"; +@import "../bower-libs/bootstrap/less/close.less"; + +// Components w/ JavaScript +@import "../bower-libs/bootstrap/less/modals.less"; +@import "../bower-libs/bootstrap/less/tooltip.less"; +@import "../bower-libs/bootstrap/less/popovers.less"; + +// Utility classes +@import "../bower-libs/bootstrap/less/utilities.less"; + +@import (less) "../libs/highlight/styles/default.css"; +@import (less) "../li/public/fontello/c/public/fontello.css"; +*/ + +/* Pretty printing styles. Used with prettify.js. */ + +/* SPAN elements with the classes below are added by prettyprint. */ +.pln { color: #000 } /* plain text */ + +.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 */ + +/* 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 } + + +@body-bg: #fff; +@text-color: #000; +@kbd-color: #333; +@kbd-bg-color: #FFF; +@kbd-border-color: fade(@text-color, 25%); +@blockquote-border-color: #eee; +@blockquote-bg: #f8f8f8; +@title-base-size: 1em; +@code-color: @text-color; +@code-bg: fade(@text-color, 4%); +@pre-bg: @blockquote-bg; +@pre-border-color: @blockquote-border-color; +@font-size-base: 15px; +@line-height-base: 1.45; +@p-margin: 1.1em; +@headings-font-family: inherit; +@headings-font-weight: 300; + +@font-face { + font-family: 'fontello'; + src: url('/font/fontello.svg#fontello') format('svg'), + url('/font/fontello.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url("/font/SourceSansPro-Light-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro'), local('SourceSansPro'), url("/font/SourceSansPro-Regular-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url("/font/SourceSansPro-Bold-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 300; + src: local('Source Sans Pro Light Italic'), local('SourceSansProLight-Italic'), url("/font/SourceSansPro-LightItalic-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 400; + src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url("/font/SourceSansPro-Italic-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Sans Pro'; + font-style: italic; + font-weight: 700; + src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldItalic'), url("/font/SourceSansPro-BoldItalic-webfont.woff") format('woff'); +} + +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Code Pro'), local('SourceCodePro-Regular'), url("/font/SourceCodePro-Regular-webfont.woff") format('woff'); +} +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 700; + src: local('Source Code Pro Bold'), local('SourceCodePro-Bold'), url("/font/SourceCodePro-Bold-webfont.woff") format('woff'); +} + +@font-family-sans-serif: "Source Sans Pro", sans-serif; +@font-family-monospace: "Source Code Pro", monospace; + +// Copied from Bootstrap in order to have correct urls +.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) { + background-image: url("@{file-1x}"); + + @media + only screen and (-webkit-min-device-pixel-ratio: 2), + only screen and ( min--moz-device-pixel-ratio: 2), + only screen and ( -o-min-device-pixel-ratio: 2/1), + only screen and ( min-device-pixel-ratio: 2), + only screen and ( min-resolution: 192dpi), + only screen and ( min-resolution: 2dppx) { + background-image: url("@{file-2x}"); + background-size: @width-1x @height-1x; + } +} + +.container { +/* margin-bottom: 180px; */ + text-align: justify; +} + +a code { + color: inherit; +} + +h1 { font-size: @title-base-size * 2.60; } +h2 { font-size: @title-base-size * 2.15; } +h3 { font-size: @title-base-size * 1.70; } +h4 { font-size: @title-base-size * 1.25; } +h5 { font-size: @title-base-size; } +h6 { font-size: @title-base-size * 0.85; } + +h1, h2, h3, h4, h5, h6 { + margin: 1.5em 0; + text-align: start; +} + +pre { + word-break: break-word; +} + +p, +pre, +pre.prettyprint, +blockquote { + margin: 0 0 @p-margin; +} + +hr { + margin: 2em 0; +} + +img { + max-width: 100%; +} + +.sequence-diagram, .flow-chart { + text-align: center; + margin-bottom: @p-margin; + text { + font-size: 15px !important; + font-family: @font-family-sans-serif !important; + } + [fill="#ffffff"] { + fill: @body-bg; + } + [stroke="#000000"] { + stroke: @text-color; + } + text[stroke="#000000"] { + stroke: none; + } + [fill="#000"], [fill="#000000"], [fill="black"] { + fill: @text-color; + } +} + +code, pre { + font-family: @font-family-monospace; + font-size: 0.9em; +} + +code { + white-space: normal; +} + +pre, pre.prettyprint { + text-align: start; + border: 0; + padding: 10px 20px; + border-radius: 5px; + code { + background-color: transparent !important; + } +} + +/* Definition list */ +dt,dd { + margin-top: 5px; + margin-bottom: 5px; +} + +dd { + margin-left: 40px; +} + +/* Table style */ +table { + margin-bottom: 20px; +} + +table th,table td { + padding: 8px; + line-height: 20px; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +table th { + font-weight: bold; +} + +table thead th { + vertical-align: bottom; +} + +table caption+thead tr:first-child th,table caption+thead tr:first-child td,table colgroup+thead tr:first-child th,table colgroup+thead tr:first-child td,table thead:first-child tr:first-child th,table thead:first-child tr:first-child td + { + border-top: 0; +} + +table tbody+tbody { + border-top: 2px solid #dddddd; +} + +blockquote { + border-left-width: 10px; + background-color: @blockquote-bg; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + padding: 15px 20px; + p { + margin-bottom: @p-margin; + font-size: 1em; + line-height: @line-height-base; + } + + ul:last-child, + ol:last-child { + margin-bottom: 0; + } +} + +ul,ol { + margin-bottom: @p-margin; + ul,ol { + margin-bottom: @p-margin; + } +} + +kbd { + padding: 0.1em 0.6em; + border: 1px solid @kbd-border-color; + // .box-shadow(0 1px 0px @kbd-border-color); + font-size: 0.7em; + font-family: sans-serif; + background-color: @kbd-bg-color; + color: @kbd-color; + border-radius: 3px; + display: inline-block; + margin: 0 0.1em; + white-space: nowrap; +} + +.toc ul { + list-style-type: none; + margin-bottom: 15px; +} + +.footnote { + vertical-align: top; + position: relative; + top: -0.5em; + font-size: 0.8em; +} + +/*********************** + * Icons + ***********************/ + +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + line-height: 1.35em; + vertical-align: middle; + background-repeat: no-repeat; +} + +// Custom icons (not from Font Awesome) +.icon-code { + font-size: 83%; + line-height: 1.65em; + &:before { + margin-left: 0.1em; + margin-right: 0.6em; + } +} + +.icon-trash { + line-height: 1.50em; +} + +.icon-folder-open { + font-size: 80%; + &:before { + margin-right: 0.6em; + } +} + +.icon-chart-bar { + font-size: 95%; + &:before { + margin-left: 0.3em; + margin-right: 0.3em; + } +} + +.icon-comment-alt, .icon-chat { + font-size: 92%; + &:before { + margin-left: 0.1em; + margin-right: 0.4em; + } +} + +.icon-file { + font-size: 104%; + margin-left: 0; + margin-right: 0; +} + +.icon-link { + font-size: 104%; +} + +// Provider's icons (the colored ones) +[class^="icon-provider-"], [class*=" icon-provider-"] { + .img-retina('../img/icons.png', '../img/icons2x.png', 256px, 16px); + width: 18px; + height: 16px; + margin-top: -2px; + margin-left: 2px; +} + +.icon-provider-stackedit { + background-position: 0 0; +} + +.icon-provider-gdrive, .icon-provider-gdrivesec, .icon-provider-gdriveter { + background-position: -18px 0; +} + +.icon-provider-dropbox { + background-position: -37px 0; +} + +.icon-provider-github,.icon-provider-gist { + background-position: -54px 0; +} + +.icon-provider-blogger, .icon-provider-bloggerpage { + background-position: -72px 0; +} + +.icon-provider-tumblr { + background-position: -90px 0; +} + +.icon-provider-wordpress { + background-position: -108px 0; +} + +.icon-provider-ssh { + background-position: -126px 0; +} + +.icon-provider-gplus { + background-position: -144px 0; +} + +.icon-provider-couchdb { + background-position: -162px 0; +} + +/******************* + * RTL + *******************/ +body.rtl { + #wmd-input, + #preview-contents, + .input-file-title, + .search-bar input, + .modal-document-manager input, + .comments-popover, + .container { + direction: rtl; + } +} diff --git a/app/javascript/css/edit.scss b/app/javascript/css/edit.scss new file mode 100644 index 0000000000000000000000000000000000000000..dd7a022d061cabbc8dc30abab58f6674a5173ec5 --- /dev/null +++ b/app/javascript/css/edit.scss @@ -0,0 +1,156 @@ +.wmd-input { + font-family: $editor_font_family; + font-size:15px; + line-height:1.45; + color:#3f3f3f; + background-color:#f6f6f6; +} +.wmd-previewx { margin-bottom: 40px; background-color: #eef; } + + +.wmd-panel +{ + margin-left: 25%; + margin-right: 25%; + width: 50%; + min-width: 500px; +} + +.wmd-button-bar +{ + display: inline-block; +} + +.editor-button-bar +{ + margin-bottom: 5px; + margin-left: 5px; +} + +.wmd-input { + width: 100%; + height: 80vh; + background-color: Gainsboro; + border: 1px solid DarkGray; + overflow: scroll; + white-space: pre; +} + +.wmd-preview +{ + width: 100%; + height: 80vh; + background-color: #c0e0ff; + border: 1px solid DarkGray; + overflow: scroll; +} + +.wmd-button-row +{ + position: relative; + margin-left: 5px; + margin-right: 5px; + margin-bottom: 5px; + margin-top: 10px; + padding: 0px; + height: 20px; + top: 13px; +} + +.wmd-spacer +{ + width: 1px; + height: 20px; + margin-left: 14px; + + position: absolute; + background-color: Silver; + display: inline-block; + list-style: none; +} + +.wmd-button { + width: 20px; + height: 20px; + padding-left: 2px; + padding-right: 3px; + position: absolute; + display: inline-block; + list-style: none; + cursor: pointer; +} + +.wmd-button > span { + background-image: url("../images/wmd-buttons.png"); + background-repeat: no-repeat; + background-position: 0px 0px; + width: 20px; + height: 20px; + display: inline-block; +} + +.wmd-spacer1 +{ + left: 50px; +} +.wmd-spacer2 +{ + left: 175px; +} +.wmd-spacer3 +{ + left: 300px; +} + + + + +.wmd-prompt-background +{ + background-color: Black; +} + +.wmd-prompt-dialog +{ + border: 1px solid #999999; + background-color: #F5F5F5; +} + +.wmd-prompt-dialog > div { + font-size: 0.8em; + font-family: arial, helvetica, sans-serif; +} + +.wmd-prompt-dialog > form > input[type="text"] { + border: 1px solid #999999; + color: black; +} + +.wmd-prompt-dialog > form > input[type="button"]{ + border: 1px solid #888888; + font-family: trebuchet MS, helvetica, sans-serif; + font-size: 0.8em; + font-weight: bold; +} + + + +.hidden { + position: absolute; + top: 0; + left:0; + width:0; + height:0; + overflow: hidden; + visibility: hidden; +} + +#wrap-lines-checkbox { + margin-left: 6px; +} +.wrap-editor { + overflow-y: scroll; + overflow-x: initial; + white-space:pre-wrap; + word-wrap:break-word; +} diff --git a/app/javascript/css/enotes.scss b/app/javascript/css/enotes.scss new file mode 100644 index 0000000000000000000000000000000000000000..0e8b59b3799a7e453273b5a5aa994aff54a77de3 --- /dev/null +++ b/app/javascript/css/enotes.scss @@ -0,0 +1,10 @@ +// Place all the styles related to the enotes controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ + + .pdf-viewer-container { + margin-top: ($header_height + 1)px; + height:100%; + position:fixed; + width:100%; +} diff --git a/app/javascript/css/exercise.scss b/app/javascript/css/exercise.scss new file mode 100644 index 0000000000000000000000000000000000000000..441b23b54d077c787b9a842ccc2b82376188c6ed --- /dev/null +++ b/app/javascript/css/exercise.scss @@ -0,0 +1,198 @@ +// Place all the styles related to the exercise controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ + + +.btn-hint, .btn-answer, .btn-askbot { + display: inline-block; + margin: 0 auto; + text-align: center; +} + +.btn-hint, .btn-answer { + display: block; + width: 140px; +} + +.askbot-directive { + display:block; + text-align:center; +} + +.question { + background-color: #f0f0f0; + position: relative; + top: auto; + left: auto; + width: auto; + height: auto; +} + +.hide { + position: absolute; + top: 0; + left: 0; + width: 0; + height: 0; + overflow: hidden; + visibility: hidden; +} + +/* directives */ + +$quiz-internal-question-separation: 1vh; + +.directive-region { + /*margin-right: $quiz-internal-question-separation;*/ + text-align:left; + margin: 10px 0 10px 0; + width: 100%; +} +.directive-region-label { +} +.directive-region-list { +} +.directive-region-item { + display:table-cell; + padding: 10px 10px 0 10px; + margin: auto 0; + vertical-align: middle; + width: 100%; +} + +.directive-region-item-container { + border: 1px solid; + border-radius: 5px; + border-spacing: 0; + display:table; + margin-top: 5px; +} + + +.directive-region-label { + height:100%; + margin: 0; + padding: 0; + border-radius: 5px; + border-spacing: 0; + font-size:18px; + text-transform: uppercase; + color:white; + display:table-cell; + vertical-align: middle; + padding-right: 5px; + height: 50px; + max-width: 24px; + min-width: 24px; + div { + position: absolute; + top: 50%; + left: 14px; + transform: translateX(-50%) translateY(-50%) rotate(-90deg); + } +} + +.directive-region { + + > button { + + } +} + + +.question { + .directive-region-item-container { + background-color: lighten($butter-light, 30%); + border: 1px $butter-dark solid; + .directive-region-label { + background-color: $butter-dark; + border-right: 1px $butter-dark solid; + color: lighten($butter-light, 30%); + div { + transform: translateX(-50%) translateY(-50%) rotate(0deg); + } + } + } +} + +.hint { + .directive-region-item-container { + border-color: $plum-dark; + background-color: lighten($plum-light, 30%); + border: 1px $plum-dark solid; + .directive-region-label { + border-right: 1px $plum-dark solid; + background-color: $plum-dark; + color: lighten($plum-light, 30%); + } + } +} + +.answer { + position: relative; + .directive-region-item-container { + border-color: $sky-blue-dark; + background-color: lighten($sky-blue-light, 30%); + border: 1px $sky-blue-dark solid; + .directive-region-label { + border-right: 1px $sky-blue-dark solid; + background-color: $sky-blue-dark; + color: lighten($sky-blue-light, 30%); + } + } +} + +.btn-hint, +.btn-hint:hover, +.btn-hint:active, +.btn-hint:visited, +.btn-hint:focus { +/* + background-color: $sky-blue; + border-color: $sky-blue-dark; +*/ +} + +.btn-answer, +.btn-answer:hover, +.btn-answer:active, +.btn-answer:visited, +.btn-answer:focus { +/* + background-color: $chameleon; + border-color: $chameleon-dark; +*/ +} + + +/* just because "ANSWER" takes up so much room */ +.answer { + .directive-region-item-container { + height: 100px; + min-height: 100px; + } +} + +.btn-hidden-directive { + margin: 10px auto; +} + +@media print { + .btn-hint, .btn-answer { + display: none; + } + + .answer, .hint, .edit, .report-a-bug { + position: absolute; + top: 0; + left:0; + width:0; + height:0; + overflow: hidden; + visibility: hidden; + } + + .directive-region { + page-break-inside: avoid; + } +} diff --git a/app/javascript/css/feedback.scss b/app/javascript/css/feedback.scss new file mode 100644 index 0000000000000000000000000000000000000000..1b6b62e0c2a2d2eda5bcddfc8c4cca6fcf50c12b --- /dev/null +++ b/app/javascript/css/feedback.scss @@ -0,0 +1,34 @@ +.feedback-btn-group { + right: auto; + left: 60px; + line-height: 27px; + float: right; + font-size: 0.8em; + position: fixed; + bottom: -3px; + + display: flex; + flex-direction: column; + + margin-bottom: 44px; + + height: 80px; + justify-content: space-evenly; + +} + +.feedbacks-btn, +.feedback-btn { + height: 29px; + padding: 0 8px; + text-align: center; + border: 1px solid #aaa; + outline: 0; + background-clip: padding-box; + + -webkit-box-shadow: 0 4px 16px rgba(0,0,0,.2); + -moz-box-shadow: 0 4px 16px rgba(0,0,0,.2); + box-shadow: 0 4px 16px rgba(0,0,0,.2); + + z-index: 40000; +} diff --git a/app/javascript/css/home.scss b/app/javascript/css/home.scss new file mode 100644 index 0000000000000000000000000000000000000000..465f6e54f285a783dfae66bbc57273d6de65bda4 --- /dev/null +++ b/app/javascript/css/home.scss @@ -0,0 +1,101 @@ + +body{ + margin:0px; + padding:0px; +// font-family:Verdana, Arial, Sans-Serif; +} +ul, ol { + margin:0px; + padding:0px; + padding-left:20px; +} +li { + margin:0px; + padding:0px; +} +h1,h2,h3 { + margin-top:10px; + margin-bottom:10px; +} + +h4,h5,h6 { + margin-top:1.5em; + margin-bottom:0; +} + +/* issue #153 */ +hr { + border-color: #777777; +} + + +/* ltd section css */ + +.heading{ + margin-bottom:20px !important; +} +.heading h4 { + border-bottom:1px solid $header-text; + padding-bottom: 5px; + font-style:normal; + font-weight:bold; + font-size:15px; + color:#1C1C1C; +} +.panel-default { + border-color: $panel-border !important; +} +.panel-default > .panel-heading { + color: #333; + background-color: rgba(191, 44, 55, 0.1); + border-color: $header-text; +} +.panel a{ +color:#BF2C37; +} +/* rtd content section css */ +#heading-text h3{ + border-bottom:1px solid $header-text; + padding-bottom: 5px; + font-style:normal; + font-weight:bold; + font-size:18px; + color:#333; +} + + + + + + + +.panel { + border:none; +} + + + + + +@media print { + /* General rules for printing. */ + body { + background: transparent none; + } + + nav { + display:none; + } +} + +img { + max-width: 400px; +} +.centered-image-parent { + text-align: center; +} + +.feedbacks-modal-label { + font-weight: bold; + margin-right: 1rem; +} \ No newline at end of file diff --git a/app/javascript/css/nav.scss b/app/javascript/css/nav.scss new file mode 100644 index 0000000000000000000000000000000000000000..74f66bd477a37fec86000aa5cffcb29006aab56d --- /dev/null +++ b/app/javascript/css/nav.scss @@ -0,0 +1,511 @@ +/* header css */ +.navbar { + border-radius: 0px; + background: $bgDefault; + max-height: 100px; + transition:all 0.3s ease-in; + -moz-transition:all 0.3s ease-in; + -ms-transition:all 0.3s ease-in; + -o-transition:all 0.3s ease-in; + -webkit-transition:all 0.3s ease-in; + -khtml-transition:all 0.3s ease-in; +} + +.top-menu, .navbar-nav { + margin: 0px !important; +} + +.below-nav { + margin-top: ($header_height + 1) + px; +} + +.logo{ + line-height:47px; +/* height: 65px;*/ + padding: 13px 15px; +} +.logo img{ + width:50px; + float:left; + transition:all 0.3s ease-in; + -moz-transition:all 0.3s ease-in; + -ms-transition:all 0.3s ease-in; + -o-transition:all 0.3s ease-in; + -webkit-transition:all 0.3s ease-in; + -khtml-transition:all 0.3s ease-in; +} +.top-menu > li > a { + margin-bottom: $header_margin; + padding-top: 15px; + padding-bottom: 15px; + padding-right: 15px; + padding-left: 15px; + color: $header-color !important; + font-size: $header-font-size; + line-height: $header-font-size + 2px; + transition:all 0.3s ease-in; + -moz-transition:all 0.3s ease-in; + -ms-transition:all 0.3s ease-in; + -o-transition:all 0.3s ease-in; + -webkit-transition:all 0.3s ease-in; + -khtml-transition:all 0.3s ease-in; +} +.top-menu > li > a:hover,.top-menu > li > a:active{ + color: $header-color !important; + background-color: $bgHighlight; +} +.navbar-toggle { + margin-top: 8px; /* toggle is 34px, +8px for the margin makes the shrunk title of 50px*/ + margin-bottom: 8px; + margin-right: 15px; + border-color: #898A8D !important; +} + +.nav-scroll{ + max-height: 70px; + transition:all 0.3s ease-in; + -moz-transition:all 0.3s ease-in; + -ms-transition:all 0.3s ease-in; + -o-transition:all 0.3s ease-in; + -webkit-transition:all 0.3s ease-in; + -khtml-transition:all 0.3s ease-in; +} +.nav-scroll .logo img{ + width: 30px; + float: left; + transition:all 0.3s ease-in; + -moz-transition:all 0.3s ease-in; + -ms-transition:all 0.3s ease-in; + -o-transition:all 0.3s ease-in; + -webkit-transition:all 0.3s ease-in; + -khtml-transition:all 0.3s ease-in; +} +.nav-scroll .top-menu > li > a{ + line-height:30px; + transition:all 0.3s ease-in; + -moz-transition:all 0.3s ease-in; + -ms-transition:all 0.3s ease-in; + -o-transition:all 0.3s ease-in; + -webkit-transition:all 0.3s ease-in; + -khtml-transition:all 0.3s ease-in; +} +.login > li > a{ + border:0px solid transparent; + font-size: $header-font-size; +} +.login > li > a:hover, .login > li > a:active{ + border:0px solid transparent; + font-size: $header-font-size; +} + +.navbar .left-space,.navbar .right-space { + width:25px; + height:38px +} +.navbar .nav { + float:left; + margin:5px 9px; + height:38px +} +.navbar .nav>li { + display:inline-block +} +.navbar .nav.pull-right { + float:right +} +.navbar .nav.pull-right>li>.dropdown-menu { + right:0; + left:auto +} +.navbar .nav.pull-right>li>.dropdown-menu .dropdown-menu { + right:100%; + left:auto; + margin-right:-1px; + margin-left:0 +} +.navbar .btn { + height:38px; + padding:6px 8px +} +.navbar .btn-group>.btn.disabled *,.navbar .btn-group>.btn.blocked *,.navbar .btn-group>.btn[disabled] * { + color:rgba(221,221,221,0.3) +} +.navbar .button-open-discussion.some { + color:#e0b800 !important +} +.navbar .button-open-discussion.replied { + color:#e74434 !important +} +.navbar .file-title-navbar { + display:inline-block; + vertical-align:middle; + padding:1px 15px; + font-size:1.5em; + line-height:1.45em; + font-weight:200; + overflow:hidden; + white-space:nowrap +} +.navbar .file-title-navbar a i { + -webkit-transition:all ease-in-out .15s; + transition:all ease-in-out .15s +} +.navbar .file-title-navbar a .icon-link-ext-alt { + color:transparent; + position:relative; + font-size:12px; + top:-12px; + right:6px; + width:0 +} +.navbar .file-title-navbar a:hover [class^="icon-provider-"],.navbar .file-title-navbar a:hover [class*=" icon-provider-"] { + opacity:.5; + filter:alpha(opacity=50) +} +.navbar .file-title-navbar a:hover .icon-link-ext-alt { + color:#fff +} +.navbar .input-file-title-container { + display:inline-block; + vertical-align:middle +} +.navbar .input-file-title-container .input-file-title { + width:400px; + font-size:16px; + height:38px +} +.navbar .working-indicator { + display:inline-block; + vertical-align:middle; + overflow:hidden; + height:38px; + width:60px; + padding-top:8px +} +.navbar .working-indicator .bar { + display:inline-block; + width:14px; + height:6px; + border-radius:1px; + margin:0 2px; + opacity:.25; + filter:alpha(opacity=25); + background-color:rgba(221,221,221,0.75) +} +.navbar .offline-status>div { + display:inline-block; + vertical-align:middle; + height:38px; + padding:9px 10px +} +.navbar .buttons-dropdown>.nav { + margin-left:0; + margin-right:0 +} +.navbar div.dropdown-menu { + top:initial; + padding:5px; + margin:10px +} +.navbar-right > li > a { + padding-right:15px; +} + +.navbar-inverse { + background-color: $bgDefault; + border-color: $bgHighlight; + .navbar-brand { + color: $colDefault; + height: unset; + &:hover, &:focus { + color: $colHighlight; }} + .navbar-text { + color: $colDefault; } + .navbar-nav { + > li { + > a { + color: $colDefault; + &:hover, &:focus { + color: $colHighlight; + background-color: $colHighlight; + }}} + > .active { + > a, > a:hover, > a:focus { + color: $colHighlight; + background-color: $bgHighlight; }} + > .open { + > a, > a:hover, > a:focus { + color: $colHighlight; + background-color: $bgHighlight; }}} + .navbar-toggle { + border-color: $bgHighlight; + &:hover, &:focus { + background-color: $bgHighlight; } + .icon-bar { + background-color: $colDefault; }} + .navbar-collapse, + .navbar-form { + border-color: $colDefault; } + .navbar-link { + color: $colDefault; + &:hover { + color: $colHighlight; }}} +@media (max-width: 767px) { + .navbar-nav > li > a { + padding-left:5px; + padding-top:5px; + padding-right:5px; + } + .navbar-default .navbar-nav .open .dropdown-menu { + > li > a { + color: $colDefault; + &:hover, &:focus { + color: $colHighlight; }} + > .active { + > a, > a:hover, > a:focus { + color: $colHighlight; + background-color: $bgHighlight; }}} +} + +nav.navbar { + -webkit-transition: all 0.4s ease; + transition: all 0.4s ease; +} + +.loginout-text { + display: inline; + font-size:16px; + font-family: $font_name; + margin-left: 3px; +} + +/* Issue #144 */ + +.scrollable-menu { + height: auto; + max-height: 80vh; + overflow-x: hidden; +} + +@media only screen and (max-device-height: 667px) { + .scrollable-menu { + max-height: 400px; + } +} + +@media only screen and (max-device-height: 300px) { + .scrollable-menu { + max-height: 200px; + } +} + + + +@media (max-width: 768px) { + .logo img{ + width:30px; + float:left; + margin-left:10px; + transition:all 0.3s ease-in; + -moz-transition:all 0.3s ease-in; + -ms-transition:all 0.3s ease-in; + -o-transition:all 0.3s ease-in; + -webkit-transition:all 0.3s ease-in; + -khtml-transition:all 0.3s ease-in; + } + .navbar-inverse .navbar-collapse{ + border-color:transparent; + } + .navbar-collapse.in { + overflow-y: hidden; + } + .navbar-nav { + margin: 0.5px -15px; + } + .top-menu > li > a { + line-height: 30px; + color: #999 !important; + background:#707070; + border-bottom: 1px solid rgba(238, 238, 238, 0.32); + border-top: 4px solid transparent; + } + .top-menu > li > a:hover,.top-menu > li > a:focus{ + background:#999 !important; + color:#fff !important; + } + .navbar-fixed-top .navbar-collapse, .navbar-fixed-bottom .navbar-collapse{ + max-height:385px; + } + +} + +/* +.navbar-nav > li > a { + padding-top: $header_margin; + margin-top: 5px; +} +*/ + +.nav-info-strip { + display: block; + padding: 0; + color: $header-color; + font-size: $header-font-size; + line-height: $header-font-size + 2px; + height: 20px; +} + +.course-info-info-strip { + margin-top: 20px; +} + +.navbar-collapse.collapse.navbar-strip.menu-info-strip { + margin-top: 5px; +} + +.menu-info-strip { + margin-top: 5px; +} + +.navbar.shrink > .container > .nav-info-strip { + display:none; + height: 0px; +} + +.navbar.shrink > .container > .navbar-strip { + margin-top: 0px; + > .top-menu { + margin: 5px !important; + } +} + +.navbar.shrink > .container > .navbar-header { + img { + -webkit-transform: scale(0.75); /* Saf3.1+, Chrome */ + -moz-transform: scale(0.75); /* FF3.5+ */ + -ms-transform: scale(0.75); /* IE9 */ + -o-transform: scale(0.75); /* Opera 10.5+ */ + transform: scale(0.75); + } + .logo { + line-height:47px; + height: 0px; + padding: 10px 0px; + } + .logo img{ + width:25px; + } +} + + + + +.course-title { + float: left; + margin: 0px; + /* margin: 5px 9px; /* just like .top-menu*/ + padding-left: 15px; + a { + color: $header-color; + text-decoration: none; + } + a:hover, a:focus { + background:#999 !important; + color:#fff !important; + } +} + +.logged-in-user { + display: inline-block; + float: right; + padding-right: 15px; + margin-top: 5px; /* just like .top-menu*/; + height: 20px; +} + + +.navbar-collapse.collapse.navbar-strip { + margin-top: 10px; +} + + +/* SHRINK */ + +.shrunk-course-title { + display: none; +} + +.navbar.shrink > .container > .navbar-header > .shrunk-course-title { + display:block; + margin: 15px 30px 15px 15px; +} + +/* https://github.com/dtu-compute/dtu-enote-website/issues/77 */ +.navbar.shrink > .container > .navbar-header .logo { + margin-top: -3px; +} + +.navbar-nav > li > .dropdown-menu { + margin-top: -15px; +} + +.navbar.shrink > .container > .navbar-strip > .navbar-nav > li > .dropdown-menu { + margin-top: 0px; +} + + +nav.navbar.shrink { + min-height: 50px; + max-height: 50px; + + .container > .navbar-strip > .navbar-nav > li > a { + padding-top:12px; + padding-bottom:10px; + margin:0px; + } +} + + +.below-shrunken-nav { + margin-top: ($header_height_shrunk + 1) + px; + margin-bottom: 100px; +} + +/* Mobile -- always shrink*/ + +@media (max-width: 768px) { + nav.navbar { + min-height: 50px; + max-height: 50px; + } + .course-title { + display: none; + } + .navbar > .container > .navbar-header > .shrunk-course-title { + display: block; + margin: 15px 30px 15px 15px; + } + .navbar > .container > .navbar-header { + img { + -webkit-transform: scale(0.75); /* Saf3.1+, Chrome */ + -moz-transform: scale(0.75); /* FF3.5+ */ + -ms-transform: scale(0.75); /* IE9 */ + -o-transform: scale(0.75); /* Opera 10.5+ */ + transform: scale(0.75); + } + .logo { + line-height:47px; + height: 0px; + padding: 10px 0px; + margin-top: -3px; + } + .logo img{ + width:25px; + } + } + + .below-nav { + margin-top: ($header_height_shrunk + 1) + px; + } +} + diff --git a/app/javascript/css/pages.scss b/app/javascript/css/pages.scss new file mode 100644 index 0000000000000000000000000000000000000000..75253b0d7168072f308ffc71cfa16137fb86cedf --- /dev/null +++ b/app/javascript/css/pages.scss @@ -0,0 +1,69 @@ +// Place all the styles related to the pages controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ + +.edit { + position:fixed; + left: 2px; + top: 0px; + background-color:$header-color; + z-index: 200; + // Animation + -webkit-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.edit button span { + max-width: 0; + -webkit-transition: max-width 1s; + transition: max-width 1s; + vertical-align: top; + white-space: nowrap; + display: inline-block; + overflow: hidden; +} +.edit:hover button span { + max-width: 10rem; +} + +.edit-0 { + left: 2px; +} + +.edit-1 { + right: 2px !important; + left: auto +} + + +/* https://github.com/dtu-compute/dtu-enote-pdfjs/issues/4 */ +@media (min-width: 1199px) { + #left-rail { + overflow-y: hidden; + position: fixed; + top: 100px; + bottom: 0px; + margin-right: 20px; + margin-top: 40px; + width: 300px !important; + transition: padding-top 0.3s ease, padding-bottom 0.3s ease; + } + #content { + padding-left: 25px; + } + .shrink-rail { + top: 50px !important; + } +} + +table.view-feedbacks { + .tr { + .td { + height:120px; + overflow: clip; + img { + max-width:120px; + } + } + } +} diff --git a/app/javascript/css/podcast.scss b/app/javascript/css/podcast.scss new file mode 100644 index 0000000000000000000000000000000000000000..2a13a26365bfbc631fbfbde400e5a371f5460e7e --- /dev/null +++ b/app/javascript/css/podcast.scss @@ -0,0 +1,46 @@ +// Place all the styles related to the podcast controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ + + +.podcasts { + display: table; + border-collapse:separate; + border-spacing:5px; +} +.podcast { + display: table-row; + height: 100%; + white-space: nowrap; + text-align: center; +} +.podcast-lef2t > img:before{ + content: ""; + display: inline-block; + vertical-align: middle; + width: 0; + /* adjust for white space between pseudo element and next sibling */ + margin-right: -.25em; + /* stretch line height */ + height: 100%; +} +.podcast-left > img:before{ + text-align: right; +} +.podcast-left { + display: table-cell; + text-align: right; + vertical-align: middle; + white-space: normal; + width: 40%; + height:100%; + padding:0px; +} +.podcast-right{ + display: inline-block; + vertical-align: middle; + text-align: left; + white-space: normal; + padding: 0px; + width: 95%; +} diff --git a/app/javascript/css/printable.scss b/app/javascript/css/printable.scss new file mode 100644 index 0000000000000000000000000000000000000000..077f86823e362a5f561c3d964bad051f54961cc0 --- /dev/null +++ b/app/javascript/css/printable.scss @@ -0,0 +1,24 @@ +@media print { + /* General rules for printing. */ + body { + background: transparent none; + } + + .btn-hint, btn-answer { + display:none; + } + + .answer, .hint, .edit, .report-a-bug { + position: absolute; + top: 0; + left:0; + width:0; + height:0; + overflow: hidden; + visibility: hidden; + } + + .chat-modal { + display: none; + } +} diff --git a/app/javascript/css/quiz.scss b/app/javascript/css/quiz.scss new file mode 100644 index 0000000000000000000000000000000000000000..fefff2cd81222c6a9bac6e133066ad04b983c280 --- /dev/null +++ b/app/javascript/css/quiz.scss @@ -0,0 +1,164 @@ +$body-bg: #fff !global; +$font-size-base: 20px !global; +$light-yellow-highlight: rgba(255,245,125, 0.6); +$answer-selected: rgba(240,235,115, 0.8); +$correct-answer: rgba(115,240,115, 0.8); +$incorrect-answer: rgba(240,115,115, 0.8); +$feedback-answer: rgba(140,140,250, 0.8); +$quiz-question-separation: 5vh; +$quiz-internal-question-separation: 1vh; +$quiz-internal-answer-separation: 0.5vh; + + + +section.quiz-question { + border: 1px solid $butter-dark; + border-left: 5px solid $butter-dark; + border-radius: 5px; + padding-left: $quiz-internal-question-separation; + background-color: lighten( $butter-light, 30%) +} + +.quiz-question-elements { + padding-bottom: $quiz-internal-question-separation; + display:none; /* on purpose: don't display question texts */ +} + +/* +.correct .quiz-option, +.option-row.correct>label.quiz-option, +.feedback-correct-answer, +.feedback-set-correct-answer { + background-color: $correct-answer; + background-opacity: 0.3; +} + +.incorrect .quiz-option, +.option-row.incorrect>label.quiz-option, +.feedback-incorrect-answer, +.feedback-set-incorrect-answer { + background-color: $incorrect-answer; + background-opacity: 0.3; +} +*/ + +.quiz-feedback { + display: inline-block; + vertical-align: middle; + text-align:left; + position: relative; + z-index: 5; + font-weight:normal; + line-height:normal; + padding: 4 0 4 0; +} + +.option-row div { + padding-right: 0px; +} + +.feedback-answer { + /* background-color: $feedback-answer; + */ + background-opacity: 0.3; +} + + +.tick-mark { + display:none; + padding-top: 2px; +} + +/* per Martin: no tick marks */ +.correct { + .tick-mark { + display:inline; + .glyphicon-ok { + color: $correct-answer; + } + .glyphicon-remove { + display:none; + } + } +} + +.incorrect { + .tick-mark { + display:inline; + .glyphicon-remove { + color: $incorrect-answer; + } + .glyphicon-ok { + display:none; + } + } +} + +.col-max-xs-1 { + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; + float:left; + width:22px; + max-width: 8.333333333333332%; +} + +/* ---- */ + +.quiz-feedback-row { + max-height:0; + height:auto; + overflow:hidden; + -webkit-transition: all 0.8s ease-in-out; + -moz-transition: all 0.8s ease-in-out; + -o-transition: all 0.8s ease-in-out; + transition: all 0.8s ease-in-out; + padding-bottom: 0; +} + +.show-feedback { + max-height:300px; +} + +label.quiz-option { + margin-bottom: 0px; +} + +.correct .quiz-option { +} + +.quiz-option-control { + margin-right:5px !important; +} + +.all-that-apply-submit-btn, +.fill-in-the-blank-submit-btn { + margin-top: 15px; + margin-bottom: 15px; +} + +.row.answer-and-feedback { + margin-bottom: $quiz-internal-answer-separation; +} + +.quiz-option, +.quiz-feedback { + line-height: 1.2; + padding-top: .2em; + padding-bottom: .2em; +} + +.fill-in-the-blank.correct { + background-color: $correct-answer; +} + +//.fill-in-the-blank-wrong-text, +.fill-in-the-blank.incorrect { + background-color: $incorrect-answer; +} + +.feedback-text { + color: blue; + font-style: italic; +} \ No newline at end of file diff --git a/app/javascript/images/dtulogo.svg b/app/javascript/images/dtulogo.svg new file mode 100644 index 0000000000000000000000000000000000000000..cafd65237441a572b488e69399aae39b570dc513 --- /dev/null +++ b/app/javascript/images/dtulogo.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + viewBox="0 0 51.785331 75.5428" + height="75.542801" + width="51.785332" + xml:space="preserve" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="dtulogo.svg"><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1313" + inkscape:window-height="924" + id="namedview14" + showgrid="true" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:zoom="3.3638598" + inkscape:cx="39.711236" + inkscape:cy="-34.847759" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:current-layer="svg2"><inkscape:grid + type="xygrid" + id="grid3342" + originx="-0.40638376" + originy="-1166.8806" /></sodipodi:namedview><metadata + id="metadata8"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs6"><clipPath + id="clipPath18" + clipPathUnits="userSpaceOnUse"><path + id="path16" + d="m 0,841.89 595.276,0 L 595.276,0 0,0 Z" + inkscape:connector-curvature="0" /></clipPath></defs><g + transform="matrix(1.3333333,0,0,-1.3333333,-457.91652,597.92572)" + id="g10"><g + id="g12"><g + clip-path="url(#clipPath18)" + id="g14"><g + transform="translate(345.9375,448.4443)" + id="g20"><path + id="path22" + style="fill:#848282;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 0,0 c -0.154,0 -0.249,-0.047 -0.318,-0.114 -0.069,-0.07 -0.114,-0.162 -0.114,-0.318 l 0,-19.712 c 0,-0.154 0.045,-0.248 0.114,-0.316 0.069,-0.068 0.164,-0.114 0.318,-0.114 l 5.156,0 c 2.003,0 3.225,0.455 3.965,1.414 1.093,1.308 1.128,3.422 1.128,6.661 l 0,4.423 c 0,3.24 -0.035,5.352 -1.128,6.661 C 8.381,-0.455 7.159,0 5.156,0 Z m 2.84,-2.405 1.818,0 c 0.803,0 1.282,-0.131 1.654,-0.576 0.572,-0.687 0.621,-2.074 0.621,-4.869 l 0,-4.875 c 0,-2.796 -0.049,-4.181 -0.621,-4.869 -0.372,-0.445 -0.851,-0.575 -1.654,-0.575 l -1.818,0 z m 31.317,1.973 c 0,0.156 -0.047,0.248 -0.115,0.318 C 33.975,-0.047 33.879,0 33.726,0 l -2.411,0 c -0.154,0 -0.248,-0.047 -0.316,-0.114 -0.069,-0.07 -0.115,-0.162 -0.115,-0.318 l 0,-14.552 c 0,-1.519 -0.115,-2.421 -0.608,-2.963 -0.335,-0.367 -0.809,-0.547 -1.471,-0.547 -0.604,0 -1.059,0.167 -1.407,0.55 -0.466,0.513 -0.608,1.386 -0.608,2.96 l 0,14.552 c 0,0.156 -0.048,0.248 -0.117,0.318 C 26.606,-0.047 26.512,0 26.356,0 l -2.408,0 c -0.155,0 -0.25,-0.047 -0.316,-0.114 -0.07,-0.07 -0.115,-0.162 -0.115,-0.318 l 0,-14.556 c 0,-2.119 0.288,-3.448 1.129,-4.374 0.875,-0.962 2.198,-1.473 4.201,-1.473 2.026,0 3.331,0.543 4.133,1.476 0.944,1.095 1.177,2.403 1.177,4.371 z M 18.599,-20.144 c 0,-0.154 -0.045,-0.248 -0.114,-0.316 -0.069,-0.068 -0.163,-0.114 -0.316,-0.114 l -2.638,0 c -0.153,0 -0.249,0.046 -0.316,0.114 -0.07,0.068 -0.115,0.162 -0.115,0.316 l 0,17.543 -3.095,0 c -0.155,0 -0.248,0.046 -0.318,0.115 -0.069,0.068 -0.116,0.163 -0.116,0.317 l 0,1.737 c 0,0.156 0.047,0.248 0.116,0.318 C 11.757,-0.047 11.85,0 12.005,0 l 9.689,0 c 0.156,0 0.25,-0.047 0.32,-0.114 0.065,-0.07 0.113,-0.162 0.113,-0.318 l 0,-1.737 c 0,-0.154 -0.048,-0.249 -0.113,-0.317 -0.07,-0.069 -0.164,-0.115 -0.32,-0.115 l -3.095,0 z" + inkscape:connector-curvature="0" /></g><g + transform="translate(382.2764,417.5732)" + id="g24"><path + id="path26" + style="fill:#bf2033;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 0,0 -8.266,-4.337 c -10.701,4.162 -11.604,4.162 -22.309,0 L -38.839,0 l 8.264,4.341 c 10.705,-4.164 11.608,-4.164 22.309,0 z m 0,-10.724 -8.266,-4.339 c -10.701,4.165 -11.604,4.165 -22.309,0 l -8.264,4.339 8.264,4.339 c 10.705,-4.163 11.608,-4.163 22.309,0 z m 0,-10.723 -8.266,-4.339 c -10.701,4.162 -11.604,4.162 -22.309,0 l -8.264,4.339 8.264,4.337 c 10.705,-4.163 11.608,-4.163 22.309,0 L 0,-21.447" + inkscape:connector-curvature="0" /></g></g></g></g></svg> \ No newline at end of file diff --git a/app/javascript/images/kunlogo.png b/app/javascript/images/kunlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..45991ffd89c5e2347301095b2618f1bb4038282e Binary files /dev/null and b/app/javascript/images/kunlogo.png differ diff --git a/app/javascript/images/wmd-buttons.png b/app/javascript/images/wmd-buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..50b37090363e6757e7bd0ba75cd1e0dfaabd13d2 Binary files /dev/null and b/app/javascript/images/wmd-buttons.png differ diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js new file mode 100644 index 0000000000000000000000000000000000000000..1b928b085bf668eec678a8532de69a5a3551b231 --- /dev/null +++ b/app/javascript/packs/application.js @@ -0,0 +1,47 @@ +/* eslint no-console:0 */ +// This file is automatically compiled by Webpack, along with any other files +// present in this directory. You're encouraged to place your actual application logic in +// a relevant structure within app/javascript and only use these pack files to reference +// that code so it'll be compiled. +// +// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate +// layout file, like app/views/layouts/application.html.erb + + +// Uncomment to copy all static images under ../images to the output folder and reference +// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>) +// or the `imagePath` JavaScript helper below. +// +//const images = require.context('../images', true); +//const imagePath = (name) => images(name, true); + +import $ from 'jquery'; +window.$ = $; +import 'jquery-ujs'; +import 'bootstrap/dist/js/bootstrap'; +import 'underscore'; +import 'bootstrap-treeview'; +import { ClientDebug, stringifySafe, serializerSafe } from 'dtu_core_assets'; + +window.ClientDebug = ClientDebug; +window.stringifySafe = stringifySafe; +window.serializerSafe = serializerSafe; + +import '../src/utils'; +import '../src/nav'; +import '../src/exercise'; +import '../src/client-flash'; +import '../src/modal'; +import '../src/quiz'; + +// +// Pages +// + +import '../src/md-page'; +import '../src/page-index'; +import '../src/admin'; + +import '../src/page-load'; + +console.log('LOADED'); diff --git a/app/javascript/packs/edit-page.js b/app/javascript/packs/edit-page.js new file mode 100644 index 0000000000000000000000000000000000000000..fecd125f8bdb2935faf64392912d95087fa43d68 --- /dev/null +++ b/app/javascript/packs/edit-page.js @@ -0,0 +1,38 @@ +import $ from 'jquery'; +window.$ = $; +import 'jquery-ujs'; +import 'bootstrap/dist/js/bootstrap'; +import 'underscore'; +import 'bootstrap-treeview'; +import { ClientDebug, stringifySafe, serializerSafe } from 'dtu_core_assets'; + +window.ClientDebug = ClientDebug; +window.stringifySafe = stringifySafe; +window.serializerSafe = serializerSafe; + +import Markdown from 'pagedown-extra/pagedown/Markdown.Converter'; + +window.Markdown = { ...Markdown, ...require('pagedown-extra/pagedown/Markdown.Sanitizer') }; + +require('pagedown-extra/pagedown/Markdown.Editor'); +require('pagedown-extra/Markdown.Extra'); + +import 'feedbackjs/dist/feedback.js'; + +import '../src/utils'; +import '../src/nav'; +import '../src/exercise'; +import '../src/client-flash'; +import '../src/modal'; +import '../src/quiz'; +import '../src/editing-directives'; +import MJPD from '../src/mathjax-editing'; +window.MJPD = MJPD; + +// +// Pages +// + +import '../src/md-page'; +import '../src/page-editor'; +import '../src/page-load'; diff --git a/app/javascript/packs/styles.scss b/app/javascript/packs/styles.scss new file mode 100644 index 0000000000000000000000000000000000000000..32dfea4e737d4df5ad5215c0eb1efb7b7210bf9c --- /dev/null +++ b/app/javascript/packs/styles.scss @@ -0,0 +1,53 @@ +@import '~bootstrap/dist/css/bootstrap'; + +@import '~dtu_core_assets/index.scss'; +@import '~feedbackjs/src/feedback.scss'; + +@import '../css/base-style.scss'; + +body { + font-family: $font_name; + font-size:15px; + line-height:1.45; + color:#3f3f3f; + background-color:#f6f6f6 +} + +.only { + display: none; +} + +@import "../css/home"; + +@import "../css/agenda"; + +@import "../css/enotes"; + +@import "../css/nav"; + +@import "../css/exercise"; + +@import "../css/podcast"; + +@import "../css/admin"; + +@import "../css/edit"; + +@import "../css/pages"; + +@import "../css/quiz"; + +@import "../css/feedback"; + +@import "../css/printable"; + +div.container { + text-align: left; +} + +@media (min-width: 992px) { + .modal-lg { + width: 90vw; + max-height: 90vh; + } +} diff --git a/app/javascript/src/admin.js b/app/javascript/src/admin.js new file mode 100644 index 0000000000000000000000000000000000000000..f30b5bf3b3b5b71623ce66735236a9f90edd814c --- /dev/null +++ b/app/javascript/src/admin.js @@ -0,0 +1,707 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__ + * DS206: Consider reworking classes to avoid initClass + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +//TODO: Move all the loose window functions to the AdminPage class + +window.toQuizString = date => (`0${date.getDate()}`).slice(-2) + '/' + (`0${date.getMonth() + 1}`).slice(-2) + "-" + (`0${date.getYear()}`).slice(-2) + " " + (`0${date.getHours()}`).slice(-2) + ":" + (`0${date.getMinutes()}`).slice(-2); + +window.waitingDialog = window.waitingDialog || ( function($) { + const dialog_html = `\ +<div id="admin-modal" class="modal fade" data-backdrop="static" data-keyboard="false" + tabindex="-1" role="dialog" aria-hidden="true" + style="padding-top:15%; overflow-y:scroll;"> + <div class="modal-dialog modal-m"> + <div class="modal-content"> + <div class="modal-header"> + <h3 style="margin:0;"></h3> + </div> + <div class="modal-body"> + <div class="progress progress-striped active" style="margin-bottom:0;"> + <div class="progress-bar" style="width: 100%"> + </div> + </div> + </div> + </div> + </div> +</div>\ +`; + const $dialog = $(dialog_html); + + const x = { + show(message, options) { + if (!options) { options = {}; } + if (!message) { message = 'Loading'; } + const settings = $.extend({ + dialogSize: 'm', + progressType: '', + onHide: null + }, options); + + $dialog.find('.modal-dialog'). + attr('class', 'modal-dialog'). + addClass(`modal-${settings.dialogSize}`); + $dialog.find('.progress-bar').attr('class', 'progress-bar'); + if (settings.progressType) { + $dialog.find('.progress-bar'). + addClass(`progress-bar-${settings.progressType}`); + } + $dialog.find('h3').text(message); + + if (typeof settings.onHide === 'function') { + $dialog.off('hidden.bs.modal').on('hidden.bs.modal', e => settings.onHide.call($dialog)); + } + + return $dialog.modal(); + }, + hide() { + return $dialog.modal('hide'); + } + }; + + return x; +}(jQuery)); + + +window.startGetPDFJobPoller = function(jobid) { + console.log(`Starting getpdf job poll for ${jobid}`); + let max_counts = 100; + var poller = function() { + const success = function(data) { + let lfa; + waitingDialog.hide(); + console.log(`Success in getting getpdf job poll ${max_counts}`); + console.dir(data); + if (!data.hasOwnProperty('status')) { + console.log("No status field!"); + return; + } + $(`.getpdf_status_${data._id}`).text(data.status); + if ($('#current-getpdf-job').data('getpdfjobid') === data._id) { + $('#current-getpdf-job .getpdf_job_status').text(data.status); + $('#current-getpdf-job .getpdf_job_lastRunAt').text(toQuizString(new Date(data.lastRunAt))); + lfa = "N/A"; + if (data.lastFinishedAt) { + lfa = toQuizString(new Date(data.lastFinishedAt)); + } + $('#current-getpdf-job .getpdf_job_lastFinishedAt').text(lfa); + } + if ((data.status !== "running") || (max_counts < 0)) { + return location.reload(); + } else { + if (lfa === "N/A") { + return setTimeout(poller, 2000); + } + } + }; + + const fail = function() { + console.error(`Failed to get getpdf job poll ${max_counts}`); + return setTimeout(poller, 2000); + }; + + let path = window.ADMIN_CONFIG.urls.getpdf_job_url; + path = path.replace('JOB_ID', jobid); + + max_counts -= 1; + + const ajax_parms = { + method: "GET", + url: path + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + }; + + return setTimeout(poller, 2000); +}; + +window.startAllGetPDFPollers = function(running_getpdf) { + console.dir(running_getpdf); + return running_getpdf.forEach(job => window.startGetPDFJobPoller(job._id)); +}; + +window.updateCourseWebsite = function(event, path) { + const success = function() { + console.log('updateCourseWebsite: Success'); + waitingDialog.hide(); + return location.reload(); + }; + + const fail = function() { + console.error('updateCourseWebsite: Failed to update'); + return waitingDialog.hide(); + }; + + waitingDialog.show('Updating webNotes...'); + + const ajax_parms = { + method: "GET", + url: path + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); +}; + + + + +window.buildEnotes = function(event, path) { + const success = function(data) { + console.log('buildEnotes: Success'); + waitingDialog.hide(); + console.dir(data); + location.hash = 'sharelatex'; + $('#current-getpdf-job').data('getpdfjobid', data._id); + return startGetPDFJobPoller(data._id); + }; + + const fail = function() { + console.error('buildEnotes: Failed to compile enotes'); + return waitingDialog.hide(); + }; + + waitingDialog.show('Starting eNote Compile...'); + + const ajax_parms = { + method: "GET", + url: path + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); +}; + +window.updateEnotes = function(event, path) { + const success = function() { + console.log('updateEnotes: Success'); + waitingDialog.hide(); + location.hash = 'sharelatex'; + return location.reload(); + }; + + const fail = function() { + console.error('updateEnotes: Failed to update enotes'); + return waitingDialog.hide(); + }; + + waitingDialog.show('Updating eNotes...'); + + const ajax_parms = { + method: "GET", + url: path + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); +}; + +window.updateFileManager = function(event, path) { + const success = function() { + console.log('updateFileManager: Success'); + waitingDialog.hide(); + location.hash = 'filemanager'; + return location.reload(); + }; + + const fail = function() { + console.error('updateFileManager: Failed to update file manager'); + return waitingDialog.hide(); + }; + + waitingDialog.show('Updating File Manager...'); + + const ajax_parms = { + method: "GET", + url: path + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); +}; + + +class AdminPage { + static initClass() { + + // + // Data + // + + this.instance = null; + } + + constructor(urls, course_id) { + const self = this; + + if (AdminPage.instance) { + console.error("Multiple AdminPage"); + return; + } + + AdminPage.instance = this; + + this.urls = urls; + this.course_id = course_id; + + if (typeof console !== 'undefined' && console !== null) { + console.log(`AdminPage page for ${course_id}`); + } + if (typeof console !== 'undefined' && console !== null) { + console.log(urls); + } + } + + + static getGetPDFJobInfo(event, path) { + const success = function(data) { + waitingDialog.hide(); + console.log('getGetPDFJobInfo: Success'); + console.dir(data); + const dialog = $("#getpdf_job_logs"); + dialog.find(".modal-title").text("Job Logs"); + + const logs = (__guard__(data !== null ? data.data : undefined, x => x.logs) || ['no logs!']).map(x => x).join("\n"); + dialog.find(".modal-body").empty(); + dialog.find(".modal-body").html('<pre></pre>'); + dialog.find(".modal-body pre").text(logs); + return dialog.modal().show(); + }; + // location.hash = 'sharelatex' + // location.reload() + + const fail = function() { + console.error('getGetPDFJobInfo: Failed to update enotes'); + return waitingDialog.hide(); + }; + + waitingDialog.show('Getting Conversion Logs'); + + const ajax_parms = { + method: "GET", + url: path + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + static cancelGetPDFJob(event, path) { + const success = function(data) { + waitingDialog.hide(); + location.hash = 'sharelatex'; + return location.reload(); + }; + + const fail = function() { + console.error('cancelGetPDFJob: Failed to cancel'); + return waitingDialog.hide(); + }; + + waitingDialog.show('Cancelling Job'); + + const ajax_parms = { + method: "GET", + url: path, + data: JSON.stringify({}, null, 2) + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + static publishEnotes(event, path) { + const success = function() { + console.log('publishEnotes: Success'); + waitingDialog.hide(); + location.hash = 'sharelatex'; + return location.reload(); + }; + + const fail = function() { + console.error('publishEnotes: Failed to publish eNotes'); + return waitingDialog.hide(); + }; + + waitingDialog.show('Publishing eNotes...'); + + const ajax_parms = { + method: "GET", + url: path, + data: JSON.stringify({}, null, 2) + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + static showEnotes(event, path) { + event.preventDefault(); + const success = function(data) { + let title; + waitingDialog.hide(); + console.log('showEnotes: Success'); + const dialog = $("#getpdf_job_logs"); + if (path.indexOf("staging") === -1) { + title = "Enotes"; + } else { + title = "Enotes Staging"; + } + dialog.find(".modal-title").text(title); + dialog.find(".modal-body").html(data); + console.dir(dialog.find(".modal-body")); + return dialog.modal().show(); + }; + // location.hash = 'sharelatex' + // location.reload() + + const fail = function() { + console.error('showEnotes: Failed to query eNotes'); + return waitingDialog.hide(); + }; + + waitingDialog.show("Getting eNotes"); + console.log(`Getting eNotes ${path}`); + + const ajax_parms = { + method: "GET", + url: path, + dataType: 'html' + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + // + // course operations + // + + static changeCourseNumber(event, path, url) { + + let new_value; + const re = /[0-9]{6}/g; + const matches = []; + + while (true) { + const m = re.exec(url); + if (!m) { break; } + delete m.input; + matches.push(m); + } + + if (matches.length > 0) { + new_value = matches[matches.length - 1][0]; + } else { + flash('alert-danger', "URL must be in the form https://cn.inside.dtu.dk/cnnet/element/123456"); + return; + } + + + console.log(path); + const success = function(data) { + console.log('changeCourseNumber: Success'); + waitingDialog.hide(); + flash('alert-success', data.message); + return location.reload(); + }; + + const fail = function() { + console.error('changeCourseNumber: Failed to change course number'); + waitingDialog.hide(); + return flash('alert-danger', 'Failed to update course number'); + }; + + waitingDialog.show('Change course number...'); + + const ajax_parms = { + method: "GET", + url: path, + data: {number:new_value} + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + + // + // feedback operations + // + static thumbnailNotFound(img) { + img.onerror = null; + return $(img).replaceWith($("<p><b>Thumbnail:</b> not found<p>")); + } + + static getSelectedIds() { + const ids = $('.select-feedback-checkbox:checkbox:checked').map(function() { + if ($(this).prop('checked')) { return parseInt($(this).data('feedback-id'), 10); } + }); + + return (ids.filter(id => !!id)).get(); + } + + static selectFeedback(event) { + let text; + const checkbox = $(event.target); + const new_allow = checkbox.prop('checked'); + console.log(`selectFeedback ${new_allow}`); + const ids = this.getSelectedIds(); + + const row = checkbox.closest("tr"); + if (ids.length === 1) { + text = row.find("td.feedback-text div").text(); + $("#feedback-text").text(text); + $("button.feedback-reply").attr('disabled', false); + $("#feedback-comment").attr('disabled', false); + return $("#feedback-comment").text(""); + } else { + $("#feedback-text").text(""); + $("button.feedback-reply").attr('disabled', true); + return $("#feedback-comment").attr('disabled', true); + } + } + + static submitFeedback(event, path) { + const card = $(event.target).closest(".feedback-card"); + if (!card) { return; } + const feedback_id = card.data("feedbackid"); + const comment = card.find("textarea.feedback-reply").val(); + const status = card.find(".feedback-status").val(); + + path = path.replace('FEEDBACK_ID', feedback_id); + + console.log(`submitFeedback c:${comment} s:${status}`); + const success = function(data) { + console.log('submitFeedback: Success'); + flash('alert-success', data.message); + return window.location.reload(); + }; + + const fail = function() { + console.error('submitFeedback: Failed'); + return flash('alert-danger', 'Failed to submit response'); + }; + + const ajax_parms = { + method: "PUT", + url: path, + data: JSON.stringify({ reply: comment, status }) + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + + + static setFeedbackComment(event, path) { + const ids = this.getSelectedIds(); + const comment = $("#feedback-comment").val(); + if (ids.length < 1) { + return; + } + + path = path.replace('FEEDBACK_ID', ids[0].toString()); + + console.log(`setFeedbackComment c:${comment}`); + const success = function(data) { + console.log('setFeedbackComment: Success'); + flash('alert-success', data.message); + return window.location.reload(); + }; + + const fail = function() { + console.error('setFeedbackComment: Failed'); + return flash('alert-danger', 'Failed to set reply comment'); + }; + + const ajax_parms = { + method: "PUT", + url: path, + data: JSON.stringify({ reply: comment }) + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + static deleteAllSelected(event, path) { + const ids = this.getSelectedIds(); + + console.dir(ids); + + const success = function(data) { + console.log('deleteAllSelected: Success'); + flash('alert-success', data.message); + return window.location.reload(); + }; + + const fail = function() { + console.error('deleteAllSelected: Failed'); + return flash('alert-danger', 'Failed to delete feedbacks'); + }; + + const ajax_parms = { + method: "DELETE", + url: path, + data: JSON.stringify({ ids}) + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + static setAllowFeedback(event, path) { + const new_allow = $(event.target).prop('checked'); + console.log(`ALLOW ${new_allow}`); + + const success = data => console.log('setAllowFeedback: Success'); + + const fail = () => console.error('setAllowFeedback: Failed'); + + const ajax_parms = { + method: "PUT", + url: path, + data: JSON.stringify({ allow_feedback: new_allow}) + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + // TODO: combine this with setAllowFeedback; make sure we have the right JSON payload (allow_chat, allow_feedback) + static setAllowChat(event, path) { + const new_allow = $(event.target).prop('checked'); + console.log(`ALLOW ${new_allow}`); + + const success = data => console.log('setAllowChat: Success'); + + const fail = () => console.error('setAllowChat: Failed'); + + const ajax_parms = { + method: "PUT", + url: path, + data: JSON.stringify({ allow_chat: new_allow}) + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + static changeFeedbackStatus(event, path) { + const new_status = $(event.target).val(); + console.log(new_status); + + const success = data => console.log('changeFeedbackStatus: Success'); + + const fail = () => console.error('changeFeedbackStatus: Failed'); + + const ajax_parms = { + method: "PUT", + url: path, + data: JSON.stringify({ status: new_status}) + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + static deleteFeedback(event, path) { + console.log(path); + const success = function(data) { + console.log('deleteFeedback: Success'); + waitingDialog.hide(); + flash('alert-success', data.message); + + return AdminPage.reloadFeedbackGrid(); + }; + + const fail = function() { + console.error('deleteFeedback: Failed'); + waitingDialog.hide(); + return flash('alert-danger', 'Failed to delete feedback'); + }; + + waitingDialog.show('Delete feedback ...'); + + const ajax_parms = { + method: "DELETE", + url: path, + data: {} + }; + + return $.ajax(ajax_parms) + .done(success) + .fail(fail); + } + + + static reloadFeedbackGrid() { + const self = this; + // document.location.reload(true) + return $('.feedback-grid-form').each( function(event) { + return $.get($(this).attr("action"), $(this).serialize(), data => $('.feedback-grid-table').html(data.table)); + }); + } + +// +// Init +// + + static isMyPage() { + const parts = window.location.pathname.split('/').filter( d => d); + if (parts.length < 1) { + return false; + } else if (parts.length > 1) { + return (parts[parts.length-1] === "admin") || (parts[parts.length-2] === "admin"); + } else { + return (parts[parts.length-1] === "admin"); + } + } + + static initPage() { + if (!window.ADMIN_CONFIG) { + if (typeof console !== 'undefined' && console !== null) { + console.log(`reloading because page was accessed\ +via turbolink and page isn't configured`); + } + window.location.reload(); + return; + } + if (AdminPage.instance !== null) { + AdminPage.instance = null; + } + window.admin_page = new AdminPage(window.ADMIN_CONFIG.urls, window.ADMIN_CONFIG.course_id); + return window.admin_page; + } +} +AdminPage.initClass(); + +window.AdminPage = AdminPage; + +function __guard__(value, transform) { + return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; +} diff --git a/app/javascript/src/client-flash.js b/app/javascript/src/client-flash.js new file mode 100644 index 0000000000000000000000000000000000000000..eb9a1b463e99e0f7a9bd55c8748b32c8f53f6a93 --- /dev/null +++ b/app/javascript/src/client-flash.js @@ -0,0 +1,27 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +window.flash = function(kind, message) { + const allowed_kinds = ['alert-success', + 'alert-info', + 'alert-warning', + 'alert-danger']; + + if (allowed_kinds.indexOf(kind) === -1) { + console.error(`ASSERT: invalid flash message kind ${kind}`); + } + + const now = new Date(); + const hh = (`0${now.getHours()}`).slice(-2); + const mm = (`0${now.getMinutes()}`).slice(-2); + const timestamp = hh + ":" + mm; + + const flash_msg = $(`<div class="alert ${kind} fade in">` + + '<button class="close" data-dismiss="alert">×</button>' + + '<b>' + timestamp + '</b>: ' + message + '</div>'); + + $("#flash-message").empty(); + return flash_msg.prependTo("#flash-message"); +}; diff --git a/app/javascript/src/edit-page.js b/app/javascript/src/edit-page.js new file mode 100644 index 0000000000000000000000000000000000000000..e84d2288d01e6ab7e465d05f569aaa439355f857 --- /dev/null +++ b/app/javascript/src/edit-page.js @@ -0,0 +1,23 @@ +//= require jquery +//= require jquery-ujs +// = re quire MathJax/MathJax.js +// = re quire MathJax/config/TeX-AMS_HTML-full.js +//= require pagedown-extra/pagedown/Markdown.Converter.js +//= require pagedown-extra/pagedown/Markdown.Sanitizer.js +//= require pagedown-extra/pagedown/Markdown.Editor.js +//= require pagedown-extra/Markdown.Extra.js +//= re qui re turbolinks +//= require underscore +//= require bootstrap/dist/js/bootstrap +//= require bootstrap-treeview +//= require utils +//= require nav.js +//= require render.js +//= require md-page.js +//= require client-flash.js +//= require json-stringify-safe +//= require dtu_core_app/application +//= require page-load.js +//= require page-editor.js +//= require mathjax-editing.js +//= require editing-directives.js diff --git a/app/javascript/src/editing-directives.js b/app/javascript/src/editing-directives.js new file mode 100644 index 0000000000000000000000000000000000000000..47cb263f66ca35fefe4e5149dfea4593b6b3c4e2 --- /dev/null +++ b/app/javascript/src/editing-directives.js @@ -0,0 +1,74 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS206: Consider reworking classes to avoid initClass + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +class EditingDirectives { + static initClass() { + + this.prototype.macros = null; + this.instance = null; + } + + constructor() { + EditingDirectives.instance = this; + } + + addDirectivesHandlers(editorObject, macros) { + this.macros = macros; + const converterObject = editorObject.getConverter(); + return converterObject.hooks.chain("preConversion", + (this.replaceDirectives).bind(this)); + } + + replaceDirectives(text) { + let expanded = text.replace(/^[\#]{7} include (.*)/, function(match_text, macro_name) { + let wrapped; + const macro = PageEditor.instance.macros[macro_name]; + if (macro) { + wrapped = "<div class='hidden inline'>" + + "$$\n" + + macro.split('\n'). + filter(x => !!x && x.replace(/\s/g, '').length). + map( x => x).join('\n') + + "$$\n" + + "</div>\n";//# c.f. page_compiler_service.rb + } else { + wrapped = "<div class='error-directive'> " + + macro_name + + " does not exist </div>\n"; + } + return wrapped; + }); + + const re = /^[\#]{7}\s*(begin|end):(only|hint|answer|question)([\s0-9a-zA-Z,]*)$/gm; + expanded = expanded.replace(re, function(match_text, beginend, kind, parameters) { + // this would be nice, but the sanitizing converter + // removes all this stuff... + let wrapped = `<div class='directive-region ${kind}'>` + + "<div class='directive-region-item-container'>" + + "<div class='directive-region-label'>" + + "<div>" + kind + "</div>" + + "</div>" + + "<div class='directive-region-item'>" + + "<p>" + beginend + "<b>:</b>" + kind + "</p>" + + //(parameters ? "(" + parameters + ")" : "") + + "</div>"+ + "</div>" + + "</div>\n";//# c.f. page_compiler_service.rb + if (parameters.replace(/^\s+|\s+$/g, "")) { + parameters = `(${parameters})`; + } + wrapped = `<b>${beginend}</b>:<b>` + + kind + "</b>" + parameters;// + "<br/>" + return wrapped; + }); + + return expanded; + } +} +EditingDirectives.initClass(); + +window.EditingDirectives = EditingDirectives; + diff --git a/app/javascript/src/exercise.js b/app/javascript/src/exercise.js new file mode 100644 index 0000000000000000000000000000000000000000..24b7f067908874d0c631464270c0003245954446 --- /dev/null +++ b/app/javascript/src/exercise.js @@ -0,0 +1,87 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// 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/ + +// note: using this method instead of display:none because of +// https://www.peterkrautzberger.org/0165/ +// which appears to be the cause of the super-painful issue #67 +const makeVisible = el => el.removeClass('hide'); + +window.replaceHints = function() { + let current_question = null; + $(".hint").each(function(i,x) { + let btn_style, hide, text; + const q = $(x).data('question'); + if (current_question) { + if (current_question !== q) { current_question = null; } + } + if ($(this).hasClass('hint')) { + text = "Show Hint!"; + btn_style = 'btn-hidden-directive btn-hint'; + } else { + text = "Show Answer!"; + btn_style = 'btn-hidden-directive btn-answer'; + } + if (current_question) { hide = 'hide'; } + const attributes = { + type: 'button', + name: 'btn1', + 'data-question': q, + value: text, + class: `btn btn-primary ${hide} ${btn_style}` + }; + current_question = q; + const button = $('<input/>').attr(attributes); + const me = $(this); + button.on('click', function(e) { + makeVisible(me); + const questionNo = $(me).data('question'); + // show the next button + $(this).nextAll(`input.btn[data-question='${questionNo}'].hide`).first().each(function(b) { + return $(this).removeClass('hide'); + }); + return button.remove(); + }); + return me.before(button); + }); + return $(".answer").each(function(i,x) { + const button = $('<input/>').attr({ + type: 'button', + name: 'btn1', + value: "Show Answer!", + class: 'btn btn-primary btn-hidden-directive btn-answer' + }); + const me = $(this); + button.on('click', function(e) { + makeVisible(me); + return button.remove(); + }); + return me.before(button); + }); +}; + +window.enforceGroupPermission = function(groups) { + console.dir(groups); + const group_names = (Array.from(groups).map((group) => group.group)); + console.log(`enforceGroupPermission: ${JSON.stringify(group_names)}`); + console.dir(group_names); + return $(".only").each(function(el) { + const me = $(this); + const only_groups = me.data("only-groups").split(" "); + console.log("only "); + console.log(only_groups); + const int = _.intersection(only_groups, group_names); + console.log("intersection "); + console.log(int); + if (int.length) { + return me.show(); + } + }); +}; + diff --git a/app/javascript/src/home.js b/app/javascript/src/home.js new file mode 100644 index 0000000000000000000000000000000000000000..634ec0421c6faf79b219049e74e013a601612420 --- /dev/null +++ b/app/javascript/src/home.js @@ -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/javascript/src/mathjax-editing.js b/app/javascript/src/mathjax-editing.js new file mode 100644 index 0000000000000000000000000000000000000000..7ba77162e5cb3c33e2f5e68b293e8033b34fbc9d --- /dev/null +++ b/app/javascript/src/mathjax-editing.js @@ -0,0 +1,329 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Based on the Stack Exchange's modification of the original mathjax-editing.js + * written by Davide Cervone. SE's version is available here: + * + * http://dev.stackoverflow.com/content/js/mathjax-editing.js + * + * Davide's original version can be found here: + * + * http://www.math.union.edu/~dpvc/transfer/mathjax/mathjax-editing.js + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +"use strict"; + +export default function MJPD() { + this.Editing = (function() { + var ready = false; // true after initial typeset is complete + var pending = false; // true when MathJax has been requested + var preview = null; // the preview container + var inline = "$"; // the inline math delimiter + var blocks, start, end, last, braces; // used in searching for math + var math; // stores math until markdone is done + var HUB = MathJax.Hub; + + // + // Runs after initial typeset + // + HUB.Queue(function() { + ready = true; + HUB.processUpdateTime = 50; // reduce update time so that we can cancel easier + HUB.Config({ + "HTML-CSS": { + EqnChunk: 10, + EqnChunkFactor: 1 + }, + // reduce chunk for more frequent updates + SVG: { + EqnChunk: 10, + EqnChunkFactor: 1 + } + }); + }); + + // + // The pattern for math delimiters and special symbols + // needed for searching for math in the page. + // + var SPLIT = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i; + + // + // The math is in blocks i through j, so + // collect it into one block and clear the others. + // Replace &, <, and > by named entities. + // For IE, put <br> at the ends of comments since IE removes \n. + // Clear the current math positions and store the index of the + // math, then push the math string onto the storage array. + // + function processMath(i, j, preProcess) { + var block = blocks.slice(i, j + 1).join("").replace(/&/g, "&") // use HTML entity for & + .replace(/</g, "<") // use HTML entity for < + .replace(/>/g, ">"); // use HTML entity for > + + if (HUB.Browser.isMSIE) { + block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n") + } + while (j > i) { + blocks[j] = ""; + j--; + } + blocks[i] = "@@" + math.length + "@@"; + if (preProcess) block = preProcess(block); + math.push(block); + start = end = last = null; + } + + + var capturingStringSplit; + if ("aba".split(/(b)/).length === 3) { + capturingStringSplit = function(str, regex) { + return str.split(regex) + } + } else { // IE8 + capturingStringSplit = function(str, regex) { + var result = [], + match; + if (!regex.global) { + var source = regex.toString(), + flags = ""; + source = source.replace(/^\/(.*)\/([im]*)$/, function(wholematch, re, fl) { + flags = fl; + return re; + }); + regex = new RegExp(source, flags + "g"); + } + regex.lastIndex = 0; + var lastPos = 0; + while (match = regex.exec(str)) { + result.push(str.substring(lastPos, match.index)); + result.push.apply(result, match.slice(1)); + lastPos = match.index + match[0].length; + } + result.push(str.substring(lastPos)); + return result; + } + } + + + // + // Break up the text into its component parts and search + // through them for math delimiters, braces, linebreaks, etc. + // Math delimiters must match and braces must balance. + // Don't allow math to pass through a double linebreak + // (which will be a paragraph). + // + function removeMath(text) { + start = end = last = null; // for tracking math delimiters + math = []; // stores math strings for latter + + // Except for extreme edge cases, this should catch precisely those pieces of the markdown + // source that will later be turned into code spans. While MathJax will not TeXify code spans, + // we still have to consider them at this point; the following issue has happened several times: + // + // `$foo` and `$bar` are varibales. --> <code>$foo ` and `$bar</code> are variables. + + var hasCodeSpans = /`/.test(text), + deTilde; + if (hasCodeSpans) { + text = text.replace(/~/g, "~T").replace(/(^|[^\\`])(`+)(?!`)([^\n]*?[^`\n])\2(?!`)/gm, function(wholematch) { + return wholematch.replace(/\$/g, "~D"); + }); + deTilde = function(text) { + return text.replace(/~([TD])/g, function(wholematch, character) { + return { + T: "~", + D: "$" + }[character]; + }) + }; + } else { + deTilde = function(text) { + return text; + }; + } + + + blocks = capturingStringSplit(text.replace(/\r\n?/g, "\n"), SPLIT); + + for (var i = 1, m = blocks.length; i < m; i += 2) { + var block = blocks[i]; + if (block.charAt(0) === "@") { + // + // Things that look like our math markers will get + // stored and then retrieved along with the math. + // + blocks[i] = "@@" + math.length + "@@"; + math.push(block); + } else if (start) { + // + // If we are in math, look for the end delimiter, + // but don't go past double line breaks, and + // and balance braces within the math. + // + if (block === end) { + if (braces) { + last = i + } else { + processMath(start, i, deTilde) + } + } else if (block.match(/\n.*\n/)) { + if (last) { + i = last; + processMath(start, i, deTilde) + } + start = end = last = null; + braces = 0; + } else if (block === "{") { + braces++ + } else if (block === "}" && braces) { + braces-- + } + } else { + // + // Look for math start delimiters and when + // found, set up the end delimiter. + // + if (block === inline || block === "$$") { + start = i; + end = block; + braces = 0; + } else if (block.substr(1, 5) === "begin") { + start = i; + end = "\\end" + block.substr(6); + braces = 0; + } + } + } + if (last) { + processMath(start, last, deTilde) + } + return deTilde(blocks.join("")); + } + + // + // Put back the math strings that were saved, + // and clear the math array (no need to keep it around). + // + function replaceMath(text) { + text = text.replace(/@@(\d+)@@/g, function(match, n) { + return math[n] + }); + math = null; + return text; + } + + // + // This is run to restart MathJax after it has finished + // the previous run (that may have been canceled) + // + function RestartMJ() { + pending = false; + HUB.cancelTypeset = false; // won't need to do this in the future + HUB.Queue(["Typeset", HUB, preview]); + } + + // + // When the preview changes, cancel MathJax and restart, + // if we haven't done that already. + // + function UpdateMJ() { + if (!pending && ready) { + pending = true; + HUB.Cancel(); + HUB.Queue(RestartMJ); + } + } + + // + // Save the preview ID and the inline math delimiter. + // Create a converter for the editor and register a preConversion hook + // to handle escaping the math. + // Create a preview refresh hook to handle starting MathJax. + // + function prepareWmdForMathJax(editorObject, wmdId, delimiters) { + preview = document.getElementById("wmd-preview" + wmdId); + inline = delimiters[0][0]; + + var converterObject = editorObject.getConverter(); + converterObject.hooks.chain("preConversion", removeMath); + converterObject.hooks.chain("postConversion", replaceMath); + editorObject.hooks.chain("onPreviewRefresh", UpdateMJ); + } + + return { + prepareWmdForMathJax: prepareWmdForMathJax + } + }()); +} + +// +// Set up MathJax to allow canceling of typesetting, if it +// doesn't already have that. +// +(function() { + var HUB = MathJax.Hub; + + if (!HUB.Cancel) { + + HUB.cancelTypeset = false; + var CANCELMESSAGE = "MathJax Canceled"; + + HUB.Register.StartupHook("HTML-CSS Jax Config", function() { + var HTMLCSS = MathJax.OutputJax["HTML-CSS"], + TRANSLATE = HTMLCSS.Translate; + HTMLCSS.Augment({ + Translate: function(script, state) { + if (HUB.cancelTypeset || state.cancelled) { + throw Error(CANCELMESSAGE) + } + return TRANSLATE.call(HTMLCSS, script, state); + } + }); + }); + + HUB.Register.StartupHook("SVG Jax Config", function() { + var SVG = MathJax.OutputJax["SVG"], + TRANSLATE = SVG.Translate; + SVG.Augment({ + Translate: function(script, state) { + if (HUB.cancelTypeset || state.cancelled) { + throw Error(CANCELMESSAGE) + } + return TRANSLATE.call(SVG, script, state); + } + }); + }); + + HUB.Register.StartupHook("TeX Jax Config", function() { + var TEX = MathJax.InputJax.TeX, + TRANSLATE = TEX.Translate; + TEX.Augment({ + Translate: function(script, state) { + if (HUB.cancelTypeset || state.cancelled) { + throw Error(CANCELMESSAGE) + } + return TRANSLATE.call(TEX, script, state); + } + }); + }); + + var PROCESSERROR = HUB.processError; + HUB.processError = function(error, state, type) { + if (error.message !== CANCELMESSAGE) { + return PROCESSERROR.call(HUB, error, state, type) + } + MathJax.Message.Clear(0, 0); + state.jaxIDs = []; + state.jax = {}; + state.scripts = []; + state.i = state.j = 0; + state.cancelled = true; + return null; + }; + + HUB.Cancel = function() { + this.cancelTypeset = true; + }; + } +}()); diff --git a/app/javascript/src/mathjax.js b/app/javascript/src/mathjax.js new file mode 100644 index 0000000000000000000000000000000000000000..8a8896cb0f22dbd6976fc197c2cb5298ccda4ca1 --- /dev/null +++ b/app/javascript/src/mathjax.js @@ -0,0 +1,332 @@ +/* Copied/modified from mathJax.js in StackEdit */ + +export default function() { + + console.log("Initializing MathJAX"); + + var mathJax = {}; + // mathJax.settingsBlock = mathJaxSettingsBlockHTML; + mathJax.defaultConfig = { + tex: "{}", + tex2jax: '{ inlineMath: [["$","$"],["\\\\\\\\(","\\\\\\\\)"]], displayMath: [["$$","$$"],["\\\\[","\\\\]"]], processEscapes: true }' + }; + + mathJax.onLoadSettings = function() { + utils.setInputValue("#input-mathjax-config-tex", mathJax.config.tex); + utils.setInputValue("#input-mathjax-config-tex2jax", mathJax.config.tex2jax); + }; + + mathJax.onSaveSettings = function(newConfig, event) { + newConfig.tex = utils.getInputJsValue("#input-mathjax-config-tex", event); + newConfig.tex2jax = utils.getInputJsValue("#input-mathjax-config-tex2jax", event); + }; + + /*jshint ignore:start */ + mathJax.onPagedownConfigure = function(converter) { + converter.hooks.chain("preConversion", removeMath); + converter.hooks.chain("postConversion", replaceMath); + }; + + var afterRefreshCallback; + mathJax.onAsyncPreview = function(callback) { + afterRefreshCallback = callback; + UpdateMJ(); + }; + + // From math.stackexchange.com... + + // + // The math is in blocks i through j, so + // collect it into one block and clear the others. + // Replace &, <, and > by named entities. + // For IE, put <br> at the ends of comments since IE removes \n. + // Clear the current math positions and store the index of the + // math, then push the math string onto the storage array. + // + function processMath(i, j, unescape) { + var block = blocks.slice(i, j + 1).join("") + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">"); + for (HUB.Browser.isMSIE && (block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n")); j > i;) blocks[j] = "", j--; + blocks[i] = "@@" + math.length + "@@"; + unescape && (block = unescape(block)); + math.push(block); + start = end = last = null; + } + + function removeMath(text) { + start = end = last = null; + math = []; + var unescape; + if (/`/.test(text)) { + text = text.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function(text) { + return text.replace(/\$/g, "~D") + }); + unescape = function(text) { + return text.replace(/~([TD])/g, + function(match, n) { + return { + T: "~", + D: "$" + }[n] + }) + }; + } else { + unescape = function(text) { + return text + }; + } + blocks = split(text.replace(/\r\n?/g, "\n"), splitDelimiter); + for (var i = 1, m = blocks.length; i < m; i += 2) { + var block = blocks[i]; + if ("@" === block.charAt(0)) { + // + // Things that look like our math markers will get + // stored and then retrieved along with the math. + // + blocks[i] = "@@" + math.length + "@@"; + math.push(block) + } else if (start) { + // Ignore inline maths that are actually multiline (fixes #136) + if (end == inline && block.charAt(0) == '\n') { + if (last) { + i = last; + processMath(start, i, unescape); + } + start = end = last = null; + braces = 0; + } + // + // If we are in math, look for the end delimiter, + // but don't go past double line breaks, and + // and balance braces within the math. + // + else if (block === end) { + if (braces) { + last = i + } else { + processMath(start, i, unescape) + } + } else { + if (block.match(/\n.*\n/)) { + if (last) { + i = last; + processMath(start, i, unescape); + } + start = end = last = null; + braces = 0; + } else { + if ("{" === block) { + braces++ + } else { + "}" === block && braces && braces-- + } + } + } + } else { + if (block === inline || "$$" === block) { + start = i; + end = block; + braces = 0; + } else { + if ("begin" === block.substr(1, 5)) { + start = i; + end = "\\end" + block.substr(6); + braces = 0; + } + } + } + + } + last && processMath(start, last, unescape); + return unescape(blocks.join("")) + } + + // + // Put back the math strings that were saved, + // and clear the math array (no need to keep it around). + // + function replaceMath(text) { + text = text.replace(/@@(\d+)@@/g, function(match, n) { + return math[n] + }); + math = null; + return text + } + + // + // This is run to restart MathJax after it has finished + // the previous run (that may have been canceled) + // + function RestartMJ() { + pending = false; + HUB.cancelTypeset = false; + HUB.Queue([ + "Typeset", + HUB, + preview + ]); + HUB.Queue(afterRefreshCallback); //benweet + } + + // + // When the preview changes, cancel MathJax and restart, + // if we haven't done that already. + // + function UpdateMJ() { + if (!pending /*benweet (we need to call our afterRefreshCallback) && ready */ ) { + pending = true; + HUB.Cancel(); + HUB.Queue(RestartMJ); + } + } + + var ready = false, + pending = false, + preview = null, + inline = "$", + blocks, start, end, last, braces, math, HUB = MathJax.Hub; + + // + // Runs after initial typeset + // + HUB.Queue(function() { + console.log("Config after initial typeset"); + ready = true; + HUB.processUpdateTime = 50; + HUB.Config({ + "HTML-CSS": { + EqnChunk: 10, + EqnChunkFactor: 1 + }, + SVG: { + EqnChunk: 10, + EqnChunkFactor: 1 + } + }) + }); + + + /*benweet + Don't hash inline math $...$ (see https://github.com/benweet/stackedit/issues/136) + var u = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i, r; + */ + + + // + // The pattern for math delimiters and special symbols + // needed for searching for math in the page. + // + var splitDelimiter = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i; + var split; + + if (3 === "aba".split(/(b)/).length) { + split = function(text, delimiter) { + return text.split(delimiter) + }; + } else { + split = function(text, delimiter) { + var b = [], + c; + if (!delimiter.global) { + c = delimiter.toString(); + var d = ""; + c = c.replace(/^\/(.*)\/([im]*)$/, function(a, c, b) { + d = b; + return c + }); + delimiter = RegExp(c, d + "g") + } + for (var e = delimiter.lastIndex = 0; c = delimiter.exec(text);) { + b.push(text.substring(e, c.index)); + b.push.apply(b, c.slice(1)); + e = c.index + c[0].length; + } + b.push(text.substring(e)); + return b + }; + } + + (function() { + var HUB = MathJax.Hub; + if (!HUB.Cancel) { + HUB.cancelTypeset = !1; + HUB.Register.StartupHook("HTML-CSS Jax Config", function() { + console.log("StartupHook('HTML-CSS Jax Config')"); + var HTMLCSS = MathJax.OutputJax["HTML-CSS"], + TRANSLATE = HTMLCSS.Translate; + HTMLCSS.Augment({ + Translate: function(script, state) { + if (HUB.cancelTypeset || state.cancelled) throw Error("MathJax Canceled"); + return TRANSLATE.call(HTMLCSS, script, state) + } + }) + }); + HUB.Register.StartupHook("SVG Jax Config", function() { + console.log("StartupHook('SVG Jax Config')"); + var SVG = MathJax.OutputJax.SVG, + TRANSLATE = SVG.Translate; + SVG.Augment({ + Translate: function(script, state) { + if (HUB.cancelTypeset || state.cancelled) throw Error("MathJax Canceled"); + return TRANSLATE.call(SVG, + script, state) + } + }) + }); + HUB.Register.StartupHook("TeX Jax Config", function() { + console.log("StartupHook('TeX Jax Config')"); + var TEX = MathJax.InputJax.TeX, + TRANSLATE = TEX.Translate; + TEX.Augment({ + Translate: function(script, state) { + if (HUB.cancelTypeset || state.cancelled) throw Error("MathJax Canceled"); + return TRANSLATE.call(TEX, script, state) + } + }) + }); + HUB.Register.StartupHook("End", function() { + console.log("MathJax Startup hook end"); + scroll_to_anchor(); + }); + HUB.Register.MessageHook("Math Processing Error", function(message) { + var err = { + type: 'rendering-error', + message: "Math Processing error from. ", + location: window.location.href, + info: message + }; + console.dir(err); + ClientDebug.send('info', err); + }); + HUB.Register.MessageHook("TeX Jax - parse error", function(message) { + var err = { + type: 'rendering-error', + message: "Tex Jax parse error. ", + location: window.location.href, + info: message + }; + console.dir(err); + ClientDebug.send('info', err); + }); + var PROCESSERROR = HUB.processError; + HUB.processError = function(error, state, type) { + if ("MathJax Canceled" !== error.message) return PROCESSERROR.call(HUB, error, state, type); + MathJax.Message.Clear(0, 0); + state.jaxIDs = []; + state.jax = {}; + state.scripts = []; + state.i = state.j = 0; + state.cancelled = true; + return null + }; + HUB.Cancel = function() { + this.cancelTypeset = true + } + } + }()); + /*jshint ignore:end */ + + window.mathJax = mathJax; +}; diff --git a/app/javascript/src/md-page.js b/app/javascript/src/md-page.js new file mode 100644 index 0000000000000000000000000000000000000000..c4c5440b62edaf8784600ae334cff0dc63fd4da0 --- /dev/null +++ b/app/javascript/src/md-page.js @@ -0,0 +1,151 @@ +import renderPage from './render'; +import { Feedback } from 'feedbackjs/dist/index'; + +window.Feedback = Feedback; + +class MdPage { + static initClass() { + + // c.f. page_compiler_service.rb + this.VERBATIM_HTML_START = "<div class='verbatim-html'>"; + this.VERBATIM_HTML_END = "</div><!-- verbatim-html -->"; + + // + // Data + // + + this.instance = null; + } + + constructor(config) { + const self = this; + self.config = config; + + if (MdPage.instance) { + console.error("Multiple MdPage"); + return; + } + + MdPage.instance = this; + + if (typeof console !== 'undefined' && console !== null) { + console.log("Markdown page"); + } + console.dir(config); + + const csrfToken = document.getElementsByName('csrf-token')[0].content; + if (config.allow_feedback) { + const feedbackOpts = { + endpoint: '/feedbacks', + headers: { 'X-CSRF-Token': csrfToken } + }; + this.feedback = new Feedback(feedbackOpts); + + const addOpenListener = (el) => el.addEventListener('click', () => this.feedback.open()); + [...document.querySelectorAll('.feedback-btn')].forEach(addOpenListener); + } else { + console.warn('no feedback ¯\\_(ツ)_/¯' ); + } + } + + static preConvertMarkdown(page) { + const output = []; + const block_no = 0; + let in_non_md_block = false; + let non_md_block = []; + const emitBlock = () => $(`<div id='pcm${block_no}'>${non_md_block.join('\n')}</div>`).appendTo(pcm); + var pcm = $("<div id='preConvertMarkdown'></div>").hide().appendTo("body"); + for (let line of Array.from(page.split(/\n/))) { + if (in_non_md_block) { + if (line === MdPage.VERBATIM_HTML_END) { + in_non_md_block = false; + emitBlock(); + non_md_block = []; + } else { + non_md_block.push(line); + } + } else { + if (line === MdPage.VERBATIM_HTML_START) { + in_non_md_block = true; + output.push(`<div class='pcm-paceholder' data-pcmid='pcm${block_no}'></div>`); + } else { + output.push(line); + } + } + } + + if (in_non_md_block) { emitBlock(); } + + const new_page = output.join("\n"); + return new_page; + } + + static postConvertMarkdown(page) { + const lineMapper = function(line) { + const m = line.match(/<div class='pcm-paceholder' data-pcmid='(pcm\d+)'><\/div>/); + if (m) { + const e = $(`#${m[1]}`); + console.dir(e); + const h = e.html(); + e.remove(); + return h; + } else { + return line; + } + }; + return page.split(/\n/).map(lineMapper).join('\n'); + } + + static showFullFeedbackImage(event, url) { + $(".full-feedback-image").attr('src', url); + return $("#full-feedback-image-modal").modal('show'); + } +// + // Init + // + + static isMyPage() { + return (typeof renderCoursePage === 'function'); + } + + static initPage() { + + // if !window.MD_PAGE_CONFIG? + // console?.log "reloading because page was accessed\ + // via turbolink and page isn't configured" + // window.location.reload() + // return + + if (MdPage.instance !== null) { + MdPage.instance = null; + } + + window.md_page = new MdPage(window.MD_PAGE_CONFIG); + + if (typeof window.Markdown === 'object') { + ClientDebug.send('info', { + type: 'rendering-info', + message: "MD Rendering starting. ", + location: window.location.href + }); + + renderPage(); + + return ClientDebug.send('info', { + type: 'rendering-info', + message: "MD Rendering complete. ", + location: window.location.href + }); + } else { + // if Markdown hasn't been loaded then we must reload the entire page -- + // we're turbolinking from a non-MD page to a MD page + if (typeof console !== 'undefined' && console !== null) { + console.log('Markdown is not loaded; forcing full reload'); + } + return location.reload(); + } + } +} +MdPage.initClass(); + +window.MdPage = MdPage; diff --git a/app/javascript/src/modal.js b/app/javascript/src/modal.js new file mode 100644 index 0000000000000000000000000000000000000000..890f0a168f60301191e1d0da0408868270fe7c08 --- /dev/null +++ b/app/javascript/src/modal.js @@ -0,0 +1,38 @@ +$(function() { + const default_modal_holder_id = 'modal-holder'; + const modal_selector = '.modal'; + + $(document).on('click', 'a[data-modal]', function() { + const location = $(this).attr('href'); + const modal_holder_id = $(this).attr('modal-holder') || default_modal_holder_id; + if (typeof console !== 'undefined' && console !== null) { + console.log(`Fetching modal from ${location}`); + } + + const success = data => $(`#${modal_holder_id}`).html(data). + find(modal_selector).modal(); + + + // Load modal dialog from server + $.ajax({type: 'GET',url: location, dataType: 'html', success}); + return false; + }); + + return $(document).on('ajax:success', + 'form[data-modal]', function(event, data, status, xhr){ + const url = xhr.getResponseHeader('Location'); + if (url) { + // Redirect to url + window.location = url; + } + + // Remove old modal backdrop + $('.modal-backdrop').remove(); + + // Replace old modal with new one + return $(modal_holder_selector).html(data). + find(modal_selector).modal(); + }, + + false); +}); diff --git a/app/javascript/src/nav.js b/app/javascript/src/nav.js new file mode 100644 index 0000000000000000000000000000000000000000..fd6b2e6f06c9408d1b94420abc216890e73a51d8 --- /dev/null +++ b/app/javascript/src/nav.js @@ -0,0 +1,26 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +$(window).on("scroll", function() { + const scrollTop = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop); + + const shrunk = $("nav").hasClass("shrink"); + + let toggle = false; + + // implement a hysteresis for bug 219 + if (!shrunk && (scrollTop > 50)) { + toggle = true; + } + if (shrunk && (scrollTop < 1)) { + toggle = true; + } + + if (toggle) { + $(".below-nav").toggleClass("below-shrunken-nav", !shrunk); + $("nav").toggleClass("shrink", !shrunk); + return $("#left-rail").toggleClass("shrink-rail", !shrunk); + } +}); diff --git a/app/javascript/src/page-editor.js b/app/javascript/src/page-editor.js new file mode 100644 index 0000000000000000000000000000000000000000..dfb0e419f67e7a26cc7d81605d76590617895733 --- /dev/null +++ b/app/javascript/src/page-editor.js @@ -0,0 +1,196 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS206: Consider reworking classes to avoid initClass + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +class PageEditor { + static initClass() { + + // + // Data + // + + this.instance = null; + } + + constructor(page, md, macros, urls) { + const self = this; + + if (PageEditor.instance) { + console.error("Multiple PageEditor"); + return; + } + + PageEditor.instance = this; + + this.urls = urls; + this.page = page; + this.md = md; + this.macros = macros; + + $("#wmd-input-dtu-course-editor").val(md); + + if (typeof console !== 'undefined' && console !== null) { + console.log("PageEditor page"); + } + } + + static save_page(e) { + if (typeof console !== 'undefined' && console !== null) { + console.log("save_page"); + } + const message = { content: $("#wmd-input-dtu-course-editor").val() }; + return PageEditor.ajax_page_operation('POST', window.location, null, null, message); + } + + static stop_editing(e) { + if (typeof console !== 'undefined' && console !== null) { + console.log("stop_editing"); + } + const message = { }; + const success = () => { window.location.href = PageEditor.instance.urls["view"]; }; + const url = PageEditor.instance.urls["stop_editing"]; + return PageEditor.ajax_page_operation('GET', url, success, null, message); + } + + static wrap_mode_changed(e) { + if (typeof console !== 'undefined' && console !== null) { + console.log("wrap_mode_changed"); + } + if ($(e.target).prop('checked')) { + return $("#wmd-input-dtu-course-editor").addClass('wrap-editor'); + } else { + return $("#wmd-input-dtu-course-editor").removeClass('wrap-editor'); + } + } + + static reload(e) { + if (typeof console !== 'undefined' && console !== null) { + console.log("reload"); + } + const message = { }; + const success = function(data) { + PageEditor.instance.macros = data.macros; + $('#wmd-input-dtu-course-editor').get(0).value = + $('#wmd-input-dtu-course-editor').get(0).value; + return PageEditor.editor.refreshPreview(); + }; + const url = PageEditor.instance.urls["edit"]; + return PageEditor.ajax_page_operation('GET', url, success, null, message); + } + + + static ajax_page_operation(method, + path, + success_callback, + error_callback, + message, + reload_on_success, + reload_on_failure) { + + message = message || {}; + + const to_bool = (x, default_val) => x || default_val; + + if (typeof console !== 'undefined' && console !== null) { + console.log("reload "); + } + if (typeof console !== 'undefined' && console !== null) { + console.log(reload_on_success); + } + reload_on_success = to_bool(reload_on_success, true); + reload_on_failure = to_bool(reload_on_failure, false); + if (typeof console !== 'undefined' && console !== null) { + console.log(reload_on_success); + } + + const success = function(data) { + if (typeof success_callback === 'function') { + success_callback(data); + } + return window.render_simple_json_response(data, "The operation succeeded"); + }; + + const fail = function(jqXHR, textStatus, errorThrown) { + if (typeof error_callback === 'function') { + error_callback(); + } + console.dir(jqXHR); + console.dir(textStatus); + console.dir(errorThrown); + return window.render_simple_json_response(JSON.parse(jqXHR.responseText), + undefined, + "The operation failed"); + }; + + const ajax_parms = { + method, + url: path, + dataType: 'json', + contentType: "application/json; charset=utf-8", + data: JSON.stringify(message, null, 2) + }; + + if (typeof console !== 'undefined' && console !== null) { + console.log(path); + } + + return $.ajax(ajax_parms).done(success).fail(fail); + } + + + static disable_all_commands() { + } + + static update_valid_commands() { + } + + + // + // Init + // + + static isMyPage() { + return PageEditor.getParameterByName('mode') === 'edit'; + } + + static initPage() { + if (!window.EDITOR_CONFIG) { + if (typeof console !== 'undefined' && console !== null) { + console.log(`editor not configured.\ +we assume this is because it is locked`); + } + return; + } + if (PageEditor.instance !== null) { + PageEditor.instance = null; + } + window.page_index = new PageEditor(window.EDITOR_CONFIG.page, + window.EDITOR_CONFIG.md, + window.EDITOR_CONFIG.macros, + window.EDITOR_CONFIG.urls); + return window.page_index; + } + + static getParameterByName(name, url) { + if (!url) { + url = window.location.href; + } + name = name.replace(/[\[\]]/g, "\\$&"); + const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`); + const results = regex.exec(url); + if (!results) { + return null; + } + if (!results[2]) { + return ''; + } + return decodeURIComponent(results[2].replace(/\+/g, " ")); + } +} +PageEditor.initClass(); + + +window.PageEditor = PageEditor; diff --git a/app/javascript/src/page-index.js b/app/javascript/src/page-index.js new file mode 100644 index 0000000000000000000000000000000000000000..957ee3389efa00f0a4ff0d1b09dbd5d49ff90b58 --- /dev/null +++ b/app/javascript/src/page-index.js @@ -0,0 +1,419 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS206: Consider reworking classes to avoid initClass + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +class PageIndex { + static initClass() { + + // + // Data + // + + this.all_commands = [ + "delete-page", + "new-page", + "rename-quiz" + ]; + this.modal_args = { + backdrop: 'static', // This disable for click outside event + keyboard: true // This for keyboard event + }; + + this.instance = null; + } + + constructor(urls, course_id) { + const self = this; + + if (PageIndex.instance) { + console.error("Multiple PageIndex"); + return; + } + + PageIndex.instance = this; + + this.urls = urls; + this.course_id = course_id; + + if (typeof console !== 'undefined' && console !== null) { + console.log(`PageIndex page for ${course_id}`); + } + if (typeof console !== 'undefined' && console !== null) { + console.log(urls); + } + + $('td:first :checkbox').each(function(d) { + return $(this).closest('tr').toggleClass('page-selected', this.checked); + }); + + $('.page-index-grid').on('click', 'tr', function(e) { + e.stopPropagation(); + return $(this).find('td:first :checkbox').trigger('click'); + }).on('click', ':checkbox.select-page-checkbox', function(e) { + e.stopPropagation(); + + $(this).closest('tr').toggleClass('page-selected', this.checked); + + const trs = $(this).closest('tr'); + if (this.checked) { + const f = this.false; + trs.siblings('tr.page-selected').toggleClass('page-selected', f); + } + if (this.checked) { + trs.siblings('tr').find('td:first :checkbox').prop('checked', false); + } + + return PageIndex.update_valid_commands(); + }); + + PageIndex.update_valid_commands(); + PageIndex.add_visibility_handlers(); + PageIndex.set_admin_sort(); + } + +// Status Dialog + + static show_status(description) { + $('#status-modal').modal(PageIndex.modal_args, 'show'); + $('#status-dismiss-button').prop('disabled', true); + return $('#status-modal-body').text(description || "Working..."); + } + + static dismiss_status(success, message) { + if (success) { + $('#status-dismiss-button').prop('disabled', false); + return $('#status-modal').modal('hide'); + } else { + $('#status-modal-body').text(message); + $('#status-dismiss-button').prop('disabled', false); + return $('#status-dismiss-button').click( function() { + $('#status-modal').modal('hide'); + return location.reload(); + }); + } + } + + +// Commands + + static disable_all_commands() { + } + + static update_valid_commands() { + } + + static get_selected_page_row() { + return $(".select-page-checkbox:checked"); + } + + static get_selected_page() { + return PageIndex.get_selected_page_row().data("page-name"); + } + + static selected_page_operation(op) { + const page = PageIndex.get_selected_page(); + if (!page) { + alert("you must select a page"); + //flash('alert-danger', "You must select a page") + return; + } + + return op(page); + } + + static rename_page(e) { + return PageIndex.selected_page_operation(function(page_name) { + console.log(`rename page ${page_name}`); + + $('#rename-page-name').text(`Rename from ${page_name} to `); + $('#rename-modal').modal(PageIndex.modal_args, 'show'); + $('#confirm-rename-button').unbind('click'); + return $('#confirm-rename-button').on('click', function(e) { + const to_name = $('#rename_rename_to').val(); + const desc = `Renaming page from ${page_name} to ${to_name}`; + console.log(desc); + let url = PageIndex.instance.urls.rename_page_url; + url = url.replace('FROM_NAME', page_name).replace('TO_NAME', to_name); + console.log(url); + const op = { + method: 'PUT', + path: url, + description: desc + }; + return PageIndex.ajax_page_operation(op); + }); + }); + } + + static new_page(e, page) { + if (typeof console !== 'undefined' && console !== null) { + console.log("new_page"); + } + let page_name = $('#new_page_new_page_name').val(page); + //$('#new-page-modal').modal(PageIndex.modal_args, 'show') + $('#new-page-modal').modal('show'); + $('#confirm-new-page-button').unbind('click'); + return $('#confirm-new-page-button').on('click', function(e) { + page_name = $('#new_page_new_page_name').val(); + const desc = `Creating page ${page_name}`; + let url = PageIndex.instance.urls.page_index_url; + url = url.replace('PAGE_NAME', page_name); + const op = { + method: 'POST', + path: url, + description: desc + }; + return PageIndex.ajax_page_operation(op); + }); + } + + static delete_page(e) { + return PageIndex.selected_page_operation(function(page_name) { + const desc = `Deleting page ${page_name}`; + console.log(desc); + + $('#confirm-delete-page-name').text(page_name); + //$('#confirm-delete-modal').modal(PageIndex.modal_args, 'show') + $('#confirm-delete-modal').modal('show'); + $('#confirm-delete-button').unbind('click'); + return $('#confirm-delete-button').on('click', function(e) { + let url = PageIndex.instance.urls.page_index_url; + url = url.replace('PAGE_NAME', page_name); + const op = { + method: 'DELETE', + path: url, + description: desc + }; + return PageIndex.ajax_page_operation(op); + }); + }); + } + + static stop_editing_page(e, page_name) { + let url = PageIndex.instance.urls.stop_editing_page_url; + url = url.replace('PAGE_NAME', page_name); + if (typeof console !== 'undefined' && console !== null) { + console.log(url); + } + const desc = `Stopping editing page ${page_name}`; + console.log(desc); + const op = { + method: 'GET', + path: url, + description: desc, + show_status: false + }; + return PageIndex.ajax_page_operation(op); + } + + // See note for @edit_page + static revoke_page(e, page_name, course_id) { + if (!course_id) { course_id = undefined; } + let url = "/COURSE_ID/pages/PAGE_NAME/stop_editing"; + url = url.replace('PAGE_NAME', page_name); + if (PageIndex.instance !== null) { + ({ course_id } = PageIndex.instance); + } + url = url.replace('COURSE_ID', course_id); + if (typeof console !== 'undefined' && console !== null) { + console.log(url); + } + const desc = `Stopping editing page ${page_name}`; + console.log(desc); + return $.get(url, "{}", data => location.reload()); + } + + static recompile_all_pages(e, page_name) { + const url = PageIndex.instance.urls.recompile_all_pages_url; + if (typeof console !== 'undefined' && console !== null) { + console.log(url); + } + const desc = 'Recompiling all pages'; + const op = { + method: 'GET', + path: url, + description: desc + }; + return PageIndex.ajax_page_operation(op); + } + + static ajax_page_operation(op) { + + // prevent double clicking + this.disable_all_commands(); + + const message = op.message || {}; + if (!op.show_status) { op.show_status = true; } + + const to_bool = (x, default_val) => x || default_val; +// return ((typeof x == 'undefined') ? default_val : x) + + if (typeof console !== 'undefined' && console !== null) { + console.log(op.description); + } + op.reload_on_success = to_bool(op.reload_on_success, true); + op.reload_on_failure = to_bool(op.reload_on_failure, false); + + if (op.show_status) { + PageIndex.show_status(op.description); + } + + const success = function(data) { + if (op.reload_on_success) { + console.warn('reloading grids on operation success!'); + PageIndex.reload_grid(); + } + PageIndex.update_valid_commands(); + if (typeof op.success_callback === 'function') { + op.success_callback(data); + } + const res = window.render_simple_json_response(data, "The operation succeeded"); + if (op.show_status) { + return PageIndex.dismiss_status(res.success, res.message); + } + }; + + const fail = function(jqXHR, textStatus, errorThrown) { + if (op.reload_on_failure) { + console.warn('reloading grids on operation failure!'); + PageIndex.reload_grid(); + } + PageIndex.update_valid_commands(); + if (typeof op.error_callback === 'function') { + op.error_callback(); + } + + //TODO: ideally we'd wrap all parses in such a test + let detailed_response = { message: jqXHR.responseText}; + try { + detailed_response = JSON.parse(jqXHR.responseText); + } catch (e) { + detailed_response = {success:false, message: "An unknown error has occurred."}; + console.error(e); + } + + const res = window.render_simple_json_response(detailed_response, + undefined, + "The operation failed"); + if (op.show_status) { + return PageIndex.dismiss_status(res.success, res.message); + } + }; + + const ajax_parms = { + method: op.method, + url: op.path, + data: JSON.stringify(op.message, null, 2) + }; + + if (typeof console !== 'undefined' && console !== null) { + console.log(op.path); + } + + return $.ajax(ajax_parms).done(success).fail(fail); + } + + static add_visibility_handlers() { + return $('.visible-checkbox').on('click', PageIndex.viz_handler); + } + + + // + // Sorting + // + static sort_admin_field(event, field) { + const sort_url = "page_index_grid[descending]=true&page_index_grid[order]="; + window.location.search = sort_url + field; + return window.location.search + } + + static set_admin_sort() { + const order = {}; + for (let component of Array.from(window.location.search.split(/&/))) { + const dec_component = decodeURIComponent(component); + const m = dec_component.match(".*page_index_grid.\(.+\).\=\(.+\)"); + if (m) { + order[m[1]] = m[2]; + } + } + + const order_by = order["order"] || "qid"; + + $(".admin-sort-button.btn-active").removeClass("active"); + return $(`#sort-${order_by}`).addClass("active"); + } + + static reload_grid() { + const self = this; + // document.location.reload(true) + $('.page-index-grid-form').each( function(event) { + return $.get($(this).attr("action"), $(this).serialize(), function(data) { + $('.page-index-grid-table').html(data.table); + return PageIndex.add_visibility_handlers(); + }); + }); + return $('.page-errors-index-grid-form').each( function(event) { + return $.get($(this).attr("action"), $(this).serialize(), data => $('.page-errors-index-grid-table').html(data.table)); + }); + } + + static viz_handler(e) { + let new_state; + e.stopPropagation(); + + const checkbox = $(this); + new_state = checkbox.prop('checked'); + return new_state; + } + + // NOTE: we can't rely on PageIndex being defined here because + // the edit button exists on all pages. + static edit_page(event, page_name, course_id) { + if (!course_id) { course_id = undefined; } + let url = "/COURSE_ID/PAGE_NAME?mode=edit";//PageIndex.instance.urls.edit_page_url + if (!page_name) { page_name = location.pathname.replace('/', ''); } + url = url.replace('PAGE_NAME', page_name); + if (PageIndex.instance !== null) { + ({ course_id } = PageIndex.instance); + } + url = url.replace('COURSE_ID', course_id); + window.location.href = url; + return window.location.href; + } + + // + // Init + // + + static isMyPage() { + const parts = window.location.pathname.split('/').filter( d => d); + if (parts.length < 2) { + return false; + } + return ((parts[parts.length-2] === "admin") && (parts[parts.length-1] === "pages")); + } + + static initPage() { + if (!window.ADMIN_CONFIG) { + if (typeof console !== 'undefined' && console !== null) { + console.log(`reloading because page was accessed\ +via turbolink and page isn't configured`); + } + window.location.reload(); + return; + } + if (PageIndex.instance !== null) { + PageIndex.instance = null; + } + window.page_index = new PageIndex(window.ADMIN_CONFIG.urls, window.ADMIN_CONFIG.course_id); + return window.page_index; + } +} + +PageIndex.initClass(); + +window.PageIndex = PageIndex; diff --git a/app/javascript/src/page-load.js b/app/javascript/src/page-load.js new file mode 100644 index 0000000000000000000000000000000000000000..7f1b5a05b02db0320fdb73834d169bd13cc63a39 --- /dev/null +++ b/app/javascript/src/page-load.js @@ -0,0 +1,33 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ + +// page:load required to deal with turbo links issue: +// http://stackoverflow.com/questions/18770517/rails-4-how-to-use-document-ready-with-turbo-links + +// Rails 4.2.x gets new turbolinks with new behavior + +const pageClassNames = ['AdminPage', 'PageIndex', 'MdPage', 'PageEditor']; + +$(document).ready(() => { +// $(document).on 'turbolinks:load', (x) -> +// console.log(`Page Loaded: ${x.type} ${window.location.href}`); + + console.log(`Page Loaded: ${window.location.href}`); + + $('.dropdown-toggle').dropdown(); + + const pages = pageClassNames.filter((pageClassName) => { + const klass = window[pageClassName]; + return ((typeof klass === 'function') && klass.isMyPage()); + }); + + if (pages.length > 0) { + console.log('Initializing pages %o', pages); + pages.forEach((page) => window[page].initPage()); + } else { + return console.warn('Not a Feature Page'); + } +}); diff --git a/app/javascript/src/pages.js b/app/javascript/src/pages.js new file mode 100644 index 0000000000000000000000000000000000000000..4532725d59129d3eeeff5e042d7d20fa0ed2834e --- /dev/null +++ b/app/javascript/src/pages.js @@ -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/javascript/src/podcast.js b/app/javascript/src/podcast.js new file mode 100644 index 0000000000000000000000000000000000000000..4532725d59129d3eeeff5e042d7d20fa0ed2834e --- /dev/null +++ b/app/javascript/src/podcast.js @@ -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/javascript/src/quiz.js b/app/javascript/src/quiz.js new file mode 100644 index 0000000000000000000000000000000000000000..4ab4742b47b091a696ba4fe69c0c16a057822b08 --- /dev/null +++ b/app/javascript/src/quiz.js @@ -0,0 +1,114 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +class Quiz { + static mcChange(event) { + const choice = $(event.target); + + Quiz.clearFeedback(choice); + + const answer_index = choice.val(); + const answers = choice.closest(".quiz-question-answer-list"); + const answer = choice.closest(".quiz-student-answer"); + const option = choice.closest(".option-row"); + const answer_and_feedback = choice.closest(".answer-and-feedback"); + const correctness = option.data('question'); + console.log(`correct: ${correctness}`); + const correct = (correctness === 'right'); + const feedback = answers.find(`.feedback-row-${answer_index}`); + const feedback_text = answers.find(`.feedback-text-${answer_index}`); + const highlight = (correctness === "wrong") ? 'feedback-incorrect-answer' : 'feedback-correct-answer'; + feedback.addClass('show-feedback'); + feedback_text.addClass(highlight); + option.find('.quiz-option').addClass(highlight); + answer_and_feedback.removeClass("correct"); + answer_and_feedback.removeClass("correct"); + return answer_and_feedback.addClass(correct ? "correct" : "incorrect"); + } + + static clearFeedback(el) { + const root = el.closest(".quiz-question-answer-list"); + root.find('.correct').removeClass('correct'); + root.find('.incorrect').removeClass('incorrect'); + root.find('.show-feedback').removeClass('show-feedback'); + root.find('.feedback-incorrect-answer').removeClass('feedback-incorrect-answer'); + return root.find('.feedback-correct-answer').removeClass('feedback-correct-answer'); + } + + static ataChange(event) { + Quiz.clearFeedback($(event.target)); + } + + static ataSubmit(event) { + const target = $(event.target); + const answers = target.closest(".quiz-question-answer-list"); + const options = answers.find(".answer-and-feedback"); + return options.each((i, el) => { + const answer_and_feedback = $(el); + const input = answer_and_feedback.find("input"); + const answer_index = input.val(); + const checked = input.prop('checked'); + const answer = checked ? 'right' : 'wrong'; + const option_row = input.closest('.option-row'); + const correctness = option_row.data('question'); + const correct = (correctness === answer); + console.log(`correct: ${correctness}`); + const feedback = answers.find(`.feedback-row-${answer_index}`); + const feedback_text = answers.find(`.feedback-text-${answer_index}`); + const highlight = correct ? 'feedback-correct-answer' : 'feedback-incorrect-answer'; + const text = feedback_text.text().replace(/\s/g,''); + // show feedback only if checked (per Martin) + if (!!text && checked) { + feedback.addClass('show-feedback'); + feedback_text.addClass(highlight); + } + option_row.addClass(correct ? "correct" : "incorrect"); + answer_and_feedback.removeClass("correct"); + answer_and_feedback.removeClass("correct"); + answer_and_feedback.addClass(correct ? "correct" : "incorrect"); + return true; + }); + } + + static ftbSubmit(event) { + const target = $(event.target); + const $question = target.closest(".quiz-question"); + const feedback = $question.find(".feedback-row"); + const option_row = $question.closest('.option-row'); + const right_answers = $question.find("input"). + map(function(x) { return $(this). + data('answer'); }).toArray(); + //console.dir right_answers + let all_correct = true; + $question.find("input").each(function() { + const $input = $(this); + $input.removeClass('correct'); + $input.removeClass('incorrect'); + const right_answer = $input.data('answer'); + const correct = right_answer === $input.val(); + $input.addClass( correct ? 'correct' : 'incorrect'); + $input.closest('.fill-in-the-blank-answer-and-tick').addClass( correct ? 'correct' : 'incorrect'); + if (!correct) { all_correct = false; } + //console.log("r = #{right_answer} here #{correct}") + return true; + }); // loop through all the inputs + + option_row.addClass(all_correct ? "correct" : "incorrect"); + if (!all_correct) { feedback.addClass('show-feedback'); } + if (all_correct) { return feedback.removeClass('show-feedback'); } + } + + static fillInTheBlankEdit(event) { + console.log("edit"); + Quiz.clearFeedback($(event.target)); + } + + static fillInTheBlankChanged(event) { + Quiz.clearFeedback($(event.target)); + } +} + + +window.Quiz = Quiz; \ No newline at end of file diff --git a/app/javascript/src/render.js b/app/javascript/src/render.js new file mode 100644 index 0000000000000000000000000000000000000000..448a9eb159ff80b25afb6d83ef93d524303f6a79 --- /dev/null +++ b/app/javascript/src/render.js @@ -0,0 +1,125 @@ +import mathJaxInit from './mathjax'; +const Markdown = require('pagedown-extra/pagedown/Markdown.Converter'); +window.Markdown = Markdown; +require('pagedown-extra/pagedown/Markdown.Editor'); // IIFE depending on window.Markdown +require('pagedown-extra/Markdown.Extra'); // IIFE depending on window.Markdown + +export default function renderPage() { + "use strict"; + + console.log("Rendering"); + + var doMathjax = typeof MathJax !== 'undefined'; + + if (doMathjax) { + mathJaxInit(); + + if (typeof window.mathJax === 'undefined') { + doMathjax = false; + } else { + MathJax.Hub.Config({ + skipStartupTypeset: true, + "HTML-CSS": { + preferredFont: "TeX", + availableFonts: [ + "TeX" + ], + linebreaks: { + automatic: true + }, + EqnChunk: 10, + imageFont: null + }, + // root: '/assets/MathJax', + tex2jax: { + inlineMath: [ + ["$", "$"], + ["\\\\\\\\(", "\\\\\\\\)"] + ], + displayMath: [ + ["$$", "$$"], + ["\\\\[", "\\\\]"] + ], + processEscapes: true + }, + TeX: { + noUndefined: { + attributes: { + mathcolor: "red", + mathbackground: "#FFEEEE", + mathsize: "90%" + } + }, + Safe: { + allow: { + URLs: "safe", + classes: "safe", + cssIDs: "safe", + styles: "safe", + fontsize: "all" + } + } + }, + messageStyle: "none" + }); + } + } + + function createMarkdownConverter() { + var converter = new Markdown.Converter(); + Markdown.Extra.init(converter, { + table_class: "table table-striped" + }); + return converter; + } + + var converter = createMarkdownConverter(); + + converter.hooks.chain("preConversion", function(x) { + console.log('render.js: pre conversion'); + return MdPage.preConvertMarkdown(x); + }); + + if (doMathjax) { + mathJax.onPagedownConfigure(converter); + } + + converter.hooks.chain("postConversion", function(x) { + console.log('render.js: post conversion'); + return MdPage.postConvertMarkdown(x); + }); + + if (typeof renderCoursePage === "function") { + console.log('render.js: rendering full page md'); + renderCoursePage(converter); + console.log('render.js: rendering full page md finished'); + scroll_to_anchor(); + $("p:has(img)").toggleClass('centered-image-parent'); // issue#136 + } + + // setTimeout(function() { + + // debugger; + if (doMathjax) { + console.log("Queuing a typeset"); + + MathJax.Hub.Queue( + ["Typeset", MathJax.Hub, "content"] + ); + MathJax.Hub.Queue(function () { + console.log("Typeset complete."); + scroll_to_anchor(); + }); + } + // }, 200) + //setTimeout(queueMathjax, 200) + +} + +function queueMathjax() { + console.log("Queuing a typeset"); + + MathJax.Hub.Queue( + ["Typeset", MathJax.Hub, "content"] + ); +} diff --git a/app/javascript/src/utils.js b/app/javascript/src/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..fa3532ea24ef6a51cfc33d9c474d1466c2a0a03b --- /dev/null +++ b/app/javascript/src/utils.js @@ -0,0 +1,54 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const render_simple_json_response = (res, def_suc_msg, def_err_msg, extra_fields) => { + let message, success; + console.log("response "); + console.log(res); + if ((res.hasOwnProperty('success') && !res.success) || def_err_msg) { + success = false; + const messsage = res.message || def_err_msg; + flash("alert-danger", message); + } else if ((res.hasOwnProperty('success') && res.success) || def_suc_msg) { + success = true; + message = res.message || def_suc_msg; + flash("alert-success", message); + } + + return { success, message }; +}; + +const scroll_to_anchor_old = function() { + if (location.hash) { + location.href = location.hash; // Issue#108 + const navHeight = $("#navbar-main").first().height(); + const new_el = $(`[name=${location.hash.toString().substring(1)}]`); + const elHeight = new_el.parent().first().height(); + if (typeof console !== 'undefined' && console !== null) { + console.log(`Adjusting scroll to hash ${location.hash}` + + " by navbar height " + navHeight + ',' + elHeight); + } + const fixHeight = Math.max(navHeight, elHeight); + return $(document).scrollTop($(document).scrollTop() - fixHeight); // header + } +}; + +const scroll_to_anchor = function() { + const hash = location.hash.toString().substring(1); + if (!hash || hash === '') return; + const hashAnchor = `[name=${hash}]`; + const a = $(hashAnchor); + const anchor = a.parent().first(); + if (!anchor || (anchor.length === 0)) { return; } + const offset = anchor.offset().top - $('#navbar-main').outerHeight(); + + return $('html, body').animate({ + scrollTop: offset + }, 200); +}; + +window.render_simple_json_response = render_simple_json_response; +window.scroll_to_anchor = scroll_to_anchor; diff --git a/app/mailers/.keep b/app/mailers/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/models/.keep b/app/models/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000000000000000000000000000000000000..10a4cba84df37181f4cf310fd85d8f0aaa5d90ba --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/models/enotes.rb b/app/models/enotes.rb new file mode 100644 index 0000000000000000000000000000000000000000..f390fff20a8505f9cb51f74568ceae8aed888350 --- /dev/null +++ b/app/models/enotes.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'enote_titleize' + +## +# Cacher for eNotes +class Enotes < EnotesBase + include Singleton + + def initialize + super + @filemanager_kind = :enotes + end + + def self.menuize(enote) + enote.enote_titleize + end + + def suffix + 'Enotes' + end +end diff --git a/app/models/enotes_base.rb b/app/models/enotes_base.rb new file mode 100644 index 0000000000000000000000000000000000000000..a4b6a046ddaed49d67f6ae791c051f755d7a25b5 --- /dev/null +++ b/app/models/enotes_base.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require 'enote_titleize' + +## +# Base class for all enotes cachers +# TODO: this and DTU Filemanager should be merged in some way. +class EnotesBase + def initialize + @file_manager = DTUFileManagement::FileManager.instance + end + + def get(course) + unless $redis_course_website + Rails.logger.warn "No course redis! Returning empty enotes." + return empty_enotes + end + + key = redis_key(course) + enotes_json = $redis_course_website.get(key) + + if enotes_json.nil? + Rails.logger.debug "Refreshing enotes from disc" + enotes = refresh(course) + else + Rails.logger.debug "Using redis enotes from #{key}" + enotes = (JSON.parse enotes_json).symbolize_keys! + enotes[:enote_stats].map(&:symbolize_keys!) + end + enotes + end + + def refresh_all + courses = WebsiteConfig.get.courses.keys + + courses.each do |course| + refresh(course) + end + end + + def refresh(course) + course_enote_info = empty_enotes + + course_enote_info[:enote_files] = get_file_list course + course_enote_info[:enote_stats] = course_enote_info[:enote_files].map do |file| + s = File.stat(file) + { + size: s.size, + mtime: s.mtime + } + end + + enote_root = get_root_path course + + rel_paths = course_enote_info[:enote_files].map { |file| Pathname.new(file).relative_path_from(enote_root); } + course_enote_info[:enote_files] = rel_paths.select { |file| (File.dirname(file).eql? '.') && (File.extname(file).eql? '.pdf') } + + course_enote_info[:enotes] = course_enote_info[:enote_files].map { |m| File.basename(m, '.pdf') } if course_enote_info[:enote_files] + course_enote_info[:enotes].each { |enote| course_enote_info[:enote_titles][Enotes.menuize enote] = enote } + + course_enote_info[:enote_dirs] = rel_paths.map { |file| File.dirname(file) } + + Rails.logger.debug "Enote info for #{course}/#{@filemanager_kind}: #{course_enote_info.ai}" + Rails.logger.info "Enote titles for #{course}/#{@filemanager_kind}: #{course_enote_info[:enote_titles].ai}" + + $redis_course_website&.set(redis_key(course), course_enote_info.to_json) + + course_enote_info + end + + def get_file_list(course) + @file_manager.update + @file_manager.files_for(@filemanager_kind, course) || [] + end + + def get_root_path(course) + Pathname.new(@file_manager.folder_for(@filemanager_kind, course)) + end + + def redis_key(course) + "#{@filemanager_kind}_#{course}" + end + + private + + def empty_enotes + { + enotes: [], + enote_titles: {}, + enote_files: [], + enote_dirs: [] + } + end +end diff --git a/app/models/enotes_staging.rb b/app/models/enotes_staging.rb new file mode 100644 index 0000000000000000000000000000000000000000..4255bbd37a63f9be94a011d36827e8fa22773953 --- /dev/null +++ b/app/models/enotes_staging.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'enote_titleize' + +## +# Enotes cacher for stating +class EnotesStaging < EnotesBase + include Singleton + + def initialize + super + @filemanager_kind = :enotes_staging + end + + def self.menuize(enote) + enote.enote_titleize + end + + def suffix + 'EnotesStaging' + end +end diff --git a/app/models/errors.rb b/app/models/errors.rb new file mode 100644 index 0000000000000000000000000000000000000000..a81a1a3a81a119aea4f608b2cc204eab993f0e4a --- /dev/null +++ b/app/models/errors.rb @@ -0,0 +1,195 @@ +require 'json' + +class Errors + attr_accessor :errors + attr_accessor :error_list + attr_accessor :course + + def initialize(options) + FileUtils.mkdir_p Errors.errors_folder options[:course] + + @course = options[:course] + + if options.has_key? :error_list + Rails.logger.debug "Loading errors from redis" + @error_list = [] + @errors = {} + options[:error_list].map do |page_error_hash| + page_error = PageError.new(page_error_hash.symbolize_keys) + + @error_list << page_error + @errors[page_error.page] = [] unless @errors[page_error.page] + @errors[page_error.page] << page_error + end + else + self.refresh + end + end + + def self.get(course) + return Errors.new({course: course}) unless $redis_course_website + + json = $redis_course_website.get("errors:#{course}") + + if json.nil? + Errors.new({ course: course }) + else + Errors.new JSON.load(json).symbolize_keys! + end + end + + def self.for_page(course, page) + json = $redis_course_website.get("errors:#{course}:#{page}") + + if json.nil? + return nil + else + PageError.new(json.symbolize_keys.merge(:course_id => @course)) + end + end + + def self.refresh(course) + Errors.delete_all_page_keys course + Errors.new({ :course => course }) + end + + def refresh + Rails.logger.info "Refreshing errors for #{course}" + + @error_list = [] + + @errors = errors_files.map do |errors_file| + page = File.basename(errors_file, "-errors.json") + page_errors = [] + if File.exist? errors_file + error_text = File.read errors_file + if error_text.blank? + page_errors = [] + FileUtils.rm errors_file + else + page_errors = JSON.parse(error_text).map{|j| PageError.new(j.symbolize_keys.merge(:course_id => @course))} + end + end + + @error_list.concat(page_errors) + [page, page_errors] + end.reject{|p| p[1] == nil }.to_h + + Rails.logger.info "Errors: #{@errors.ai}" + $redis_course_website.set("errors:#{@course}", self.to_json) if $redis_course_website + end + + def self.set_page(course, page_file, errors) + page = File.basename(page_file, ".md") + errors_file = File.join(Errors.errors_folder(course), "#{page}-errors.json") + + if errors.empty? + if File.exist? errors_file + Rails.logger.info("Removing errors file #{errors_file} since errors have been cleared...") + FileUtils.rm errors_file + @errors.delete page + $redis_course_website.del("errors:#{course}:#{page}") if $redis_course_website + end + + Rails.logger.info("Setting no errors for #{page_file}...") + # full errors list is invalid and needs to be recreated + $redis_course_website.del("errors:#{course}") if $redis_course_website + return + end + + Rails.logger.info("Writing errors for #{page_file} to #{errors_file}...") + + json = errors.to_json + + File.open(errors_file, 'w') do |f| + f.puts json + end + + $redis_course_website.set("errors:#{course}:#{page}", json) if $redis_course_website + + # full errors list is invalid and needs to be recreated + $redis_course_website.del("errors:#{course}") if $redis_course_website + end + + def self.clear_all!(course) + FileUtils.rm_rf(Dir.glob(File.join(Errors.errors_folder(course), '*'))) + + Errors.delete_all_page_keys course + end + + # https://gist.github.com/brasic/d48851840e91c0ad7b28 + def self.delete_all_page_keys(course) + return unless $redis_course_website + while true + keys = $redis_course_website.scan_each(match: "errors:#{course}*", count:1000).to_a + + return if keys.empty? + + keys.each_slice(500) do |chunk| + $redis_course_website.pipelined do + chunk.each do |key| + $redis_course_website.del key + end + end + end + end + end + + def clear_all_missing!(all_pages) + @error_list = @error_list.select do |error| + unless (all_pages.include? error.page) + page = error.page + errors_file = File.join(Errors.errors_folder(course), "#{page}-errors.json") + @errors.delete(page) if @errors.has_key? page + FileUtils.rm errors_file if File.exist? errors_file + $redis_course_website.del("errors:#{course}:#{page}") if $redis_course_website + next false + end + + true + end + + # full errors list is invalid and needs to be recreated + $redis_course_website.set("errors:#{course}", self.to_json) if $redis_course_website + end + + # Clears the 'missing page' errors concerning the given page on all the pages + # Params: + # +page+:: the page which is no longer missing + def clear_missing_page_error(page) + @error_list = @error_list.select do |error| + if error.missing_page? + if page.eql? error.refer_page + @errors[error.page] = @errors[error.page].reject{ |e| page.eql?(e.refer_page) && e.missing_page? } + errors_file = File.join(Errors.errors_folder(course), "#{error.page}-errors.json") + if @errors[error.page].empty? + @errors[error.page] = nil + FileUtils.rm errors_file if File.exist? errors_file + $redis_course_website.del("errors:#{course}:#{page}") if $redis_course_website + else + json = @errors[error.page].to_json + + File.open(errors_file, 'w') do |f| + f.puts json + end + $redis_course_website.set("errors:#{course}:#{page}", json) if $redis_course_website + end + next false + end + end + + true + end + + # full errors list is invalid and needs to be recreated + $redis_course_website.set("errors:#{course}", self.to_json) if $redis_course_website + end + + def errors_files + Dir.glob(File.join(Errors.errors_folder(course), '*-errors.json')) + end + + def self.errors_folder(course) + File.join(PagesService.new(course).compiled_folder, "_errors") + end +end diff --git a/app/models/feedback.rb b/app/models/feedback.rb new file mode 100644 index 0000000000000000000000000000000000000000..59718fdbcbb1aae92fb66de135f2b43ec83ad74f --- /dev/null +++ b/app/models/feedback.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +require 'micro_magick' + +DATA_URL_REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m + +## +# Model class for feedbacks +class Feedback < ApplicationRecord + cattr_accessor :STATUS_OPTIONS + cattr_accessor :STATUS_FRIENDLY + + self.STATUS_OPTIONS = %w[new accepted needs_info not_a_bug solved] + + self.STATUS_FRIENDLY = { + 'new' => 'NEW', + 'accepted' => 'ACCEPTED', + 'needs_info' => 'NEEDS INFO', + 'not_a_bug' => 'NOT A BUG', + 'solved' => 'SOLVED' + } + + validates :status, inclusion: { in: Feedback.STATUS_OPTIONS } + + def html_filename + root = Feedback.feedbacks_folder(course_id) + File.join(root, id.to_s + '.html') + end + + def image_filename + root = Feedback.feedbacks_folder(course_id) + File.join(root, id.to_s + '.png') + end + + def image_thumb_filename + root = Feedback.feedbacks_folder(course_id) + File.join(root, id.to_s + '-thumb.png') + end + + def html_url + "/assets#{course_id}/_feedbacks/#{id}.html" + end + + def image_url + "/assets/#{course_id}/_feedbacks/#{id}.png" + end + + def image_thumb_url + "/assets/#{course_id}/_feedbacks/#{id}-thumb.png" + end + + def self.url_to_page(url, course_id = nil) + uri = URI.parse url + paths = uri.path.split('/').reject(&:empty?) + if course_id.nil? + return nil unless paths.length >= 2 + { + course_id: paths[0], + page: paths[1] + } + else + return nil unless paths.length >= 1 + { + course_id: course_id, + page: paths[0] + } + end + end + + def self.build_from_post_params(params) + page_info = Feedback.url_to_page(params[:url], params[:course_id]) + f = Feedback.new( + url: params[:url], + page: page_info[:page], + course_id: page_info[:course_id], + user_id: params[:user_id], + user_name: params[:user_name], + text: params[:note] + ) + + root = Feedback.feedbacks_folder(page_info[:course_id]) + + return nil unless f.save + + FileUtils.mkdir_p root + + data_uri_parts = params[:screenshot].match(DATA_URL_REGEXP) || [] + extension = MIME::Types[data_uri_parts[1]].first.preferred_extension + + # We could accept different image types, but for now just error... + unless extension.eql? 'png' + Rails.logger.error "Invalid POST extension #{extension}" + return nil + end + + Rails.logger.info "Saving feedback image: #{f.image_filename}" + File.open(f.image_filename, 'wb') do |image_file| + image_file.write(Base64.decode64(data_uri_parts[2])) + end + + # create thumnail + img = MicroMagick::Convert.new(f.image_filename) + img.resize('x120') + img.unsharp(1.5) + Rails.logger.info "Saving thumbnail #{f.image_thumb_filename}" + img.write(f.image_thumb_filename) + + f + end + + def self.feedbacks_folder(course_id) + File.join(PagesService.new(course_id).compiled_folder, '_feedbacks') + end +end diff --git a/app/models/git_repo_info.rb b/app/models/git_repo_info.rb new file mode 100644 index 0000000000000000000000000000000000000000..91d492042b9fd2264b64ae6c150ba9b4b8fe7e75 --- /dev/null +++ b/app/models/git_repo_info.rb @@ -0,0 +1,12 @@ +class GitRepoInfo + attr_accessor( + :repo, + :key_folder, + :local_repo_folder, + :branch) + + def initialize(args = nil) + args.each {|k,v| instance_variable_set("@#{k}",v)} unless args.nil? + yield self if block_given? + end +end diff --git a/app/models/included_pages.rb b/app/models/included_pages.rb new file mode 100644 index 0000000000000000000000000000000000000000..0f1f37fa9893c656b01f008a8ab8ba84897e22f1 --- /dev/null +++ b/app/models/included_pages.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +# IncludedPages model; interface class to work with the included pages +# +class IncludedPages + cattr_accessor(:instance) + + attr_accessor :pages + attr_accessor :course + + def initialize(options = nil) + options.each { |k, v| instance_variable_set("@#{k}", v) } + refresh unless options.key? :pages + # This optimization was added in 2018, but without the time to test it. So to be safe it's off +# @@instance = {} unless @@instance +# @@instance[self.course] = self + end + + def self.clear + @@instance = {} + end + + def self.get(course) +# return @@instance[course] unless @@instance.nil? || !@instance.has_key(course) + + return IncludedPages.new(course: course) unless $redis_course_website + + json = $redis_course_website.get('#{course}_included_pages') + + if json.nil? + IncludedPages.new(course: course) + else + ip = IncludedPages.new JSON.parse json + # if it's the wrong course, just rebuild + ip = IncludedPages.new(course: course) unless (ip.course.eql?(course)) + ip + end + end + + def self.refresh(course) + $redis_course_website.del('#{course}_included_pages') if $redis_course_website + IncludedPages.new(course: course) + end + + def refresh(page = nil) + raw_md_folder = WebsiteConfig.get.courses[@course].pages_source_path + Rails.logger.info "Refreshing includes for course #{@course} in #{raw_md_folder}" + page_files = Dir.glob(File.join(raw_md_folder, (page ? page : '*') + '.tex')) + + @pages = page_files.map do |page_file| + page = File.basename(page_file) + [page, File.read(page_file)] + end.to_h + + $redis_course_website.set("#{@course}_included_pages", self.to_json) if page.nil? and $redis_course_website + + #Rails.logger.debug "Includes: #{@pages.ai}" + end +end diff --git a/app/models/menu.rb b/app/models/menu.rb new file mode 100644 index 0000000000000000000000000000000000000000..e5029277659220ccf227b9460edaad6090790e00 --- /dev/null +++ b/app/models/menu.rb @@ -0,0 +1,116 @@ +require 'yaml' + +class Menu + attr_accessor(:items) + cattr_accessor(:PageName) + + self.PageName = "Menu" + + def initialize(options = nil) + if options + options.each {|k,v| instance_variable_set("@#{k}",v)} + else + set_default_menu! + end + end + + def self.clear(course) + $redis_course_website.del("#{course}_menu") if $redis_course_website + end + + def self.get(course) + return Menu.new unless $redis_course_website + + menu_json = $redis_course_website.get("#{course}_menu") + + if menu_json.nil? + menu, errs = self.refresh course + else + options = (JSON.load menu_json).symbolize_keys! + options[:items].each(&:symbolize_keys!) + menu = Menu.new options + end + + menu + end + + def self.refresh(course, menu_config_filename = nil) + Rails.logger.info "Refreshing menu for #{course}" + menu_config_filename = File.join(PagesService.new(course).raw_md_folder, @@PageName + '.md') unless menu_config_filename + Rails.logger.info "INIT menu config for #{course} from " + menu_config_filename.to_s + + course_menu = Menu.new() + + if File.exist? menu_config_filename + errors = [] + parsed_items = [] + File.open(menu_config_filename, "r") do |f| + lineno = 1 + f.each_line do |line| + item, error = course_menu.parse_config_line line + if error + error[:file] = menu_config_filename + error[:line] = lineno + errors << error + end + parsed_items << item if item + lineno = lineno + 1 + end + end + + if errors.empty? + Rails.logger.info "Successfully parsed menu config." + course_menu.items = parsed_items + $redis_course_website.set("#{course}_menu", course_menu.to_json) if $redis_course_website + return course_menu, [] + end + + Rails.logger.warn "Could not parse menu file #{menu_config_filename} #{errors}" + + Errors.set_page(course, 'menu', errors) + + return nil, errors + end + + Rails.logger.warn "Using default menu" + + course_menu.set_default_menu! + $redis_course_website.set("#{course}_menu", course_menu.to_json) if $redis_course_website + + return course_menu, [] + end + + def parse_config_line(line) + a = line.split(',') + + if a.length != 2 + return nil, {file: nil, line: 0, text: "exactly one comma, separating name from url, required"} + end + + menu = a[0].strip + url = a[1].strip + + unless url.start_with? 'http' + url = '/' + url.delete('/') + end + + return { :menu => menu, :url => url }, nil + end + + def set_default_menu! + self.items = [ + { :menu => "Agendas", :url => "/Agendas" }, + { :menu => "Book", :url => "/eNotes" }, + { :menu => "Course Material", :url => "/Material" }, + { :menu => "Podcast", :url => "/podcast" }, + { :menu => "Quiz", :url => WebsiteConfig.get.quiz_url || "https://quiz.compute.dtu.dk/" } + ] + end + + def expected_menu_pages + # strip out menu pages which correspond to direct links or "special" pages -- i.e. those not backed with a markdown file + menu_items = items.reject { |item| (['eNotes'].include? item[:url].delete('/')) or item[:url].start_with? "http" }.map{ |item| item[:url].delete('/') } + # add in the default Markdown pages + Set.new(["Frontpage-right", "Frontpage-left"].concat(menu_items).uniq) + end +end diff --git a/app/models/page.rb b/app/models/page.rb new file mode 100644 index 0000000000000000000000000000000000000000..aef782ebae09ddbefd62d5faa4284563b78836d2 --- /dev/null +++ b/app/models/page.rb @@ -0,0 +1,21 @@ + +class Page + + attr_accessor(:path) + attr_accessor(:stat) + attr_accessor(:mtime) + attr_accessor(:pretty_name) + attr_accessor(:edit_info) + attr_accessor(:viewable) + attr_accessor(:editable) + attr_accessor(:course_id) + + def initialize(file_path, stat, edit_info, course_id) + @path = file_path + @stat = stat + @pretty_name = File.basename(@path, '.md') + @mtime = stat.mtime + @edit_info = edit_info + @course_id = course_id + end +end diff --git a/app/models/page_error.rb b/app/models/page_error.rb new file mode 100644 index 0000000000000000000000000000000000000000..5c23a093be6aa4c6abb60156489965e30b3b1eb4 --- /dev/null +++ b/app/models/page_error.rb @@ -0,0 +1,23 @@ +class PageError + attr_accessor(:file) + attr_accessor(:page) + attr_accessor(:refer_page) + attr_accessor(:error_type) + attr_accessor(:line) + attr_accessor(:text) + attr_accessor(:course_id) + + def initialize(kwargs) + @file = kwargs[:file] + @page = File.basename(kwargs[:file], '.md') + @refer_page = kwargs[:refer_page] + @error_type = kwargs[:error_type] + @line = kwargs[:line] + @text = kwargs[:text] + @course_id = kwargs[:course_id] + end + + def missing_page? + @text.eql? "Missing file" + end +end diff --git a/app/models/page_util.rb b/app/models/page_util.rb new file mode 100644 index 0000000000000000000000000000000000000000..7fc863a2c881f55d1eccf7df6d97d98be0c19d0e --- /dev/null +++ b/app/models/page_util.rb @@ -0,0 +1,48 @@ +require 'uri_utils' + +class PageUtil + + # TODO: how to include this as class methods? + include UriUtils + + def self.uri?(uri) + PageUtil.new.uri?(uri) + end + + def self.url_map(course) + { + "/uploads" => "/filemanager/uploads/#{course}" + } + end + + def self.page_link(course, label, url, valid_link_names) + + # if it's a valid URI, then don't mess with it (Issue#72) + return "[#{label}](#{url})", nil if uri?(url) + + page_path = (url && !url.empty?) ? url : label + + comps = page_path.split('/').reject{ |x| x.blank? } + + link_kind = '' + if comps.length > 1 + link_kind = '/'+comps[0] + page_target = comps.drop(1).join('/') + else + page_target = comps[0] + end + + url = page_path + url = '/' + url unless url.start_with? '/' + + page_name = page_target.split('#')[0] + + if valid_link_names.has_key?(link_kind) && valid_link_names[link_kind].include?(page_name) + url = PageUtil.url_map(course)[link_kind] + '/' + page_target if PageUtil.url_map(course).has_key? link_kind + return "[#{label}](#{url})", nil + else + return "<span class='link-error'>#{page_path}</span>", "Missing page referenced \"#{page_path}\"" + end + end + +end diff --git a/app/models/pages.rb b/app/models/pages.rb new file mode 100644 index 0000000000000000000000000000000000000000..23d7cb04f1de1e3cb3bbed2d69970cb38e77e4ea --- /dev/null +++ b/app/models/pages.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +# Pages model; interface class to work on the full list of pages +# +class Pages + attr_accessor :pages + attr_accessor :course + attr_accessor :valid_page_names + + def initialize(options = nil) + options.each { |k, v| instance_variable_set("@#{k}", v) } + if options.has_key? :pages + Rails.logger.debug "Loading pages from redis" + else + refresh + end + end + + def self.get(course) + return Pages.new({course: course}) unless $redis_course_website + + json = $redis_course_website.get('pages:${course}') + + if json.nil? + Pages.new({course: course}) + else + Pages.new JSON.parse json + end + end + + def self.refresh(course) + Rails.logger.debug "Force refreshing pages" + Pages.clear(course) + Pages.new({course: course}) + end + + def self.clear(course) + Rails.logger.debug "Clearing pages from redis" + $redis_course_website.del('pages:#{course}') if $redis_course_website + end + + def refresh + Rails.logger.info "Refreshing pages for #{@course}" + raw_md_folder = WebsiteConfig.get.courses[@course].pages_source_path + page_files = Pages.all_page_files raw_md_folder + + edits = PagesService.new(@course).all_current_edits.map { |e| [e[:name], e] }.to_h + + @pages = page_files.map do |page_file| + page_name = File.basename(page_file, '.md') + page = Page.new(page_file, File.stat(page_file), edits[page_name], course) + page.viewable = File.extname(page_file).eql? '.md' + page.editable = true + + page + end + + @valid_page_names = Set.new(@pages.map(&:pretty_name)) + + $redis_course_website.set("pages:#{@course}", to_json) if $redis_course_website + Rails.logger.info "END Refreshing pages for #{@course}" + end + + def self.macros_page?(page_name) + page_name.eql? 'macros' + end + + def self.get_file_name(folder, page_name) + if page_name.eql? 'macros' + File.join(folder, page_name + '.tex') + else + File.join(folder, page_name + '.md') + end + end + + def self.all_page_files(root) + Dir.glob(File.join(root, '*.md')).concat(Dir.glob(File.join(root, 'macros.tex'))) + end +end diff --git a/app/models/website_config.rb b/app/models/website_config.rb new file mode 100644 index 0000000000000000000000000000000000000000..1635bfe438dc46222e16e3c84a61fa485ffb8824 --- /dev/null +++ b/app/models/website_config.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +require 'yaml' + +## +# Configuration class for the whole website +class WebsiteConfig + cattr_accessor(:data_root) + cattr_accessor(:config_root) + cattr_accessor(:instance) + + self.data_root = Rails.configuration.dtu_data[:root_path] + self.config_root = File.join(data_root, 'config') + + attr_accessor(:courses) + attr_accessor(:getpdf_server_url) + attr_accessor(:quiz_url) + + def initialize(options = nil) + WebsiteConfig.instance = self + if options.nil? + from_yml + else + Rails.logger.debug 'INIT website config redis' + options.each { |k, v| instance_variable_set("@#{k}", v) } + self.courses = options['courses'].map do |course, course_h| + course_h['course_external_url'] = quiz_url.gsub('quiz', course) unless course_h.key? 'course_external_url' + [course, WebsiteCourseConfig.new(course_h)] + end.to_h + end + end + + def self.clear + WebsiteConfig.instance = nil + $redis_course_website&.del 'website_config' + end + + def self.get + return WebsiteConfig.instance unless WebsiteConfig.instance.nil? + + config_json = $redis_course_website&.get('website_config') + + if config_json.nil? + WebsiteConfig.new + else + # Rails.logger.debug JSON.pretty_generate(JSON.parse(config_json)) + + WebsiteConfig.new JSON.parse config_json + end + end + + def from_yml(website_config_filename = File.join(@@config_root, 'website.yaml')) + Rails.logger.debug 'INIT website config from ' + website_config_filename.to_s + + website_config = YAML.load_file(website_config_filename) + + @getpdf_server_url = website_config['getpdf_server_url'] + @quiz_url = website_config['quiz_url'] + + self.courses = website_config['courses'].map do |course, course_config| + course_config['course_external_url'] = @quiz_url.gsub('quiz', course) unless course_config.key? 'course_external_url' + [course, WebsiteCourseConfig.new(course: course, config: course_config)] + end.to_h + + config_json = to_json + # Rails.logger.debug JSON.pretty_generate(JSON.load(config_json)) + + Rails.logger.warn "Not saving website config to redis" unless $redis_course_website + $redis_course_website&.set('website_config', config_json) + end + + def to_yml(website_config_filename = File.join(@@config_root, 'website.yaml')) + Rails.logger.debug 'SAVE website config from ' + website_config_filename.to_s + + config_hash = JSON.parse(to_json) + + File.write(website_config_filename, config_hash.to_yaml) + + config_json = to_json + + $redis_course_website&.set('website_config', config_json) + end +end diff --git a/app/models/website_course_config.rb b/app/models/website_course_config.rb new file mode 100644 index 0000000000000000000000000000000000000000..c393051e39ae25b2bbe5b6a90cc475fd4743f968 --- /dev/null +++ b/app/models/website_course_config.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'yaml' + +## +# Configuration for an individual course +class WebsiteCourseConfig + attr_accessor(:course) + attr_accessor(:show_report_a_bug) + attr_accessor(:allow_feedback) + attr_accessor(:course_external_url) + + def initialize(args) + if args.key? :config + initialize_from_config(args) + else + args.each { |k, v| instance_variable_set("@#{k}", v) } + end + end + + def pages_source_path + File.join Rails.configuration.dtu_data[:root_path], 'content', @course, 'pages' + end + + def pages_compiled_path + File.join Rails.configuration.dtu_data[:root_path], 'website-public', "assets/#{@course}" + end + + def page_external_url(page) + path = Rails.application.routes.url_helpers.show_page_path(course_id: '', page: page).gsub('//', '/') + (course_external_url || '/').chomp('/') + path + end + + def enote_external_url(enote) + path = Rails.application.routes.url_helpers.enote_path(course_id: '', enote: enote).gsub('//', '/') + (course_external_url || '/').chomp('/') + path + end + + def enote_file_external_url(enote_file) + path = Rails.application.routes.url_helpers.enote_file_path(course_id: @course, file: enote_file).gsub('//', '/') + (course_external_url || '/').chomp('/') + path + end + + private + + def initialize_from_config(args) + @mode = 'editor' + @last_git_commit = nil + @show_report_a_bug = false + @allow_feedback = false + @allow_chat = false + @course = args[:course] + website_config = args[:config] + + @show_report_a_bug = website_config['show_report_a_bug'] if website_config.key? 'show_report_a_bug' + @allow_feedback = website_config['allow_feedback'] if website_config.key? 'allow_feedback' + @course_external_url = website_config['course_external_url'] if website_config.key? 'course_external_url' + end +end diff --git a/app/responders/modal_responder.rb b/app/responders/modal_responder.rb new file mode 100644 index 0000000000000000000000000000000000000000..61711bbdcbd60d28aec70de5946b8ae27d8fb85d --- /dev/null +++ b/app/responders/modal_responder.rb @@ -0,0 +1,29 @@ + +# frozen_string_literal: true + +## +# Responder for sending modal dialogs +# +class ModalResponder < ActionController::Responder + cattr_accessor :modal_layout + + self.modal_layout = 'modal' + + def render(*args) + options = args.extract_options! + options[:layout] = modal_layout if request.xhr? + controller.render(*args, options) + end + + def default_render(*args) + render(*args) + end + + def redirect_to(options) + if request.xhr? + head :ok, location: controller.url_for(options) + else + controller.redirect_to(options) + end + end +end diff --git a/app/services/enotes_service.rb b/app/services/enotes_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..645367aee1aa8619fe9521e9b8b30c21c47d49ec --- /dev/null +++ b/app/services/enotes_service.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +require 'ostruct' +require 'rest-client' + +class GetpdfJobsApi + def self.safe_api_call(default_value, &block) + begin + return block.call || default_value + rescue RestClient::ExceptionWithResponse => ex + Rails.logger.error "GETPDF API Server error response #{ex.response.ai} #{Rack::Utils::HTTP_STATUS_CODES[ex.response.code]}" + rescue SocketError => e + Rails.logger.error "GETPDF API Server socket exception: #{e.ai}" + rescue => e + Rails.logger.error "GETPDF API Server exception: #{e.ai}" + end + return default_value + end + + def self.getpdf_jobs(course) + safe_api_call([]) do + response = RestClient.get "#{WebsiteConfig.get.getpdf_server_url}/api/getpdf/#{course}/summary", accept: :json + + Rails.logger.debug "GETPDF API Server response #{response.ai} #{Rack::Utils::HTTP_STATUS_CODES[response.code]}" + + if response.code == Rack::Utils::SYMBOL_TO_STATUS_CODE[:ok] + js = JSON.parse(response.body).map do |j| + j['lastFinishedAt'] = '' unless j['lastFinishedAt'] + if j['data']&.[]('status') && !j['status'] + j['status'] = j['data']['status'] + end + OpenStruct.new j + end + Rails.logger.info("JSON #{js.ai}") + + js + end + end + end + + def self.getpdf_job(course, jobid) + safe_api_call({}) do + response = RestClient.get "#{WebsiteConfig.get.getpdf_server_url}/api/getpdf/#{course}/#{jobid}", accept: :json + Rails.logger.debug "GETPDF API Server response #{response.ai} #{Rack::Utils::HTTP_STATUS_CODES[response.code]}" + + if response.code == Rack::Utils::SYMBOL_TO_STATUS_CODE[:ok] + js = JSON.parse(response.body) + j = js[0] + if j['data']&.[]('status') && !j['status'] + j['status'] = j['data']['status'] + end + js = OpenStruct.new j + Rails.logger.info("JSON #{js.ai}") + + js + end + end + end + + def self.cancel_getpdf_job(course, jobid) + safe_api_call(nil) do + response = RestClient.delete "#{WebsiteConfig.get.getpdf_server_url}/api/getpdf/#{course}/#{jobid}", accept: :json + Rails.logger.debug "GETPDF API Server response #{response.ai} #{Rack::Utils::HTTP_STATUS_CODES[response.code]}" + + js = nil + if response.code == Rack::Utils::SYMBOL_TO_STATUS_CODE[:no_content] + js = nil + elsif response.code == Rack::Utils::SYMBOL_TO_STATUS_CODE[:ok] + js = JSON.parse(response.body) + end + Rails.logger.info("JSON #{js.ai}") + + js + end + end + + def self.purge_getpdf_jobs(course) + safe_api_call(nil) do + response = RestClient.get "#{WebsiteConfig.get.getpdf_server_url}/api/getpdf/#{course}/purge", accept: :json + Rails.logger.debug "GETPDF API Server response #{response.ai} #{Rack::Utils::HTTP_STATUS_CODES[response.code]}" + end + end + + def self.start_getpdf_job(course) + safe_api_call(nil) do + response = RestClient.post "#{WebsiteConfig.get.getpdf_server_url}/api/getpdf/#{course}", accept: :json + Rails.logger.debug "GETPDF API Server response #{response.ai} #{Rack::Utils::HTTP_STATUS_CODES[response.code]}" + + if response.code == Rack::Utils::SYMBOL_TO_STATUS_CODE[:created] + js = OpenStruct.new JSON.parse(response.body) + Rails.logger.info("JSON #{js.ai}") + + js + end + end + end +end + +class EnotesService + attr_accessor( + :course + ) + + def initialize(course) + @course = course + end + + def getpdf_jobs + GetpdfJobsApi.getpdf_jobs @course + end + + def getpdf_job(jobid) + GetpdfJobsApi.getpdf_job @course, jobid + end + + def cancel_getpdf_job(jobid) + GetpdfJobsApi.getpdf_job @course, jobid + end + + def start_getpdf_job + GetpdfJobsApi.purge_getpdf_jobs course + + GetpdfJobsApi.start_getpdf_job @course + end +end diff --git a/app/services/markdown_service.rb b/app/services/markdown_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..8655c908b6f539b75b2cc97d737b7af5d1a16a35 --- /dev/null +++ b/app/services/markdown_service.rb @@ -0,0 +1,44 @@ +require 'open3' +require 'fileutils' +require 'uri_utils' + +class MarkdownService + + attr_accessor(:md) + + def initialize(md) + @md = md + end + + def check_auth(line, group_set) + m = line.match(/<div class='only' data-only-groups='(.*)'/) + if m + only_groups = Set.new(m[1].split(',').map(&:strip)) + + authorized = group_set.intersect? only_groups + return true, authorized + else + return false, true + end + end + + def enforce_groups(group_set) + authorized = false + in_only = false + div_indent = 0 + + # TODO: this might be a really insufficient parser if folks write a bunch of HTML in their markdown. + # in particular, this will go wrong if there more than one DIV started per line. + md = @md.split(/\r?\n|\r/).map do |line| + if !in_only + (in_only, authorized) = check_auth(line, group_set) + else + in_only = false if (line.match(/<\/div><!-- only -->/)) and div_indent == 0 + end + line if authorized + end.reject(&:nil?).join("\n") + return md + end + +end + diff --git a/app/services/page_compiler_service.rb b/app/services/page_compiler_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..c1367c78541c84e9b22c83baa784c52d4f3968fc --- /dev/null +++ b/app/services/page_compiler_service.rb @@ -0,0 +1,369 @@ +# frozen_string_literal: true + +require 'open3' +require 'fileutils' +require 'uri_utils' +require 'alph' +require 'digest' + +# md-page.coffee will use these tags to prevent the pagedown code +# from messing with the code in between. This is necessary because +# PageDown does not work correctly with significant HTML chunks +VERBATIM_HTML_START = "<div class='verbatim-html'>" +VERBATIM_HTML_END = "</div><!-- verbatim-html -->" + +## +# Page compiler +class PageCompilerService + attr_accessor(:course_id) + attr_accessor(:page_path) + attr_accessor(:valid_link_names) + + def initialize(course_id, page_path, valid_link_names = nil) + valid_link_names ||= { + '' => Set.new([]), + '/uploads' => Set.new([]), + '/enotes' => Set.new([]) + } + @course_id = course_id + @page_path = page_path + @valid_link_names = valid_link_names + end + + def compile_page(out_path) + Rails.logger.info("Processing markdown file #{page_path} to #{out_path}...") + + out_f = File.open(out_path, 'w') + + directive_stack, errors = compile_lines File.open(page_path), page_path do |line_out| + out_f.puts(line_out) + end + + directive_stack.each do |dir| + errors << { file: page_path, line: dir[:line_no], text: 'end of file without closing begin' } + out_f.puts('</div>') + end + + out_f.close + + errors + end + + # private + + cattr_reader :valid_directives + @@valid_directives = %w[only hint answer question quiz] + + cattr_reader :directive_re + @@directive_re = /^\#{7}\s+(?<directive>begin|end|include)/ + + cattr_reader :directive_include_detail_re + @@directive_include_detail_re = /^\#{7}\s+(?<directive>include)(?<file>\s+.*)/ + + cattr_reader :directive_detail_re + @@directive_detail_re = /^\#{7}\s+(?<beginend>begin|end):(?<kind>#{@@valid_directives.join('|')})(?<parameters>\s+.*)?/ + + def compile_lines(input_lines, page_path) + state = PageParseState.new + state.page_path = page_path + + errors = [] + + input_lines.each do |line| + begin + next if line.start_with? '%' + + state.update_doc_location line + + e = compile_line state + compiled_errors = e.nil? ? [] : Array(e) + + compiled_errors = compiled_errors.map do |err| + if err.is_a?(Hash) + err + else + { file: page_path, line: state.line_no, text: err } + end + end + + errors.concat(compiled_errors) + + next if state.output_lines.nil? + + compiled_lines = Array(state.output_lines) + + compiled_lines.each do |compiled_line| + begin + line_out, errs = process_links compiled_line + errs.each { |err| errors << { file: page_path, line: state.line_no, text: err } } + yield line_out + rescue StandardError => e + Rails.logger.error "Error processing links #{e}" + errors << { file: page_path, line: state.line_no, text: 'Internal error processing links.' } + yield compiled_line + end + end + rescue StandardError => e + Rails.logger.error "Error compiling line #{e}" + errors << { file: page_path, line: state.line_no, text: 'Internal error compiling line.' } + raise e if ENV['RAILS_ENV'].eql? 'test' + yield state.output_lines + end + + state.line_no += 1 + end + + [state.directive_stack, errors] + end + + def compile_line(state) + m = PageCompilerService.directive_re.match state.input_line + + unless m + return process_non_directive_line(state) + end + + return process_include_directive(state) if m['directive'].eql? 'include' + + m = PageCompilerService.directive_detail_re.match state.input_line + + unless m + state.output_lines = state.input_line + return nil + end + + process_multiline_directive(state, m) + end + + def process_include_directive(state) + m = PageCompilerService.directive_include_detail_re.match state.input_line + + unless m + state.output_lines = state.input_line + return nil + end + + file = m['file'].strip + + included_page = IncludedPages.get(course_id).pages[file] + + if included_page.nil? + state.output_lines = "<div class='error-directive'> #{file} does not exist </div>" + return "Missing included page #{file} at #{state.line_no}" + end + + inc = ["<div class='hidden inline'>", '$$'] + # note we need to remove any double newlines as this terminates the parsing + # of the block as MathJAX + # TODO: perhaps we should just whitelist actual LaTeX commands, and only include lines with them? + inc.concat(included_page.split("\n").select { |x| x && !x.to_s.strip.empty? }.map { |x| x }) + inc.concat ['$$', '</div>'] + + state.output_lines = inc + nil + end + + def create_directive(state, parameters, kind) + directive = { beginend: 'begin', parameters: parameters, kind: kind, line_no: state.line_no } + doc_location = state.doc_location + + label_map = { + 'only' => '', + 'question' => (doc_location[:question_no]).alph, + 'hint' => 'Hint', + 'answer' => 'Answer' + } + + case kind + when 'only' + directive[:start_output] = + "<div class='only' data-only-groups='#{directive[:parameters]}'>" + directive[:end_output] = + "</div><!-- #{directive[:kind]} -->" # semi-magic: it's how we find the end of the begin:only for enforcing group permissions + else + doc_attr = '' + if doc_location + question_id = doc_location[:section_no][0].to_s + '.' + doc_location[:section_no][1].to_s + '.' + doc_location[:question_no].to_s + doc_attr = "data-section='#{doc_location[:section_no][0]}'" \ + " data-subsection='#{doc_location[:section_no][1]}'" \ + " data-question='#{question_id}'" + end + directive[:start_output] = + "<div class='#{directive[:kind]}#{' hide' if directive[:kind].eql?('answer') || directive[:kind].eql?('hint')} directive-region' #{doc_attr}>" \ + "<div class='directive-region-item-container'>" \ + "<div class='directive-region-label'>" \ + "<div class=' '>#{label_map[directive[:kind]]}</div>" \ + "</div>" \ + "<div class='directive-region-item'>" + directive[:end_output] = + "</div>"\ + "</div>"\ + "</div>"#"<!-- #{directive[:kind]} -->" # semi-magic: it's how we find the end of the begin:only for enforcing group permissions + end + + directive + end + + def end_directive(state) + dir = state.directive_stack.pop + + unless dir[:kind].eql? 'quiz' + state.output_lines = dir[:end_output] + return nil + end + + qs = QuizService.new(state.quiz_question_lines) + + if qs.quiz_errors.empty? + Rails.logger.info "QUIZ QUESTION\n#{qs.quiz_model.ai}" + + #qs.quiz_model.sections[0].elements.each { |e| Rails.logger.info "#{e.class} #{e.ai}" } + + html = ApplicationController.renderer.render(qs.quiz_model, + layout: false) + + state.output_lines = [VERBATIM_HTML_START, (html), VERBATIM_HTML_END] + + return nil + end + + state.output_lines = "<span class='quiz-error'>Error in quiz definition. See Admin panel for details.</span>" + qs.quiz_errors.map do |qe| + question_err_line = dir[:line_no] + question_err_line += qe[:line_num] if qe[:line_num].is_a?(Integer) + { file: state.page_path, + line: question_err_line, + text: "#{qe[:fatality]} #{qe[:kind]} #{qe[:text]}" } + end + end + + def process_begin_multiline_directive(state, kind, parameters) + if (kind == 'only') && !parameters + 'begin:only without a list of groups' + else + state.quiz_question_lines = [] if state.in_quiz_question? + + state.doc_location[:question_no] = state.doc_location[:question_no] + 1 if state.doc_location && question?(kind) + + state.directive_stack.push(create_directive(state, parameters, kind)) + + state.quiz_question_lines = [] + state.output_lines = state.directive_stack.last[:start_output] unless kind.eql? "quiz" + nil + end + end + + def process_multiline_directive(state, m) + return process_begin_multiline_directive(state, m['kind'], m['parameters']) if m['beginend'].eql? 'begin' + + if state.directive_stack.empty? + return 'end without a corresponding begin' + else + current_directive = state.directive_stack.last + + if current_directive[:kind] != m['kind'] + return "end:#{m[:kind]} attempting to close a begin:#{current_directive[:kind]} from line #{current_directive[:line_no]}" + else + unless PageCompilerService.valid_directives.include? current_directive[:kind] + return "invalid directive #{current_directive[:kind]} from current_directive[:line_no]} to #{line_no}" + end + return end_directive state + end + end + + error + end + + def process_links(line) + errs = [] + line = line.gsub(PageCompilerService.md_link_re) do |m| + lm = Regexp.last_match + + link_name = lm['nm'] + href = lm['href'] + href = href.slice(1, href.length - 2) # remove parens + + return process_podcast_link(href) if link_name.eql?('Podcast link') + + if href.start_with?('http') + m + else + link, err = PageUtil.page_link(course_id, link_name, href, valid_link_names) + errs << err if err + link + end + end + + [line, errs] + end + + def process_podcast_link(href) + podcast_svc = PodcastService.new(page_path, href, @course_id) + + podcast_json = podcast_svc.parse + + if podcast_json + + ## TODO: it would be better to convert the podcast feed JSON into + # a view model for the .erb; the .erb code is way too complex, and + # now we have the PodcastService which would be a great place to host + # such code... + # + # sort by date: https://github.com/dtu-compute/dtu-enote-website/issues/63 + podcast_json['episodes'].sort! { |epl, epr| epl['pubDate'] <=> epr['pubDate'] }.reverse! + + html = ApplicationController.renderer.render template: 'podcasts/index.html.erb', + locals: { podcast_json: podcast_json }, layout: false + return html, [] + else + return "\n<span class='link-error'>Unreadable podcast link [#{href}](#{href})</span>\n", ["Cannot read podcast feed #{href}"] + end + end + + # magic regexp to catch nested () (but not nested []) + # http://stackoverflow.com/questions/6331065/matching-balanced-parenthesis-in-ruby-using-recursive-regular-expressions-like-p + # sadly this is too greedy. + cattr_reader :md_link_re + @@md_link_rre = / +\[(?<nm>.*)\](?<href> + \( + (?: + (?> [^()]+ ) + | + \g<href> + )* + \) +) +/x + + @@md_link_re = / +\[(?<nm>[^\[\]\]]*)\](?<href>\([^()]+\)) +/x + + def question?(kind) + kind.eql? 'question' + end + + private + + ## + # Process a line without a directive + def process_non_directive_line(state) + if state.in_quiz_question? + + state.quiz_question_lines << state.input_line + + # inject fake text element because we want a simpler syntax for the + # website + if state.input_line.match %r{begin:multiple_choice\s*} or + state.input_line.match %r{begin:all_that_apply\s*} + state.quiz_question_lines << "text 'question'" + end + state.output_lines = nil + else + state.output_lines = state.input_line + end + + nil + end +end diff --git a/app/services/page_parse_state.rb b/app/services/page_parse_state.rb new file mode 100644 index 0000000000000000000000000000000000000000..98fb4ee3985dd23a742bb3f476fbe07c3adfa146 --- /dev/null +++ b/app/services/page_parse_state.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +## +# Parser state for the page +class PageParseState + attr_accessor :input_line + attr_accessor :output_lines + attr_accessor :line_no + attr_accessor :doc_location + attr_accessor :page_path + attr_accessor :error + attr_accessor :directive_stack + attr_accessor :quiz_question_lines + + def initialize + self.line_no = 1 + self.directive_stack = [] + self.quiz_question_lines = [] + self.output_lines = '' + self.doc_location = { + section_no: [0, 0], + question_no: 0 + } + self.error = nil + end + + def update_doc_location(line) + heading = /^(#+)[^#].*/.match(line) + if heading + level = heading[1].length + if level == 1 + @doc_location[:section_no] = [@doc_location[:section_no][0] + 1, 0] + elsif level == 2 + @doc_location[:section_no][1] = @doc_location[:section_no][1] + 1 + end + + if level <= 3 + # reset numbering after every header <= h3. + # This implements 'local' numbering under all h1, h2, h3 + # https://github.com/dtu-compute/dtu-enote-website/issues/220 + @doc_location[:question_no] = 0 + end + end + + @input_line = line + @output_line = nil + end + + def in_quiz_question? + directive_stack.last&.[](:kind).eql?('quiz') || false + end +end diff --git a/app/services/pages_service.rb b/app/services/pages_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..6c13b0b5a3560a08d4a7ce4a1877578990c1e358 --- /dev/null +++ b/app/services/pages_service.rb @@ -0,0 +1,329 @@ +# frozen_string_literal: true + +# Service class for operations on pages: compiling, renaming deleting, etc... +# +class PagesService + def initialize(course) + @course = course + end + + def update + rebuild_all_pages + + Pages.refresh @course + + ServiceResult.new(true, 'Pages updated successfully') + end + + def remove_all_compiled_pages + old_files = Dir.glob(File.join(compiled_folder, '*.md')) + Rails.logger.info("Deleting old markdown pages #{old_files.ai}...") + old_files.each do |f| + Rails.logger.debug("Deleting #{f}") + File.delete(f) + end + + Errors.clear_all! @course + end + + # smarter version of the recompile which only files which have changed, and only deleted + # those which are excess + def rebuild_all_pages(page_files = nil, delete_other_files = true) + page_files = Dir.glob(File.join(raw_md_folder, '*.md')) if page_files.nil? + + compiled_files = page_files.map do |page_file| + [page_file, File.join(compiled_folder, File.basename(page_file))] + end.to_h + errors = [] + + to_compile = page_files.reject do |page_file| + out_path = compiled_files[page_file] + File.exist?(out_path) && File.stat(out_path).mtime >= File.stat(page_file).mtime + end + + Rails.logger.info("Compiling markdown for course #{@course} pages #{to_compile}...") + + IncludedPages.get(@course).refresh + + to_compile.each do |page_file| + error = file_updated page_file, compiled_files[page_file] + Errors.set_page(@course, page_file, error) + errors.concat error unless error.empty? + end + + errors.each do |error| + Rails.logger.warn("Parse error: #{error[:file]}:#{error[:line]} #{error[:text]}") + end + + compiled_files = Dir.glob(File.join(compiled_folder, '*.md')) + compiled_set = Set.new(compiled_files.map { |x| File.basename(x) }) + raw_set = Set.new(page_files.map { |x| File.basename(x) }) + + if delete_other_files + to_delete = compiled_set - raw_set + + Rails.logger.warn "Files to be deleted: #{to_delete.ai}" + + to_delete.each do |f| + Rails.logger.debug("Deleting #{f}") + File.delete(f) + end + end + + uncompiled = raw_set - compiled_set + + check_missing_menu_pages + + Rails.logger.warn "Files which aren't compiled #{uncompiled.ai}" + end + + def special_page?(page) + (page.eql? Menu.PageName) + end + + def compile_all_pages + pages = Dir.glob(File.join(raw_md_folder, '*.md')).map { |f| File.basename(f, '.md') } + + # make sure to compile all the "non special" pages first + pages = pages.reject { |p| special_page? p }.sort + pages.select { |p| special_page? p } + + remove_all_compiled_pages + + Rails.logger.info("Compiling markdown pages #{pages.ai}...") + + errors = [] + + DTUFileManagement::FileManager.instance.update + IncludedPages.get(@course).refresh + Enotes.instance.refresh @course + + pages.each do |page| + out_path = File.join(compiled_folder, page + '.md') + page_file = File.join(raw_md_folder, page + '.md') + + error = file_updated page_file, out_path + + Errors.set_page(@course, page_file, error) + + errors.concat error unless error.empty? + end + + check_missing_menu_pages + + Rails.logger.info 'Compile_all_pages completed. Errors:' + + Errors.get(@course).errors.map do |error| + Rails.logger.warn("Parse error: #{error}") + end + end + + def check_missing_menu_pages + expected_pages = Menu.get(@course).expected_menu_pages + expected_pages.each do |page| + expected_file = Pages.get_file_name(compiled_folder, page) + + next if File.exist? expected_file + + Errors.set_page(@course, expected_file, [ + { file: expected_file, refer_page: page, line: 0, text: 'Missing file referenced in Menu' } + ]) + end + end + + def new_page(new_page_name) + if Pages.macros_page? new_page_name + new_macros_page new_page_name + else + new_md_page new_page_name + end + end + + def new_md_page(new_page_name) + page_path = Pages.get_file_name(raw_md_folder, new_page_name) + + return ServiceResult.new(false, "Page #{new_page_name} already exist") if File.exist? page_path + + File.open(page_path, 'w') { |f| f.puts("# #{new_page_name}\n") } + + Pages.refresh @course + Errors.get(@course).clear_missing_page_error new_page_name + rebuild_all_pages + + ServiceResult.new(true, "Page #{new_page_name} added successfully") + end + + def new_macros_page(new_page_name) + page_path = Pages.get_file_name(raw_md_folder, new_page_name) + + return ServiceResult.new(false, "Page #{new_page_name} already exist") if File.exist? page_path + + File.open(page_path, 'w') { |f| f.puts("\n") } + + Pages.refresh @course + + ServiceResult.new(true, "Macros page #{new_page_name} added successfully") + end + + def delete_page(page_name) + if Pages.macros_page?(page_name) + delete_macros_page page_name + else + delete_md_page page_name + end + end + + def delete_md_page(page_name) + page_path = Pages.get_file_name(raw_md_folder, page_name) + compiled_page_path = Pages.get_file_name(compiled_folder, page_name) + + return ServiceResult.new(false, "Page #{page_name} does not exist (#{page_path})") unless File.exist?(page_path) + + lock_path = Pages.get_file_name(raw_md_folder, page_name) + '.lock' + + if File.exist? lock_path + Rails.logger.info "Removing #{lock_path}" + FileUtils.rm lock_path + end + + Rails.logger.info "Removing #{page_path} #{compiled_page_path}" + Errors.set_page(@course, page_name, []) + FileUtils.rm page_path + FileUtils.rm compiled_page_path + + Pages.refresh @course + compile_all_pages # must compile not rebuild since links could be referencing deleted page + + ServiceResult.new(true, "Page #{page_name} removed successfully") + end + + def delete_macros_page(page_name) + page_path = Pages.get_file_name(raw_md_folder, page_name) + + return ServiceResult.new(false, "Macros page #{page_name} does not exist (#{page_path})") unless File.exist?(page_path) + + lock_path = Pages.get_file_name(raw_md_folder, page_name) + '.lock' + + if File.exist? lock_path + Rails.logger.info "Removing macros page lock #{lock_path}" + FileUtils.rm lock_path + end + + Rails.logger.info "Removing macros page files #{page_path} and #{compiled_page_path}" + FileUtils.rm page_path + + Pages.refresh @course + compile_all_pages # any file might depend upon the macros + + ServiceResult.new(true, "Macros #{page_name} removed successfully") + end + + def rename_page(page_name, new_page_name) + return ServiceResult.new(false, 'Cannot rename macros file') if Pages.macros_page?(page_name) + + page_path = Pages.get_file_name(raw_md_folder, page_name) + compiled_page_path = Pages.get_file_name(compiled_folder, page_name) + + return ServiceResult.new(false, "Page #{page_name} does not exist") unless File.exist? page_path + + new_page_path = Pages.get_file_name(raw_md_folder, new_page_name) + new_compiled_page_path = Pages.get_file_name(compiled_folder, new_page_name) + + Rails.logger.info "Renaming #{page_path} to #{new_page_path}" + Errors.set_page(@course, page_name, []) + FileUtils.mv page_path, new_page_path + FileUtils.mv compiled_page_path, new_compiled_page_path + + Pages.refresh @course + compile_all_pages # must compile not rebuild since links could be referencing old page + + ServiceResult.new(true, "Page #{page_name} moved to #{new_page_name} successfully") + end + + def edit_page(page_name, user) + editing = who_is_editing? page_name + + lock_path = Pages.get_file_name(raw_md_folder, page_name) + '.lock' + + if editing + if user.nil? + FileUtils.rm lock_path + (who_is_editing? page_name).nil? # we succeed if there's no one editing the file (slight potential race cond.) + else + false + end + else + File.open(lock_path, 'w') { |f| f.write user._id } + true + end + end + + def file_updated(page_file, compiled_file) + page = File.basename(page_file, '.md') + + begin + if page.eql? Menu.PageName + _menu, errors = Menu.refresh @course + return errors + end + + uploads = (DTUFileManagement::FileManager.instance.uploads_files[@course] || []).map do |u| + u.gsub(DTUFileManagement::FileManager.instance.get_local_folder_path(:uploads, @course), '') + .delete_prefix('/') + end + valid_links = { + '' => Pages.get(@course).valid_page_names, + '/uploads' => Set.new(uploads), + '/enotes' => Set.new(Enotes.instance.get(@course)[:enotes]) + } + + Rails.logger.debug("valid links = #{valid_links.ai}") + + return PageCompilerService.new(@course, page_file, valid_links).compile_page compiled_file + rescue StandardError => e + Rails.logger.error "Error compiling #{page_file} to #{compiled_file}: #{e.ai}" + Rails.logger.error e.backtrace.ai + return [{ file: page_file, line: 0, text: 'Internal error compiling file.' }] + end + end + + def who_is_editing?(page_name) + page_path = Pages.get_file_name raw_md_folder, page_name + + unless File.exist? page_path + Rails.logger.error "attempt to ask for who is editing a file which doesn't exist: #{page_name} #{page_path}" + return nil + end + + lock_path = page_path + '.lock' + + read_lockfile lock_path + end + + def read_lockfile(lock_path) + return nil unless File.exist? lock_path + File.read lock_path + end + + def all_current_edits + lock_files = Dir.glob(File.join(raw_md_folder, '*.lock')) + lock_files.map do |lock_file| + page_file_name = File.basename(lock_file, '.lock') + + page_name = File.basename(page_file_name, File.extname(page_file_name)) + + { + name: page_name, + user: read_lockfile(lock_file), + locked_time: File.stat(lock_file).ctime + } + end || [] + end + + def raw_md_folder + WebsiteConfig.get.courses[@course].pages_source_path + end + + def compiled_folder + WebsiteConfig.get.courses[@course].pages_compiled_path + end +end diff --git a/app/services/podcast_service.rb b/app/services/podcast_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..44bdbb4e2da76e6a058b231dd8be895f253463a0 --- /dev/null +++ b/app/services/podcast_service.rb @@ -0,0 +1,131 @@ +require 'digest' +require 'open-uri' + +def get_durations(episodes) + episodes.map do |ep| + ep['media'].each.select {|key, info| key != 'thumbnail'}.map do |key, info| + info['duration'] + end.reject(&:nil?) + end.flatten! +end + + +class PodcastService + attr_accessor(:page_path) + attr_accessor(:podcast_href) + attr_accessor(:course_id) + + def initialize(page_path, podcast_href, course_id = nil) + @page_path = page_path + @podcast_href = podcast_href + @course_id = course_id + end + + def self.load_file(podcast_json_path) + Rails.logger.info "Attempting to load cached stream #{podcast_json_path}" + begin + record = JSON.parse(File.read(podcast_json_path)) + # check that we have all the expected fields + return nil unless ['page_path', 'href', 'content'].map{|k| record.has_key? k}.reduce(:&) + return record + rescue JSON::ParserError => ef + Rails.logger.error "Error parsing podcast JSON from file at #{podcast_json_path} #{ef}" + end + end + + def self.new_podcasts?(podcast_json_path) + old_podcast_record = PodcastService.load_file podcast_json_path + + unless old_podcast_record + Rails.logger.warn "Could not load podcast record file #{podcast_json_path}" + return true + end + + new_svc = PodcastService.new old_podcast_record['page_path'], old_podcast_record['href'] + + new_podcast_json = new_svc.parse false + + unless new_podcast_json + Rails.logger.warn "Could not fetch podcast feed for #{@page_path} #{@podcast_href}" + return false + end + + Rails.logger.debug "Checking for new episodes of #{old_podcast_record['href']} for #{old_podcast_record['page_path']}" + PodcastService.new_podcast_episodes? old_podcast_record['content'], new_podcast_json + end + + def self.new_podcast_episodes?(old_feed, new_feed) + old_pubs = Set.new(old_feed['episodes'].map{|p| p['pubDate']}.reject(&:nil?)) + new_pubs = Set.new(new_feed['episodes'].map{|p| p['pubDate']}.reject(&:nil?)) + + diff = old_pubs - new_pubs + + Rails.logger.debug "Differences in pubDates: #{diff.ai}" + + return true unless diff.empty? + + + old_durations = Set.new(get_durations old_feed['episodes']) + new_durations = Set.new(get_durations new_feed['episodes']) + #Rails.logger.debug "Old durations: #{old_durations.ai}" + #Rails.logger.debug "New durations: #{new_durations.ai}" + + diff = new_durations - old_durations + + Rails.logger.debug "Differences in durations: #{diff.ai}" + + return !diff.empty? + end + + def parse(cache = true) + # testing provision: + if podcast_href.starts_with? '/' + return JSON.parse(File.read(File.join(PagesService.new(@course_id).raw_md_folder, podcast_href))) + end + + uri = URI.parse( podcast_href ) + + href_filename = filename + + # Submit request + podcast_json = nil + begin + Rails.logger.info "Fetching podcast #{uri} #{href_filename} #{cache}" + body = uri.read + podcast_json = JSON.parse(body) + + record = { + downloaded_time: DateTime.now, + page_path: page_path, + href: podcast_href, + content: podcast_json + } + + return podcast_json unless cache + + Rails.logger.info "Writing podcast JSON file to #{href_filename} for #{page_path}" + File.open(href_filename,"w") do |f| + f.write(record.to_json) + end + rescue JSON::ParserError => e + Rails.logger.error "Error parsing podcast JSON at uri #{uri.ai} #{e}" + + return nil unless cache + + if File.exist? href_filename + podcast_json = (PodcastService.load_file(href_filename)).content + else + Rails.logger.warn "No load cached stream #{href_filename} for #{page_path}" + end + end + + podcast_json + end + + def filename() + href_part = Digest::SHA256.hexdigest podcast_href + File.join(File.dirname(page_path), File.basename(page_path, ".md") + "-" + href_part + ".json") + end + + +end diff --git a/app/services/quiz_service.rb b/app/services/quiz_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..3bbe13694a23c294273d2149fe328f40d9b28ba9 --- /dev/null +++ b/app/services/quiz_service.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +## +# Service for parsing DTU quiz format +class QuizService + attr_accessor :quiz_model + attr_accessor :quiz_errors + + def initialize(quiz_text) + @quiz_errors = [] + @quiz_content = [] + begin + Rails.logger.info 'Parsing quiz.' + + fulltext = quiz_text.join('\n') + '\n' + '\n' + + Rails.logger.info fulltext + quiz_strio = StringIO.new # fulltext, 'r' + + quiz_text.each { |str| quiz_strio.puts(str) } + quiz_strio.rewind + + quiz_parser = Quiz::QuizParser.new nil + + quiz_parser.build! quiz_strio + + @quiz_model = quiz_parser.content + + @quiz_errors = JSON.parse(quiz_parser.errors.to_json).map(&:symbolize_keys) + rescue StandardError => e + Rails.logger.error "Parser failed! #{e}" + @quiz_errors << { + fatality: 'critical', + line_num: '-', + kind: 'parse error', + text: "Catastrophic parser failure #{e}" + } + end + end +end diff --git a/app/services/service_result.rb b/app/services/service_result.rb new file mode 100644 index 0000000000000000000000000000000000000000..d6cc4736c85af0a28c13c93d050a979928d581e8 --- /dev/null +++ b/app/services/service_result.rb @@ -0,0 +1,17 @@ +class ServiceResult + attr_accessor( + :success, + :message, + :details) + + def initialize(success, message, details = {}) + @success = success + @message = message + @details = details + end + + def status + @success ? :ok : :bad_request + end + +end diff --git a/app/services/update_service.rb b/app/services/update_service.rb new file mode 100644 index 0000000000000000000000000000000000000000..884595e12f1c72e61c5e7f2dfba206e29416c5cb --- /dev/null +++ b/app/services/update_service.rb @@ -0,0 +1,143 @@ +# frozen_string_literal: true + +require 'open3' +require 'fileutils' + +## +# Updates +class UpdateService + attr_accessor( + :course + ) + + def initialize(course) + @course = course + end + + def raw_md_folder + WebsiteConfig.get.courses[course].pages_source_path + end + + def compile_pages + PagesService.new(course).compile_all_pages + end + + def launch_compile_enotes + Rails.logger.info("Launching Compiling eNotes for course #{course}...") + + js = EnotesService.new(course).start_getpdf_job + + if js + Rails.logger.info('API completed successfully') + else + Rails.logger.error('API returned error condition') + end + + js + end + + def compile_enotes + compile_job = launch_compile_enotes + + if compile_job.nil? + Rails.logger.error('Failed to launch getpdf job') + return nil + end + + Rails.logger.debug(compile_job.ai.to_s) + + Rails.logger.info("Waiting for eNotes to finish compiling for course #{course}...") + + enotes_svc = EnotesService.new(course) + 100.times do + job = enotes_svc.getpdf_job compile_job._id + + Rails.logger.debug(job.ai.to_s) + + unless job.nil? + if job['status'].eql? 'completed' + Rails.logger.info('API job completed successfully') + return job + end + if job['status'].eql? 'failed' + Rails.logger.info('API job failed') + return job + end + end + + sleep 2 + end + + Rails.logger.error('Timeout waiting for api job to complete!') + nil + end + + def any_staging_enotes_to_publish? + staging_path = EnotesStaging.instance.get_root_path(course) + + Dir.glob(File.join(staging_path, '**/*')).length.positive? + end + + def publish_enotes + pub_path = Enotes.instance.get_root_path(course) + staging_path = EnotesStaging.instance.get_root_path(course) + + Rails.logger.info "Publishing #{staging_path} to #{pub_path}" + FileUtils.rm_rf(Dir.glob(File.join(pub_path, '**/*'))) + + Dir.glob(File.join(staging_path, '**/*')).each do |file| + dest = File.join(pub_path, file.gsub(staging_path.to_s, '')) + # will raise if this fails + # FileUtils.move file, dest + FileUtils.mv(file, dest, verbose: true, force: true) + end + + update_enotes + end + + def update_enotes + DTUFileManagement::FileManager.instance.update + Enotes.instance.refresh course + EnotesStaging.instance.refresh course + Rails.logger.info(DTUFileManagement::FileManager.instance.enotes_files.ai) + end + + def update_filemanager(_user = DTUAuth2::CachedAuthorizationManager.system_user) + Rails.logger.info('Updating FileManager') + + # TODO: in the new world order of the filemanager, does anything happen here? + # sync_website_repo(:files, user) + # + # fm_folder = DTUFileManagement::FileManager.instance.uploads_folder(@course) + # gitinfo = WebsiteConfig.get.courses[@course].files_git_repo_info + # + # Rails.logger.info("emptying #{fm_folder}") + # + # FileUtils.rm_rf(Dir.glob(fm_folder + '/*')) + # + # Rails.logger.info("copying #{gitinfo.local_repo_folder} to #{fm_folder}") + # + # FileUtils.copy_entry gitinfo.local_repo_folder, fm_folder # , :remove_destination => true + # + # FileUtils.rm_rf(Dir.glob(fm_folder + '/.git')) + Rails.logger.info('Updating file manager') + + DTUFileManagement::FileManager.instance.update + end + + def new_podcasts? + podcast_cache_records = Dir.glob(File.join(raw_md_folder, '*.json')) + + new_podcasts = podcast_cache_records.map do |podcast_record_path| + podcast_record_path if PodcastService.new_podcasts? podcast_record_path + end.reject(&:nil?) + + new_podcasts_href = new_podcasts.map do |podcast_json_path| + (PodcastService.load_file podcast_json_path)&.[]('href') + end + + abort("new podcasts found #{new_podcasts.ai}, #{new_podcasts_href.ai}") unless new_podcasts.empty? + + false + end +end diff --git a/app/views/admin/_feedback.html.erb b/app/views/admin/_feedback.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..f49af8546bddefa0972655a492fdf23762a603c3 --- /dev/null +++ b/app/views/admin/_feedback.html.erb @@ -0,0 +1,42 @@ +<div id="modal-holder"></div> + +<div class="row"> + <div class="checkbox-inline col-md-offset-5 col-2 "> + <form> <!-- input checked="checked" won't work in FF unless it's in a form ¯\_(ツ)_/¯ outes--> + <label class="enable-feedback"> + <input id="enable-feedback-checkbox" + type="checkbox" + checked="<%= {true => 'checked', false => 'unchecked' }[WebsiteConfig.get.courses[my_course_id].allow_feedback] %>" + onchange="AdminPage.setAllowFeedback(event, '<%= admin_feedback_set_allowed_path(my_course_id) %>');" /> + Enable Feedback + </label> + </form> + </div> +</div> + +<div class="row"> + <div class="col-md-offset-1 col-md-10 admin-feedback-spacer"></div> +</div> + +<div class="row"> + <div class="feedback-actions"> + <div class="col-md-offset-1 col-md-2 "> + <button class='btn btn-primary' onclick="AdminPage.deleteAllSelected(event, <%= course_feedbacks_path(my_course_id) %>);">Delete all Selected</button> + </div> + </div> +</div> + +<div class="row"> + <div class="col-md-offset-1 col-md-10 admin-feedback-spacer"></div> +</div> + +<div class="row"> + <div class="col-md-12 feedback-grid"> + <%= datagrid_form_for @feedback_grid, :html => {:class => "feedback-grid-form"}, :method => :get, :url => course_feedbacks_path(my_course_id) %> + + <%= render :partial => "admin/feedback_grid.html.erb", :locals => {grid: @feedback_grid} %> + + <%= paginate(@feedback_grid.assets) %> + + </div> +</div> \ No newline at end of file diff --git a/app/views/admin/_feedback_grid.html.erb b/app/views/admin/_feedback_grid.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..47fe59fd8359b1be22c4a45b153ee5cef38b189b --- /dev/null +++ b/app/views/admin/_feedback_grid.html.erb @@ -0,0 +1,2 @@ + +<%= datagrid_table @feedback_grid, :partials => "feedback_datagrid", :html => {:class => "datagrid feedbackx-grid-table feedback-grid col-md-12 "} %> diff --git a/app/views/admin/_filemanager.html.erb b/app/views/admin/_filemanager.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..79df5fb7757b4e3d04d899c00faed3a49ac7cb51 --- /dev/null +++ b/app/views/admin/_filemanager.html.erb @@ -0,0 +1,64 @@ +<h3>Edit</h3> + +<a href="https://filemanager<%= Rails.configuration.deployment_environment['enote_domain_suffix'] %>?expandedFolder=/<%= my_course_id %>" target='blank' class="btn btn-default">Edit in Filemanager</a> + +<h3>Files</h3> + +<div class="container"> + <div class="row"> + <div class="col-md-8" style="display:none;"> + <h2>eNotes</h2> + <%= form_for :course_enotes_files, html: {method: "get"} do |f| %> + <table class="table"> + <thead> + <tr> + <th></th> + <th>Filename</th> + <th>Uploaded</th> + </tr> + </thead> + <tbody> + <% if @course_enotes_viewmodel.any? %> + <% @course_enotes_viewmodel.each do |file| %> + <tr> + <td><%= check_box_tag 'files[]', file %></td> + <td><%= file[:friendly_name] %></td> + <td><%= file[:mtime] %></td> + </tr> + <% end %> + <% end %> + </tbody> + </table> + <%= f.submit 'Remove From Live', class: 'btn btn-danger' %> + <%= f.submit 'Refresh', class: 'btn btn-primary' %> + <% end %> + </div> + <div class="col-md-8" style="display:block;"> + <h2>Uploads</h2> + <div id="filemanager_tree"></div> + <div class='btn-group'> + <button class="btn btn-primary" id="update-uploads" onclick='return updateFileManager(event, "<%= update_filemanager_path %>");'> Update </button> + <% unless files_href.nil? %> + <a href="<%= files_href %>" class="btn btn-primary" target="_blank" role="button">View Files</a> + <% end %> + </div> + <hr/> + </div> + </div> +</div> +<script> + $('#course_select').bind('change', function() { + window.location.pathname = $(this).val() }); + + function renameClicked(event) { + event.preventDefault() + var file = $(event.target).data('file'); + $("#course_enotes_rename_rename_to").val(file); + $("#course_enotes_rename_rename_from").val(file); + $('#rename-modal').on("click", 'input[type="submit"]', function(d) { $('#rename-modal').modal('hide'); }); + $('#rename-modal').modal('show'); + } + + var filemanager_tree = <%= filemanager_tree.to_json.html_safe %>; + $('#filemanager_tree').treeview({data: filemanager_tree.nodes, showTags: true, enableLinks: true}); +</script> diff --git a/app/views/admin/_getpdf_job_log_dialog.html.erb b/app/views/admin/_getpdf_job_log_dialog.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..1260a970aa6f2c6412aa5649fe76ce1bacc1b81a --- /dev/null +++ b/app/views/admin/_getpdf_job_log_dialog.html.erb @@ -0,0 +1,24 @@ + +<!-- Modal --> +<div id="getpdf_job_logs" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitle" aria-hidden="true"> + <div class="modal-dialog modal-xl" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <div style="display: inline-block"> + <h5 class="modal-title" id="exampleModalLongTitle">eNote PDF Conversion Logs</h5> + </div> + <div style="display: inline"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + </div> + </div> + <div class="modal-body"> + <pre id="log-content"></pre> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/app/views/admin/_header.html.erb b/app/views/admin/_header.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..383d3daa28a64b65012a273709767736b24e9736 --- /dev/null +++ b/app/views/admin/_header.html.erb @@ -0,0 +1,25 @@ + +<ul class="nav nav-tabs" role="tablist"> + <li role="presentation" class="<%= "active" if selected_tab.eql? "pages" %>"> + <a href="<%= map_url({course_id: course_id}) { |p| admin_pages_path p } %>">Pages</a> + </li> + <li role="presentation" class="<%= "active" if selected_tab.eql? "enotes" %>"> + <a href="<%= map_url({course_id: course_id}) { |p| admin_enotes_path p } %>">ShareLatex</a> + </li> + <li role="presentation" class="<%= "active" if selected_tab.eql? "files" %>"> + <a href="<%= map_url({course_id: course_id}) { |p| admin_files_path p } %>">File Manager</a> + </li> + <li role="presentation" class="<%= "active" if selected_tab.eql? "course" %>"> + <a href="<%= map_url({course_id: course_id}) { |p| admin_course_path p } %>">Course</a> + </li> + <li role="presentation" class="<%= "active" if selected_tab.eql? "feedback" %>"> + <a href="<%= map_url({course_id: course_id}) { |p| admin_feedback_path p } %>">Feedback</a> + </li> +</ul> + +<div class="row flash-container"> + <div class="col-offset-3 col-6" id="flash-message"> + <% flash_messages %> + </div> +</div> + diff --git a/app/views/admin/_script.js.erb b/app/views/admin/_script.js.erb new file mode 100644 index 0000000000000000000000000000000000000000..58447950a2c98f1a69dac99e809340cb546678b3 --- /dev/null +++ b/app/views/admin/_script.js.erb @@ -0,0 +1,27 @@ +var renderCoursePage = {}; + +<% if Rails.env.production? %> +function stripCourse(config) { + for (var url in config.urls) { + if (config.urls.hasOwnProperty(url)) { + config.urls[url] = config.urls[url].replace(new RegExp("^\/("+config.course_id+")"),""); + } + } + return config; +} +<% else %> +function stripCourse(config) { return config; }; +<% end %> + +var ADMIN_CONFIG = stripCourse({ + course_id: '<%= course_id %>', + urls: { + page_index_url: '<%= page_index_path(:page_name => 'PAGE_NAME') %>', + edit_page_url: '<%= show_page_path(:page => 'PAGE_NAME') %>?mode=edit', + show_page_url: '<%= show_page_path(:page => 'PAGE_NAME') %>', + recompile_all_pages_url: '<%= recompile_all_pages_path %>', + rename_page_url: '<%= rename_page_path(:page_name => 'FROM_NAME', :to_name => 'TO_NAME') %>', + stop_editing_page_url: '<%= stop_editing_path(:page_name => 'PAGE_NAME') %>', + getpdf_job_url: '<%= getpdf_job_path(:job_id => 'JOB_ID') %>' + } +}); diff --git a/app/views/admin/_sharelatex.html.erb b/app/views/admin/_sharelatex.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..9d90abd4699757d551170a14bd9da90cd793bf94 --- /dev/null +++ b/app/views/admin/_sharelatex.html.erb @@ -0,0 +1,94 @@ + +<h3>Edit</h3> + +<a href="/sharelatex" target='blank' class="btn btn-default">Edit in Sharelatex</a> + +<h3>Compile</h3> + +<button class="btn btn-primary" id="build-enotes" onclick='return buildEnotes(event, "<%= build_enotes_path %>");'> + Compile +</button> + +<table class="getpdf-jobs-grid-table"> + <thead> + <tr> + <th>Status</th> + <th>Started</th> + <th>Finished</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + <% if @latest_getpdf_job %> + <tr id="current-getpdf-job" data-getpdfjobid="<%= @latest_getpdf_job._id %>"> + <td class='getpdf_job_status getpdf_status_<%= @latest_getpdf_job._id %>'> + <%= (@latest_getpdf_job.status || 'UNKNOWN').html_safe %> + </td> + <td class="getpdf_job_lastRunAt"> + <%= render_getpdf_time @latest_getpdf_job.lastRunAt %> + </td> + <td class='getpdf_job_lastFinishedAt'> + <%= render_getpdf_time @latest_getpdf_job.lastFinishedAt %> + </td> + <td> + <% + data_path = Rails.application.routes.url_helpers.getpdf_job_path my_course_id, @latest_getpdf_job._id + cancel_path = Rails.application.routes.url_helpers.cancel_getpdf_job_path my_course_id, @latest_getpdf_job._id + publish_path = Rails.application.routes.url_helpers.publish_enotes_path my_course_id + %> + <div class="xbtn-group"> + <button class="btn btn-primary" + id="view-getpdf-job-logs" + onclick='return AdminPage.getGetPDFJobInfo(event, "<%= data_path %>");'> View Logs + </button> + <% if @latest_getpdf_job.status.eql? 'running' %> + <button class="btn btn-primary" + id="cancel-getpdf-job" + onclick='return AdminPage.cancelGetPDFJob(event, "<%= cancel_path %>");'> Cancel Job + </button> + <% end %> + <button class="btn btn-primary" + id="show-staging-enotes" + onclick='return AdminPage.showEnotes(event, "<%= enotes_path %>?kind=staging");'> + List + </button> + <button class="btn btn-primary" + id="publish-staging" + <%= "disabled" unless ready_to_publish?(@latest_getpdf_job) %> + onclick='return AdminPage.publishEnotes(event, "<%= publish_path %>");'> Publish + </button> + + </div> + </td> + </tr> + <% end %> + </tbody> +</table> + +<h3>Published</h3> + +<div class="xbtn-group"> + <button class="btn btn-primary" id="show-staging-enotes" onclick='return AdminPage.showEnotes(event, "<%= enotes_path %>");'> + List + </button> + + <button class="btn btn-primary" id="update-enotes" onclick='return updateEnotes(event, "<%= update_enotes_path %>");'> + Update Menu + </button> +</div> + + + + +<div style="display:none"> + <h3>Sharelatex to eNote PDF Conversion Jobs</h3> + + <div class="col-md-12 getpdf-jobs-grid"> + <%= datagrid_form_for @getpdf_jobs_grid, :html => {:class => "getpdf-jobs-grid-form"}, :method => :get, :url => '/getpdf_jobs/' %> + <%= datagrid_table @getpdf_jobs_grid, :html => {:class => "datagrid getpdf-jobs-grid-table getpdf-jobs-grid col-md-12 "} %> + </div> +</div> + +<script> + window.startAllGetPDFPollers(<%= @running_getpdf.to_json.html_safe %>); +</script> diff --git a/app/views/admin/_view_course_config_dialog.html.erb b/app/views/admin/_view_course_config_dialog.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..2566cde18733cb1be4db734ebd7d8bfe407a3de8 --- /dev/null +++ b/app/views/admin/_view_course_config_dialog.html.erb @@ -0,0 +1,16 @@ +<div id="<%= modal_name %>-modal" class="modal fade" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="<%= modal_name %>-modal-title" class="modal-title"><%= title %></h4> + </div> + <div id="<%= modal_name %>-modal-body" class="modal-body"> + <pre><%= content %> + </pre> + </div> + <div class="modal-footer"> + <button id="status-dismiss-button" type="button" class="btn btn-default btn-primary" data-dismiss="modal">Dismiss</button> + </div> + </div> + </div> +</div> diff --git a/app/views/admin/admin/index.html.erb b/app/views/admin/admin/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..80eba4baec97898a95f2168213d0a8382befe555 --- /dev/null +++ b/app/views/admin/admin/index.html.erb @@ -0,0 +1,27 @@ +<div class="content" style="margin-top: 118px;"> + + <div id="content" class="col-lg-8 col-centered col-lg-offset-2"> + + <%= render :partial => "admin/header", :locals => {selected_tab: @admin_tab, course_id: my_course_id} %> + + <div class="tab-content"> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "pages" %>" id="pages"> + <div style="margin-top:25px"></div> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "enotes" %>" id="enotes"> + <div style="margin-top:25px"></div> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "files" %>" id="files"> + <div style="margin-top:25px"></div> + </div> + </div> + + <div style="margin-top:25px"></div> + <h3>Choose an Administrative Tab</h3> + </div> +</div> + +<script> + <%= render :partial => "admin/script.js.erb", :locals => {course_id: my_course_id} %> +</script> + diff --git a/app/views/admin/admin_course/index.html.erb b/app/views/admin/admin_course/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..0ad3e2725e406c2842fd0aaa754732020798fe97 --- /dev/null +++ b/app/views/admin/admin_course/index.html.erb @@ -0,0 +1,80 @@ + +<%= render :partial => "admin/view_course_config_dialog", :locals => {modal_name: "view-users", content: @users, title: "View users.yaml"} %> +<%= render :partial => "admin/view_course_config_dialog", :locals => {modal_name: "view-groups", content: @groups, title: "View groups.yaml"} %> + + +<div class="content" style="margin-top: 118px;"> + + <div id="content" class="col-lg-8 col-centered col-lg-offset-2"> + + <%= render :partial => "admin/header", :locals => {selected_tab: @admin_tab, course_id: my_course_id} %> + + <div class="tab-content"> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "pages" %>" id="pages"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "enotes" %>" id="enotes"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "files" %>" id="files"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "course" %>" id="course"> + <div class="container"> + <div class="row"> + <div class="col-12 col-centered form-horizontal"> + <div class="form-horizontal"> + <div class="form-group"> + <label class="col-md-3 control-label" for="course-number">CampusNET Participants URL: </label> + <div class="col-md-6"> + <input name="course_number[url]" type="url" class="form-control" id="course-number" value="<%= "https://cn.inside.dtu.dk/cnnet/element/"+@course_element %>"> + </div> + <button class="btn btn-primary btn-default col-md-1" + onclick="return AdminPage.changeCourseNumber(event, '<%= change_course_number_path %>', $('#course-number').val());"> + Save + </button> + </div> + </div> + </div> + </div> + + <div class="row"> + <div class="col-12 col-centered form-horizontal"> + <div class="form-group"> + <label class="col-md-3 align-middle control-label" for="course-updated">Course Member List Updated:</label> + <div class=" col-md-6 align-middle"> + <input class="form-control" id="course-updated" readonly value="<%= @course_members_updated %>"> + </div> + </div> + </div> + </div> + + <div class="row"> + <div class="col-12 col-centered form-horizontal"> + <div class="form-group"> + <label class="col-md-3 control-label" for="course-name">CampusNET Course Name:</label> + <div class=" col-md-6"> + <input class="form-control" id="course-name" readonly value="<%= @course_name %>"> + </div> + </div> + </div> + </div> + + <div class="row"> + <div class="col-12 col-centered"> + <div class="btn-group col-md-offset-4 col-md-4"> + <button class="btn btn-primary" id="view-users" data-toggle="modal" data-target="#view-users-modal"> View Users </button> + <button class="btn btn-primary" id="view-groups"data-toggle="modal" data-target="#view-groups-modal"> View Groups </button> + </div> + </div> + </div> + + </div> + </div> + + </div> +</div> + +</div> + +<script> + <%= render :partial => "admin/script.js.erb", :locals => {course_id: my_course_id} %> +</script> + diff --git a/app/views/admin/admin_enotes/index.html.erb b/app/views/admin/admin_enotes/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..0d1213acd6445e5cae476793171d31d836ae0a37 --- /dev/null +++ b/app/views/admin/admin_enotes/index.html.erb @@ -0,0 +1,24 @@ +<%= render :partial => "admin/getpdf_job_log_dialog", :locals => {} %> + +<div class="content" style="margin-top: 118px;"> + + <div id="content" class="col-lg-8 col-centered col-lg-offset-2"> + + <%= render :partial => "admin/header", :locals => {selected_tab: @admin_tab, course_id: my_course_id} %> + + <div class="tab-content"> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "pages" %>" id="pages"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "enotes" %>" id="enotes"> + <%= render :partial => "admin/sharelatex", :locals => { :running_getpdf => @running_getpdf } %> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "files" %>" id="files"> + </div> + </div> + </div> +</div> + +<script> + <%= render :partial => "admin/script.js.erb", :locals => {course_id: my_course_id} %> +</script> + diff --git a/app/views/admin/admin_feedback/index.html.erb b/app/views/admin/admin_feedback/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..f4d14f7be4fa9143fd58a4dc0f02e5871cc85f48 --- /dev/null +++ b/app/views/admin/admin_feedback/index.html.erb @@ -0,0 +1,24 @@ +<div class="content" style="margin-top: 118px;"> + + <div id="content" class="col-lg-8 col-centered col-lg-offset-2"> + + <%= render :partial => "admin/header", :locals => {selected_tab: @admin_tab, course_id: my_course_id} %> + + <div class="tab-content"> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "pages" %>" id="pages"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "enotes" %>" id="enotes"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "files" %>" id="files"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "feedback" %>" id="feedback"> + <%= render :partial => "admin/feedback", :locals => { :running_getpdf => @running_getpdf } %> + </div> + </div> + </div> +</div> + +<script> + <%= render :partial => "admin/script.js.erb", :locals => {course_id: my_course_id} %> +</script> + diff --git a/app/views/admin/admin_files/index.html.erb b/app/views/admin/admin_files/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..1abe6050b33ebbce797697fd1d2dfffbbbca4736 --- /dev/null +++ b/app/views/admin/admin_files/index.html.erb @@ -0,0 +1,23 @@ +<div class="content" style="margin-top: 118px;"> + + <div id="content" class="col-lg-8 col-centered col-lg-offset-2"> + + <%= render :partial => "admin/header", :locals => {selected_tab: @admin_tab, course_id: my_course_id} %> + + <div class="tab-content"> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "pages" %>" id="pages"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "enotes" %>" id="enotes"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "files" %>" id="files"> + <%= render :partial => "admin/filemanager", :locals => {:filemanager_tree => @filemanager_tree, :files_href => @files_href} %> + </div> + </div> + </div> + </div> +</div> + +<script> + <%= render :partial => "admin/script.js.erb", :locals => {course_id: my_course_id} %> +</script> + diff --git a/app/views/admin/admin_pages/index.html.erb b/app/views/admin/admin_pages/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..4aa0544fbbac8f122218fdb53c36b01217bfba77 --- /dev/null +++ b/app/views/admin/admin_pages/index.html.erb @@ -0,0 +1,136 @@ +<div id="status-modal" class="modal" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="status-modal-title" class="modal-title">Alert</h4> + </div> + <div id="status-modal-body" class="modal-body"> + </div> + <div class="modal-footer"> + <button id="status-dismiss-button" type="button" class="btn btn-default btn-primary" data-dismiss="modal">Dismiss</button> + </div> + </div> + </div> +</div> + +<div id="confirm-delete-modal" class="modal fade" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title">Alert</h4> + </div> + <div class="modal-body"> + <p>Do you really want to delete <span id="confirm-delete-page-name"></span>?</p> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default btn-primary" data-dismiss="modal">No</button> + <button id="confirm-delete-button" type="button" class="btn btn-default" data-dismiss="modal">Delete</button> + </div> + </div> + </div> +</div> + +<div id="rename-modal" class="modal fade" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title">Alert</h4> + </div> + <div class="modal-body"> + <div class="form-group"> + <%= label :rename_to, "Rename to", class: "col-md-4 control-label" %> + <div class="col-md-8"> + <%= text_field :rename, :rename_to, class: "form-control" %> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default btn-primary" data-dismiss="modal">No</button> + <button id="confirm-rename-button" type="button" class="btn btn-default" data-dismiss="modal">Rename</button> + </div> + </div> + </div> +</div> + +<div id="new-page-modal" class="modal fade" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title">Alert</h4> + </div> + <div class="modal-body"> + <div class="form-group"> + <%= label :new_page_name, "New page name: ", class: "col-md-4 control-label" %> + <div class="col-md-8"> + <%= text_field :new_page, :new_page_name, class: "form-control" %> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default btn-primary" data-dismiss="modal">No</button> + <button id="confirm-new-page-button" type="button" class="btn btn-default" data-dismiss="modal">Create</button> + </div> + </div> + </div> +</div> + + +<div class="content" style="margin-top: 118px;"> + + <div id="content" class="col-lg-8 col-centered col-lg-offset-2"> + + <%= render :partial => "admin/header", :locals => {selected_tab: @admin_tab, course_id: my_course_id} %> + + <div class="tab-content"> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "pages" %>" id="pages"> + + <div style="display:none"> + <a href="https://stackedit<%= ENV['ENOTE_DOMAIN_SUFFIX']%>" target='blank' class="btn btn-default">Edit in Stackedit</a> + <button class="btn btn-primary" id="update" onclick='return updateCourseWebsite(event, "<%= update_path %>");'> Update </button> + </div> + + <h3> Page Errors <button class='btn btn-primary btn-group inline' onclick='return PageIndex.recompile_all_pages(event);' > Recompile </button></h3> + + <div class="col-md-12 page-errors-index-grid"> + <%= datagrid_form_for @page_errors_grid, :html => {:class => "page-errors-index-grid-form"}, :method => :get, :url => errors_path(my_course_id) %> + <!-- %= paginate(@grid.assets) % --> + <%= datagrid_table @page_errors_grid, :html => {:class => "datagrid page-errors-index-grid-table page-errors-index-grid col-md-12 "} %> + </div> + + <h3> Valid Groups </h3> + + <div id='valid-groups'> + <% my_groups.each do |group| %> + <div class='valid-group'> <%= group.group %> </div> + <% end %> + </div> + + <h3> Page Index </h3> + + <div class="col-md-12"> + </div> + <div id="editor-commands" class="col-md-12 page-index-commands"> + <button class="btn btn-primary" id="rename-page" onclick='return PageIndex.rename_page(event);'> Rename Page </button> + <button class="btn btn-primary" id="delete-page" onclick='return PageIndex.delete_page(event);'> Delete Page </button> + <button class="btn btn-primary" id="new-page" onclick='return PageIndex.new_page(event);'> New Page </button> + </div> + <div class="col-md-12 page-index-grid"> + <%= datagrid_form_for @page_grid, :html => {:class => "page-index-grid-form"}, :method => :get, :url => pages_path(my_course_id) %> + <!-- %= paginate(@grid.assets) % --> + <%= datagrid_table @page_grid, :html => {:class => "datagrid page-index-grid-table page-index-grid col-md-12 "} %> + </div> + + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "enotes" %>" id="enotes"> + </div> + <div role="tabpanel" class="tab-pane <%= "active" if @admin_tab.eql? "files" %>" id="files"> + </div> + </div> + + </div> +</div> + +<script> + <%= render :partial => "admin/script.js.erb", :locals => {course_id: my_course_id} %> +</script> + diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..4a14d4e8ed2890e2ed8f08ee2c5e0c5b5b1793c4 --- /dev/null +++ b/app/views/admin/index.html.erb @@ -0,0 +1,100 @@ +<%= render :partial => "admin/getpdf_job_log_dialog", :locals => {} %> + + + + <div class="content" style="margin-top: 118px;"> + + <div id="content" class="col-lg-8 col-centered col-lg-offset-2"> + + <ul class="nav nav-tabs" role="tablist"> + <li role="presentation" class="active"><a href="#stackedit" aria-controls="stackedit" role="tab" data-toggle="tab">Pages</a></li> + <li role="presentation"><a href="#sharelatex" aria-controls="sharelatex" role="tab" data-toggle="tab">ShareLatex</a></li> + <li role="presentation"><a href="#filemanager" aria-controls="filemanager" role="tab" data-toggle="tab">File Manager</a></li> + </ul> + + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="stackedit"> + <div style="margin-top:25px"></div> + + <div style="display:none"> + <a href="https://stackedit<%= ENV['ENOTE_DOMAIN_SUFFIX']%>" target='blank' class="btn btn-default">Edit in Stackedit</a> + <button class="btn btn-primary" id="update" onclick='return updateCourseWebsite(event, "<%= update_path %>");'> Update </button> + </div> + + <h3> Page Errors <button class='btn btn-primary btn-group inline' onclick='return PageIndex.recompile_all_pages(event);' > Recompile </button></h3> + + <div class="col-md-12 page-errors-index-grid"> + <%= datagrid_form_for @page_errors_grid, :html => {:class => "page-errors-index-grid-form"}, :method => :get, :url => errors_path(my_course_id) %> + <!-- %= paginate(@grid.assets) % --> + <%= datagrid_table @page_errors_grid, :html => {:class => "datagrid page-errors-index-grid-table page-errors-index-grid col-md-12 "} %> + </div> + + <h3> Valid Groups </h3> + + <div id='valid-groups'> + <% my_groups.each do |group| %> + <div class='valid-group'> <%= group.group %> </div> + <% end %> + </div> + + <h3> Page Index </h3> + + <div class="col-md-12"> + </div> + <div id="editor-commands" class="col-md-12 page-index-commands"> + <button class="btn btn-primary" id="rename-page" onclick='return PageIndex.rename_page(event);'> Rename Page </button> + <button class="btn btn-primary" id="delete-page" onclick='return PageIndex.delete_page(event);'> Delete Page </button> + <button class="btn btn-primary" id="new-page" onclick='return PageIndex.new_page(event);'> New Page </button> + </div> + <div class="col-md-12 page-index-grid"> + <%= datagrid_form_for @page_grid, :html => {:class => "page-index-grid-form"}, :method => :get, :url => pages_path(my_course_id) %> + <!-- %= paginate(@grid.assets) % --> + <%= datagrid_table @page_grid, :html => {:class => "datagrid page-index-grid-table page-index-grid col-md-12 "} %> + </div> + </div> + <div role="tabpanel" class="tab-pane" id="sharelatex"> + <div style="margin-top:25px"></div> + <%= render :partial => "admin/sharelatex", :locals => {:filemanager_tree => @filemanager_tree, :files_git_href => @files_git_href}, :running_getpdf => @running_getpdf %> + </div> + <div role="tabpanel" class="tab-pane" id="filemanager"> + <div style="margin-top:25px"></div> + <%= render :partial => "admin/filemanager", :locals => {:filemanager_tree => @filemanager_tree, :files_git_href => @files_git_href} %> + </div> + </div> + + + +<!-- <%= button_to "Update", {:controller => :admin, :action => 'update'}, { :method => :get, :class => 'btn btn-primary'} %> +--> + </div> + </div> + +<script> +var renderCoursePage = {}; +var ADMIN_CONFIG = { + course_id: '<%= my_course_id %>', + urls: { + page_index_url: '<%= page_index_path(my_course_id, 'PAGE_NAME') %>', + edit_page_url: '<%= show_page_path(my_course_id, 'PAGE_NAME') %>?mode=edit', + show_page_url: '<%= show_page_path(my_course_id, 'PAGE_NAME') %>', + recompile_all_pages_url: '<%= recompile_all_pages_path %>', + rename_page_url: '<%= rename_page_path(my_course_id, 'FROM_NAME', 'TO_NAME') %>', + stop_editing_page_url: '<%= stop_editing_path(:course_id => my_course_id, :page_name => 'PAGE_NAME') %>', + getpdf_job_url: '<%= getpdf_job_path(:course_id => my_course_id, :job_id => 'JOB_ID') %>' + } +}; + +(function() { + var url = document.location.toString(); + if (url.match('#')) { + $('.nav-tabs a[href="#' + url.split('#')[1] + '"]').tab('show'); + } + + $('#myTabs a').click(function (e) { + e.preventDefault(); + $(this).tab('show') + }) +})(); + +</script> + diff --git a/app/views/admin/update_pending_files.js.erb b/app/views/admin/update_pending_files.js.erb new file mode 100644 index 0000000000000000000000000000000000000000..4ac3b1f9231178630602f6a820355265514b21f7 --- /dev/null +++ b/app/views/admin/update_pending_files.js.erb @@ -0,0 +1 @@ +$("#pending_files_select").empty().append("<%= escape_javascript(render(:partial => @pending_files)) %>") diff --git a/app/views/enotes/index.html.erb b/app/views/enotes/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..fb499fb87ee73bdeefdb90738c886f9de8de3233 --- /dev/null +++ b/app/views/enotes/index.html.erb @@ -0,0 +1,18 @@ +<table> + <thead> + <tr> + <th>Name</th> + <th>Size</th> + <th>Modified</th> + </tr> + </thead> + <% @enotes[:enotes].each_with_index do |enote, enote_idx | %> +<tr> + <td> + <%= link_to enote, enote_path(my_course_id, enote) + @kind_query, { data: { no_turbolink: true } } %> + </td> + <td><%= @enotes[:enote_stats][enote_idx][:size] %></td> + <td><%= DateTime.parse(@enotes[:enote_stats][enote_idx][:mtime]).to_s :quiz %></td> +</tr> +<% end %> +</table> diff --git a/app/views/enotes/show.html.erb b/app/views/enotes/show.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..41e8f31ca9b94d8c1815db765f56302fdd84d0f6 --- /dev/null +++ b/app/views/enotes/show.html.erb @@ -0,0 +1,13 @@ +<div class='pdf-viewer-container below-shrunken-nav'> + <iframe id="pdfjs-frame" frameborder="0" style="width:100%; height:100%;" id="external-frame"></iframe> +<div> + +<div id ="enote-canvas" class="enote enote-pdf" data-pdf-url="<%= @pdf_url %>"> +</div> + +<script> +(function() { + var hash = location.hash ? ('#nameddest='+location.hash.replace(/#(.*)/, '$1')) : ''; + $("#pdfjs-frame").attr('src', "/assets/pdfjs-viewer/web/viewer.html?file=<%= @pdf_url %>" + hash) +})() +</script> \ No newline at end of file diff --git a/app/views/errors/course_not_configured.html.erb b/app/views/errors/course_not_configured.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..6454f612dfa3b4d2b155096f6a4a7e1ea5282222 --- /dev/null +++ b/app/views/errors/course_not_configured.html.erb @@ -0,0 +1,6 @@ +<div class="content below-nav" id="content"> + <div id="right-content" class="col-lg-9 col-lg-offset-2"> + <h1><%= @error_message %></h1> + </div> +</div> + diff --git a/app/views/feedback/view_feedbacks.html.erb b/app/views/feedback/view_feedbacks.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..33cc3cf71e97807c57666fa618daabc63a589a22 --- /dev/null +++ b/app/views/feedback/view_feedbacks.html.erb @@ -0,0 +1,57 @@ +<% content_for :title do %> + Feedbacks +<% end %> + +<% content_for :dialog_class do %> + modal-md +<% end %> + +<% @feedbacks.each do |feedback| %> + <div class="feedback-card" data-feedbackid="<%= feedback.id %>"> + <table> + <tr> + <td class=""> + <span class="feedbacks-modal-label">Date:</span><span><%= feedback.created_at.in_time_zone.to_s(:quiz) %></span> + </td> + </tr> + <tr> + <td class=""> + <span class="feedbacks-modal-label">User:</span><span><%= feedback.user_name %></span> + </td> + </tr> + <tr> + <td class=""> + <span class="feedbacks-modal-label">Status:</span><span><%= feedback.status %></span> + </td> + </tr> + <tr> + <td> + <img src="<%= feedback.image_thumb_url %>" + onerror='AdminPage.thumbnailNotFound(this);' + onclick="MdPage.showFullFeedbackImage(event,'<%= feedback.image_url %>')"/> + </td> + </tr> + <tr> + <td class="feedbacks-modal-text"> + <div class="feedbacks-modal-label">Feedback:</div> + <p> + <%= feedback.text.truncate(500) unless feedback.text.blank? %> + </p> + </td> + </tr> + <tr> + <td class="feedbacks-modal-reply"> + <div class="feedbacks-modal-label">Reply:</div> + <p> + <% if feedback.reply.blank? %> + <b>None yet!</b> + <% else %> + <%= feedback.reply.truncate(500)%> + <% end %> + </p> + </td> + </tr> + </table> + </div> +<% end %> + diff --git a/app/views/feedback/view_full_image.html.erb b/app/views/feedback/view_full_image.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..a6af9a959477e34213277cda9d2bf55614c123e0 --- /dev/null +++ b/app/views/feedback/view_full_image.html.erb @@ -0,0 +1,10 @@ + +<% content_for :title do %> + Feedback Sceenshot +<% end %> + +<% content_for :dialog_class do %> + modal-lg +<% end %> + +<img src="<%= @feedback.image_url %>" class="img-responsive full-feedback-image" /> diff --git a/app/views/feedback_datagrid/_enum_checkboxes.html.erb b/app/views/feedback_datagrid/_enum_checkboxes.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..ed11aa71f97f9d1f01ea61df0ba7f5d86e8a65dc --- /dev/null +++ b/app/views/feedback_datagrid/_enum_checkboxes.html.erb @@ -0,0 +1,11 @@ +<%# +Indent in this file may cause extra space to appear. +You can add indent if whitespace doesn't matter for you +%> +<%- elements.each do |value, text, checked| -%> +<%- id = [form.object_name, filter.name, value].join('_').underscore -%> +<%= form.label filter.name, options.merge(:for => id) do -%> +<%= form.check_box(filter.name, {:multiple => true, :id => id, :checked => checked, :include_hidden => false}, value.to_s, nil) -%> +<%= text -%> +<%- end -%> +<%- end -%> diff --git a/app/views/feedback_datagrid/_form.html.erb b/app/views/feedback_datagrid/_form.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..461039172ffbd25e7fdaeaeffd8367db5d845dc0 --- /dev/null +++ b/app/views/feedback_datagrid/_form.html.erb @@ -0,0 +1,14 @@ +<%= form_for grid, options do |f| -%> + <% grid.filters.each do |filter| %> + <div class="datagrid-filter filter"> + <%= f.datagrid_label filter %> + <%= f.datagrid_filter filter %> + </div> + <% end %> + <div class="datagrid-actions"> + <%= f.submit I18n.t("datagrid.form.search").html_safe, :class => "datagrid-submit" %> + <%# https://github.com/rails/rails/pull/14949 -%> + <% empty_parameter = Rails.version >= "4.1.0" && Rails.version <= '4.1.2' ? nil : {}-%> + <%= link_to I18n.t('datagrid.form.reset').html_safe, url_for(grid.to_param => empty_parameter), :class => "datagrid-reset" %> + </div> +<% end -%> diff --git a/app/views/feedback_datagrid/_head.html.erb b/app/views/feedback_datagrid/_head.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..e93912892ad80cf70b1812687a35d6728e2ab4ab --- /dev/null +++ b/app/views/feedback_datagrid/_head.html.erb @@ -0,0 +1,8 @@ +<tr> + <% grid.html_columns(*options[:columns]).each do |column| %> + <th class="<%= datagrid_column_classes(grid, column) %>"> + <%= column.header %> + <%= datagrid_order_for(grid, column, options) if column.supports_order? && options[:order]%> + </th> + <% end %> +</tr> diff --git a/app/views/feedback_datagrid/_order_for.html.erb b/app/views/feedback_datagrid/_order_for.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..b3b518843439b93215b93044614338d9028b4baf --- /dev/null +++ b/app/views/feedback_datagrid/_order_for.html.erb @@ -0,0 +1,10 @@ +<div class="order"> + <%= link_to( + I18n.t("datagrid.table.order.asc").html_safe, + datagrid_order_path(grid, column, false), + :class => "asc") %> + <%= link_to( + I18n.t("datagrid.table.order.desc").html_safe, + datagrid_order_path(grid, column, true), + :class => "desc") %> +</div> diff --git a/app/views/feedback_datagrid/_range_filter.html.erb b/app/views/feedback_datagrid/_range_filter.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..2bfba44655bb7b4e188e13ff4995b2a75ba77c8b --- /dev/null +++ b/app/views/feedback_datagrid/_range_filter.html.erb @@ -0,0 +1,3 @@ +<%= form.text_field(filter.name, from_options) %> +<span class="separator <%= filter.type %>"> - </span> +<%= form.text_field(filter.name, to_options) %> diff --git a/app/views/feedback_datagrid/_row.html.erb b/app/views/feedback_datagrid/_row.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..ccfb5de8f78b3a05141f5afc0d8c3f6e5bde43c2 --- /dev/null +++ b/app/views/feedback_datagrid/_row.html.erb @@ -0,0 +1,35 @@ +<tr> + <td> + <%= datagrid_value(grid, grid.html_columns(*options[:columns]).first, asset) %> + </td> + <td> + <div class="feedback-card admin-feedback-card" data-feedbackid="<%= asset.id %>"> + <table> + <% grid.html_columns(*options[:columns])[1..-4].each do |column| %> + <tr> + <td class="<%= datagrid_column_classes(grid, column) %>"> + <%= datagrid_value(grid, column, asset) %> + </td> + </tr> + <% end %> + <tr> + <td> + <div class="row"> + <div class="col-md-1"> + <%= datagrid_value(grid, grid.html_columns(*options[:columns])[-3], asset) %> + </div> + <div class="col-md-4"> + <%= datagrid_value(grid, grid.html_columns(*options[:columns])[-2], asset) %> + </div> + <div class="col-md-5"> + </div> + <div class="col-md-2"> + <%= datagrid_value(grid, grid.html_columns(*options[:columns])[-1], asset) %> + </div> + </div> + </td> + </tr> + </table> + </div> + </td> +</tr> \ No newline at end of file diff --git a/app/views/feedback_datagrid/_table.html.erb b/app/views/feedback_datagrid/_table.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..24c8a28091642f0c019c407224cb503765f35196 --- /dev/null +++ b/app/views/feedback_datagrid/_table.html.erb @@ -0,0 +1,28 @@ +<%# +Local variables: +* grid - instance of Datagrid +* assets - Array of database Entities +* options - passed options Hash +%> + +<% if grid.html_columns(*options[:columns]).any? %> + <div class="row"> + + <div class="centered col-centered col-12"> + + <table class="table feedbacks-table"> + <tbody> + <% if assets.any? %> + <%= datagrid_rows(grid, assets, options) %> + <% else %> + <tr><td class="noresults" colspan="100%"><%= I18n.t('datagrid.no_results').html_safe %></td></tr> + <% end %> + </tbody> + </table> + </div> + </div> + <%= content_tag :table, options[:html] do %> + <% end %> +<% else -%> + <%= I18n.t("datagrid.table.no_columns").html_safe %> +<% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..f82e509e1ace7e1d972db5de85cb61bcd631df6e --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> + <title>DTU Compute Course Website <%= my_course._id if my_course %> </title> + <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML-full"></script> + <%= stylesheet_pack_tag 'styles', media: 'all' %> + <%= javascript_pack_tag 'application' %> + <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon"/> + <link href="/images/kunlogo.png" rel="apple-touch-icon" type="image/png"/> +</head> +<%= csrf_meta_tags %> +</head> +<body data-no-turbolink="true"> + +<div class="wrapper"> + + <%= render :partial => "shared/header", :locals => {:is_admin => admin?, + :current_user_id => current_user_id, + :course => @course, + :menu_items => Menu.get(my_course._id).items, + always_shrunk: false, + show_report_a_bug: @website_course_config.show_report_a_bug } %> + + <%= yield %> +</div> + +</body> +</html> diff --git a/app/views/layouts/edit_page.html.erb b/app/views/layouts/edit_page.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..41618823d9531e6fe66b84591ded60a27eec2af5 --- /dev/null +++ b/app/views/layouts/edit_page.html.erb @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> + <title>DTU Compute Course Website <%= my_course._id if my_course %></title> + <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML-full"></script> + + <%= stylesheet_pack_tag 'styles', media: 'all' %> + + <%= javascript_pack_tag 'edit-page' %> + <script> + MathJax.Hub.Config({"HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"], linebreaks: { automatic:true }, EqnChunk: (MathJax.Hub.Browser.isMobile ? 10 : 50) }, + tex2jax: { inlineMath: [ ["$", "$"], ["\\\\(","\\\\)"] ], displayMath: [ ["$$","$$"], ["\\[", "\\]"] ], processEscapes: true, ignoreClass: "tex2jax_ignore|dno" }, + TeX: { noUndefined: { attributes: { mathcolor: "red", mathbackground: "#FFEEEE", mathsize: "90%" } }, Macros: { href: "{}" } }, + messageStyle: "none" + }); + </script> + + <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" /> + <link href="/images/kunlogo.png" rel="apple-touch-icon" type="image/png" /> + <%= csrf_meta_tags %> +</head> +<body data-no-turbolink="true"> + <%= render :partial => "shared/header", :locals => { :is_admin => admin?, + :current_user_id => current_user_id, + :course => @course, + :menu_items => Menu.get(my_course._id).items, + always_shrunk: false, + show_report_a_bug: @website_course_config.show_report_a_bug } %> + + <%= yield %> +</body> +</html> diff --git a/app/views/layouts/enote.html.erb b/app/views/layouts/enote.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..8e73e5f518f37a4669c0282127688fbcddff8a83 --- /dev/null +++ b/app/views/layouts/enote.html.erb @@ -0,0 +1,27 @@ +<!DOCTYPE html> + +<html> +<head> + <title>DTU Compute Course Website <%= my_course._id if my_course %> </title> + <%= stylesheet_pack_tag 'styles.css', media: 'all' %> + <%= javascript_pack_tag 'application' %> + <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon"/> + <link href="/images/kunlogo.png" rel="apple-touch-icon" type="image/png"/> + <%= csrf_meta_tags %> +</head> + +<body data-no-turbolink="true"> + +<div class="wrapper"> + <%= render :partial => "shared/header", :locals => {:is_admin => admin?, + :current_user_id => current_user_id, + :course => @course, + :menu_items => Menu.get(my_course._id).items, + always_shrunk: true, + show_report_a_bug: @website_course_config.show_report_a_bug } %> + + <%= yield %> +</div> + +</body> +</html> diff --git a/app/views/layouts/error.html.erb b/app/views/layouts/error.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..75da4e452680164f2f207f1af47a8593bb3cb0de --- /dev/null +++ b/app/views/layouts/error.html.erb @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> + <title>DTU Compute Course Website <%= my_course._id if my_course %> </title> + <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML-full"></script> + <%= stylesheet_pack_tag 'styles', media: 'all' %> + <%= javascript_pack_tag 'application' %> + <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon"/> + <link href="<%= image_path 'kunlogo.png' %>" rel="apple-touch-icon" type="image/png"/> + <%= csrf_meta_tags %> +</head> + +<body data-no-turbolink="true"> + +<div class="wrapper"> + + <%= render :partial => "shared/header", :locals => {:is_admin => false, + :current_user_id => "", + :course => "", + :menu_items => [], + always_shrunk: false, + show_report_a_bug: false } %> + + <%= yield %> +</div> + +</body> +</html> diff --git a/app/views/layouts/md_rendered_page.html.erb b/app/views/layouts/md_rendered_page.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..b5c3ecaef6c368398b7462459bca31bbd166ca5a --- /dev/null +++ b/app/views/layouts/md_rendered_page.html.erb @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> +<head> + <title>DTU Course Website <%= my_course._id if my_course %> </title> + <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML-full"></script> + <%= stylesheet_pack_tag 'styles.css', media: 'all' %> + <%= javascript_pack_tag 'application' %> + <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon"/> + <link href="<%= image_path 'kunlogo.png' %>" rel="apple-touch-icon" type="image/png"/> + <%= csrf_meta_tags %> +</head> +<body data-no-turbolink="true"> + <%= render :partial => "shared/header", :locals => {:is_admin => admin?, + :current_user_id => current_user_id, + :course => @course, + :menu_items => Menu.get(my_course_id).items, + :quick_button => @quick_button, + always_shrunk: false, + show_report_a_bug: @website_course_config.show_report_a_bug} %> + + <div class="container"> + <div id="modal-holder"></div> + <%= yield %> + </div> + <div class="wrapper"> + </div> +<footer> + +</footer> +</body> +</html> diff --git a/app/views/layouts/modal.html.erb b/app/views/layouts/modal.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..9ac8463967cb1843286581f70847638fb3f72dc3 --- /dev/null +++ b/app/views/layouts/modal.html.erb @@ -0,0 +1,16 @@ +<div class="modal" id="mainModal" tabindex="-1" role="dialog" aria-labelledby="mainModalLabel" aria-hidden="true"> + <div class="modal-dialog <%= yield :dialog_class if content_for? :dialog_class %>"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> + <h4 class="modal-title" id="mainModalLabel"> + <%= yield :title if content_for? :title %> + </h4> + </div> + + <div class="modal-body"> + <%= yield %> + </div> + </div> + </div> +</div> diff --git a/app/views/layouts/print_page.html.erb b/app/views/layouts/print_page.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..29daf10635aa37555a56bf39e79d39248f49b81f --- /dev/null +++ b/app/views/layouts/print_page.html.erb @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> + <title>DTUCourseWebsite</title> + <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML-full"></script> + <%= stylesheet_pack_tag 'styles', media: 'all' %> + <%= javascript_pack_tag 'application' %> + <%= javascript_pack_tag 'printable' %> + <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" /> + <link href="/images/kunlogo.png" rel="apple-touch-icon" type="image/png" /> +</head> + <%= csrf_meta_tags %> +</head> +<body data-no-turbolink="true"> + <div class="container"> + <%= yield %> + </div> + <div class="wrapper"> + </div> +</body> +</html> diff --git a/app/views/md_single_page/_editor_config.json.erb b/app/views/md_single_page/_editor_config.json.erb new file mode 100644 index 0000000000000000000000000000000000000000..904d346153bdfc47fdc3409d64627979b7b5e98c --- /dev/null +++ b/app/views/md_single_page/_editor_config.json.erb @@ -0,0 +1,10 @@ +{ + "page": "<%= @page %>", + "md": <%== @edit_md.to_json %>, + "macros": {"macros.tex": <%== @macros_tex.to_json %>}, + "urls": { + "view": "<%= show_page_path(:page => @page) %>", + "edit": "<%= show_page_path(:page => @page) + "?mode=edit" %>", + "stop_editing": "<%= stop_editing_path(:page_name => @page) %>" + } +} \ No newline at end of file diff --git a/app/views/md_single_page/edit.html.erb b/app/views/md_single_page/edit.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..be002acff50d783f9c0d7868a762823e0648bb2d --- /dev/null +++ b/app/views/md_single_page/edit.html.erb @@ -0,0 +1,66 @@ +<!--**************************** Content Section*********************--> +<div class="content" style="margin-top: 118px;"> +<!-- +<%= @error_message %> +--> +<% if @error_message %> + <h1> Cannot edit </h1> + <h3> You cannot edit this page. <%= @error_message %>. Click <a href="<%= '/' + @page + '?mode=view' %>">here</a> to view the page.</h3> +<% else %> +<div id="editor-button-bar" class="editor-button-bar"> + <button class="btn btn-primary" id="save-page" onclick='return PageEditor.save_page(event);'>Save Page</button> + <button class="btn btn-primary" id="stop-editing" onclick='return PageEditor.stop_editing(event);'>Stop Editing</button> + <button class="btn btn-primary" id="reload-macros" onclick='return PageEditor.reload(event);'>Reload Macros</button> + <label id="wrap-lines-checkbox" class="checkbox-inline"><input type="checkbox" checked onclick='return PageEditor.wrap_mode_changed(event);' value="">Wrap Lines</label> + <div id="wmd-button-bar-dtu-course-editor" class="wmd-button-bar"></div> +</div> + <div id="left-content" class="col-lg-6"> + <textarea id="wmd-input-dtu-course-editor" class="wmd-input wrap-editor"> + </textarea> + </div> + <div id="right-content" class="col-lg-6"> + <div id="wmd-preview-dtu-course-editor" class="wmd-preview"></div> + </div> +<% end %> +</div> + +<div id="" class="" > +</div> + +<% unless @error_message %> + <script type="text/javascript"> +(function () { + // first editor + var uniqueEditorSuffix = '-dtu-course-editor'; + // create a new Markdown converter and Markdown editor associated with + // the input textarea and the preview div + var converter1 = Markdown.getSanitizingConverter(); + //var converter1 = new Markdown.Converter(); + Markdown.Extra.init(converter1, { + table_class: "table table-striped" + }); + var editor1 = new Markdown.Editor(converter1, uniqueEditorSuffix); + + converter1.hooks.chain("postConversion", function(x) { + return x; + }); + + PageEditor.editor = editor1; + // coordinate the Markdown editor with MathJax rendering via MJPDEditing + + var dir = new EditingDirectives(); + dir.addDirectivesHandlers(editor1); + + var mjpd1 = new MJPD(); // create a new MJPD for each editor on the page + mjpd1.Editing.prepareWmdForMathJax(editor1, uniqueEditorSuffix, [["$", "$"]]); + // start rendering + editor1.run(); +})(); + +var renderCoursePage = {}; +var EDITOR_CONFIG = <%= render :partial => "md_single_page/editor_config.json", :object => @editor_config %>; + </script> +<% end %> + + + diff --git a/app/views/md_single_page/edit_locked.html.erb b/app/views/md_single_page/edit_locked.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..3217e143fa041575f30def7df80038a083c2625f --- /dev/null +++ b/app/views/md_single_page/edit_locked.html.erb @@ -0,0 +1,8 @@ +<div class="content" style="margin-top: 118px;"> + <h1> Page Locked</h1> + <h3> You cannot edit this page, it is locked by <%= @editing %>. Click <a href="<%= '/' + @page + '?mode=view' %>">here</a> to view the page or <a href="<%= '/admin' %>">here</a> to revoke the lock.</h3> +</div> + + + + diff --git a/app/views/md_single_page/show.html.erb b/app/views/md_single_page/show.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..bdf098c6804849772eae5272e4916ecf7ad05e00 --- /dev/null +++ b/app/views/md_single_page/show.html.erb @@ -0,0 +1,82 @@ +<!--**************************** Content Section*********************--> +<div class="content below-nav" id="content"> + + <div id="full-feedback-image-modal" class="modal fade" tabindex="-1" role="dialog"> + <div class="modal-dialog modal-lg"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> + <h4> + Feedback Screenshot + </h4> + </div> + <div class="modal-body"> + <img class="img-responsive full-feedback-image"/> + </div> + </div> + </div> + </div> + + + <% if admin? %> + <% @quick_buttons.each_with_index do |quick_button, button_idx| %> + <%= render :partial => "shared/edit_button.html.erb", :locals => { quick_button: quick_button, button_idx: button_idx, course_id: my_course_id } %> + <% end %> + <% end %> + <div id="left-rail" class=" col-lg-3"><!--*** left Section*****--> + <div class="panel panel-default"> + <div class="panel-body" id="left-content"></div> + </div> + </div> + <div id="right-content" class="col-lg-8"> + </div> + <% if @mdpage_config[:allow_feedback] %> + <div class="feedback-btn-group"> + <% unless @page_feedbacks.empty? %> + <%= link_to "Feedback (#{@page_feedbacks.length.to_s})", view_feedbacks_path({page_name: @page, course_id: my_course_id}), + data: { modal: true }, + class: "feedback-btn-gray feedbacks-btn" + %> + <% end %> + + <button class="feedback-btn feedback-btn-gray">Send feedback</button> + </div> + <% end %> +</div> +<script> + + <% if @left_md %> + var left_md = "<%== escape_javascript @left_md %>"; + <% end %> + + var right_md = "<%== escape_javascript @right_md %>"; + + var MD_PAGE_CONFIG = <%= @mdpage_config.to_json.html_safe %>; + + function renderCoursePage(converter) { + if (typeof(left_md) !== 'undefined') { + $('#left-content').html(converter.makeHtml(left_md)); + $('#right-content').addClass('col-lg-offset-3'); // since left bar is fixed per #162 + } else { + $('#left-rail').hide(); + } + + $('#right-content').html(converter.makeHtml(right_md)); + + if (typeof(left_md) !== 'undefined') { + $('#right-content').addClass('col-lg-offset-3'); // since left bar is fixed per #162 + } + + $('.to-markdown').each(function() { + $(this).html(converter.makeHtml($(this).text())).removeClass('to-markdown'); + }); + + $('.directive-region-item').each(function() { + $(this).html(converter.makeHtml($(this).text())); + }); + + replaceHints(); + + enforceGroupPermission(<%= my_groups.to_json.html_safe %>); + } +</script> diff --git a/app/views/podcasts/index.html.erb b/app/views/podcasts/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..ba2378ba3fe4c6b28817c4c6791af674afaa1fc0 --- /dev/null +++ b/app/views/podcasts/index.html.erb @@ -0,0 +1,10 @@ +<br/> + +<div class="podcasts"> +<% podcast_json["episodes"].each do |episode| %> + +<%= render partial: "shared/podcast_episode", locals: {episode: episode} %> + +<% end %> +</div> + diff --git a/app/views/quiz/all_that_applies/_all_that_apply.html.erb b/app/views/quiz/all_that_applies/_all_that_apply.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..19b4d4baf59b1389bd2ecd4b847781f0408baf81 --- /dev/null +++ b/app/views/quiz/all_that_applies/_all_that_apply.html.erb @@ -0,0 +1,43 @@ + + +<div class='quiz-question'> + <div class='quiz-question-elements'> + <% all_that_apply.question_elements.map do |q| %> + <%= render q %> + <% end %> + </div> + <div class='quiz-student-answer quiz-question-answer-list span9'> + <% all_that_apply.options.each_with_index.each do |entry, i| %> + <div class="row answer-and-feedback"> + <div class='option-row row' data-question='<%= entry.answer_kind.to_s %>'> + <div class='col-max-xs-1'> + <div class="tick-mark col-xs-2"> + <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> + <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> + </div> + </div> + <div class='col-xs-1'> + <input class='pull-right quiz-option-control' type='checkbox' id='<%= entry.id %>' name='answer_<%= 0 %>' value='<%= i %>' <%= 'checked' if false %> onchange='return Quiz.ataChange(event);'/> + </div> + <label class='col-xs-10 quiz-option' for='<%= entry.id.to_s %>'> + <%= entry.answer_text %> + </label> + </div> + <div class='option-row row quiz-feedback-row feedback-row-<%= i %>'> + <div class="col-max-xs-1"> </div> + <div class="col-xs-1"> </div> + <div class='quiz-feedback feedback-text feedback-text-<%= i %> col-xs-10'> + <%= entry.feedback_text %> + </div> + </div> + </div> + <% end %> + <button class='btn btn-primary all-that-apply-submit-btn' onClick="return Quiz.ataSubmit(event);">Submit</button> + </div> + + <% if all_that_apply.hints? %> + <div class='quiz-vspacer'></div> + <%= render :partial => 'shared/hint', :locals => {:hint => all_that_apply.hint, :editable => editable} %> + <% else %> + <% end %> +</div><!-- quiz-question --> \ No newline at end of file diff --git a/app/views/quiz/fill_in_the_blanks/_fill_in_the_blank.html.erb b/app/views/quiz/fill_in_the_blanks/_fill_in_the_blank.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..39e08d8173dc203ccc47e6126077501a02a75601 --- /dev/null +++ b/app/views/quiz/fill_in_the_blanks/_fill_in_the_blank.html.erb @@ -0,0 +1,49 @@ +<div class='quiz-question'> + <div class='quiz-question-answer-list'> + + <div class='option-row row '> + <div class='col-xs-12'> + <% i = 0 %> + <% fill_in_the_blank.elements.each do |element| %> + <% if element.is_a? Quiz::Text %> + <span class='fill-in-the-blank'><%= element.text %></span> + <% else %> + <span class="fill-in-the-blank-answer-and-tick"> + <span class="tick-mark"> + <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> + <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> + </span> + <input class='fill-in-the-blank' + maxlength="<%= element.blank_len %>" + size="<%= element.blank_len %>" + type="text" + class="form-control" + columns="3" + onchange="return Quiz.fillInTheBlankChanged(event);" + onpaste="return Quiz.fillInTheBlankEdit(event);" + onkeydown="return Quiz.fillInTheBlankEdit(event);" + oncut="return Quiz.fillInTheBlankEdit(event);" + data-answer="<%= fill_in_the_blank.answers&.answer_texts&.[](i) %>" + /> + </span> + <% i = i + 1 %> + <% end %> + <% end %> + </div> + </div> + + <% unless fill_in_the_blank.wrong_text.nil? %> + <div class='option-row row quiz-feedback-row feedback-row'> + <div class='quiz-feedback feedback-text col-xs-12 fill-in-the-blank-wrong-text incorrect'> + <%= fill_in_the_blank.wrong_text.answer_text %> + </div> + </div> + + <div class='option-row row '> + <div class='quiz-feedback feedback-text col-xs-12'> + <button class='btn btn-primary fill-in-the-blank-submit-btn' onClick="return Quiz.ftbSubmit(event);">Submit</button> + </div> + </div> + <% end %> + </div> +</div> diff --git a/app/views/quiz/index.html.erb b/app/views/quiz/index.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app/views/quiz/multiple_choices/_multiple_choice.html.erb b/app/views/quiz/multiple_choices/_multiple_choice.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..1e78265bf94ab5486e82f077df7c4e9a42a6d2cd --- /dev/null +++ b/app/views/quiz/multiple_choices/_multiple_choice.html.erb @@ -0,0 +1,43 @@ + + +<div class='quiz-question'> + <div class=' quiz-question-elements'> + <% multiple_choice.question_elements.map do |q| %> + <%= render q %> + <% end %> + </div> + <div class='quiz-student-answer quiz-question-answer-list span9'> + <% multiple_choice.options.each_with_index.each do |entry, i| %> + <div class="row answer-and-feedback"> + <div class='option-row row' data-question='<%= entry.answer_kind.to_s %>'> + <div class='col-max-xs-1'> + <div class="tick-mark col-xs-2"> + <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> + <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> + </div> + </div> + <div class='col-xs-1'> + <input class='pull-right quiz-option-control' type='radio' id='<%= entry.id %>' name='answer_<%= 0 %>' value='<%= i %>' <%= 'checked' if false %> onchange='return Quiz.mcChange(event);'> + </input> + </div> + <label class='col-xs-10 quiz-option' for='<%= entry.id.to_s %>'> + <%= entry.answer_text %> + </label> + </div> + <div class='option-row row quiz-feedback-row feedback-row-<%= i %>'> + <div class="col-max-xs-1"></div> + <div class="col-xs-1"></div> + <div class='quiz-feedback feedback-text feedback-text-<%= i %> col-xs-10'> + <%= entry.feedback_text %> + </div> + </div> + </div> + <% end %> + </div> + + <% if multiple_choice.hints? %> + <div class='quiz-vspacer'></div> + <%= render :partial => 'shared/hint', :locals => {:hint => multiple_choice.hint, :editable => editable} %> + <% else %> + <% end %> +</div><!-- quiz-question --> \ No newline at end of file diff --git a/app/views/quiz/options/_option.html.erb b/app/views/quiz/options/_option.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..522b5bb6359249b92ea0a75ccf966101f259f088 --- /dev/null +++ b/app/views/quiz/options/_option.html.erb @@ -0,0 +1 @@ +<p><%= option.answer_text %></p> \ No newline at end of file diff --git a/app/views/quiz/quizzes/_quiz.html.erb b/app/views/quiz/quizzes/_quiz.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..15bf4b4f32de758b5d98836a7dee8446648d945e --- /dev/null +++ b/app/views/quiz/quizzes/_quiz.html.erb @@ -0,0 +1,3 @@ +<% quiz.sections.each_with_index do |section, _| %> + <%= render section %> +<% end %> diff --git a/app/views/quiz/texts/_text.html.erb b/app/views/quiz/texts/_text.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..4654be9859d5b3ac6bb5514bee0fe3c48960bc88 --- /dev/null +++ b/app/views/quiz/texts/_text.html.erb @@ -0,0 +1,2 @@ + +<span class="to-markdown"><%= text.text.html_safe %></span> \ No newline at end of file diff --git a/app/views/shared/_edit_button.html.erb b/app/views/shared/_edit_button.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..29114543ad7c13a6e25b45351002f04d1eb8b0ed --- /dev/null +++ b/app/views/shared/_edit_button.html.erb @@ -0,0 +1,13 @@ +<div class="edit edit-<%= button_idx %> below-nav"> + <% if quick_button[:kind] == :edit %> + <button class="btn btn-primary" id="edit-page" onclick='return PageIndex.edit_page(event, "<%= quick_button[:page] %>", "<%= course_id %>");'> + <%= quick_button[:text] %> + <span> <%= quick_button[:page] %></span> + </button> + <% elsif quick_button[:kind] == :revoke %> + <button class="btn btn-primary" id="edit-page" onclick='return PageIndex.revoke_page(event, "<%= quick_button[:page] %>", "<%= course_id %>");'> + <%= quick_button[:text] %> + <span> <%= quick_button[:page] %></span> + </button> + <% end %> +</div> diff --git a/app/views/shared/_header.html.erb b/app/views/shared/_header.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..804993a68d7a961aab9e826d4ae9e60f3176b292 --- /dev/null +++ b/app/views/shared/_header.html.erb @@ -0,0 +1,82 @@ +<header> + <nav class="navbar navbar-inverse navbar-fixed-top <%= "shrink" if always_shrunk %>" id="navbar-main"> + <div class="container"> + <!-- Brand and toggle get grouped for better mobile display --> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse-1" aria-expanded="false"> + <span class="sr-only">Menu-Toggle</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand logo" href="<%= map_url({course_id: my_course_id}) { '/home' } %>"> + <img src="<%= image_path 'kunlogo.png' %>" alt="logo" class="img-responsive"> + </a> + <p class="navbar-text collapsed shrunk-course-title course-title" > + <%= link_to (my_course ? my_course.name : "Course #{my_course_id} not configured"), map_url({course_id: my_course_id}) { '/home' }, { data: { no_turbolink: true }, :class => current_class?('/home') } %> + </p> + </div> + <!-- Collect the nav links, forms, and other content for toggling --> + <div class="navbar-collapse nav-info-strip course-info-info-strip"> + <div class='course-title'> + <%= link_to (my_course ? my_course.name : "Course #{my_course_id} not configured"), map_url({course_id: my_course_id}) { '/home' }, { data: { no_turbolink: true }, :class => current_class?('/home') } %> + </div> + <div class="logged-in-user hidden-xs"> <%= current_user_id %></div> + </div> + <div id="navbar-collapse-1" class="collapse navbar-collapse navbar-strip menu-info-strip" > + <ul class="nav navbar-nav top-menu"> + <% for item in menu_items do %> + <% if item[:url].downcase.eql? "/enotes" %> + <li class="dropdown <%= current_class?(item[:url]) %>"> + <a href=item[:menu] class="dropdown-toggle " data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="caret"></span> <%= item[:menu] %> </a> + <ul class="dropdown-menu scrollable-menu"> + <% enotes(my_course_id)[:enote_titles].sort().each do |title, enote| %> + <li> + <%= link_to title, enote_path(my_course_id, enote), { data: { no_turbolink: true } } %> + </li> + <% end %> + </ul> + </li> + <% else %> + <li class="<%= current_class?(item[:url]) %>"> + <%= link_to item[:menu], map_url({course_id: my_course_id}) { item[:url] }, { data: { no_turbolink: true }, :class => current_class?(item[:url]) } %> + </li> + <% end %> + <% end %> + <% if is_admin %> + <li class="<%= current_class?('/admin') %>"> + <%= link_to "Admin", map_url({course_id: my_course_id}) { '/admin' }, { data: { no_turbolink: true }, :class => current_class?('/admin') } %> + </li> + <% end %> + </ul> + <ul class="nav navbar-nav top-menu navbar-right login hidden-xs"> + <li> + <%= + if current_user_id + link_to core.logout_path, { :id => 'logout-button', :class => 'fa fa-sign-in', :method => :delete } do + content_tag(:div, " Logout", class: "loginout-text") + end + else + if (Rails.env.production?) + link_to("Login", EnoteCas::Filter.login_url(controller)) + else + link_to core.login_path, { :id => 'logout-button', :class => 'fa fa-sign-in' } do + content_tag(:div, " Login", class: "loginout-text") + end + end + end + %> + </li> + </ul> + </div> + <!-- /.navbar-collapse --> + </div> + <!-- /.container-fluid --> + </nav> + <div class="clearfix"></div> +</header> +<% if @show_report_a_bug %> + <%= render :partial => "dtu_core_app/shared/report_a_bug.html.erb", :locals => { } %> +<% else %> + <div style="display:none;">show_report_a_bug <%= @show_report_a_bug %></div> +<% end %> diff --git a/app/views/shared/_podcast_episode.html.erb b/app/views/shared/_podcast_episode.html.erb new file mode 100644 index 0000000000000000000000000000000000000000..6f05252c6c1701f15f9c449b7d566c6296d1c585 --- /dev/null +++ b/app/views/shared/_podcast_episode.html.erb @@ -0,0 +1,25 @@ +<% def podcast_duration(episode) + first_media = episode['media'].each.select { |key, info| key != 'thumbnail' }.first + first_media ? first_media[1]['duration'] : '??:??:??' + end +%> +<div class="podcast"> + <div class="podcast-left"> + <%= image_tag episode['media']['thumbnail'][0]["250"] if (episode['media']['thumbnail'] && episode['media']['thumbnail'][0]["250"]) %> + </div> + <div class="podcast-right"> + <h3><%= episode["title"] %> </h3> + <p><%= episode["description"] %> </p> + <p>Date: <%= Time.at(episode["pubDate"]).to_datetime().to_s(:quiz) %> · + Duration: <%= podcast_duration(episode) %> </p> + <p> + <% episode['media'].each.select {|key, info| (key != 'thumbnail')}.each do |key, info| %> + <% if info['filename'] %> + <%= link_to key, info['filename'] %> + <% else %> + <p> Unavailable </p> + <% end %> + <% end %> + </p> + </div> +</div> \ No newline at end of file diff --git a/app/views/sitemap/index.xml.erb b/app/views/sitemap/index.xml.erb new file mode 100644 index 0000000000000000000000000000000000000000..0db96a7927ed0a2ca14f719a68bda0c456a45fc5 --- /dev/null +++ b/app/views/sitemap/index.xml.erb @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> + <% for page in @pages %> + <url> + <loc><%= page[:loc] %></loc> + <lastmod><%= page[:lastmod].strftime('%Y-%m-%d') %></lastmod> + <changefreq><%= page[:changefreq] %></changefreq> + <priority><%= page[:priority] %></priority> + </url> + <% end %> +</urlset> diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000000000000000000000000000000000000..27270e5dd3d50da6f509c2d86fdc6e1d31c5f243 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,71 @@ +module.exports = function(api) { + var validEnv = ['development', 'test', 'production'] + var currentEnv = api.env() + var isDevelopmentEnv = api.env('development') + var isProductionEnv = api.env('production') + var isTestEnv = api.env('test') + + if (!validEnv.includes(currentEnv)) { + throw new Error( + 'Please specify a valid `NODE_ENV` or ' + + '`BABEL_ENV` environment variables. Valid values are "development", ' + + '"test", and "production". Instead, received: ' + + JSON.stringify(currentEnv) + + '.' + ) + } + + return { + presets: [ + isTestEnv && [ + require('@babel/preset-env').default, + { + targets: { + node: 'current' + } + } + ], + (isProductionEnv || isDevelopmentEnv) && [ + require('@babel/preset-env').default, + { + forceAllTransforms: true, + useBuiltIns: 'entry', + corejs: 3, + modules: false, + exclude: ['transform-typeof-symbol'] + } + ] + ].filter(Boolean), + plugins: [ + require('babel-plugin-macros'), + require('@babel/plugin-syntax-dynamic-import').default, + isTestEnv && require('babel-plugin-dynamic-import-node'), + require('@babel/plugin-transform-destructuring').default, + [ + require('@babel/plugin-proposal-class-properties').default, + { + loose: true + } + ], + [ + require('@babel/plugin-proposal-object-rest-spread').default, + { + useBuiltIns: true + } + ], + [ + require('@babel/plugin-transform-runtime').default, + { + helpers: false, + regenerator: true + } + ], + [ + require('@babel/plugin-transform-regenerator').default, + { + async: false + } + ] + ].filter(Boolean) + } +} diff --git a/bin/bundle b/bin/bundle new file mode 100755 index 0000000000000000000000000000000000000000..66e9889e8b4aeea1af13e2396fb70594232a2ae3 --- /dev/null +++ b/bin/bundle @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +load Gem.bin_path('bundler', 'bundle') diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000000000000000000000000000000000000..0138d79b751b9668a1036329a9ef29a213836162 --- /dev/null +++ b/bin/rails @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +begin + load File.expand_path('../spring', __FILE__) +rescue LoadError => e + raise unless e.message.include?('spring') +end +APP_PATH = File.expand_path('../../config/application', __FILE__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000000000000000000000000000000000000..d87d5f578104597c1d1b951b55942e37f8af1277 --- /dev/null +++ b/bin/rake @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +begin + load File.expand_path('../spring', __FILE__) +rescue LoadError => e + raise unless e.message.include?('spring') +end +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000000000000000000000000000000000000..acdb2c1389c502f79a967384cac1c5adcea10ec2 --- /dev/null +++ b/bin/setup @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +require 'pathname' + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +Dir.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 || bundle install" + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # system "cp config/database.yml.sample config/database.yml" + # end + + puts "\n== Preparing database ==" + system "bin/rake db:setup" + + puts "\n== Removing old logs and tempfiles ==" + system "rm -f log/*" + system "rm -rf tmp/cache" + + puts "\n== Restarting application server ==" + system "touch tmp/restart.txt" +end diff --git a/bin/spring b/bin/spring new file mode 100755 index 0000000000000000000000000000000000000000..7fe232c3aae5996a1d6ca1f69d10e636630f5c5c --- /dev/null +++ b/bin/spring @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby + +# This file loads spring without using Bundler, in order to be fast. +# It gets overwritten when you run the `spring binstub` command. + +unless defined?(Spring) + require 'rubygems' + require 'bundler' + + if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)) + Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) } + gem 'spring', match[1] + require 'spring/binstub' + end +end diff --git a/bin/webpack b/bin/webpack new file mode 100755 index 0000000000000000000000000000000000000000..008ecb22f7c7d4daadc1b67acf2a1c974bb30729 --- /dev/null +++ b/bin/webpack @@ -0,0 +1,19 @@ +#!/usr/bin/env ruby + +ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" +ENV["NODE_ENV"] ||= "development" + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require "rubygems" +require "bundler/setup" + +require "webpacker" +require "webpacker/webpack_runner" + +APP_ROOT = File.expand_path("..", __dir__) +Dir.chdir(APP_ROOT) do + Webpacker::WebpackRunner.run(ARGV) +end diff --git a/bin/webpack-dev-server b/bin/webpack-dev-server new file mode 100755 index 0000000000000000000000000000000000000000..a931a9b7fc26c5c5d619ee5165734b77b99e8dc2 --- /dev/null +++ b/bin/webpack-dev-server @@ -0,0 +1,19 @@ +#!/usr/bin/env ruby + +ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" +ENV["NODE_ENV"] ||= "development" + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require "rubygems" +require "bundler/setup" + +require "webpacker" +require "webpacker/dev_server_runner" + +APP_ROOT = File.expand_path("..", __dir__) +Dir.chdir(APP_ROOT) do + Webpacker::DevServerRunner.run(ARGV) +end diff --git a/coffeelint.json b/coffeelint.json new file mode 100644 index 0000000000000000000000000000000000000000..86422e323d1f407c05c048bb35d67e433101e758 --- /dev/null +++ b/coffeelint.json @@ -0,0 +1,129 @@ +{ + "arrow_spacing": { + "level": "ignore" + }, + "braces_spacing": { + "level": "ignore", + "spaces": 0, + "empty_object_spaces": 0 + }, + "camel_case_classes": { + "level": "error" + }, + "coffeescript_error": { + "level": "error" + }, + "colon_assignment_spacing": { + "level": "ignore", + "spacing": { + "left": 0, + "right": 0 + } + }, + "cyclomatic_complexity": { + "value": 10, + "level": "ignore" + }, + "duplicate_key": { + "level": "error" + }, + "empty_constructor_needs_parens": { + "level": "ignore" + }, + "ensure_comprehensions": { + "level": "warn" + }, + "eol_last": { + "level": "ignore" + }, + "indentation": { + "value": 2, + "level": "error" + }, + "line_endings": { + "level": "ignore", + "value": "unix" + }, + "max_line_length": { + "value": 80, + "level": "error", + "limitComments": true + }, + "missing_fat_arrows": { + "level": "ignore", + "is_strict": false + }, + "newlines_after_classes": { + "value": 3, + "level": "ignore" + }, + "no_backticks": { + "level": "error" + }, + "no_debugger": { + "level": "warn", + "console": false + }, + "no_empty_functions": { + "level": "ignore" + }, + "no_empty_param_list": { + "level": "ignore" + }, + "no_implicit_braces": { + "level": "ignore", + "strict": true + }, + "no_implicit_parens": { + "strict": true, + "level": "ignore" + }, + "no_interpolation_in_single_quotes": { + "level": "ignore" + }, + "no_plusplus": { + "level": "ignore" + }, + "no_stand_alone_at": { + "level": "ignore" + }, + "no_tabs": { + "level": "error" + }, + "no_this": { + "level": "ignore" + }, + "no_throwing_strings": { + "level": "error" + }, + "no_trailing_semicolons": { + "level": "error" + }, + "no_trailing_whitespace": { + "level": "error", + "allowed_in_comments": false, + "allowed_in_empty_lines": true + }, + "no_unnecessary_double_quotes": { + "level": "ignore" + }, + "no_unnecessary_fat_arrows": { + "level": "warn" + }, + "non_empty_constructor_needs_parens": { + "level": "ignore" + }, + "prefer_english_operator": { + "level": "ignore", + "doubleNotLevel": "ignore" + }, + "space_operators": { + "level": "ignore" + }, + "spacing_after_comma": { + "level": "ignore" + }, + "transform_messes_up_line_numbers": { + "level": "warn" + } +} diff --git a/config.ru b/config.ru new file mode 100644 index 0000000000000000000000000000000000000000..bd83b25412305f93fdb0a892aded30e5178899ba --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run Rails.application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000000000000000000000000000000000000..bab03943c501de509f882e9bb068682a31b8825f --- /dev/null +++ b/config/application.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require File.expand_path('boot', __dir__) + +require 'rails' +# Pick the frameworks you want: +require 'active_model/railtie' +require 'active_job/railtie' +require 'active_record/railtie' +require 'action_controller/railtie' +require 'action_mailer/railtie' +require 'action_view/railtie' +require 'sprockets/railtie' +require 'rails/test_unit/railtie' + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +# Simple formatter which only displays the message. +class EnoteFormatter < ::Logger::Formatter + # This method is invoked when a log event occurs + def call(severity, timestamp, progname, msg) +# Format % [severity[0..0], format_datetime(timestamp), $$, severity, progname, msg2str(msg)] + "#{severity[0..0]} [#{format_datetime(timestamp)}] #{msg2str(msg)}\n" + end +end + +module DTUCourseWebsite + ## + # Application + class Application < Rails::Application + # Bower + config.assets.paths << Rails.root.join('node_modules') + + config.assets.paths << "#{Gem.loaded_specs['dtu-core'].full_gem_path}/app/assets/stylesheets" + + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + config.time_zone = ENV.fetch('TIMEZONE') { 'UTC' } + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + + # add service objects + config.autoload_paths += Dir["#{config.root}/app/services/**/"] + config.autoload_paths += Dir["#{config.root}/app/responders/**/"] + config.autoload_paths += Dir["#{config.root}/lib/**/"] + config.eager_load_paths += Dir["#{config.root}/lib/**/"] + + DtuCore::app_init config + + # allow precompile in dockerfile (i.e. when DB may not be available) + # http://stackoverflow.com/questions/8997226/rake-assetsprecompile-attempting-to-connect-to-database + # (note: this is not a sufficient solution: see initializes/redis.rb) + config.assets.initialize_on_precompile = false + + config.generators do |g| + g.test_framework :rspec + end + + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = EnoteFormatter.new #config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + + config.lograge.enabled = true + unless Rails.env.production? + # log rage doesn't log params by default. + # For production, though, the params can be HUGE (e.g. webgazer datapoints, so let's be cautious) + config.lograge.custom_options = lambda do |event| + exceptions = %w[controller action format id points] + { + params: event.payload[:params].except(*exceptions), + time: event.time + } + end + end + + if config.lograge.enabled + class ActionDispatch::DebugExceptions + alias old_log_error log_error + + def log_error(env, wrapper) + exception = wrapper.exception + if exception.is_a?(ActionController::RoutingError) + data = { + method: env['REQUEST_METHOD'], + path: env['REQUEST_PATH'], + status: wrapper.status_code, + error: "#{exception.class.name}: #{exception.message}" + } + formatted_message = Lograge.formatter.call(data) + logger(env).send(Lograge.log_level, formatted_message) + else + old_log_error env, wrapper + end + end + end + end + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000000000000000000000000000000000000..6b750f00b1dff4d94937b97ae0dbf76784b02164 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,3 @@ +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) + +require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/config/build_info.yml b/config/build_info.yml new file mode 100644 index 0000000000000000000000000000000000000000..d680abf294d58f9b471b3e15d33911df77f4354b --- /dev/null +++ b/config/build_info.yml @@ -0,0 +1,17 @@ +dtu-enote-website: + version: 3.533 + build_date: 2019-03-07T16:55:35-0800 + branch: "develop" + commit: "7f0244d3128afedcc5cb628631a5d8b75740cf2b" + origin_url: git@lab.compute.dtu.dk:enote/dtu-enote-website + commit_details: 2019-03-04 7f0244d (HEAD -> develop, origin/develop) Iain Bryson -- Cleanup scripts and move precompile to dockerfile + recent_commit_details: + - "2019-03-04 7f0244d (HEAD -> develop, origin/develop) Iain Bryson -- Cleanup scripts and move precompile to dockerfile" + - "2019-03-04 5df4103 Iain Bryson -- Merge branch '202-admin-feedback-doesn-t-refresh-when-deleting-saving-feedback' into 'develop'" + - "2019-03-04 94ece4f (202-admin-feedback-doesn-t-refresh-when-deleting-saving-feedback) Iain Bryson -- Make feedback reponse write-once." + - "2019-02-28 7b2ce82 Iain Bryson -- Package updates & fix double publish" + - "2019-02-22 e32e8e8 Iain Bryson -- stop docker containers" + - "2019-02-22 49b3f2a Iain Bryson -- Try raw docker compose functions for deploy" + - "2019-02-22 d31804a Iain Bryson -- Remove debugging statements; another try at deploy." + - "2019-02-22 cd0f46d Iain Bryson -- fix deployment" + - "2019-02-22 9899ddc Iain Bryson -- Clean up dead or exited containers before deploy" diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000000000000000000000000000000000000..b055983dab91ca3a7020380f5f5bf9064bd955cf --- /dev/null +++ b/config/database.yml @@ -0,0 +1,33 @@ +# SQLite version 3.x +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem 'sqlite3' +# +default: &default + adapter: sqlite3 + pool: 5 + timeout: 5000 + +development: + <<: *default +<% if ENV.has_key?('DTU_DATA_ROOT') %> + database: <%= File.join(ENV['DTU_DATA_ROOT'],"website-db", "development.sqlite3") %> +<% else %> + database: db/development.sqlite3 +<% end %> + +# 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: db/test.sqlite3 + +production: + <<: *default +<% if ENV.has_key?('DTU_DATA_ROOT') %> + database: <%= File.join(ENV['DTU_DATA_ROOT'],"website-db", "production.sqlite3") %> +<% else %> + database: /data/website-db/production.sqlite3 +<% end %> diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000000000000000000000000000000000000..8e9fca4e5cc1a1ba1a91534edb135ff7ceb4efec --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,18 @@ +# Load the Rails application. +require File.expand_path('../application', __FILE__) +require 'casclient' +require 'casclient/frameworks/rails/filter' + +# Initialize the Rails application. +Rails.application.initialize! + +# enable detailed CAS logging +cas_logger = CASClient::Logger.new('log/cas.log') +cas_logger.level = Logger::DEBUG + +CASClient::Frameworks::Rails::Filter.configure( + :cas_base_url => "https://auth.dtu.dk/dtu/", + :username_session_key => :cas_user, + :extra_attributes_session_key => :cas_extra_attributes, + :logger => cas_logger, +) diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000000000000000000000000000000000000..7e25e6de9c8a93db8b23026f02aae6cb22f7a6a2 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,40 @@ +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 + + config.serve_static_files = true + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # 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 + + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. + config.assets.digest = true + + # Adds additional error checking when serving assets at runtime. + # Checks for improperly declared sprockets dependencies. + # Raises helpful error messages. + config.assets.raise_runtime_errors = true + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000000000000000000000000000000000000..f916473571c3cd4723104679c1bbf2d61cf9ba97 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,93 @@ +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 + + # Enable Rack::Cache to put a simple HTTP cache in front of your application + # Add `rack-cache` to your Gemfile before enabling this. + # For large-scale production use, consider using a caching reverse proxy like + # NGINX, varnish or squid. + # config.action_dispatch.rack_cache = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? + + # Compress JavaScripts and CSS. + config.assets.js_compressor = Uglifier.new(harmony: true) + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. + config.assets.digest = true + + # http://stackoverflow.com/questions/29732377/how-to-disable-adding-self-in-sprockets-3-0 + config.assets.debug = false + + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb + + # 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 + + # 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 = String(ENV.fetch('LOG_LEVEL') { config.deployment_environment[:public_facing] ? 'info' : 'debug' }).upcase + + # Prepend all log lines with the following tags. + config.log_tags = [:request_id, + # http://blog.simontaranto.com/post/2018-05-18-better-rails-logs-current-user-request-context.html/ + ->(req){ + if user_id = CasTaggedLogger.extract_user_id_from_request(req) + user_id.to_s + else + "?" + end + } + ] + + # Prepend all log lines with the following tags. + # config.log_tags = [ :subdomain, :uuid ] + + # Use a different logger for distributed setups. + # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.action_controller.asset_host = 'http://assets.example.com' + + # 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 + + config.lograge.formatter = Lograge::Formatters::Logstash.new +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000000000000000000000000000000000000..1c19f08b28341c59bd4cfe1834e29f877e5fc22e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,42 @@ +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 static file server for tests with Cache-Control for performance. + config.serve_static_files = true + config.static_cache_control = 'public, max-age=3600' + + # 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 + + # 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 + + # Randomize the order test cases are executed. + config.active_support.test_order = :random + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true +end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb new file mode 100644 index 0000000000000000000000000000000000000000..f61c2fa442a84a3186cda8286b8d43d696917361 --- /dev/null +++ b/config/initializers/assets.rb @@ -0,0 +1,13 @@ +# 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 + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. +# Rails.application.config.assets.precompile += %w( search.js ) + +Rails.application.config.assets.precompile += %w( md-rendered-page.js edit-page.js pdf.js pdf.worker.js ) diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000000000000000000000000000000000000..59385cdf379bd06a8d2326dcd4de6d5cd5d3f5b0 --- /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/cookies_serializer.rb b/config/initializers/cookies_serializer.rb new file mode 100644 index 0000000000000000000000000000000000000000..7f70458dee62b4a0f5233e4be7b8838b8400cbe8 --- /dev/null +++ b/config/initializers/cookies_serializer.rb @@ -0,0 +1,3 @@ +# Be sure to restart your server when you modify this file. + +Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/config/initializers/core_exts.rb b/config/initializers/core_exts.rb new file mode 100644 index 0000000000000000000000000000000000000000..0165b1173fdb7a148334e306ec4f97ad66fc6c99 --- /dev/null +++ b/config/initializers/core_exts.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +Dir[File.join(Rails.root, 'lib', 'core_exts', '*.rb')].each { |l| require l } diff --git a/config/initializers/filemanager.rb b/config/initializers/filemanager.rb new file mode 100644 index 0000000000000000000000000000000000000000..10121446694895f29b035d94640bee4737de4409 --- /dev/null +++ b/config/initializers/filemanager.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +unless ENV.key? 'PRECOMPILE' + courses = WebsiteConfig.get.courses.keys + file_manager = DTUFileManagement::FileManager.instance + # file_manager.dtu_file_manager_root = WebsiteConfig.config_root + file_manager.update + Enotes.instance.refresh_all + + courses.each do |course| + Rails.logger.info "Enotes for #{course} from #{file_manager.enotes_folder(course)}:\n#{file_manager.enotes_files.ai}" + Rails.logger.info "Uploads for #{course} from #{file_manager.uploads_folder(course)}:\n#{file_manager.uploads_files.ai}" + end +end diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000000000000000000000000000000000000..4a994e1e7bb7ce28dcec98bad48b9a891d7dec51 --- /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 0000000000000000000000000000000000000000..ac033bf9dc846101320c96a5ce8aceb8c96ec098 --- /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/menu.rb b/config/initializers/menu.rb new file mode 100644 index 0000000000000000000000000000000000000000..7a9fd31e445cc9d06c6b58bc06403eef19de4073 --- /dev/null +++ b/config/initializers/menu.rb @@ -0,0 +1,6 @@ +unless ENV.has_key? "PRECOMPILE" + courses = WebsiteConfig.get.courses.keys + for course in courses do + Menu.refresh(course) + end +end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000000000000000000000000000000000000..dc1899682b01c3a6d9673faf746e235fb64fc4d2 --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,4 @@ +# 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 diff --git a/config/initializers/monkey_patches.rb b/config/initializers/monkey_patches.rb new file mode 100644 index 0000000000000000000000000000000000000000..f6578899582fef28c789729547d297e2b0e1b451 --- /dev/null +++ b/config/initializers/monkey_patches.rb @@ -0,0 +1,13 @@ +require "ostruct" + +module CoreExtensions + module OpenStruct + module JSON + def as_json(options = nil) + @table.as_json(options) + end + end + end +end + +OpenStruct.include CoreExtensions::OpenStruct::JSON diff --git a/config/initializers/pages.rb b/config/initializers/pages.rb new file mode 100644 index 0000000000000000000000000000000000000000..a2356dc09831167a175ac213e51970925dc3ac28 --- /dev/null +++ b/config/initializers/pages.rb @@ -0,0 +1,8 @@ +unless ENV.has_key? "PRECOMPILE" + courses = WebsiteConfig.get.courses.keys + for course in courses do + Pages.refresh course + Errors.refresh course + IncludedPages.refresh course + end +end diff --git a/config/initializers/redis.rb b/config/initializers/redis.rb new file mode 100644 index 0000000000000000000000000000000000000000..c6b8f1954cbc26f1b453d235fc81e41f17cf23a2 --- /dev/null +++ b/config/initializers/redis.rb @@ -0,0 +1,11 @@ +unless ENV.has_key? "PRECOMPILE" + Rails.logger.info "Initializing redis" + + redis_config = { host: Rails.configuration.dtu_data[:redis], port: 6379, db: 0, namespace: "cache" } + $redis = Redis::Namespace.new("dtu_enote", :redis => Redis.new(redis_config)) + + redis_config = { host: Rails.configuration.dtu_data[:redis], port: 6379, db: 1, namespace: "cache" } + $redis_course_website = Redis.new(redis_config) + + WebsiteConfig.clear # reload this and put it in redis upon next access +end diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 0000000000000000000000000000000000000000..9fb89678b8845eda610a853c073c2b5a7997406a --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1,3 @@ +# Be sure to restart your server when you modify this file. + +Rails.application.config.session_store :cookie_store, key: '_DTUCourseWebsite_session' diff --git a/config/initializers/website_config.rb b/config/initializers/website_config.rb new file mode 100644 index 0000000000000000000000000000000000000000..2cea4a5e91d4b5d92e2e77d43996b3630b0c7e0d --- /dev/null +++ b/config/initializers/website_config.rb @@ -0,0 +1,4 @@ +unless ENV.has_key? "PRECOMPILE" + Rails.logger.info "DTU Config: #{Rails.configuration.dtu_data.ai}" + Rails.logger.info "Website Config: #{WebsiteConfig.get.ai}" +end diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb new file mode 100644 index 0000000000000000000000000000000000000000..b81ea74b77c01473f831e6144412c862572a6b50 --- /dev/null +++ b/config/initializers/wrap_parameters.rb @@ -0,0 +1,9 @@ +# 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] if respond_to?(:wrap_parameters) +end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000000000000000000000000000000000000..0653957166e8182880bb87b56e36c257c988dd92 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,23 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t 'hello' +# +# In views, this is aliased to just `t`: +# +# <%= t('hello') %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# To learn more, please read the Rails Internationalization guide +# available at http://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000000000000000000000000000000000000..3d21c8d2d5720258f0e375eb297f966d59512220 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +Rails.application.routes.draw do # rubocop:disable Metrics/BlockLength + get '/:course_id/sitemap.xml', to: 'sitemap#index', defaults: { format: 'xml' } + + post '(/:course_id)/feedbacks' => 'feedback#create' + + root 'root#index' + get '/index' => 'root#index' + get '/root' => 'root#index' + + mount DtuCoreApp::Engine => '/core', :as => 'core' + + scope module: 'admin' do + # admin root + # get ':course_id/admin/index' => 'admin#index' + # get ':course_id/admin' => 'admin#index' + # Per #188 + get ':course_id/admin/index', to: redirect('/%{course_id}/admin/pages') + get ':course_id/admin', to: redirect('/%{course_id}/admin/pages') + + # admin pages + get ':course_id/admin/pages' => 'admin_pages#index', :as => 'admin_pages' + get ':course_id/admin/update' => 'admin_pages#update', :as => 'update' + get ':course_id/admin/recompile_all_pages' => 'admin_pages#recompile_all_pages', + :as => 'recompile_all_pages' + + # admin enotes + get ':course_id/admin/enotes' => 'admin_enotes#index', :as => 'admin_enotes' + get ':course_id/admin/update_enotes' => 'admin_enotes#update_enotes', :as => 'update_enotes' + get ':course_id/admin/build_enotes' => 'admin_enotes#build_enotes', :as => 'build_enotes' + get ':course_id/admin/publish_enotes' => 'admin_enotes#publish_enotes', :as => 'publish_enotes' + get ':course_id/admin/getpdf_jobs' => 'admin_enotes#getpdf_jobs', :as => 'getpdf_jobs' + get ':course_id/admin/getpdf_jobs/:job_id' => 'admin_enotes#getpdf_job', :as => 'getpdf_job' + delete ':course_id/admin/getpdf_jobs/:job_id' => 'admin_enotes#cancel_getpdf_job', + :as => 'cancel_getpdf_job' + + # admin files + get ':course_id/admin/files' => 'admin_files#index', :as => 'admin_files' + get ':course_id/admin/update_filemanager' => 'admin_files#update_filemanager', + :as => 'update_filemanager' + + # admin course + get ':course_id/admin/course' => 'admin_course#index', :as => 'admin_course' + get ':course_id/admin/course/change_course_number' => 'admin_course#change_course_number', + :as => 'change_course_number' + + # admin feedback + get ':course_id/admin/feedback' => 'admin_feedback#index', :as => 'admin_feedback' + put ':course_id/admin/feedback/allowed' => 'admin_feedback#set_allowed', + :as => 'admin_feedback_set_allowed' + end + + get ':course_id/enotes' => 'enotes#index', :as => 'enotes' + get ':course_id/enotes/:enote' => 'enotes#show', :as => 'enote' + + get ':course_id/podcast/index', to: redirect('/%{course_id}/Podcast') + get ':course_id/podcast', to: redirect('/%{course_id}/Podcast') + + get ':course_id/home/index', to: redirect('/%{course_id}/Frontpage') + get ':course_id/home', to: redirect('/%{course_id}/Frontpage'), as: :course_home + get ':course_id/', to: redirect('/%{course_id}/Frontpage') + + get ':course_id/pages' => 'pages#index', :as => :pages + get ':course_id/pages/:page_name' => 'pages#get', :as => 'page_index' + delete ':course_id/pages/:page_name' => 'pages#delete_page', :as => :delete_page + put ':course_id/pages/:page_name/rename/:to_name' => 'pages#rename_page', :as => :rename_page + post ':course_id/pages/:page_name' => 'pages#new_page', :as => :new_page + get ':course_id/pages/:page_name/stop_editing' => 'md_single_page#stop_editing', :as => :stop_editing + + get ':course_id/errors' => 'errors#index', :as => :errors + + get '/:course_id/feedbacks' => 'feedback#index', :as => :course_feedbacks + get '(/:course_id)/feedbacks/:feedback_id' => 'feedback#show', :as => :feedback + put '(/:course_id)/feedbacks/:feedback_id' => 'feedback#update' + delete '(/:course_id)/feedbacks/:feedback_id' => 'feedback#destroy' + delete '(/:course_id)/feedbacks' => 'feedback#destroy_multiple' + get '/:course_id/feedback/:page_name/view_feedbacks' => 'feedback#view_feedbacks', :as => :view_feedbacks + get '(/:course_id)/feedbacks/:feedback_id/view_full_image' => 'feedback#view_full_image', :as => :view_full_image + + get '/filemanager/enotes/:course_id/:file', to: redirect { |_path_params, req| '/assets/' + req.path }, as: :enote_file + + get '/:course_id/core', to: redirect('/core') + put '/:course_id/core', to: redirect('/core') + post '/:course_id/core', to: redirect('/core') + + get '/:course_id/:page', to: 'md_single_page#show', as: 'show_page' + post '/:course_id/:page', to: 'md_single_page#update', as: 'save_page' + + # prevent exception from missing route to mess up logging + match '*path', via: :all, to: 'site_errors#error_404' +end diff --git a/config/secrets.yml b/config/secrets.yml new file mode 100644 index 0000000000000000000000000000000000000000..3aab66db21c64c7c41f13214ed23efeb176d91ff --- /dev/null +++ b/config/secrets.yml @@ -0,0 +1,22 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key is used for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! + +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +# You can use `rake secret` to generate a secure secret key. + +# Make sure the secrets in this file are kept private +# if you're sharing your code publicly. + +development: + secret_key_base: 87ef4fa7272f5811fe27e02201403953b2ea6609cb2c0883357dae8c54dd7efc6982254031ba5f30e52e166443784929ce2b965da42869cf2572c54e77071aeb + +test: + secret_key_base: 6014c9f51feae9ade8eb0d46395e08612406b563999c376e5f90ad35262d67e84a1443bc74606c19513c6171b19ee67b05287ea96297f5decc0964183e86c356 + +# Do not keep production secrets in the repository, +# instead read values from the environment. +production: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> diff --git a/config/webpack/development.js b/config/webpack/development.js new file mode 100644 index 0000000000000000000000000000000000000000..89d35d93896a59704c85d27b7d5fbc44897cd343 --- /dev/null +++ b/config/webpack/development.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development'; + +const environment = require('./environment'); + +module.exports = environment.toWebpackConfig(); diff --git a/config/webpack/environment.js b/config/webpack/environment.js new file mode 100644 index 0000000000000000000000000000000000000000..85e27d911aae700a46c3741afaada10f46eada46 --- /dev/null +++ b/config/webpack/environment.js @@ -0,0 +1,15 @@ +const { environment } = require('@rails/webpacker'); +const webpack = require('webpack'); + +// resolve-url-loader must be used before sass-loader +environment.loaders.get('sass').use.splice(-1, 0, { + loader: 'resolve-url-loader', +}); + +environment.plugins.prepend('Provide', new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + // + Popper: ['popper.js', 'default'] +})); + +module.exports = environment; diff --git a/config/webpack/production.js b/config/webpack/production.js new file mode 100644 index 0000000000000000000000000000000000000000..81680bc97e85b6815ad43ad928fec62745233489 --- /dev/null +++ b/config/webpack/production.js @@ -0,0 +1,15 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'production'; + +const environment = require('./environment'); + +const BrotliPlugin = require('brotli-webpack-plugin'); + +environment.plugins.append('Brotli', + new BrotliPlugin({ + asset: '[path].br[query]', +test: /\.js$|\.css$|\.html$/, + threshold: 10240, + minRatio: 0.7 +})); + +module.exports = environment.toWebpackConfig(); diff --git a/config/webpack/test.js b/config/webpack/test.js new file mode 100644 index 0000000000000000000000000000000000000000..89d35d93896a59704c85d27b7d5fbc44897cd343 --- /dev/null +++ b/config/webpack/test.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development'; + +const environment = require('./environment'); + +module.exports = environment.toWebpackConfig(); diff --git a/config/webpacker.yml b/config/webpacker.yml new file mode 100644 index 0000000000000000000000000000000000000000..3666d38484838986c6d7b99fbef158f42cb788b9 --- /dev/null +++ b/config/webpacker.yml @@ -0,0 +1,95 @@ +# Note: You must restart bin/webpack-dev-server for changes to take effect + +default: &default + source_path: app/javascript + source_entry_path: packs + public_root_path: public + public_output_path: packs + cache_path: tmp/cache/webpacker + check_yarn_integrity: false + webpack_compile_output: false + + # Additional paths webpack should lookup modules + # ['app/assets', 'engine/foo/app/assets'] + resolved_paths: [] + + # Reload manifest.json on all requests so we reload latest compiled packs + cache_manifest: false + + # Extract and emit a css file + extract_css: true + + static_assets_extensions: + - .jpg + - .jpeg + - .png + - .gif + - .tiff + - .ico + - .svg + - .eot + - .otf + - .ttf + - .woff + - .woff2 + + extensions: + - .mjs + - .js + - .sass + - .scss + - .css + - .module.sass + - .module.scss + - .module.css + - .png + - .svg + - .gif + - .jpeg + - .jpg + +development: + <<: *default + compile: true + + # Verifies that versions and hashed value of the package contents in the project's package.json + check_yarn_integrity: true + + # Reference: https://webpack.js.org/configuration/dev-server/ + dev_server: + https: false + host: localhost + port: 3035 + public: localhost:3035 + hmr: false + # Inline should be set to true if using HMR + inline: true + overlay: true + compress: true + disable_host_check: true + use_local_ip: false + quiet: false + headers: + 'Access-Control-Allow-Origin': '*' + watch_options: + ignored: '**/node_modules/**' + + +test: + <<: *default + compile: true + + # Compile test packs to a separate directory + public_output_path: packs-test + +production: + <<: *default + + # Production depends on precompilation of packs prior to booting for performance. + compile: false + + # Extract and emit a css file + extract_css: true + + # Cache manifest.json for performance + cache_manifest: true diff --git a/db/migrate/20180421173824_create_feedbacks.rb b/db/migrate/20180421173824_create_feedbacks.rb new file mode 100644 index 0000000000000000000000000000000000000000..13bccbe26e0bf4683766047f65694fb133364973 --- /dev/null +++ b/db/migrate/20180421173824_create_feedbacks.rb @@ -0,0 +1,17 @@ +class CreateFeedbacks < ActiveRecord::Migration[5.1] + def change + create_table :feedbacks do |t| + t.timestamp :datetime + t.string :url + t.string :page + t.string :user_id + t.string :user_name + t.string :text + t.binary :thumbnail + + t.timestamps + end + add_index :feedbacks, :page + add_index :feedbacks, :user_id + end +end diff --git a/db/migrate/20180423030313_add_course_id_to_feedbacks.rb b/db/migrate/20180423030313_add_course_id_to_feedbacks.rb new file mode 100644 index 0000000000000000000000000000000000000000..e9ad96522b5d57806a4be6c6db751e52222c1444 --- /dev/null +++ b/db/migrate/20180423030313_add_course_id_to_feedbacks.rb @@ -0,0 +1,5 @@ +class AddCourseIdToFeedbacks < ActiveRecord::Migration[5.1] + def change + add_column :feedbacks, :course_id, :string + end +end diff --git a/db/migrate/20180423155308_add_status_to_feedbacks.rb b/db/migrate/20180423155308_add_status_to_feedbacks.rb new file mode 100644 index 0000000000000000000000000000000000000000..8452417a5248282f44e7bf1886091e29099103de --- /dev/null +++ b/db/migrate/20180423155308_add_status_to_feedbacks.rb @@ -0,0 +1,5 @@ +class AddStatusToFeedbacks < ActiveRecord::Migration[5.1] + def change + add_column :feedbacks, :status, :string, :default => 'new' + end +end diff --git a/db/migrate/20180426010530_add_reply_to_feedbacks.rb b/db/migrate/20180426010530_add_reply_to_feedbacks.rb new file mode 100644 index 0000000000000000000000000000000000000000..cdfbdefd1d9ed882e80ad4b650ee22e58d9e6ff2 --- /dev/null +++ b/db/migrate/20180426010530_add_reply_to_feedbacks.rb @@ -0,0 +1,5 @@ +class AddReplyToFeedbacks < ActiveRecord::Migration[5.1] + def change + add_column :feedbacks, :reply, :string + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000000000000000000000000000000000000..8130c2f815f1237e0d95c9c2cc3c045eac663d27 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,32 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20180426010530) do + + create_table "feedbacks", force: :cascade do |t| + t.datetime "datetime" + t.string "url" + t.string "page" + t.string "user_id" + t.string "user_name" + t.string "text" + t.binary "thumbnail" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "course_id" + t.string "status", default: "new" + t.string "reply" + t.index ["page"], name: "index_feedbacks_on_page" + t.index ["user_id"], name: "index_feedbacks_on_user_id" + end + +end diff --git a/deps/dtu-core b/deps/dtu-core new file mode 160000 index 0000000000000000000000000000000000000000..764956be7599d732bad3cf6e5ae419650d89ca96 --- /dev/null +++ b/deps/dtu-core @@ -0,0 +1 @@ +Subproject commit 764956be7599d732bad3cf6e5ae419650d89ca96 diff --git a/deps/dtu-quiz-parser b/deps/dtu-quiz-parser new file mode 160000 index 0000000000000000000000000000000000000000..bd85823fdb0a6926f45023dd886e290b1379db89 --- /dev/null +++ b/deps/dtu-quiz-parser @@ -0,0 +1 @@ +Subproject commit bd85823fdb0a6926f45023dd886e290b1379db89 diff --git a/deps/feedbackjs b/deps/feedbackjs new file mode 160000 index 0000000000000000000000000000000000000000..9af8711e9a869100065033cf22813f8baab39fc2 --- /dev/null +++ b/deps/feedbackjs @@ -0,0 +1 @@ +Subproject commit 9af8711e9a869100065033cf22813f8baab39fc2 diff --git a/deps/pdfjs b/deps/pdfjs new file mode 160000 index 0000000000000000000000000000000000000000..09a72fa2713887d9c14439cf2c6d769cf7486ee8 --- /dev/null +++ b/deps/pdfjs @@ -0,0 +1 @@ +Subproject commit 09a72fa2713887d9c14439cf2c6d769cf7486ee8 diff --git a/lib/alph.rb b/lib/alph.rb new file mode 100644 index 0000000000000000000000000000000000000000..89927ca0e2473ddecd6503a45567336a13b1211b --- /dev/null +++ b/lib/alph.rb @@ -0,0 +1,14 @@ +# https://stackoverflow.com/questions/14632304/generate-letters-to-represent-number-using-ruby +class Numeric + Alpha26 = ("A".."Z").to_a + def alph + return "" if self < 1 + s, q = "", self + loop do + q, r = (q - 1).divmod(26) + s.prepend(Alpha26[r]) + break if q.zero? + end + s + end +end diff --git a/lib/assets/.keep b/lib/assets/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lib/core_exts/tail.rb b/lib/core_exts/tail.rb new file mode 100644 index 0000000000000000000000000000000000000000..dcadfda49d53f7bdb7e4572c93c4ca065f38b726 --- /dev/null +++ b/lib/core_exts/tail.rb @@ -0,0 +1,30 @@ + +# frozen_string_literal: true + +# an improved version of https://stackoverflow.com/questions/3024372/how-to-read-a-file-from-bottom-to-top-in-ruby +# This one actually handles cases where the file isn't multiples of TAIL_BUG_LENGTH +class IO + TAIL_BUF_LENGTH = 1 << 16 + + def tail(num_lines) + return [] if num_lines < 1 + + cur_end = size + + offset = (cur_end - TAIL_BUF_LENGTH).negative? ? -cur_end : -TAIL_BUF_LENGTH + + seek offset, SEEK_END + + buf = '' + while (buf.count("\n") <= num_lines) && (cur_end != 0) + buf = read(-offset) + buf + cur_end += offset + + next_offset = (cur_end - TAIL_BUF_LENGTH).negative? ? -cur_end : -TAIL_BUF_LENGTH + seek (offset + next_offset), SEEK_CUR + offset = next_offset + end + + buf.split("\n").last(num_lines) + end +end diff --git a/lib/enote_cas.rb b/lib/enote_cas.rb new file mode 100644 index 0000000000000000000000000000000000000000..3a3058286821b4618bc4a78b3b7fdc01bbf5f77a --- /dev/null +++ b/lib/enote_cas.rb @@ -0,0 +1,78 @@ + +CASClient::Frameworks::Rails::Filter.class_eval do + class << self + def org_read_service_url(controller) + if config[:service_url] + log.debug("Using explicitly set service url: #{config[:service_url]}") + return config[:service_url] + end + + params = {}.with_indifferent_access + params.update(controller.request.query_parameters) + params.update(controller.request.path_parameters) + params.delete(:ticket) + service_url = controller.url_for(params) + log.debug("Guessed service url: #{service_url.inspect}") + return service_url + end + + def read_service_url(controller) + default_service_url = org_read_service_url(controller) + + Rails.logger.info "CAS Service URL: #{default_service_url}" + uri = URI.parse(default_service_url) + new_path = uri.path.gsub(/^\/[^\/]+\/?(.*)$/, '/\1') + new_uri = uri.scheme + "://" + + uri.host + + (uri.port ? (":#{uri.port}") : "") + + uri.path.gsub(/^\/[^\/]+\/?(.*)$/, '/\1') + + (uri.query ? "?" + uri.query : "") + Rails.logger.info "New Service URL: #{new_uri}" + return new_uri + end + end +end + +CASClient::Frameworks::Rails::GatewayFilter.class_eval do + def org_read_service_url(controller) + if config[:service_url] + log.debug("Using explicitly set service url: #{config[:service_url]}") + return config[:service_url] + end + + params = {}.with_indifferent_access + params.update(controller.request.query_parameters) + params.update(controller.request.path_parameters) + params.delete(:ticket) + service_url = controller.url_for(params) + log.debug("Guessed service url: #{service_url.inspect}") + return service_url + end + + class << self + def read_service_url(controller) + default_service_url = org_read_service_url(controller) + + Rails.logger.info "CAS Service URL: #{default_service_url}" + uri = URI.parse(default_service_url) + new_path = uri.path.gsub(/^\/[^\/]+\/?(.*)$/, '/\1') + new_uri = uri.scheme + "://" + + uri.host + + (uri.port ? (":#{uri.port}") : "") + + uri.path.gsub(/^\/[^\/]+\/?(.*)$/, '/\1') + + (uri.query ? "?" + uri.query : "") + Rails.logger.info "New Service URL: #{new_uri}" + return new_uri + end + end +end + +module EnoteCas + class Filter < CASClient::Frameworks::Rails::Filter + + end + + class GatewayFilter < CASClient::Frameworks::Rails::GatewayFilter + + end +end diff --git a/lib/enote_titleize.rb b/lib/enote_titleize.rb new file mode 100644 index 0000000000000000000000000000000000000000..bcacf79325847edb104b6c7fb86c0f33d11b8464 --- /dev/null +++ b/lib/enote_titleize.rb @@ -0,0 +1,30 @@ +module Titleize + extend self + + def enote_titleize(title) + title.tr('_', ' ') + end +end + +class String + def enote_titleize(opts={}) + if defined? ActiveSupport::Inflector + ActiveSupport::Inflector.enote_titleize(self, opts) + else + Titleize.enote_titleize(self) + end + end +end + +if defined? ActiveSupport::Inflector + module ActiveSupport::Inflector + extend self + + def enote_titleize(title, _={}) + #opts = {}.merge(opts) + + Titleize.enote_titleize(title) + end + alias_method :enote_titlecase, :enote_titleize + end +end diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake new file mode 100644 index 0000000000000000000000000000000000000000..dd9a88b8e66c9ad4ceb12c3b7df75484dc6f5f80 --- /dev/null +++ b/lib/tasks/assets.rake @@ -0,0 +1,34 @@ +# https://mattbrictson.com/gzipped-assets-nginx-rails-42 +namespace :assets do + desc "Create .gz versions of assets" + task :gzip => :environment do + zip_types = /\.(?:css|html|js|otf|svg|txt|xml)$/ + + public_assets = File.join( + Rails.root, + "public", + Rails.application.config.assets.prefix) + + Dir["#{public_assets}/**/*"].each do |f| + next unless f =~ zip_types + + mtime = File.mtime(f) + gz_file = "#{f}.gz" + next if File.exist?(gz_file) && File.mtime(gz_file) >= mtime + + File.open(gz_file, "wb") do |dest| + gz = Zlib::GzipWriter.new(dest, Zlib::BEST_COMPRESSION) + gz.mtime = mtime.to_i + IO.copy_stream(open(f), gz) + gz.close + end + + File.utime(mtime, mtime, gz_file) + end + end + + # Hook into existing assets:precompile task + Rake::Task["assets:precompile"].enhance do + Rake::Task["assets:gzip"].invoke + end +end diff --git a/lib/tasks/editor.rake b/lib/tasks/editor.rake new file mode 100644 index 0000000000000000000000000000000000000000..0db666b34980ea23a711e985f07b3df4cb2b12c9 --- /dev/null +++ b/lib/tasks/editor.rake @@ -0,0 +1,56 @@ +require 'open-uri' +require 'json' +require 'awesome_print' + +namespace :editor do + desc "switch logger to stdout" + task :to_stdout => [:environment] do + Rails.logger = Logger.new(STDOUT) + end + + desc "Revoke the lock on a specific page" + task :revoke_lock, [:course, :page] => [:to_stdout, :environment] do |_t, args| + course = args[:course] + PagesService.new(course).edit_page args[:page], nil + end + + desc "Revoke all locks" + task :revoke_all_locks, [:course] => [:to_stdout, :environment] do |_t, args| + course = args[:course] + ps = PagesService.new(course) + Rails.logger.info "Revoking these locks: #{ps.all_current_edits.ai}" + ps.all_current_edits.map{ |p| p[:name] }.each do + |page| ps.edit_page page, nil + end + end + + def dump_files(label, folder) + pages = Dir.glob(File.join(folder, '*.md')) + + pages_details = pages.map do |page_file| + File.basename(page_file, ".md") + " " + File.stat(page_file).mtime.to_s(:quiz) + end + + Rails.logger.info "#{label} (#{folder}): #{pages_details.ai}" + + end + + desc "Dump page information" + task :dump_pages, [:course] => [:to_stdout, :environment] do |_t, args| + course = args[:course] + Rails.logger.info "Pages model: #{Pages.get(course).pages.ai}" + + Rails.logger.info "Errors model: #{Errors.get(course).errors.ai}" + + Rails.logger.info "Current locks: #{PagesService.new(course).all_current_edits.ai}" + + dump_files("Local editor pages ", WebsiteConfig.get.courses[course].pages_source_path) + + dump_files("Compiled pages ", PagesService.new(course).compiled_folder) + + Rails.logger.info "Errors files: #{Errors.get(course).errors_files.ai}" + + Rails.logger.info "Errors file folder: #{Errors.errors_folder(course)}" + end + +end diff --git a/lib/tasks/maintenance.rake b/lib/tasks/maintenance.rake new file mode 100644 index 0000000000000000000000000000000000000000..d181ac2282aafe5f837dc5f786bbbfe4bb087657 --- /dev/null +++ b/lib/tasks/maintenance.rake @@ -0,0 +1,42 @@ +require 'open-uri' +require 'json' +require 'awesome_print' + +namespace :maintenance do + desc "switch logger to stdout" + task :to_stdout => [:environment] do + Rails.logger = Logger.new(STDOUT) + end + + desc "Check that required course argument is supplied" + task :require_course, [:course] do + raise "course argument must be supplied" unless args.course + end + + def do_git(keys_root, course, git_cmd) + `GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=no -i #{keys_root}/#{course}-files' git #{git_cmd}` + fail unless $? == 0 + end + + desc "sync a single course Web site git repo pair (files, pages)" + task :sync_website_repo, [:course] => [:to_stdout, :environment, :require_course] do + puts Rails.configuration.dtu_data.ai + keys_root = File.expand_path(File.join(Rails.configuration.dtu_data[:root_path], "website-keys")) + repos_root = File.expand_path(File.join(Rails.configuration.dtu_data[:root_path], "website-repos")) + + Dir.chdir repos_root do + @gitinfo = WebsiteConfig.instance.files_git_repo_info + branch = @gitinfo.branch || 'master' + Rails.logger.info "Syncing #{course} Web site files repo to #{branch}" + + unless Dir.exist? course + "-files" + do_git(keys_root, curse, "clone git@github.com:dtu-compute/#{course}-files.git #{course}-files") + end + + Dir.chdir File.join(course + '-files') do + do_git(keys_root, curse, "fetch --all") + do_git(keys_root, curse, "checkout #{branch}") + end + end + end +end diff --git a/lib/tasks/update.rake b/lib/tasks/update.rake new file mode 100644 index 0000000000000000000000000000000000000000..4754abc39738af14646692b7c2821959b8b7c387 --- /dev/null +++ b/lib/tasks/update.rake @@ -0,0 +1,54 @@ +require 'open-uri' +require 'json' +require 'awesome_print' + +namespace :update do + desc "switch logger to stdout" + task :to_stdout => [:environment] do | t, args | + Rails.logger = Logger.new(STDOUT) + end + + desc "Check that required course argument is supplied" + task :require_course, [:course] do | t, args | + raise "course argument must be supplied" unless args.course + end + + desc "Check for new podcasts" + task :check_for_podcasts, [:course] => [:require_course, :to_stdout, :environment] do | t, args | + UpdateService.new(args.course).new_podcasts? + end + + desc "Compile the pages to static pages with the proper group exclusions and hints processed" + task :compile_pages, [:course] => [:require_course, :to_stdout, :environment] do | t, args | + UpdateService.new(args.course).compile_pages + end + + desc "Update filemanager files" + task :update_filemanager, [:course] => [:require_course, :to_stdout, :environment] do | t, args | + UpdateService.new(args.course).update_filemanager + end + + desc "Update enotes files" + task :update_enotes, [:course] => [:require_course, :to_stdout, :environment] do | t, args | + UpdateService.new(args.course).update_enotes + end + + desc "Compile enotes" + task :compile_enotes, [:course] => [:require_course, :to_stdout, :environment] do | t, args | + UpdateService.new(args.course).compile_enotes + end + + desc "Update all the pages" + task :all, [:course] => [:environment] do | t, args | + courses = WebsiteConfig.get.courses.keys + courses = [args[:course]] if (args[:course]) + + courses.each do |course| + update = UpdateService.new(course) + update.compile_pages + update.update_filemanager + update.compile_enotes + update.update_enotes + end + end +end diff --git a/lib/uri_utils.rb b/lib/uri_utils.rb new file mode 100644 index 0000000000000000000000000000000000000000..9624e9ec957e8fb86e3c3959e0ce98a8f587d83c --- /dev/null +++ b/lib/uri_utils.rb @@ -0,0 +1,10 @@ +module UriUtils + def uri?(string) + uri = URI.parse(string) + %w( http https ).include?(uri.scheme) + rescue URI::BadURIError + false + rescue URI::InvalidURIError + false + end +end diff --git a/localpdfjs.sh b/localpdfjs.sh new file mode 100755 index 0000000000000000000000000000000000000000..145de7db091008052eadcf49363e76ae8d61457f --- /dev/null +++ b/localpdfjs.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +pushd ./deps/pdfjs && \ + npm install && \ + npm install gulp && \ + npm install -g gulp && \ + gulp generic + +popd + +mkdir -p public/assets/pdfjs-viewer +cp -R ./deps/pdfjs/build/generic/web/* public/assets/pdfjs-viewer/ +cp -R ./deps/pdfjs/build/generic/web public/assets/pdfjs-viewer/ +cp -R ./deps/pdfjs/build/generic/build public/assets/pdfjs-viewer/ diff --git a/maintenance.ru b/maintenance.ru new file mode 100644 index 0000000000000000000000000000000000000000..da12714ec6b6b5188ee28cb4cd00d9c0e31d91ea --- /dev/null +++ b/maintenance.ru @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby +# +# # This is the rackup file for the simple static pages we show during startup and after a fatal crash +# It allows us to respond to the reverse proxy even when the rails app is starting up (i.e. building precompiled assets) +# + +require 'rack' +require 'rack-rewrite' + +root = './public-maintenance' + +index = ENV["indexpage"] || "index.html" +urls = Dir.glob(File.join(root, "**/*")).map{ |d| d.sub(root, "") }.map{ |x| [x, x] }.to_h + +urls["/"] = index + +puts urls.inspect + +use Rack::Static, + :urls => urls, + :root => root + +body = File.read(File.join(root, index)) +headers = {"Content-Type" => "text/html", "Content-Length" => body.size.to_s} +run lambda { |_| [200, headers, [body]] } + +# thin -R startup.ru -a 127.0.0.1 -p 3000 start +# \ No newline at end of file diff --git a/mk_gits.sh b/mk_gits.sh new file mode 100755 index 0000000000000000000000000000000000000000..f64c6e0cf45c644a1779c8eee4665e4745bf7f2c --- /dev/null +++ b/mk_gits.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# TODO: replace with git submodules? + +git ls-remote https://github.com/dtu-compute/pdf.js | grep master | awk '{ print $1 }' > pdfjs.head.txt + diff --git a/package.json b/package.json new file mode 100644 index 0000000000000000000000000000000000000000..9ada319d8a475114032b2c0aeeda078151434553 --- /dev/null +++ b/package.json @@ -0,0 +1,65 @@ +{ + "name": "DTU-website-tools", + "version": "0.0.1", + "private": true, + "description": "Tools for the DTU course website.", + "engines": { + "node": "0.10.x" + }, + "scripts": { + "lint": "NODE_ENV=development eslint app/client app/assets/javascripts", + "hint": "NODE_ENV=development jshint app/client app/assets/javascripts", + "lintfix": "eslint --fix app/assets/javascripts app/javascript --fix", + "webpack:analyze": "mkdir -p public/assets/bundles && node_modules/@rails/webpacker/node_modules/.bin/webpack --config config/webpack/production.js --profile --json > public/assets/bundles/stats.json && node_modules/.bin/webpack-bundle-analyzer public/assets/bundles/stats.json", + "prettier": "prettier --single-quote --write app/client/**/*.js" + }, + "dependencies": { + "@rails/webpacker": "^4.0.2", + "bootstrap": "^3.4.1", + "bootstrap-treeview": "git+https://github.com/iainbryson/bootstrap-treeview.git", + "core-js": "3", + "dtu_core_assets": "file:./deps/dtu-core/dtu_core_assets/", + "dtu_core_js": "file:./deps/dtu-core/dtu_core_assets", + "fallback": "^1.0.1", + "feedbackjs": "file:./deps/feedbackjs", + "glob": "^7.1.1", + "jquery": "^3.3.1", + "jquery-ujs": "^1.2.2", + "mathjax": "~2.7.1", + "mv": "^2.1.1", + "nano": "^8.0.0", + "pagedown-extra": "git+https://github.com/jmcmanus/pagedown-extra.git#ea782c3d11eb78f57d00aa819527338996a70721", + "path": "^0.12.7", + "popper.js": "^1.14.3", + "q": "^1.4.1", + "rails-ujs": "^5.2.0", + "request": "^2.88.0", + "require-css": "0.1.5", + "socket.io": "^2.1.0", + "socket.io-client": "^2.1.0", + "underscore": "^1.8", + "url": "^0.11.0", + "webpack": "^4.30.0", + "yamljs": "^0.2.4" + }, + "license": "Apache License", + "bugs": { + "url": "https://github.com/" + }, + "devDependencies": { + "brotli-webpack-plugin": "^1.1.0", + "caniuse-lite": "^1.0.30000697", + "cssnano": "^4.1.10", + "eslint": "^5.16.0", + "eslint-config-airbnb-base": "^13.1.0", + "eslint-plugin-import": "^2.17.2", + "jshint": "^2.10.2", + "postcss-import": "^12.0.1", + "postcss-loader": "^3.0.0", + "postcss-preset-env": "^6.6", + "prettier": "^1.17.0", + "resolve-url-loader": "^3.1.0", + "webpack-bundle-analyzer": "^3.3.2", + "webpack-dev-server": "^3.3.1" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000000000000000000000000000000000000..d733da6fb26e66750162f0d842305732127f66e3 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,13 @@ +module.exports = { + plugins: [ + require('cssnano'), + require('postcss-import'), + require('postcss-flexbugs-fixes'), + require('postcss-preset-env')({ + autoprefixer: { + flexbox: 'no-2009' + }, + stage: 3 + }) + ] +}; diff --git a/public-maintenance/_rails_failed.html b/public-maintenance/_rails_failed.html new file mode 100644 index 0000000000000000000000000000000000000000..a7673584d28e6372834b24b875a3ecda4a570512 --- /dev/null +++ b/public-maintenance/_rails_failed.html @@ -0,0 +1,30 @@ +<!doctype html> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" /> + <link href="/images/kunlogo.png" rel="apple-touch-icon" type="image/png" /> + <title>Site Maintenance</title> + <style> + body { text-align: center; padding: 150px; } + h1 { font-size: 50px; text-align:center; } + body { font: 20px Helvetica, sans-serif; color: #333; } + article { display: block; text-align: left; width: 650px; margin: 0 auto; } + a { color: #dc8100; text-decoration: none; } + a:hover { color: #333; text-decoration: none; } + img { margin-left: auto; margin-right:auto; display: block; } + </style> +</head> +</html> +<body> +<article> + <img src="/images/kunlogo.png"/> + <h1>Site has Crashed</h1> + <div> + <p>Sorry for the inconvenience but the course website has crashed. + If you need to you can always <a href="mailto:#">contact us</a>, + otherwise we’ll be back online shortly!</p> + <p>— The Team</p> + </div> +</article> +</body> diff --git a/public-maintenance/_rails_starting.html b/public-maintenance/_rails_starting.html new file mode 100644 index 0000000000000000000000000000000000000000..eb370d5f4a80031e1eadbc93dcde9efe86263614 --- /dev/null +++ b/public-maintenance/_rails_starting.html @@ -0,0 +1,30 @@ +<!doctype html> +<html> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" /> + <link href="/images/kunlogo.png" rel="apple-touch-icon" type="image/png" /> + <title>Site Maintenance</title> + <style> + body { text-align: center; padding: 150px; } + h1 { font-size: 50px; text-align:center; } + body { font: 20px Helvetica, sans-serif; color: #333; } + article { display: block; text-align: left; width: 650px; margin: 0 auto; } + a { color: #dc8100; text-decoration: none; } + a:hover { color: #333; text-decoration: none; } + img { margin-left: auto; margin-right:auto; display: block; } + </style> +</head> +</html> +<body> +<article> + <img src="/images/kunlogo.png"/> + <h1>Site is Building</h1> + <div> + <p>Sorry for the inconvenience but we’re building the course website. + If you need to you can always <a href="mailto:#">contact us</a>, + otherwise we’ll be back online shortly!</p> + <p>— The Team</p> + </div> +</article> +</body> diff --git a/public-maintenance/favicon.ico b/public-maintenance/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..eec8a33795727d701ca0550ba23da52a90cf712c Binary files /dev/null and b/public-maintenance/favicon.ico differ diff --git a/public-maintenance/images/kunlogo.png b/public-maintenance/images/kunlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..45991ffd89c5e2347301095b2618f1bb4038282e Binary files /dev/null and b/public-maintenance/images/kunlogo.png differ diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000000000000000000000000000000000000..b612547fc21d079889046e65d1fb135ec6921eaa --- /dev/null +++ b/public/404.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<html> +<head> + <title>The page you were looking for doesn't exist (404)</title> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <style> + body { + background-color: #EFEFEF; + color: #2E2F30; + text-align: center; + font-family: arial, sans-serif; + margin: 0; + } + + div.dialog { + width: 95%; + max-width: 33em; + margin: 4em auto 0; + } + + div.dialog > div { + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #BBB; + border-top: #B00100 solid 4px; + border-top-left-radius: 9px; + border-top-right-radius: 9px; + background-color: white; + padding: 7px 12% 0; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + + h1 { + font-size: 100%; + color: #730E15; + line-height: 1.5em; + } + + div.dialog > p { + margin: 0 0 1em; + padding: 1em; + background-color: #F7F7F7; + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #999; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-top-color: #DADADA; + color: #666; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + </style> +</head> + +<body> + <!-- This file lives in public/404.html --> + <div class="dialog"> + <div> + <h1>The page you were looking for doesn't exist.</h1> + <p>You may have mistyped the address or the page may have moved.</p> + </div> + <p>If you are the application owner check the logs for more information.</p> + </div> +</body> +</html> diff --git a/public/422.html b/public/422.html new file mode 100644 index 0000000000000000000000000000000000000000..a21f82b3bdb817ecbc43f74c6fe360300739418a --- /dev/null +++ b/public/422.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<html> +<head> + <title>The change you wanted was rejected (422)</title> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <style> + body { + background-color: #EFEFEF; + color: #2E2F30; + text-align: center; + font-family: arial, sans-serif; + margin: 0; + } + + div.dialog { + width: 95%; + max-width: 33em; + margin: 4em auto 0; + } + + div.dialog > div { + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #BBB; + border-top: #B00100 solid 4px; + border-top-left-radius: 9px; + border-top-right-radius: 9px; + background-color: white; + padding: 7px 12% 0; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + + h1 { + font-size: 100%; + color: #730E15; + line-height: 1.5em; + } + + div.dialog > p { + margin: 0 0 1em; + padding: 1em; + background-color: #F7F7F7; + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #999; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-top-color: #DADADA; + color: #666; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + </style> +</head> + +<body> + <!-- This file lives in public/422.html --> + <div class="dialog"> + <div> + <h1>The change you wanted was rejected.</h1> + <p>Maybe you tried to change something you didn't have access to.</p> + </div> + <p>If you are the application owner check the logs for more information.</p> + </div> +</body> +</html> diff --git a/public/500.html b/public/500.html new file mode 100644 index 0000000000000000000000000000000000000000..061abc587dcac4cdb1d62a890e4fd4bb20b8cb61 --- /dev/null +++ b/public/500.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html> +<head> + <title>We're sorry, but something went wrong (500)</title> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <style> + body { + background-color: #EFEFEF; + color: #2E2F30; + text-align: center; + font-family: arial, sans-serif; + margin: 0; + } + + div.dialog { + width: 95%; + max-width: 33em; + margin: 4em auto 0; + } + + div.dialog > div { + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #BBB; + border-top: #B00100 solid 4px; + border-top-left-radius: 9px; + border-top-right-radius: 9px; + background-color: white; + padding: 7px 12% 0; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + + h1 { + font-size: 100%; + color: #730E15; + line-height: 1.5em; + } + + div.dialog > p { + margin: 0 0 1em; + padding: 1em; + background-color: #F7F7F7; + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #999; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-top-color: #DADADA; + color: #666; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + </style> +</head> + +<body> + <!-- This file lives in public/500.html --> + <div class="dialog"> + <div> + <h1>We're sorry, but something went wrong.</h1> + </div> + <p>If you are the application owner check the logs for more information.</p> + </div> +</body> +</html> diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..eec8a33795727d701ca0550ba23da52a90cf712c Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/font/PTSans-Bold-webfont.woff b/public/font/PTSans-Bold-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..07b5201b292cdc65382433742ae5159a18b044b5 Binary files /dev/null and b/public/font/PTSans-Bold-webfont.woff differ diff --git a/public/font/PTSans-BoldItalic-webfont.woff b/public/font/PTSans-BoldItalic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..7fa8f1572d15939dfcd82947561457f94eee638c Binary files /dev/null and b/public/font/PTSans-BoldItalic-webfont.woff differ diff --git a/public/font/PTSans-Italic-webfont.woff b/public/font/PTSans-Italic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..1f12392feb62cb016add7ee9a5571e085884abc4 Binary files /dev/null and b/public/font/PTSans-Italic-webfont.woff differ diff --git a/public/font/PTSans-Regular-webfont.woff b/public/font/PTSans-Regular-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..b5317e172b3df9f3490d4495ea634bc7695d737a Binary files /dev/null and b/public/font/PTSans-Regular-webfont.woff differ diff --git a/public/font/SourceCodePro-Bold-webfont.woff b/public/font/SourceCodePro-Bold-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..c7e0612a56d7970f35cb9ee8b377d04e9bf83df6 Binary files /dev/null and b/public/font/SourceCodePro-Bold-webfont.woff differ diff --git a/public/font/SourceCodePro-Regular-webfont.woff b/public/font/SourceCodePro-Regular-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..80f62d191459369051b1fc6f7a29c6e4ceb76865 Binary files /dev/null and b/public/font/SourceCodePro-Regular-webfont.woff differ diff --git a/public/font/SourceSansPro-Bold-webfont.woff b/public/font/SourceSansPro-Bold-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..0082e421b0fdd57d32160e81e4352eff9095e04c Binary files /dev/null and b/public/font/SourceSansPro-Bold-webfont.woff differ diff --git a/public/font/SourceSansPro-BoldItalic-webfont.woff b/public/font/SourceSansPro-BoldItalic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..ebac9a170efac1222bc81b97b2198979a7f6080e Binary files /dev/null and b/public/font/SourceSansPro-BoldItalic-webfont.woff differ diff --git a/public/font/SourceSansPro-Italic-webfont.woff b/public/font/SourceSansPro-Italic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..56ca1256072d7c595a68e5d7e68797dd1e3b7c07 Binary files /dev/null and b/public/font/SourceSansPro-Italic-webfont.woff differ diff --git a/public/font/SourceSansPro-Light-webfont.woff b/public/font/SourceSansPro-Light-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..d6131e335c3c1f7f07aedfb300afbcd3d8e08831 Binary files /dev/null and b/public/font/SourceSansPro-Light-webfont.woff differ diff --git a/public/font/SourceSansPro-LightItalic-webfont.woff b/public/font/SourceSansPro-LightItalic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..bb417952a036d201082619922aa17be813d5b419 Binary files /dev/null and b/public/font/SourceSansPro-LightItalic-webfont.woff differ diff --git a/public/font/SourceSansPro-Regular-webfont.woff b/public/font/SourceSansPro-Regular-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..de7b9c850d6f6e1ccf7d07c4787e7d252e43b026 Binary files /dev/null and b/public/font/SourceSansPro-Regular-webfont.woff differ diff --git a/public/font/cursive_standard-webfont.woff b/public/font/cursive_standard-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..744f86910d8852bb0bce2af1c48701441e85419e Binary files /dev/null and b/public/font/cursive_standard-webfont.woff differ diff --git a/public/font/fontello.svg b/public/font/fontello.svg new file mode 100644 index 0000000000000000000000000000000000000000..97027a8312f11067472cbbb04ffc624d789d8524 --- /dev/null +++ b/public/font/fontello.svg @@ -0,0 +1,331 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata> +<defs> +<font id="fontello" horiz-adv-x="1000" > +<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" /> +<missing-glyph horiz-adv-x="1000" /> +<glyph glyph-name="pause" unicode="" d="m0-43v786q0 14 11 25t25 11h285q15 0 26-11t10-25v-786q0-14-10-25t-26-11h-285q-15 0-25 11t-11 25z m500 0v786q0 14 11 25t25 11h285q15 0 26-11t10-25v-786q0-14-10-25t-26-11h-285q-15 0-25 11t-11 25z" horiz-adv-x="857.1" /> +<glyph glyph-name="glass" unicode="" d="m52 746q0 13 10 21t21 9 24 3h786q13 0 24-3t21-9 10-21q0-19-24-43l-353-353v-429h179q15 0 25-10t11-25-11-25-25-11h-500q-14 0-25 11t-11 25 11 25 25 10h179v429l-353 353q-24 24-24 43z" horiz-adv-x="1000" /> +<glyph glyph-name="music" unicode="" d="m0-43q0 28 19 50t48 34 58 17 54 6q58 0 107-21v539q0 17 10 32t28 19l464 143q7 3 16 3 22 0 38-16t15-38v-625q0-28-19-50t-48-33-58-18-53-6-54 6-58 18-48 33-19 50 19 50 48 33 58 18 54 6q58 0 107-22v300l-429-132v-396q0-28-19-49t-48-34-58-18-53-6-54 6-58 18-48 34-19 49z" horiz-adv-x="857.1" /> +<glyph glyph-name="search" unicode="" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" /> +<glyph glyph-name="mail" unicode="" d="m0 11v607q0 37 26 63t63 26h822q37 0 63-26t26-63v-607q0-37-26-63t-63-27h-822q-36 0-63 27t-26 63z m71 0q0-8 6-13t12-5h822q7 0 12 5t6 13v428q-18-20-39-37-149-114-238-188-28-24-46-38t-48-27-57-13h-2q-26 0-57 13t-48 27-46 38q-88 74-238 188-21 17-39 37v-428z m0 607q0-94 82-159 108-84 224-176 4-3 20-17t25-21 25-17 28-16 24-5h2q11 0 24 5t28 16 25 17 25 21 20 17q116 92 224 176 30 24 56 65t26 73v14t-1 7-1 7-3 5-5 4-8 2h-822q-7 0-12-6t-6-12z" horiz-adv-x="1000" /> +<glyph glyph-name="mail-alt" unicode="" d="m0 11v443q25-28 56-49 202-137 278-192 32-24 51-37t53-27 61-13h2q28 0 61 13t53 27 51 37q95 68 278 192 32 22 56 49v-443q0-37-26-63t-63-27h-822q-36 0-63 27t-26 63z m0 595q0 43 23 72t66 29h822q36 0 62-26t27-63q0-44-27-84t-68-69q-210-146-262-181-5-4-23-17t-30-22-29-18-33-15-27-5h-2q-12 0-27 5t-33 15-29 18-30 22-23 17q-51 35-147 101t-114 80q-35 23-65 64t-31 77z" horiz-adv-x="1000" /> +<glyph glyph-name="heart" unicode="" d="m0 517q0 123 71 192t196 70q34 0 70-12t67-33 54-38 42-38q20 20 42 38t54 38 67 33 70 12q125 0 196-70t71-192q0-123-128-251l-347-335q-10-10-25-10t-25 10l-348 336q-5 5-15 15t-31 36-38 55-30 67-13 77z" horiz-adv-x="1000" /> +<glyph glyph-name="heart-empty" unicode="" d="m0 517q0 123 71 192t196 70q34 0 70-12t67-33 54-38 42-38q20 20 42 38t54 38 67 33 70 12q125 0 196-70t71-192q0-123-128-251l-347-335q-10-10-25-10t-25 10l-348 336q-5 5-15 15t-31 36-38 55-30 67-13 77z m71 0q0-93 105-198l324-312 324 312q105 105 105 198 0 46-12 80t-31 55-46 33-52 18-55 4-62-14-62-36-48-40-34-34q-10-13-27-13t-27 13q-14 15-34 34t-48 40-62 36-62 14-55-4-52-18-46-33-31-55-12-80z" horiz-adv-x="1000" /> +<glyph glyph-name="star" unicode="" d="m0 489q0 21 31 26l280 40 126 254q11 23 27 23t28-23l125-254 280-40q32-5 32-26 0-12-15-27l-203-197 48-279q1-4 1-12 0-11-6-19t-17-9q-10 0-22 7l-251 132-250-132q-13-7-23-7-11 0-17 9t-6 19q0 4 1 12l48 279-203 197q-14 15-14 27z" horiz-adv-x="928.6" /> +<glyph glyph-name="star-empty" unicode="" d="m0 489q0 21 31 26l280 40 126 254q11 23 27 23t28-23l125-254 280-40q32-5 32-26 0-12-15-27l-203-197 48-279q1-4 1-12 0-28-23-28-10 0-22 7l-251 132-250-132q-13-7-23-7-11 0-17 9t-6 19q0 4 1 12l48 279-203 197q-14 15-14 27z m123-34l171-165-41-235 211 111 211-111-41 235 171 165-235 35-106 213-105-213z" horiz-adv-x="928.6" /> +<glyph glyph-name="star-half" unicode="" d="m0 489q0 21 31 26l280 40 126 254q11 23 27 23v-747l-250-132q-13-7-23-7-11 0-17 9t-6 19q0 4 1 12l48 279-203 197q-14 15-14 27z" horiz-adv-x="500" /> +<glyph glyph-name="star-half-alt" unicode="" d="m1 495q5 16 30 20l280 40 126 254q11 23 27 23 16 0 28-23l125-254 280-40q25-4 30-20t-13-33l-203-197 48-279q3-19-3-29t-19-11q-9 0-22 7l-251 132-250-132q-13-7-23-7-12 0-19 11t-3 29l48 279-203 197q-18 18-13 33z m463-329l33-17 178-94-34 198-7 37 28 26 143 139-198 29-37 6-17 34-89 179v-537z" horiz-adv-x="928.6" /> +<glyph glyph-name="user" unicode="" d="m0 66q0 30 2 58t8 61 15 60 24 55 34 45 48 30 62 11q5 0 24-12t41-27 60-27 75-12 74 12 61 27 41 27 24 12q34 0 62-11t48-30 34-45 24-55 15-60 8-61 2-58q0-67-41-106t-108-39h-488q-67 0-108 39t-41 106z m179 498q0 89 62 152t152 63 151-63 63-152-63-151-151-63-152 63-62 151z" horiz-adv-x="785.7" /> +<glyph glyph-name="users" unicode="" d="m0 367q0 197 69 197 4 0 25-11t54-24 66-12q38 0 75 13-3-21-3-37 0-78 45-143-90-3-148-72h-75q-45 0-77 23t-31 66z m71 340q0 59 42 101t101 42 101-42 42-101-42-101-101-42-101 42-42 101z m72-713q0 30 2 58t8 61 14 61 24 54 35 45 48 30 62 11q6 0 24-12t41-26 59-27 76-12 75 12 60 27 41 26 23 12q35 0 63-11t47-30 35-45 24-54 15-61 8-61 2-58q0-66-41-105t-108-39h-488q-68 0-108 39t-41 105z m178 499q0 89 63 151t152 63 151-63 63-151-63-152-151-63-152 63-63 152z m393 214q0 59 42 101t101 42 101-42 42-101-42-101-101-42-101 42-42 101z m27-357q45 65 45 143 0 16-3 37 37-13 74-13 33 0 67 12t54 24 24 11q69 0 69-197 0-43-31-66t-77-22h-75q-57 68-147 71z" horiz-adv-x="1071.4" /> +<glyph glyph-name="male" unicode="" d="m0 225v232q0 45 31 76t76 31h357q45 0 76-31t31-76v-232q0-22-15-38t-38-16-38 16-16 38v196h-35v-509q0-25-19-44t-44-18-44 18-18 44v259h-36v-259q0-25-19-44t-44-18-44 18-18 44v509h-36v-196q0-22-15-38t-38-16-38 16-16 38z m161 482q0 52 36 89t89 36 88-36 37-89-37-88-88-37-89 37-36 88z" horiz-adv-x="571.4" /> +<glyph glyph-name="female" unicode="" d="m0 261q0 16 9 29l143 215q41 59 98 59h214q58 0 99-59l142-215q9-13 9-29 0-23-15-38t-38-16q-29 0-45 24l-127 190h-25v-73l138-230q5-8 5-18 0-14-10-25t-26-11h-107v-151q0-26-18-45t-44-18h-89q-26 0-45 18t-18 45v151h-107q-15 0-25 11t-11 25q0 10 5 18l138 230v73h-25l-127-190q-16-24-44-24-23 0-38 16t-16 38z m232 446q0 52 37 89t88 36 89-36 36-89-36-88-89-37-88 37-37 88z" horiz-adv-x="714.3" /> +<glyph glyph-name="video" unicode="" d="m0-61v750q0 37 26 63t63 27h893q37 0 63-27t26-63v-750q0-37-26-63t-63-26h-893q-36 0-63 26t-26 63z m71 90v-72q0-14 11-25t25-11h72q14 0 25 11t10 25v72q0 14-10 25t-25 10h-72q-14 0-25-10t-11-25z m0 142q0-14 11-25t25-10h72q14 0 25 10t10 25v72q0 14-10 25t-25 11h-72q-14 0-25-11t-11-25v-72z m0 215q0-15 11-25t25-11h72q14 0 25 11t10 25v71q0 15-10 25t-25 11h-72q-14 0-25-11t-11-25v-71z m0 214q0-15 11-25t25-11h72q14 0 25 11t10 25v71q0 15-10 26t-25 10h-72q-14 0-25-10t-11-26v-71z m215-643q0-14 10-25t25-11h429q15 0 25 11t11 25v286q0 14-11 25t-25 11h-429q-14 0-25-11t-10-25v-286z m0 429q0-15 10-25t25-11h429q15 0 25 11t11 25v285q0 15-11 26t-25 10h-429q-14 0-25-10t-10-26v-285z m571-357v-72q0-14 11-25t25-11h71q15 0 25 11t11 25v72q0 14-11 25t-25 10h-71q-15 0-25-10t-11-25z m0 142q0-14 11-25t25-10h71q15 0 25 10t11 25v72q0 14-11 25t-25 11h-71q-15 0-25-11t-11-25v-72z m0 215q0-15 11-25t25-11h71q15 0 25 11t11 25v71q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-71z m0 214q0-15 11-25t25-11h71q15 0 25 11t11 25v71q0 15-11 26t-25 10h-71q-15 0-25-10t-11-26v-71z" horiz-adv-x="1071.4" /> +<glyph glyph-name="videocam" unicode="" d="m0 154v392q0 67 47 114t114 47h393q66 0 113-47t47-114v-92l225 225q10 10 25 10 7 0 14-3 22-9 22-32v-608q0-23-22-32-7-3-14-3-15 0-25 10l-225 225v-92q0-67-47-114t-113-47h-393q-67 0-114 47t-47 114z" horiz-adv-x="1000" /> +<glyph glyph-name="picture" unicode="" d="m0 11v678q0 37 26 63t63 27h893q37 0 63-27t26-63v-678q0-37-26-63t-63-27h-893q-36 0-63 27t-26 63z m71 0q0-8 6-13t12-5h893q7 0 13 5t5 13v678q0 8-5 13t-13 5h-893q-7 0-12-5t-6-13v-678z m72 53v107l178 179 90-89 285 285 233-232v-250h-786z m0 465q0 44 31 75t76 32 76-32 31-75-31-76-76-32-76 32-31 76z" horiz-adv-x="1071.4" /> +<glyph glyph-name="camera" unicode="" d="m0 64v500q0 59 42 101t101 42h125l28 76q11 27 39 47t58 20h286q29 0 57-20t39-47l29-76h125q59 0 101-42t41-101v-500q0-59-41-101t-101-42h-786q-59 0-101 42t-42 101z m286 250q0-103 73-176t177-74 176 74 74 176-74 177-176 73-177-73-73-177z m89 0q0 67 47 114t114 47 113-47 47-114-47-113-113-47-114 47-47 113z" horiz-adv-x="1071.4" /> +<glyph glyph-name="camera-alt" unicode="" d="m0-7v714q0 30 21 51t50 21h858q29 0 50-21t21-51v-714q0-30-21-51t-50-21h-858q-29 0-50 21t-21 51z m71 0h858v71h-858v-71z m0 571h858v143h-462l-36-71h-360v-72z m72 107h214v72h-214v-72z m143-358q0-89 63-151t151-63 152 63 62 151-62 152-152 62-151-62-63-152z m71 0q0 59 42 101t101 42 101-42 42-101-42-101-101-42-101 42-42 101z m54 1q0-8 5-13t13-5 12 5 5 13q0 23 16 38t38 16q8 0 13 5t5 13-5 13-13 5q-37 0-63-27t-26-63z" horiz-adv-x="1000" /> +<glyph glyph-name="th-large" unicode="" d="m0 64v215q0 29 21 50t50 21h286q29 0 50-21t22-50v-215q0-29-22-50t-50-21h-286q-29 0-50 21t-21 50z m0 429v214q0 29 21 50t50 22h286q29 0 50-22t22-50v-214q0-29-22-50t-50-22h-286q-29 0-50 22t-21 50z m500-429v215q0 29 21 50t50 21h286q29 0 50-21t22-50v-215q0-29-22-50t-50-21h-286q-29 0-50 21t-21 50z m0 429v214q0 29 21 50t50 22h286q29 0 50-22t22-50v-214q0-29-22-50t-50-22h-286q-29 0-50 22t-21 50z" horiz-adv-x="928.6" /> +<glyph glyph-name="th" unicode="" d="m0 46v108q0 22 16 38t38 15h178q22 0 38-15t16-38v-108q0-22-16-37t-38-16h-178q-23 0-38 16t-16 37z m0 286v107q0 23 16 38t38 16h178q22 0 38-16t16-38v-107q0-22-16-38t-38-15h-178q-23 0-38 15t-16 38z m0 286v107q0 22 16 38t38 16h178q22 0 38-16t16-38v-107q0-22-16-38t-38-16h-178q-23 0-38 16t-16 38z m357-572v108q0 22 16 38t38 15h178q23 0 38-15t16-38v-108q0-22-16-37t-38-16h-178q-23 0-38 16t-16 37z m0 286v107q0 23 16 38t38 16h178q23 0 38-16t16-38v-107q0-22-16-38t-38-15h-178q-23 0-38 15t-16 38z m0 286v107q0 22 16 38t38 16h178q23 0 38-16t16-38v-107q0-22-16-38t-38-16h-178q-23 0-38 16t-16 38z m357-572v108q0 22 16 38t38 15h178q23 0 38-15t16-38v-108q0-22-16-37t-38-16h-178q-22 0-38 16t-16 37z m0 286v107q0 23 16 38t38 16h178q23 0 38-16t16-38v-107q0-22-16-38t-38-15h-178q-22 0-38 15t-16 38z m0 286v107q0 22 16 38t38 16h178q23 0 38-16t16-38v-107q0-22-16-38t-38-16h-178q-22 0-38 16t-16 38z" horiz-adv-x="1000" /> +<glyph glyph-name="th-list" unicode="" d="m0 46v108q0 22 16 38t38 15h178q22 0 38-15t16-38v-108q0-22-16-37t-38-16h-178q-23 0-38 16t-16 37z m0 286v107q0 23 16 38t38 16h178q22 0 38-16t16-38v-107q0-22-16-38t-38-15h-178q-23 0-38 15t-16 38z m0 286v107q0 22 16 38t38 16h178q22 0 38-16t16-38v-107q0-22-16-38t-38-16h-178q-23 0-38 16t-16 38z m357-572v108q0 22 16 38t38 15h535q23 0 38-15t16-38v-108q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m0 286v107q0 23 16 38t38 16h535q23 0 38-16t16-38v-107q0-22-16-38t-38-15h-535q-23 0-38 15t-16 38z m0 286v107q0 22 16 38t38 16h535q23 0 38-16t16-38v-107q0-22-16-38t-38-16h-535q-23 0-38 16t-16 38z" horiz-adv-x="1000" /> +<glyph glyph-name="ok" unicode="" d="m68 332q0 22 15 38l76 76q16 16 38 16t38-16l164-165 366 367q16 16 38 16t38-16l76-76q15-16 15-38t-15-38l-404-404-76-76q-16-15-38-15t-38 15l-76 76-202 202q-15 16-15 38z" horiz-adv-x="1000" /> +<glyph glyph-name="ok-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m141-11q0-15 10-25l202-202q10-10 25-10 15 0 25 10l303 303q11 10 11 25 0 16-11 26l-50 50q-11 11-25 11t-26-11l-227-227-126 126q-11 11-25 11t-26-11l-50-50q-10-10-10-26z" horiz-adv-x="857.1" /> +<glyph glyph-name="ok-circled2" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41-153-41-110-111-41-152z m68 0q0 15 11 25l57 57q10 11 25 11t25-11l82-82 153 153q11 11 25 11t26-11l56-56q11-11 11-26t-11-25l-235-235q-11-11-25-11t-25 11l-164 164q-11 11-11 25z" horiz-adv-x="857.1" /> +<glyph glyph-name="ok-squared" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m122 268q0-14 10-25l200-200q11-10 25-10t25 10l343 343q10 10 10 25t-10 25l-57 57q-11 10-25 10t-25-10l-261-261-118 118q-10 11-25 11t-25-11l-57-57q-10-11-10-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="cancel" unicode="" d="m61 112q0 23 16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38t-15-38l-76-76q-16-15-38-15t-38 15l-164 164-164-164q-16-15-38-15t-38 15l-76 76q-16 16-16 38z" horiz-adv-x="785.7" /> +<glyph glyph-name="cancel-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m216-126q0-15 11-26l50-50q10-11 25-11 15 0 26 11l101 101 101-101q10-11 25-11 15 0 25 11l51 50q10 11 10 26 0 14-10 25l-101 101 101 101q10 11 10 25 0 15-10 26l-51 50q-10 11-25 11-15 0-25-11l-101-101-101 101q-11 11-26 11-15 0-25-11l-50-50q-11-11-11-26 0-14 11-25l101-101-101-101q-11-11-11-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="folder-open" unicode="" d="m1313 632h-1235q9 48 27 67 16 17 31 17h4q4-1 8-1 12 0 26 4 18 6 25 29l24 72q77 29 208 29 89 0 164-29l25-72q24-23 33-26t43-3h485q84 0 110-22 12-11 22-65z m78-164v-10l-68-523q-5-35-33-61t-65-25h-1058q-36 0-65 25t-34 61l-67 523q-1 3-1 10 0 33 23 55t55 21h1235q33 0 56-21t22-55z" horiz-adv-x="1391" /> +<glyph glyph-name="plus" unicode="" d="m0 332v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q22 0 38-16t16-38v-107q0-22-16-38t-38-16h-232v-232q0-22-16-38t-38-15h-107q-22 0-38 15t-15 38v232h-232q-23 0-38 16t-16 38z" horiz-adv-x="785.7" /> +<glyph glyph-name="plus-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m179-36q0-14 10-25t25-10h143v-143q0-15 11-25t25-11h71q15 0 25 11t11 25v143h143q14 0 25 10t11 25v72q0 14-11 25t-25 10h-143v143q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-143h-143q-14 0-25-10t-10-25v-72z" horiz-adv-x="857.1" /> +<glyph glyph-name="plus-squared" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" /> +<glyph glyph-name="download" unicode="" d="m0 84v73q0 33 24 56t57 24 56-24 24-56v-73q0-17 12-29t30-13h531q18 0 30 13t12 29v73q0 33 24 56t56 24 57-24 24-56v-73q0-84-59-143t-144-60h-531q-84 0-144 60t-59 143z m155 359q0 33 24 57 23 23 56 23t57-23l105-106v344q0 33 24 57t56 23 57-23 24-57v-344l110 110q24 24 57 24t56-24q24-23 24-56t-24-57l-247-247q-24-25-57-25-32 0-56 25l-242 242q-24 24-24 57z" horiz-adv-x="937.5" /> +<glyph glyph-name="minus" unicode="" d="m0 332v107q0 23 16 38t38 16h678q22 0 38-16t16-38v-107q0-22-16-38t-38-15h-678q-23 0-38 15t-16 38z" horiz-adv-x="785.7" /> +<glyph glyph-name="minus-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m179-36q0-14 10-25t25-10h429q14 0 25 10t11 25v72q0 14-11 25t-25 10h-429q-14 0-25-10t-10-25v-72z" horiz-adv-x="857.1" /> +<glyph glyph-name="minus-squared" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 232q0-14 11-25t25-10h500q14 0 25 10t10 25v72q0 14-10 25t-25 10h-500q-15 0-26-10t-10-25v-72z" horiz-adv-x="857.1" /> +<glyph glyph-name="minus-squared-alt" unicode="" d="m0 154v464q0 66 47 113t114 48h464q66 0 114-48t47-113v-464q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114z m71 0q0-37 27-63t63-27h464q37 0 63 27t26 63v464q0 37-26 63t-63 26h-464q-37 0-63-26t-27-63v-464z m72 214v36q0 7 5 12t13 5h464q8 0 13-5t5-12v-36q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="785.7" /> +<glyph glyph-name="upload" unicode="" d="m0 84v73q0 33 24 56t57 24 56-24 24-56v-73q0-17 12-29t30-13h531q18 0 30 13t12 29v73q0 33 24 56t56 24 57-24 24-56v-73q0-84-59-143t-144-60h-531q-84 0-143 59t-60 144z m155 407q0 33 24 57l247 247q23 23 57 23 33 0 56-23l243-242q23-24 23-57t-23-57q-24-23-57-23t-57 23l-105 105v-344q0-33-24-57t-56-24q-33 0-57 24t-24 57v344l-110-110q-24-23-57-23t-56 23-24 57z" horiz-adv-x="937.5" /> +<glyph glyph-name="help" unicode="" d="m54 543q-1 8 3 16 89 148 259 148 45 0 90-17t81-46 59-72 23-88q0-30-8-57t-20-42-31-33-32-25-34-19q-23-13-38-37t-15-37q0-10-7-18t-16-9h-134q-8 0-14 10t-6 21v25q0 47 37 88t79 60q33 15 47 32t14 42q0 23-26 41t-60 18q-36 0-60-16-20-14-60-64-7-9-17-9-7 0-14 4l-91 70q-8 6-9 14z m160-528v134q0 9 7 16t16 6h134q8 0 15-6t7-16v-134q0-9-7-16t-15-6h-134q-9 0-16 6t-7 16z" horiz-adv-x="571.4" /> +<glyph glyph-name="layers" unicode="" d="m18 183l446-112 447 112 0-112-447-112-446 112 0 112z m0 223l446-112 447 112 0-112-447-111-446 111 0 112z m0 223l446 112 447-112 0-111-447-112-446 112 0 111z" horiz-adv-x="928" /> +<glyph glyph-name="unlink" unicode="" d="m0 243q0 8 5 13t13 5h178q8 0 13-5t5-13-5-13-13-5h-178q-8 0-13 5t-5 13z m9 357q0 67 47 113l82 82q47 46 114 46 67 0 114-47l186-187q12-12 23-32l-133-10-152 153q-16 16-38 16-22 0-38-15l-82-82q-16-15-16-37 0-22 16-38l153-153-10-134q-20 12-32 24l-187 187q-47 48-47 114z m62-589q0 7 5 13l143 142q6 5 13 5t13-5q5-5 5-12t-5-13l-143-143q-5-5-13-5-6 0-13 5-5 6-5 13z m233-72v179q0 8 5 13t12 5 13-5 5-13v-179q0-8-5-13t-13-5-12 5-5 13z m49 257l134 10 152-153q15-15 38-15t38 15l82 81q15 16 15 37 0 23-15 38l-153 154 10 133q20-12 31-23l188-188q47-48 47-114 0-67-48-113l-82-81q-46-47-113-47-68 0-114 48l-186 187q-12 11-24 31z m236 458v178q0 8 5 13t13 5 13-5 5-13v-178q0-8-5-13t-13-5-13 5-5 13z m90-36q0 7 5 13l142 142q6 5 13 5t13-5q5-5 5-12t-5-13l-143-143q-6-5-13-5t-12 5q-5 6-5 13z m35-89q0 7 5 12t13 5h179q8 0 13-5t5-12-5-13-13-5h-179q-8 0-13 5t-5 13z" horiz-adv-x="928.6" /> +<glyph glyph-name="link-ext" unicode="" d="m0 154v464q0 66 47 113t114 48h393q7 0 12-5t5-13v-36q0-8-5-13t-12-5h-393q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v178q0 8 5 13t13 5h36q8 0 13-5t5-13v-178q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114z m382 160q0 8 6 13l364 364-99 98q-10 11-10 25t10 25 26 11h285q15 0 25-11t11-25v-285q0-15-11-26t-25-10-25 10l-98 99-364-364q-5-6-13-6t-13 6l-63 63q-6 6-6 13z" horiz-adv-x="1000" /> +<glyph glyph-name="link-ext-alt" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m157 89q0-14 11-25l57-57q11-10 25-10t25 10l298 298 80-80q11-11 26-11 6 0 14 3 21 10 21 33v268q0 15-10 25t-25 11h-268q-24 0-33-22-10-23 8-39l80-80-298-298q-11-11-11-26z" horiz-adv-x="857.1" /> +<glyph glyph-name="attach" unicode="" d="m2 564q0 88 62 150t150 62q88 0 152-63l338-338q5-5 5-12 0-9-17-26t-26-17q-7 0-13 5l-338 339q-44 43-101 43-59 0-100-42t-40-101q0-58 42-101l433-433q35-35 81-35 36 0 59 23t24 59q0 46-36 81l-324 324q-14 14-33 14-16 0-27-11t-11-27q0-18 14-33l229-228q6-6 6-13 0-9-18-26t-26-17q-7 0-12 5l-229 229q-35 34-35 83 0 46 32 78t77 32q49 0 83-36l325-324q55-54 55-131 0-65-44-109t-109-44q-75 0-131 56l-434 433q-63 64-63 151z" horiz-adv-x="785.7" /> +<glyph glyph-name="lock" unicode="" d="m0 46v322q0 22 16 38t38 15h17v108q0 102 74 176t176 74 177-74 73-176v-108h18q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z m179 375h285v108q0 59-42 101t-101 41-101-41-41-101v-108z" horiz-adv-x="642.9" /> +<glyph glyph-name="lock-open" unicode="" d="m0 46v322q0 22 16 38t38 15h375v108q0 103 73 176t177 74 176-74 74-176v-143q0-15-11-25t-25-11h-36q-14 0-25 11t-11 25v143q0 59-41 101t-101 41-101-41-42-101v-108h53q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="928.6" /> +<glyph glyph-name="lock-open-alt" unicode="" d="m0 46v322q0 22 16 38t38 15h17v179q0 103 74 177t176 73 177-73 73-177q0-15-10-25t-25-11h-36q-14 0-25 11t-11 25q0 59-42 101t-101 42-101-42-41-101v-179h410q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37z" horiz-adv-x="642.9" /> +<glyph glyph-name="pin" unicode="" d="m0 171q0 69 44 124t99 55v286q-29 0-50 21t-22 50 22 50 50 22h357q29 0 50-22t21-50-21-50-50-21v-286q55 0 99-55t44-124q0-14-11-25t-25-10h-239l-29-270q-1-6-6-11t-11-5h-1q-15 0-17 15l-43 271h-225q-15 0-25 10t-11 25z m232 197q0-8 5-13t13-5 13 5 5 13v250q0 8-5 13t-13 5-13-5-5-13v-250z" horiz-adv-x="642.9" /> +<glyph glyph-name="eye" unicode="" d="m0 314q0 19 11 39 78 128 210 205t279 78 279-78 210-205q11-20 11-39t-11-38q-78-129-210-206t-279-77-279 77-210 206q-11 19-11 38z m71 0q75-114 187-182t242-68 242 68 187 182q-85 132-213 197 34-58 34-125 0-104-73-177t-177-73-177 73-73 177q0 67 34 125-128-65-213-197z m259 72q0-11 8-19t19-8 19 8 8 19q0 48 34 82t82 34q11 0 19 8t8 19-8 19-19 7q-70 0-120-50t-50-119z" horiz-adv-x="1000" /> +<glyph glyph-name="eye-off" unicode="" d="m0 314q0 22 11 39 86 131 212 207t277 76q50 0 100-10l31 54q5 9 15 9 3 0 10-3t18-9 18-10 18-10 10-7q9-5 9-15 0-4 0-5-59-105-176-316t-176-316l-28-50q-5-9-15-9-7 0-75 39-9 6-9 16 0 7 25 48-80 37-147 97t-117 137q-11 17-11 38z m71 0q94-144 239-209l43 79q-48 35-76 88t-27 114q0 67 34 125-128-65-213-197z m259 72q0-11 8-19t19-8 19 8 8 19q0 48 34 82t82 34q11 0 19 8t8 19-8 19-19 7q-70 0-120-50t-50-119z m170-393l41 74q119 10 219 76t169 171q-65 100-158 164l35 63q53-36 102-86t81-102q11-19 11-39t-11-38q-22-36-61-81-84-96-194-149t-234-53z m89 159l157 281q4-26 4-47 0-78-44-142t-117-92z" horiz-adv-x="1000" /> +<glyph glyph-name="tag" unicode="" d="m0 475v232q0 29 21 50t50 22h233q29 0 65-15t57-36l399-399q20-21 20-50 0-30-20-51l-274-274q-22-21-51-21-30 0-50 21l-399 399q-21 21-36 57t-15 65z m107 125q0-30 21-50t51-21 50 21 21 50-21 51-50 20-51-20-21-51z" horiz-adv-x="857.1" /> +<glyph glyph-name="tags" unicode="" d="m0 475v232q0 29 21 50t50 22h233q29 0 65-15t57-36l399-399q20-21 20-50 0-30-20-51l-274-274q-22-21-51-21-30 0-50 21l-399 399q-21 21-36 57t-15 65z m107 125q0-30 21-50t51-21 50 21 21 50-21 51-50 20-51-20-21-51z m286 179h125q29 0 65-15t57-36l399-399q21-21 21-50 0-30-21-51l-274-274q-22-21-51-21-20 0-33 8t-29 25l262 262q21 21 21 51 0 29-21 50l-399 399q-21 21-57 36t-65 15z" horiz-adv-x="1071.4" /> +<glyph glyph-name="bookmark" unicode="" d="m0-3v719q0 19 11 35t29 23q12 5 25 5h585q12 0 24-5 19-8 29-23t11-35v-719q0-19-11-35t-29-23q-10-4-24-4-27 0-47 18l-246 236-246-236q-20-19-46-19-13 0-25 5-18 7-29 23t-11 35z" horiz-adv-x="714.3" /> +<glyph glyph-name="bookmark-empty" unicode="" d="m0-3v719q0 19 11 35t29 23q12 5 25 5h585q12 0 24-5 19-8 29-23t11-35v-719q0-19-11-35t-29-23q-10-4-24-4-27 0-47 18l-246 236-246-236q-20-19-46-19-13 0-25 5-18 7-29 23t-11 35z m71 17l237 227 49 47 50-47 236-227v693h-572v-693z" horiz-adv-x="714.3" /> +<glyph glyph-name="flag" unicode="" d="m36 707q0 30 21 51t50 21 51-21 21-51q0-40-36-61v-707q0-7-5-12t-13-6h-36q-7 0-12 6t-6 12v707q-35 21-35 61z m143-536v414q0 18 17 31 12 8 44 24 132 67 235 67 60 0 112-16t122-49q21-11 49-11 30 0 65 12t62 26 49 26 30 12q15 0 25-10t11-26v-425q0-14-7-22t-22-15q-120-65-206-65-34 0-69 12t-60 27-65 27-79 12q-107 0-259-81-10-5-19-5-14 0-25 10t-10 25z" horiz-adv-x="1000" /> +<glyph glyph-name="thumbs-up-alt" unicode="" d="m0 29v357q0 14 11 25t25 10h160q15 0 26-10t10-25v-357q0-15-10-26t-26-10h-160q-15 0-25 10t-11 26z m71 71q0-15 11-25t25-11q15 0 25 11t11 25q0 15-11 25t-25 11q-15 0-25-11t-11-25z m197-71v357q0 14 10 25t24 11q13 1 42 33t57 67q38 49 56 67 10 10 17 27t10 27 8 34q4 22 7 34t11 29 18 28q11 11 26 11 25 0 46-6t33-15 22-22 14-26 7-27 2-26 1-21q0-21-6-43t-10-33-16-31q-1-4-5-10t-6-13-5-13h155q43 0 75-32t32-75q0-48-31-83 9-25 9-43 1-42-24-76 9-32 0-66-9-31-31-52 5-63-27-101-36-43-110-44h-72q-37 0-80 9t-68 16-67 22q-69 24-88 25-15 0-26 11t-10 25z" horiz-adv-x="928.6" /> +<glyph glyph-name="thumbs-down-alt" unicode="" d="m0 243q0-15 11-25t25-11h160q15 0 26 11t10 25v357q0 15-10 25t-26 11h-160q-15 0-25-11t-11-25v-357z m71 286q0 15 11 25t25 10q15 0 25-10t11-25q0-15-11-26t-25-10q-15 0-25 10t-11 26z m197-287v358q0 15 10 25t26 11q19 0 88 24 43 15 67 22t68 16 80 9h72q74-1 110-43 32-39 27-101 22-21 31-53 9-34 0-65 25-34 24-77 0-18-9-42 31-34 31-83-1-44-32-76t-75-31h-155q2-8 5-14t6-12 5-10q10-21 15-32t11-33 6-42q0-14-1-22t-2-25-7-28-14-25-22-23-33-14-46-6q-15 0-26 11-11 11-18 27t-11 29-7 35q-5 23-8 33t-10 27-17 27q-18 19-56 67-28 36-57 68t-42 33q-14 1-24 11t-10 24z" horiz-adv-x="928.6" /> +<glyph glyph-name="comment" unicode="" d="m1137 749v-532q0-41-29-70t-71-30h-168v-268l-267 268h-502q-41 0-70 30t-30 70v532q0 41 30 71t70 29h937q41 0 71-29t29-71z" horiz-adv-x="1137" /> +<glyph glyph-name="comment-alt" unicode="" d="m1179 385q0-126-79-233t-215-170-296-62q-122 0-234 39l2-3-357-107q44 59 71 126t31 106l4 38q-106 120-106 266 0 126 79 233t215 169 295 62 296-62 215-169 79-233z" horiz-adv-x="1179" /> +<glyph glyph-name="split" unicode="" d="m576 797l112 0 0-108q0-115-82-197l-316-314q-44-45-48-106l111 0-167-169-168 169 113 0q6 111 80 185l316 314q49 50 49 118l0 108z m110-725l113 0-167-169-168 169 111 0q-4 61-48 106l-63 62 80 79 62-62q74-74 80-185z" horiz-adv-x="817" /> +<glyph glyph-name="chat" unicode="" d="m1179 385q0-126-79-233t-215-170-296-62q-122 0-234 39l2-3-357-107q44 59 71 126t31 106l4 38q-106 120-106 266 0 126 79 233t215 169 295 62 296-62 215-169 79-233z m-250 0q0 29-21 50t-51 21q-29 0-50-21t-21-50q0-30 21-51t50-21q30 0 51 21t21 51z m-250 0q0 29-21 50t-51 21q-29 0-50-21t-21-50q0-30 21-51t50-21q30 0 51 21t21 51z m-250 0q0 29-21 50t-51 21q-29 0-50-21t-21-50q0-30 21-51t50-21q30 0 51 21t21 51z" horiz-adv-x="1179" /> +<glyph glyph-name="github-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215q0-140-82-252t-211-155q-15-3-22 4t-7 17v118q0 54-29 79 32 3 57 10t53 22 45 37 30 58 11 84q0 68-44 115 21 51-5 114-15 5-45-6t-51-25l-21-13q-52 15-107 15t-108-15q-8 6-23 15t-47 22-48 7q-24-63-4-114-44-47-44-115 0-47 12-83t29-59 45-37 52-22 57-10q-22-20-27-58-12-5-25-8t-32-3-36 12-31 35q-11 18-27 29t-28 14l-11 1q-12 0-16-2t-3-7 5-8 7-6l4-3q12-6 24-21t18-29l5-13q8-21 25-34t37-17 39-4 31 2l13 3q0-22 0-50t1-30q0-10-8-17t-22-4q-129 43-211 155t-82 252z" horiz-adv-x="857.1" /> +<glyph glyph-name="reply-all" unicode="" d="m0 493q0 14 11 25l285 286q17 17 39 7 22-9 22-32v-39l-221-222q-11-11-11-25t11-25l221-222v-39q0-23-22-33-7-3-14-3-15 0-25 11l-285 286q-11 10-11 25z m214 0q0 14 11 25l286 286q16 17 39 7 21-9 21-32v-147q230-15 335-123 94-97 94-284 0-32-9-75t-22-77-27-69-22-51l-12-22q-4-10-15-10-3 0-5 1-14 4-13 19 24 223-59 315-36 40-95 62t-150 29v-140q0-23-21-33-8-3-14-3-15 0-25 11l-286 286q-11 10-11 25z" horiz-adv-x="1000" /> +<glyph glyph-name="hdd" unicode="" d="m0 171v200q0 26 17 45h0l93 123q21 29 57 29h66q112 31 269 31 157 0 269-31h65q37 0 58-29l93-123h0q17-19 17-45v-200q0-29-21-49t-49-21h-864q-29 0-49 21t-21 49z m99 60q0-15 11-26t27-11h88q15 0 26 11t11 26-11 27-26 11h-88q-16 0-27-11t-11-27z m73 236q0-23 44-41t120-30 166-11 166 11 120 30 44 41-44 41-120 30-166 11-166-11-120-30-44-41z m146-236q0-15 11-26t26-11h11q15 0 26 11t11 26-11 27-26 11h-11q-15 0-26-11t-11-27z m85 236q0 10 29 17t70 8q40 0 69-8t29-17-29-17-69-8q-41 0-70 8t-29 17z" horiz-adv-x="1004.4" /> +<glyph glyph-name="quote-left" unicode="" d="m0 100v393q0 58 23 111t61 91 91 61 111 23h35q15 0 26-11t10-25v-72q0-14-10-25t-26-10h-35q-59 0-101-42t-42-101v-18q0-22 16-38t37-16h125q45 0 76-31t32-76v-214q0-45-32-76t-76-31h-214q-44 0-76 31t-31 76z m500 0v393q0 58 23 111t61 91 91 61 111 23h35q15 0 26-11t10-25v-72q0-14-10-25t-26-10h-35q-59 0-101-42t-42-101v-18q0-22 15-38t38-16h125q45 0 76-31t32-76v-214q0-45-32-76t-76-31h-214q-44 0-76 31t-31 76z" horiz-adv-x="928.6" /> +<glyph glyph-name="quote-right" unicode="" d="m0 457v214q0 45 31 76t76 32h214q45 0 76-32t32-76v-392q0-58-23-111t-61-91-91-62-111-22h-36q-14 0-25 10t-11 26v71q0 15 11 25t25 11h36q59 0 101 42t42 101v17q0 23-16 38t-38 16h-125q-44 0-76 31t-31 76z m500 0v214q0 45 31 76t76 32h214q45 0 76-32t32-76v-392q0-58-23-111t-61-91-91-62-111-22h-36q-14 0-25 10t-11 26v71q0 15 11 25t25 11h36q59 0 101 42t42 101v17q0 23-16 38t-38 16h-125q-44 0-76 31t-31 76z" horiz-adv-x="928.6" /> +<glyph glyph-name="code" unicode="" d="m1000 849l500-500-500-500-154 154 346 346-346 346z m-692-500l346-346-154-154-500 500 500 500 154-154z" horiz-adv-x="1500" /> +<glyph glyph-name="reply" unicode="" d="m0 493q0 14 11 25l285 286q11 10 25 10t26-10 10-25v-143h125q398 0 488-225 30-75 30-186 0-93-71-252-2-4-6-13t-7-17-8-12q-6-10-15-10-9 0-13 6t-5 14q0 5 1 15t2 13q3 38 3 69 0 56-10 101t-27 77-45 56-59 39-74 24-86 12-98 3h-125v-143q0-14-10-25t-26-11-25 11l-285 286q-11 10-11 25z" horiz-adv-x="1000" /> +<glyph glyph-name="export-alt" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 161q0-101 93-226 6-6 14-6 4 0 7 1 13 5 11 19-25 197 34 264 26 29 73 42t125 13v-89q0-24 22-33 7-3 14-3 14 0 25 11l196 196q11 11 11 25t-11 25l-196 197q-17 17-39 7-22-9-22-32v-90q-66 0-121-11t-90-28-64-44-42-53-25-61-12-62-3-62z" horiz-adv-x="857.1" /> +<glyph glyph-name="pencil" unicode="" d="m0-79v233l464 464 232-232-464-465h-232z m71 143h72v-71h60l50 51-131 131-51-51v-60z m95 143q0-12 13-12 5 0 9 4l303 302q3 4 3 10 0 12-12 12-5 0-9-4l-303-302q-4-4-4-10z m334 447l93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51 0-29-20-50l-93-93z" horiz-adv-x="857.1" /> +<glyph glyph-name="pencil-squared" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143-18h161l303 304-161 161-303-304v-161z m53 107v32l29 29 85-85-29-29h-31v53h-54z m80 98q-8 7 1 16l163 163q9 9 16 1 8-7-1-16l-163-163q-9-9-16-1z m206 295l161-160 51 51q16 16 16 38t-16 38l-85 85q-15 15-38 15t-38-15z" horiz-adv-x="857.1" /> +<glyph glyph-name="gamepad" unicode="" d="m0 279q0 118 84 202t202 83h500q118 0 202-83t83-202-83-202-202-84q-107 0-189 71h-123q-81-71-188-71-119 0-202 84t-84 202z m107-36q0-8 5-13t13-5h107v-107q0-8 5-13t13-5h71q8 0 13 5t5 13v107h107q8 0 13 5t5 13v71q0 8-5 13t-13 5h-107v107q0 8-5 13t-13 5h-71q-8 0-13-5t-5-13v-107h-107q-8 0-13-5t-5-13v-71z m536-36q0-29 21-50t50-21 51 21 21 50-21 51-51 21-50-21-21-51z m143 143q0-30 21-50t50-21 51 21 21 50-21 51-51 20-50-20-21-51z" horiz-adv-x="1071.4" /> +<glyph glyph-name="twitter" unicode="" d="m25 74q19-2 43-2 126 0 224 77-59 1-105 36t-64 89q19-3 34-3 24 0 48 6-63 13-104 62t-41 115v2q38-21 82-23-37 25-59 64t-22 86q0 49 25 91 67-83 164-133t208-55q-5 21-5 41 0 75 53 127t127 53q78 0 132-57 61 12 114 44-20-64-79-100 52 6 104 28-37-54-90-93 0-8 0-23 0-73-21-145t-64-139-103-117-144-82-181-30q-151 0-276 81z" horiz-adv-x="928.6" /> +<glyph glyph-name="comment-empty" unicode="" d="m0 350q0 97 67 179t182 130 251 48 251-48 182-130 67-179-67-179-182-130-251-48q-39 0-81 4-110-97-257-135-27-8-63-12h-3q-8 0-15 6t-9 15v1q-2 2 0 6t1 6 2 5l4 5t4 5 4 5q4 5 17 19t20 22 17 22 18 28 15 33 15 42q-88 50-138 123t-51 157z m71 0q0-62 40-119t113-98l48-28-15-54q-13-50-39-96 85 36 154 96l24 21 31-3q39-5 73-5 114 0 213 39t157 105 59 142-59 142-157 105-213 39-213-39-157-105-59-142z" horiz-adv-x="1000" /> +<glyph glyph-name="chat-empty" unicode="" d="m0 421q0 78 53 144t143 104 197 38 197-38 143-104 53-144-53-143-143-104-197-38q-48 0-98 9-70-50-155-72-21-5-48-9h-2q-6 0-12 5t-6 11q-1 2-1 4t1 4 1 3l1 3t2 3 2 3 3 2 2 3q3 3 13 14t15 16 12 17 14 21 11 25q-69 40-108 98t-40 125z m71 0q0-45 30-88t83-73l54-32-19-46q19 11 34 21l25 18 30-6q43-8 85-8 85 0 159 29t118 79 44 106-44 107-118 79-159 29-160-29-118-79-44-107z m273-354q32-3 49-3 90 0 172 25t148 72q69 52 107 119t37 141q0 43-13 85 72-39 114-99t42-128q0-67-40-126t-108-98q5-14 11-25t14-21 13-16 14-17 13-14q0 0 2-2t3-3 2-3 2-3l1-3t1-3 1-4-1-3q-2-8-7-13t-13-4q-27 4-48 9-85 23-155 72-50-9-98-9-151 0-263 74z" horiz-adv-x="1000" /> +<glyph glyph-name="bell" unicode="" d="m0 64q106 90 160 222t54 278q0 92 54 146t147 66q-4 10-4 20 0 23 15 38t38 16 38-16 16-38q0-10-5-20 94-11 148-66t53-146q0-146 54-278t161-222q0-29-22-50t-50-21h-250q0-59-42-101t-101-42-101 42-42 101h-250q-29 0-50 21t-21 50z m102 0h724q-91 101-137 230t-46 270q0 143-179 143t-178-143q0-141-46-270t-138-230z m264-71q0-41 29-70t69-28q9 0 9 9t-9 8q-33 0-56 24t-24 57q0 9-9 9t-9-9z" horiz-adv-x="928.6" /> +<glyph glyph-name="bell-alt" unicode="" d="m0 64q106 90 160 222t54 278q0 92 54 146t147 66q-4 10-4 20 0 23 15 38t38 16 38-16 16-38q0-10-5-20 94-11 148-66t53-146q0-146 54-278t161-222q0-29-22-50t-50-21h-250q0-59-42-101t-101-42-101 42-42 101h-250q-29 0-50 21t-21 50z m366-71q0-41 29-70t69-28q9 0 9 9t-9 8q-33 0-56 24t-24 57q0 9-9 9t-9-9z" horiz-adv-x="928.6" /> +<glyph glyph-name="attention-alt" unicode="" d="m55 743q-1 14 9 25t25 11h179q14 0 25-11t9-25l-15-429q-1-14-12-25t-25-11h-143q-14 0-25 11t-12 25z m16-714v125q0 14 11 25t25 10h143q15 0 25-10t11-25v-125q0-15-11-26t-25-10h-143q-14 0-25 10t-11 26z" horiz-adv-x="357.1" /> +<glyph glyph-name="attention" unicode="" d="m9 27l429 786q9 17 26 27t36 10 36-10 27-27l428-786q20-35-1-70-10-17-26-26t-35-10h-858q-18 0-35 10t-26 26q-21 35-1 70z m411 519l9-255q0-5 6-9t13-3h103q8 0 13 3t6 9l10 257q0 6-5 10-7 6-14 6h-122q-7 0-14-6-5-4-5-12z m9-463q0-8 5-13t12-6h108q7 0 12 6t5 13v106q0 8-5 13t-12 5h-108q-7 0-12-5t-5-13v-106z" horiz-adv-x="1000" /> +<glyph glyph-name="attention-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m348 271l10-346q0-6 5-10t14-4h103q8 0 13 4t6 10l10 346q0 7-6 10-5 5-13 5h-123q-8 0-13-5-6-3-6-10z m9-538q0-8 6-13t13-6h107q7 0 12 6t5 13v106q0 8-5 13t-12 5h-107q-8 0-13-5t-6-13v-106z" horiz-adv-x="857.1" /> +<glyph glyph-name="location" unicode="" d="m0 493q0 118 84 202t202 84 202-84 83-202q0-61-18-100l-203-432q-9-18-27-29t-37-11-38 11-26 29l-204 432q-18 39-18 100z m143 0q0-59 42-101t101-42 101 42 42 101-42 101-101 42-101-42-42-101z" horiz-adv-x="571.4" /> +<glyph glyph-name="direction" unicode="" d="m1 306q-3 12 2 23t17 17l714 357q7 4 16 4 15 0 25-10 8-8 10-20t-3-22l-357-714q-10-20-32-20-3 0-8 1-13 3-20 13t-8 22v322h-321q-13 0-22 7t-13 20z" horiz-adv-x="785.7" /> +<glyph glyph-name="compass" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41-153-41-110-111-41-152z m161-223v303l285 143v-303z m71 116l143 71-143 72v-143z" horiz-adv-x="857.1" /> +<glyph glyph-name="forward" unicode="" d="m0 225q0 111 30 186 90 225 488 225h125v143q0 14 10 25t26 10 25-10l285-286q11-11 11-25t-11-25l-285-286q-11-11-25-11t-26 11-10 25v143h-125q-55 0-98-3t-86-12-74-24-59-39-45-56-27-77-10-101q0-31 3-69 0-4 2-13t1-15q0-8-5-14t-13-6q-9 0-15 10-4 5-8 12t-7 17-6 13q-71 159-71 252z" horiz-adv-x="1000" /> +<glyph glyph-name="doc" unicode="" d="m0-96v892q0 23 16 38t38 16h500q22 0 49-11t42-27l174-174q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38z m71 17h715v572h-232q-23 0-38 15t-16 38v233h-429v-858z m500 643h210q-5 16-12 23l-175 175q-6 7-23 12v-210z" horiz-adv-x="857.1" /> +<glyph glyph-name="docs" unicode="" d="m0 118v375q0 22 11 49t27 42l228 228q15 16 42 27t49 11h232q23 0 38-16t16-38v-183q38 23 71 23h232q23 0 38-16t16-38v-678q0-23-16-38t-38-16h-535q-23 0-38 16t-16 38v160h-303q-23 0-38 16t-16 38z m71 18h286v143q0 22 11 49t27 42l176 176v233h-214v-233q0-22-15-38t-38-15h-233v-357z m48 428h167v167z m310-643h500v643h-215v-232q0-22-15-38t-38-15h-232v-358z m47 429h167v167z" horiz-adv-x="1000" /> +<glyph glyph-name="archive" unicode="" d="m1217 806v-131q0-18-12-30t-31-13h-1131q-17 0-30 13t-13 30v131q0 17 13 30t30 13h1131q18 0 31-13t12-30z m-43-305v-609q0-17-13-30t-31-13h-1043q-18 0-31 13t-13 30v609q0 18 13 31t31 13h1043q18 0 31-13t13-31z m-304-152q0 27-19 46t-47 19h-391q-27 0-46-19t-19-46 19-46 46-19h391q27 0 47 19t19 46z" horiz-adv-x="1217" /> +<glyph glyph-name="folder-empty" unicode="" d="m0 118v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h375q51 0 88-37t37-88v-393q0-51-37-88t-88-37h-679q-51 0-88 37t-37 88z m71 0q0-22 16-38t38-16h679q22 0 38 16t15 38v393q0 22-15 38t-38 15h-393q-23 0-38 16t-16 38v36q0 22-15 38t-38 15h-179q-22 0-38-15t-16-38v-536z" horiz-adv-x="928.6" /> +<glyph glyph-name="folder-open-empty" unicode="" d="m0 118v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h303q51 0 88-37t37-88v-90h107q30 0 56-13t37-40q8-17 8-38 0-34-25-66l-165-203q-24-30-65-49t-78-19h-607q-51 0-88 37t-37 88z m71 60l143 175q25 30 65 49t78 19h429v90q0 22-16 38t-38 15h-321q-23 0-38 16t-16 38v36q0 22-15 38t-38 15h-179q-22 0-38-15t-16-38v-476z m24-94q0-20 30-20h607q22 0 48 13t40 29l164 203q10 12 10 21 0 20-30 20h-607q-22 0-48-12t-39-29l-164-203q-11-13-11-22z" horiz-adv-x="1071.4" /> +<glyph glyph-name="box" unicode="" d="m36 600v143q0 14 10 25t25 11h858q14 0 25-11t10-25v-143q0-15-10-25t-25-11h-858q-14 0-25 11t-10 25z m35-643v536q0 14 11 25t25 11h786q14 0 25-11t11-25v-536q0-14-11-25t-25-11h-786q-14 0-25 11t-11 25z m322 429q0-15 10-25t26-11h142q15 0 26 11t10 25-10 25-26 10h-142q-15 0-26-10t-10-25z" horiz-adv-x="1000" /> +<glyph glyph-name="rss" unicode="" d="m0 100q0 45 31 76t76 31 76-31 31-76-31-76-76-31-76 31-31 76z m0 282v75q0 16 12 26 9 10 24 10h3q89-7 170-45t145-101q63-63 101-145t45-171q1-15-9-26-11-12-27-12h-75q-14 0-24 9t-11 23q-12 128-103 219t-219 103q-14 1-23 11t-9 24z m0 281v80q0 15 11 26 10 10 25 10h1q147-8 280-67t238-164q104-104 164-238t67-280q1-15-10-26-10-11-26-11h-80q-14 0-25 10t-11 23q-6 120-56 228t-129 188-188 129-227 57q-14 0-24 11t-10 24z" horiz-adv-x="785.7" /> +<glyph glyph-name="rss-squared" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 54q0-30 21-51t50-21 51 21 21 51-21 50-51 21-50-21-21-50z m0 178q0-8 5-13t12-5q86-6 147-68t67-147q1-7 6-12t12-5h72q7 0 13 6t5 13q-8 130-99 221t-221 99q-8 1-14-5t-5-13v-71z m0 214q0-7 5-12t12-6q114-4 211-62t156-155 62-211q0-8 5-13t13-5h71q7 0 13 6 6 5 5 13-3 86-31 166t-78 145-115 114-145 78-166 31q-8 1-13-5-5-5-5-13v-71z" horiz-adv-x="857.1" /> +<glyph glyph-name="phone" unicode="" d="m0 589q0 52 29 104 31 57 59 68 14 6 38 12t39 6q8 0 12-2 10-3 30-43 6-10 16-30t20-35 17-30q2-2 10-14t12-20 4-16q0-11-16-27t-35-31-34-30-16-25q0-5 3-13t4-11 8-14 7-10q42-77 97-132t131-97q1 0 10-6t14-8 11-5 13-2q10 0 25 15t30 35 31 35 28 16q7 0 15-4t20-12 14-10q14-8 30-17t36-20 30-17q39-19 42-29 2-4 2-12 0-15-6-39t-12-38q-11-28-68-60-52-28-103-28-16 0-30 2t-32 7-26 8-31 11-28 10q-54 20-97 47-72 44-148 120t-120 148q-27 43-46 97-2 5-10 28t-12 31-8 26-7 32-2 29z" horiz-adv-x="785.7" /> +<glyph glyph-name="phone-squared" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 416q0-9 1-19t3-17 5-19 6-16 7-18 6-17q33-92 121-179t178-121q4-1 17-6t19-7 16-5 18-5 17-3 19-2q32 0 73 19t53 45q12 30 12 56 0 6-1 9-2 5-21 17t-50 27l-29 16q-3 2-11 8t-14 8-12 3q-10 0-26-18t-32-37-24-18q-4 0-9 2t-9 3-9 6-8 4q-56 31-95 71t-71 95q-1 2-5 8t-5 9-4 9-2 9q0 8 12 19t25 21 25 23 11 20q0 5-2 12t-9 14-7 10q-2 4-8 16t-14 25-15 27-14 23-9 10-9 1q-27 0-56-13-26-11-45-52t-19-73z" horiz-adv-x="857.1" /> +<glyph glyph-name="menu" unicode="" d="m0 29v71q0 15 11 25t25 11h785q15 0 26-11t10-25v-71q0-15-10-26t-26-10h-785q-15 0-25 10t-11 26z m0 285v72q0 14 11 25t25 10h785q15 0 26-10t10-25v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25z m0 286v71q0 15 11 26t25 10h785q15 0 26-10t10-26v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25z" horiz-adv-x="857.1" /> +<glyph glyph-name="cog" unicode="" d="m0 289v124q0 7 5 13t10 7l104 16q8 25 22 51-23 32-60 77-6 7-6 14 0 5 5 12 15 20 55 60t53 40q7 0 15-5l77-60q24 13 50 21 9 76 17 104 3 15 20 15h124q7 0 13-4t7-12l15-103q28-9 50-21l80 60q5 5 13 5 7 0 14-5 72-67 92-95 4-5 4-13 0-6-4-12-9-12-29-38t-30-39q14-28 23-55l102-15q7-1 12-7t4-13v-124q0-7-4-13t-11-7l-104-16q-10-30-21-51 19-28 59-77 6-6 6-14t-5-12q-15-21-55-61t-53-39q-7 0-14 5l-77 60q-25-13-51-21-9-76-16-104-4-16-20-16h-124q-8 0-14 5t-6 12l-16 103q-27 9-50 20l-79-59q-6-5-14-5-8 0-14 6-70 63-92 94-4 5-4 12 0 7 5 13 8 12 28 37t30 40q-15 28-23 55l-102 15q-7 1-11 7t-5 13z m286 61q0-59 42-101t101-42 101 42 41 101-41 101-101 42-101-42-42-101z" horiz-adv-x="857.1" /> +<glyph glyph-name="cog-alt" unicode="" d="m0 299v103q0 6 4 11t9 6l86 14q7 19 18 42-19 27-50 64-4 6-4 11 0 7 4 12 12 16 46 49t44 33q6 0 12-4l64-50q19 10 43 18 6 60 13 86 3 13 16 13h104q6 0 11-4t6-10l13-85q19-6 41-17l66 49q5 4 11 4 7 0 12-4 81-75 81-90 0-5-4-10-7-9-24-30t-25-34q13-27 19-46l85-12q5-2 9-6t4-11v-103q0-6-4-11t-9-6l-86-14q-6-19-18-42 19-27 50-64 4-6 4-11 0-7-4-11-13-17-46-50t-44-33q-6 0-11 4l-64 50q-21-11-43-17-6-60-13-87-4-13-17-13h-104q-6 0-11 4t-5 10l-13 85q-19 6-42 18l-66-50q-4-4-11-4-6 0-12 4-80 75-80 90 0 5 4 10 5 8 23 30t26 34q-13 24-20 46l-85 13q-5 1-9 5t-4 11z m214 51q0-59 42-101t101-42 101 42 42 101-42 101-101 42-101-42-42-101z m429-325v78q0 9 83 18 7 16 17 29-29 63-29 77 0 2 3 4 2 1 19 11t33 19 17 9q4 0 25-26t29-38q12 1 17 1t17-1q28 40 51 63l4 1q2 0 69-39 2-2 2-4 0-14-28-77 9-13 16-29 83-9 83-18v-78q0-9-83-17-6-15-16-29 28-63 28-77 0-2-2-4-68-40-69-40-5 0-26 27t-29 37q-11-1-17-1t-17 1q-7-11-29-37t-25-27q-1 0-69 40-3 2-3 4 0 14 29 77-10 14-17 29-83 8-83 17z m0 572v78q0 9 83 17 7 16 17 29-29 63-29 77 0 2 3 4 2 1 19 11t33 19 17 9q4 0 25-26t29-38q12 2 17 2t17-2q28 40 51 63l4 1q2 0 69-39 2-2 2-4 0-14-28-77 9-13 16-29 83-8 83-17v-78q0-9-83-18-6-15-16-29 28-63 28-77 0-2-2-4-68-39-69-39-5 0-26 26t-29 38q-11-1-17-1t-17 1q-7-12-29-38t-25-26q-1 0-69 39-3 2-3 4 0 14 29 77-10 14-17 29-83 9-83 18z m143-533q0-29 21-50t50-21 51 21 21 50q0 29-22 51t-50 21-50-21-21-51z m0 572q0-30 21-51t50-21 51 21 21 51q0 29-22 50t-50 21-50-21-21-50z" horiz-adv-x="1071.4" /> +<glyph glyph-name="wrench" unicode="" d="m12-7q0 29 21 51l380 380q22-55 64-97t97-64l-381-381q-21-20-50-20-29 0-51 20l-59 61q-21 20-21 50z m131 36q0-15 10-26t26-10 25 10 10 26-10 25-25 10-26-10-10-25z m286 500q0 103 73 176t177 74q32 0 67-10t60-26q9-6 9-15t-9-16l-163-94v-125l108-60q2 2 44 27t75 45 40 20q8 0 13-5t4-14q0-22-12-60-27-74-92-121t-144-47q-104 0-177 74t-73 176z" horiz-adv-x="928.6" /> +<glyph glyph-name="basket" unicode="" d="m0 671q0 15 11 26t25 10h143q9 0 16-3t11-9 7-14 4-15 3-16 3-14h670q14 0 25-11t11-25v-286q0-13-9-24t-23-12l-583-68q1-3 3-12t3-14 1-13q0-9-13-35h513q15 0 26-11t10-25-10-25-26-11h-571q-14 0-25 11t-11 25q0 8 6 22t17 33 11 21l-98 460h-114q-15 0-25 10t-11 25z m214-678q0 29 21 50t51 21 50-21 21-50-21-51-50-21-51 21-21 51z m500 0q0 29 21 50t51 21 50-21 21-50-21-51-50-21-51 21-21 51z" horiz-adv-x="928.6" /> +<glyph glyph-name="calendar" unicode="" d="m0-79v715q0 29 21 50t50 21h72v54q0 36 26 63t63 26h36q37 0 63-26t26-63v-54h214v54q0 36 27 63t63 26h35q37 0 63-26t27-63v-54h71q29 0 50-21t22-50v-715q0-29-22-50t-50-21h-786q-29 0-50 21t-21 50z m71 0h161v161h-161v-161z m0 197h161v178h-161v-178z m0 214h161v161h-161v-161z m143 268q0-7 6-13t12-5h36q7 0 12 5t6 13v161q0 7-6 12t-12 6h-36q-7 0-12-6t-6-12v-161z m54-679h178v161h-178v-161z m0 197h178v178h-178v-178z m0 214h178v161h-178v-161z m214-411h179v161h-179v-161z m0 197h179v178h-179v-178z m0 214h179v161h-179v-161z m161 268q0-7 5-13t13-5h35q8 0 13 5t5 13v161q0 7-5 12t-13 6h-35q-8 0-13-6t-5-12v-161z m53-679h161v161h-161v-161z m0 197h161v178h-161v-178z m0 214h161v161h-161v-161z" horiz-adv-x="928.6" /> +<glyph glyph-name="calendar-empty" unicode="" d="m0-79v715q0 29 21 50t50 21h72v54q0 36 26 63t63 26h36q37 0 63-26t26-63v-54h214v54q0 36 27 63t63 26h35q37 0 63-26t27-63v-54h71q29 0 50-21t22-50v-715q0-29-22-50t-50-21h-786q-29 0-50 21t-21 50z m71 0h786v572h-786v-572z m143 679q0-8 5-13t13-5h36q8 0 13 5t5 13v161q0 8-5 13t-13 5h-36q-8 0-13-5t-5-13v-161z m429 0q0-8 5-13t13-5h35q8 0 13 5t5 13v161q0 8-5 13t-13 5h-35q-8 0-13-5t-5-13v-161z" horiz-adv-x="928.6" /> +<glyph glyph-name="login" unicode="" d="m0 243v214q0 15 11 25t25 11h250v161q0 14 10 25t25 10 26-10l303-304q11-10 11-25t-11-25l-303-304q-11-10-26-10t-25 10-10 25v161h-250q-15 0-25 11t-11 25z m499-206q0 6 2 13t5 11 12 3h178q37 0 63 27t27 63v392q0 37-27 63t-63 27h-174t-6 0-6 2-5 3-4 5-1 8q0 2-1 11t0 15 2 13 5 11 12 3h178q67 0 114-47t47-114v-392q0-67-47-114t-114-47h-178q-7 0-13 5t-5 13q0 2-1 11t0 15z" horiz-adv-x="857.1" /> +<glyph glyph-name="volume-down" unicode="" d="m0 243v214q0 15 11 25t25 11h146l186 186q10 10 25 10t25-10 11-25v-608q0-14-11-25t-25-10-25 10l-186 186h-146q-15 0-25 11t-11 25z m507 9q0 12 6 20t17 14 19 12 16 20 6 32-6 32-16 20-19 12-17 14-6 20q0 15 10 26t25 10q9 0 14-3 39-15 63-52t24-79-24-79-63-52q-5-3-14-3-14 0-25 10t-10 26z" horiz-adv-x="642.9" /> +<glyph glyph-name="volume-up" unicode="" d="m0 243v214q0 15 11 25t25 11h146l186 186q10 10 25 10t25-10 11-25v-608q0-14-11-25t-25-10-25 10l-186 186h-146q-15 0-25 11t-11 25z m507 9q0 12 6 20t17 14 19 12 16 20 6 32-6 32-16 20-19 12-17 14-6 20q0 15 10 26t25 10q9 0 14-3 39-15 63-52t24-79-24-79-63-52q-5-3-14-3-14 0-25 10t-10 26z m56-132q0 22 21 33 32 16 43 25 41 30 64 75t23 97-23 97-64 75q-11 9-43 25-21 11-21 33 0 14 10 25t25 11q7 0 15-3 78-33 125-105t48-158-48-158-125-105q-8-3-14-3-15 0-26 11t-10 25z m56-131q0 20 22 33 4 2 12 6t13 6q25 14 45 28 69 51 108 127t38 161-38 161-108 127q-20 14-45 28-4 3-13 6t-12 6q-22 13-22 33 0 14 10 25t26 11q7 0 14-3 118-51 189-158t71-236-71-236-189-158q-7-3-14-3-15 0-26 11t-10 25z" horiz-adv-x="928.6" /> +<glyph glyph-name="headphones" unicode="" d="m0 356q0 84 37 162t100 135 149 92 178 34 179-34 148-92 100-135 38-162q0-93-34-176l-11-27-103-18q-13-47-51-77t-87-29v-18q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q8 0 13-5t5-13v-18q39 0 72-20t52-53l38 7q16 53 16 108 0 82-49 155t-132 117-176 43-176-43-132-117-49-155q0-55 16-108l38-7q19 34 52 53t73 20v18q0 8 5 13t13 5h35q8 0 13-5t5-13v-321q0-8-5-13t-13-5h-35q-8 0-13 5t-5 13v18q-49 0-88 29t-50 77l-103 18-11 27q-34 83-34 176z" horiz-adv-x="928.6" /> +<glyph glyph-name="clock" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41-153-41-110-111-41-152z m161-54v36q0 8 5 13t13 5h125v196q0 8 5 13t12 5h36q8 0 13-5t5-13v-250q0-7-5-12t-13-5h-178q-8 0-13 5t-5 12z" horiz-adv-x="857.1" /> +<glyph glyph-name="lightbulb" unicode="" d="m0 529q0 55 25 103t65 79 92 49 104 19 104-19 91-49 66-79 24-103q0-87-57-150-25-27-42-49t-33-53-19-60q26-15 26-46 0-20-14-35 14-15 14-36 0-29-25-45 8-13 8-26 0-26-18-40t-43-14q-11-25-34-39t-48-15-49 15-33 39q-26 0-44 14t-17 40q0 13 7 26-25 16-25 45 0 21 14 36-14 15-14 35 0 31 26 46-2 28-19 60t-33 53-41 49q-58 63-58 150z m71 0q0-57 38-101 6-6 17-18t17-19q72-85 79-166h127q8 81 79 166 6 6 17 19t17 18q38 44 38 101 0 40-19 74t-50 57-69 35-76 12-76-12-69-35-50-57-20-74z m197 71q0 7 5 13t13 5q28 0 55-9t49-30 21-50q0-8-6-13t-12-5-13 5-5 13q0 25-30 39t-59 14q-8 0-13 5t-5 13z" horiz-adv-x="571.4" /> +<glyph glyph-name="block" unicode="" d="m0 352q0 87 34 167t91 137 137 91 167 34 166-34 137-91 91-137 34-167-34-168-91-137-137-92-166-34-167 34-137 92-91 137-34 168z m125 0q0-91 50-167l421 421q-75 50-167 50-83 0-153-40t-110-112-41-152z m138-256q76-50 166-50 62 0 118 25t96 65 65 97 24 119q0 90-48 164z" horiz-adv-x="857.1" /> +<glyph glyph-name="cancel-circled2" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41-153-41-110-111-41-152z m114-89q0 7 6 13l76 76-76 76q-6 6-6 13t6 13l81 82q6 5 13 5t13-5l77-77 76 77q6 5 13 5t13-5l81-82q6-5 6-13t-6-13l-76-76 76-76q6-6 6-13t-6-13l-81-82q-6-5-13-5t-13 5l-76 77-77-77q-5-5-13-5t-13 5l-81 82q-6 5-6 13z" horiz-adv-x="857.1" /> +<glyph glyph-name="resize-full-alt" unicode="" d="m0-43v250q0 24 22 33 22 10 39-8l80-80 198 198-198 198-80-80q-11-11-25-11-7 0-14 3-22 9-22 33v250q0 14 11 25t25 11h250q23 0 33-23 9-22-8-38l-80-81 198-198 198 198-81 81q-17 16-7 38 9 23 32 23h250q15 0 26-11t10-25v-250q0-24-22-33-7-3-14-3-14 0-25 11l-80 80-198-198 198-198 80 80q16 17 39 8 22-9 22-33v-250q0-14-10-25t-26-11h-250q-23 0-32 23-10 21 7 38l81 81-198 198-198-198 80-81q17-17 8-38-10-23-33-23h-250q-15 0-25 11t-11 25z" horiz-adv-x="857.1" /> +<glyph glyph-name="resize-small" unicode="" d="m7 11q0 7 6 13l185 185-80 80q-11 11-11 25t11 25 25 11h250q14 0 25-11t11-25v-250q0-14-11-25t-25-10-25 10l-81 81-185-186q-5-5-13-5t-13 5l-63 64q-6 5-6 13z m422 375v250q0 14 10 25t25 10 25-10l81-81 185 186q6 5 13 5t13-5l63-64q6-5 6-13t-6-13l-185-185 80-80q11-11 11-25t-11-25-25-11h-250q-14 0-25 11t-10 25z" horiz-adv-x="857.1" /> +<glyph glyph-name="resize-vertical" unicode="" d="m36 29q0 14 10 25t25 10h72v572h-72q-14 0-25 10t-10 25 10 26l143 142q11 11 25 11t25-11l143-142q11-11 11-26t-11-25-25-10h-71v-572h71q15 0 25-10t11-25-11-26l-143-142q-10-11-25-11t-25 11l-143 142q-10 11-10 26z" horiz-adv-x="428.6" /> +<glyph glyph-name="resize-horizontal" unicode="" d="m0 350q0 15 11 25l143 143q10 11 25 11t25-11 10-25v-72h572v72q0 14 10 25t25 11 26-11l142-143q11-10 11-25t-11-25l-142-143q-11-11-26-11t-25 11-10 25v72h-572v-72q0-14-10-25t-25-11-25 11l-143 143q-11 11-11 25z" horiz-adv-x="1000" /> +<glyph glyph-name="move" unicode="" d="m0 350q0 15 11 25l143 143q10 11 25 11t25-11 10-25v-72h215v215h-72q-14 0-25 10t-11 25 11 26l143 142q11 11 25 11t25-11l143-142q11-11 11-26t-11-25-25-10h-72v-215h215v72q0 14 10 25t25 11 26-11l142-143q11-10 11-25t-11-25l-142-143q-11-11-26-11t-25 11-10 25v72h-215v-215h72q14 0 25-10t11-25-11-26l-143-142q-10-11-25-11t-25 11l-143 142q-11 11-11 26t11 25 25 10h72v215h-215v-72q0-14-10-25t-25-11-26 11l-142 143q-11 11-11 25z" horiz-adv-x="1000" /> +<glyph glyph-name="zoom-in" unicode="" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51t-21-50-51-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z m71-18v36q0 7 6 12t12 5h125v125q0 8 5 13t13 5h36q7 0 12-5t6-13v-125h125q7 0 12-5t5-12v-36q0-7-5-13t-12-5h-125v-125q0-7-6-13t-12-5h-36q-7 0-13 5t-5 13v125h-125q-7 0-12 5t-6 13z" horiz-adv-x="928.6" /> +<glyph glyph-name="zoom-out" unicode="" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51t-21-50-51-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z m71-18v36q0 7 6 12t12 5h322q7 0 12-5t5-12v-36q0-7-5-13t-12-5h-322q-7 0-12 5t-6 13z" horiz-adv-x="928.6" /> +<glyph glyph-name="down-circled2" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41-153-41-110-111-41-152z m108-11q5 11 17 11h107v196q0 8 5 13t13 5h107q8 0 13-5t5-13v-196h107q8 0 13-5t5-13q0-7-6-13l-178-178q-6-5-12-5t-13 5l-179 178q-8 9-4 20z" horiz-adv-x="857.1" /> +<glyph glyph-name="up-circled2" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41-153-41-110-111-41-152z m107 18q0 7 6 13l178 178q6 5 13 5t12-5l179-178q8-9 4-20-5-11-17-11h-107v-196q0-8-5-13t-13-5h-107q-8 0-13 5t-5 13v196h-107q-8 0-13 5t-5 13z" horiz-adv-x="857.1" /> +<glyph glyph-name="down-open" unicode="" d="m50 425q0 14 11 25l92 92q11 11 26 11t25-11l296-296 296 296q11 11 25 11t26-11l92-92q11-11 11-25t-11-26l-414-413q-10-11-25-11t-25 11l-414 413q-11 11-11 26z" horiz-adv-x="1000" /> +<glyph glyph-name="left-open" unicode="" d="m86 386q0 14 11 25l414 414q10 10 25 10t25-10l92-93q11-10 11-25t-11-25l-296-296 296-297q11-10 11-25t-11-25l-92-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25z" horiz-adv-x="714.3" /> +<glyph glyph-name="right-open" unicode="" d="m50 64q0 15 11 25l296 297-296 296q-11 11-11 25t11 25l92 93q11 10 26 10t25-10l414-414q10-11 10-25t-10-25l-414-414q-11-11-25-11t-26 11l-92 92q-11 11-11 25z" horiz-adv-x="714.3" /> +<glyph glyph-name="up-open" unicode="" d="m50 133q0 14 11 25l414 414q11 10 25 10t25-10l414-414q11-11 11-25t-11-26l-92-92q-11-10-26-10t-25 10l-296 297-296-297q-11-10-25-10t-26 10l-92 92q-11 11-11 26z" horiz-adv-x="1000" /> +<glyph glyph-name="angle-left" unicode="" d="m25 314q0 8 6 13l260 260q5 6 13 6t12-6l28-28q6-5 6-13t-6-12l-219-220 219-219q6-6 6-13t-6-13l-28-28q-5-5-12-5t-13 5l-260 260q-6 6-6 13z" horiz-adv-x="357.1" /> +<glyph glyph-name="angle-right" unicode="" d="m7 82q0 7 6 13l219 219-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l260-260q6-5 6-13t-6-13l-260-260q-5-5-12-5t-13 5l-28 28q-6 6-6 13z" horiz-adv-x="357.1" /> +<glyph glyph-name="angle-up" unicode="" d="m43 189q0 8 6 13l260 260q5 6 12 6t13-6l260-260q6-5 6-13t-6-13l-28-27q-5-6-12-6t-13 6l-220 219-219-219q-5-6-13-6t-13 6l-27 27q-6 6-6 13z" horiz-adv-x="642.9" /> +<glyph glyph-name="angle-down" unicode="" d="m43 439q0 8 6 13l27 28q6 6 13 6t13-6l219-219 220 219q5 6 13 6t12-6l28-28q6-5 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" /> +<glyph glyph-name="angle-circled-left" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m193 0q0-14 11-25l253-253q11-11 25-11t25 11l57 56q11 11 11 26t-11 25l-171 171 171 171q11 11 11 25t-11 25l-57 57q-10 11-25 11t-25-11l-253-253q-11-11-11-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="angle-circled-right" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m282-196q0-15 11-26l57-56q11-11 25-11t25 11l253 253q11 11 11 25t-11 25l-253 253q-10 11-25 11t-25-11l-57-56q-11-11-11-26t11-25l171-171-171-171q-11-11-11-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="angle-circled-up" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m140-54q0-14 10-25l57-57q11-10 25-10t25 10l172 172 171-172q11-10 25-10t25 10l57 57q11 11 11 25t-11 26l-253 253q-11 10-25 10t-26-10l-253-254q-10-10-10-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="angle-circled-down" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m140 54q0-15 10-26l253-253q11-10 26-10t25 10l253 253q11 11 11 26t-11 25l-57 57q-10 10-25 10t-25-10l-171-172-172 172q-10 10-25 10t-25-10l-57-57q-10-11-10-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="angle-double-left" unicode="" d="m25 314q0 8 6 13l260 260q5 6 13 6t12-6l28-28q6-5 6-13t-6-12l-219-220 219-219q6-6 6-13t-6-13l-28-28q-5-5-12-5t-13 5l-260 260q-6 6-6 13z m214 0q0 8 6 13l260 260q6 6 13 6t13-6l28-28q5-5 5-13t-5-12l-220-220 220-219q5-6 5-13t-5-13l-28-28q-6-5-13-5t-13 5l-260 260q-6 6-6 13z" horiz-adv-x="571.4" /> +<glyph glyph-name="angle-double-right" unicode="" d="m7 82q0 7 6 13l219 219-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l260-260q6-5 6-13t-6-13l-260-260q-5-5-12-5t-13 5l-28 28q-6 6-6 13z m215 0q0 7 5 13l219 219-219 220q-5 5-5 12t5 13l28 28q6 6 13 6t13-6l260-260q5-5 5-13t-5-13l-260-260q-6-5-13-5t-13 5l-28 28q-5 6-5 13z" horiz-adv-x="571.4" /> +<glyph glyph-name="angle-double-up" unicode="" d="m43 118q0 7 6 13l260 260q5 5 12 5t13-5l260-260q6-6 6-13t-6-13l-28-28q-5-5-12-5t-13 5l-220 219-219-219q-5-5-13-5t-13 5l-27 28q-6 6-6 13z m0 214q0 7 6 13l260 260q5 6 12 6t13-6l260-260q6-6 6-13t-6-13l-28-28q-5-5-12-5t-13 5l-220 220-219-220q-5-5-13-5t-13 5l-27 28q-6 6-6 13z" horiz-adv-x="642.9" /> +<glyph glyph-name="angle-double-down" unicode="" d="m43 368q0 7 6 13l27 28q6 5 13 5t13-5l219-220 220 220q5 5 13 5t12-5l28-28q6-6 6-13t-6-13l-260-260q-5-6-13-6t-12 6l-260 260q-6 6-6 13z m0 214q0 7 6 13l27 28q6 5 13 5t13-5l219-220 220 220q5 5 13 5t12-5l28-28q6-6 6-13t-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13z" horiz-adv-x="642.9" /> +<glyph glyph-name="down-big" unicode="" d="m30 386q0 29 21 51l41 41q22 21 51 21 29 0 50-21l164-164v393q0 29 21 50t51 22h71q29 0 50-22t21-50v-393l164 164q21 21 51 21 29 0 50-21l42-42q21-21 21-50 0-30-21-51l-363-363q-22-21-51-21-29 0-50 21l-363 363q-21 20-21 51z" horiz-adv-x="928.6" /> +<glyph glyph-name="left-big" unicode="" d="m36 314q0 29 20 51l364 363q21 21 50 21 29 0 51-21l42-42q21-21 21-50t-21-51l-164-164h393q29 0 47-20t18-51v-71q0-30-18-51t-47-21h-393l164-164q21-20 21-50t-21-50l-42-43q-21-20-51-20-29 0-50 20l-364 364q-20 21-20 50z" horiz-adv-x="857.1" /> +<glyph glyph-name="right-big" unicode="" d="m0 279v71q0 30 18 51t47 20h393l-163 164q-22 21-22 51t22 50l42 42q21 21 50 21 29 0 51-21l363-363q20-20 20-51 0-30-20-50l-363-364q-22-20-51-20-29 0-50 20l-42 42q-22 21-22 51t22 51l163 163h-393q-29 0-47 21t-18 51z" horiz-adv-x="857.1" /> +<glyph glyph-name="up-big" unicode="" d="m30 308q0 30 21 51l363 363q20 21 50 21 30 0 51-21l363-363q21-22 21-51 0-28-21-50l-42-42q-21-21-50-21-30 0-51 21l-164 164v-393q0-29-20-47t-51-19h-71q-30 0-51 19t-21 47v393l-164-164q-20-21-50-21t-50 21l-42 42q-21 21-21 50z" horiz-adv-x="928.6" /> +<glyph glyph-name="right-hand" unicode="" d="m0 64v357q0 30 21 51t50 21h161q6 0 12 2t13 8 13 10 13 13 12 12 10 12 8 9q36 42 56 72 7 12 18 35t21 40 23 35 30 28 39 10q70 0 115-38t46-105q0-38-13-72h209q58 0 101-42t42-100q0-59-42-101t-101-42h-94q-2-35-21-67 2-12 2-24 0-56-34-99 1-78-47-123t-127-45q-74 0-179 39-92 33-125 33h-161q-29 0-50 21t-21 50z m71 36q0-14 11-25t25-11 25 11 11 25-11 25-25 11-25-11-11-25z m143-36h18q40 0 93-18t108-35 100-18q106 0 106 93 0 15-3 31 17 9 27 30t9 41-10 38q30 28 30 67 0 13-6 31t-14 26h185q29 0 50 21t22 50q0 29-22 50t-50 22h-321q0 11 8 27t19 31 18 38 8 47q0 37-25 54t-64 17q-13 0-50-77-14-25-21-37-22-35-62-81-40-45-57-59-38-32-78-32h-18v-357z" horiz-adv-x="1000" /> +<glyph glyph-name="left-hand" unicode="" d="m0 422q0 57 42 100t101 42h209q-13 34-13 72 0 68 46 105t115 37q21 0 39-9t30-28 23-35 21-40 18-35q20-30 56-72 1-1 8-9t10-12 12-12 13-13 13-10 13-8 12-2h161q29 0 50-21t21-51v-357q0-29-21-50t-50-21h-161q-33 0-125-33-106-39-176-39-80 0-129 44t-48 121l0 3q-34 42-34 99 0 12 2 24-19 32-21 66h-94q-59 0-101 43t-42 101z m71-1q0-29 22-50t50-21h185q-9-9-14-26t-6-31q0-39 30-67-10-18-10-38t9-41 27-30q-2-13-2-31 0-47 27-70t75-23q47 0 102 18t109 35 93 18h18v357h-18q-20 0-38 7t-35 21-28 25-27 31q-1 1-2 2t-2 3-3 2q-40 46-62 81-8 13-21 38-1 2-6 13t-11 20-11 20-12 17-10 6q-40 0-64-17t-25-54q0-24 8-47t19-38 18-31 8-27h-321q-28 0-50-22t-22-50z m786-321q0-14 11-25t25-11 25 11 11 25-11 25-25 11-25-11-11-25z" horiz-adv-x="1000" /> +<glyph glyph-name="up-hand" unicode="" d="m0 350q0 70 37 115t106 46q38 0 71-13v209q0 58 43 101t100 42q58 0 101-42t42-101v-94q35-2 66-21 12 2 24 2 57 0 100-34 77 1 122-47t45-127q0-74-38-179-33-92-33-125v-161q0-29-21-50t-51-21h-357q-29 0-50 21t-21 50v161q0 6-3 12t-8 13-10 13-12 13-12 12-12 10-10 8q-41 36-72 56-11 7-34 18t-40 21-36 22-27 31-10 39z m71 0q0-13 78-50 25-14 36-21 36-22 81-62 45-40 59-57 32-38 32-78v-18h357v18q0 40 18 93t36 108 18 100q0 106-93 106-15 0-32-3-9 17-29 27t-41 9-39-10q-27 30-66 30-14 0-31-6t-26-14v185q0 29-22 50t-50 22q-28 0-50-22t-21-50v-321q-11 0-27 8t-31 18-38 19-47 8q-37 0-55-25t-17-64z m572-393q0-14 10-25t26-11 25 11 10 25-10 25-25 11-26-11-10-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="down-hand" unicode="" d="m0 350q0 21 10 39t27 30 36 23 40 21 34 18q31 20 72 56 2 1 10 8t12 10 12 12 12 13 10 13 8 13 3 12v161q0 29 21 50t50 21h357q30 0 51-21t21-50v-161q0-33 33-125 38-106 38-177 0-79-43-128t-121-48l-3 0q-43-34-100-34-12 0-24 2-30-17-66-21v-94q0-59-42-101t-101-42q-58 0-100 42t-43 101v208q-30-12-71-12-68 0-105 46t-38 115z m71 0q0-40 17-64t55-25q24 0 47 8t38 19 31 18 27 8v-321q0-28 21-50t50-22q29 0 50 22t22 50v185q25-20 57-20 39 0 66 30 18-10 39-10t41 9 29 27q14-2 32-2 47 0 70 27t23 75q0 47-18 102t-36 109-18 93v18h-357v-18q0-20-7-38t-20-35-26-28-30-27q-5-4-8-7-45-40-81-62-12-8-38-21-1-1-12-6t-20-11-20-11-17-12-7-10z m572 393q0-15 10-25t26-11 25 11 10 25-10 25-25 11-26-11-10-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="left-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m140 0q0-15 10-25l51-51 202-202q10-10 25-10t25 10l51 51q10 10 10 25t-10 25l-106 106h281q14 0 25 10t10 25v72q0 14-10 25t-25 10h-281l106 106q11 11 11 25t-11 25l-51 51q-10 10-25 10t-25-10l-202-202-51-51q-10-10-10-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="right-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m143-36q0-14 11-25t25-10h280l-106-106q-10-10-10-25t10-25l51-51q10-10 25-10t25 10l202 202 51 51q10 10 10 25t-10 25l-51 51-202 202q-10 10-25 10t-25-10l-51-51q-10-10-10-25t10-25l106-106h-280q-15 0-25-10t-11-25v-72z" horiz-adv-x="857.1" /> +<glyph glyph-name="up-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m141 1q0-15 10-26l50-50q11-10 26-10t25 10l105 105v-280q0-14 11-25t25-11h71q15 0 25 11t11 25v280l105-105q11-11 26-11t25 11l50 50q11 11 11 26t-11 25l-202 202-50 50q-10 11-25 11t-26-11l-50-50-202-202q-10-10-10-25z" horiz-adv-x="857.1" /> +<glyph glyph-name="down-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m141-1q0-15 10-25l202-202 50-50q11-10 26-10t25 10l50 50 202 202q11 10 11 25t-11 26l-50 50q-10 10-25 10t-26-10l-105-105v280q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-280l-105 105q-11 11-25 11t-26-11l-50-50q-10-10-10-26z" horiz-adv-x="857.1" /> +<glyph glyph-name="cw" unicode="" d="m0 350q0 87 34 166t92 137 136 92 167 34q82 0 158-31t137-88l72 72q16 18 39 8 22-9 22-33v-250q0-14-10-25t-26-11h-250q-23 0-32 23-10 22 7 38l77 77q-82 77-194 77-58 0-111-23t-91-61-62-91-22-111 22-111 62-91 91-61 111-23q66 0 125 29t100 82q4 6 13 7 8 0 14-5l76-77q5-4 6-11t-5-13q-60-74-147-114t-182-41q-87 0-167 34t-136 92-92 137-34 166z" horiz-adv-x="857.1" /> +<glyph glyph-name="ccw" unicode="" d="m0 457v250q0 24 22 33 22 10 39-8l72-72q60 57 137 88t159 31q87 0 166-34t137-92 91-137 34-166-34-166-91-137-137-92-166-34q-96 0-183 41t-147 114q-4 6-4 12t5 12l76 77q6 5 14 5 9-1 13-7 41-53 100-82t126-29q58 0 110 23t92 61 61 91 22 111-22 111-61 91-92 61-110 23q-55 0-105-20t-90-57l77-77q17-16 8-38-10-23-33-23h-250q-15 0-25 11t-11 25z" horiz-adv-x="857.1" /> +<glyph glyph-name="refresh" unicode="" d="m0-7v250q0 14 11 25t25 11h250q14 0 25-11t10-25-10-25l-77-77q40-37 90-57t105-20q74 0 139 37t104 99q6 10 29 66 5 13 17 13h107q8 0 13-6t5-12q0-3 0-4-36-150-150-243t-267-93q-81 0-157 31t-136 88l-72-72q-11-11-25-11t-25 11-11 25z m10 446v4q36 150 151 243t268 93q81 0 158-31t137-88l72 72q11 11 25 11t26-11 10-25v-250q0-14-10-25t-26-11h-250q-14 0-25 11t-10 25 10 25l77 77q-82 77-194 77-75 0-140-37t-104-99q-6-10-29-66-5-13-17-13h-111q-7 0-13 6t-5 12z" horiz-adv-x="857.1" /> +<glyph glyph-name="level-up" unicode="" d="m2 3q-5 11 2 19l89 108q5 6 14 6h179v357h-107q-23 0-33 21-9 20 5 37l179 215q10 12 27 12t28-12l178-215q15-17 5-37-10-21-32-21h-107v-482q0-8-5-13t-13-5h-393q-12 0-16 10z" horiz-adv-x="571.4" /> +<glyph glyph-name="collapse-top" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 0q0-7 5-12t13-6h535q8 0 13 6t5 12v536q0 7-5 12t-13 6h-535q-7 0-13-6t-5-12v-536z m75 145q-10 19 3 37l179 250q10 15 29 15t29-15l178-250q13-18 3-37-10-20-32-20h-357q-22 0-32 20z" horiz-adv-x="857.1" /> +<glyph glyph-name="expand" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 0q0-8 5-13t13-5h535q8 0 13 5t5 13v536q0 8-5 13t-13 5h-535q-8 0-13-5t-5-13v-536z m143 89v358q0 22 19 31 20 10 37-2l250-179q15-11 15-29t-15-29l-250-179q-17-12-37-2-19 9-19 31z" horiz-adv-x="857.1" /> +<glyph glyph-name="play" unicode="" d="m0-61v822q0 14 9 20t22-2l741-412q13-7 13-17t-13-17l-741-412q-13-7-22-2t-9 20z" horiz-adv-x="785.7" /> +<glyph glyph-name="play-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-179q0-20 18-31 9-4 17-4 10 0 18 5l304 178q18 10 18 31t-18 31l-304 178q-17 11-35 1-18-11-18-31v-358z" horiz-adv-x="857.1" /> +<glyph glyph-name="play-circled2" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41-153-41-110-111-41-152z m161-179v358q0 20 18 31 18 10 35-1l304-178q18-10 18-31t-18-31l-304-178q-8-5-18-5-8 0-17 4-18 11-18 31z" horiz-adv-x="857.1" /> +<glyph glyph-name="stop" unicode="" d="m0-43v786q0 14 11 25t25 11h785q15 0 26-11t10-25v-786q0-14-10-25t-26-11h-785q-15 0-25 11t-11 25z" horiz-adv-x="857.1" /> +<glyph glyph-name="trash" unicode="" d="m0 633l0 141 289 0 0 76 246 0 0-76 289 0 0-141-824 0z m43-783l0 676 738 0 0-676-738 0z" horiz-adv-x="824" /> +<glyph glyph-name="to-end" unicode="" d="m0-61v822q0 14 7 18t18-8l396-396q5-4 8-11v379q0 14 10 25t25 11h72q14 0 25-11t10-25v-786q0-14-10-25t-25-11h-72q-14 0-25 11t-10 25v379q-3-6-8-11l-396-396q-10-11-18-8t-7 18z" horiz-adv-x="571.4" /> +<glyph glyph-name="to-end-alt" unicode="" d="m0-61v822q0 14 7 18t18-8l396-396q5-4 8-11v397q0 14 7 18t18-8l396-396q4-4 7-11v379q0 14 11 25t25 11h71q15 0 25-11t11-25v-786q0-14-11-25t-25-11h-71q-15 0-25 11t-11 25v379q-3-6-7-11l-396-396q-11-11-18-8t-7 18v397q-3-6-8-11l-396-396q-10-11-18-8t-7 18z" horiz-adv-x="1000" /> +<glyph glyph-name="to-start" unicode="" d="m0-43v786q0 14 11 25t25 11h71q15 0 25-11t11-25v-379q2 7 7 11l396 396q11 11 18 8t7-18v-822q0-14-7-18t-18 8l-396 396q-5 5-7 11v-379q0-14-11-25t-25-11h-71q-15 0-25 11t-11 25z" horiz-adv-x="571.4" /> +<glyph glyph-name="to-start-alt" unicode="" d="m0-43v786q0 14 11 25t25 11h71q15 0 25-11t11-25v-379q2 7 7 11l396 396q11 11 18 8t7-18v-396q3 6 8 10l396 396q10 11 18 8t7-18v-822q0-14-7-18t-18 8l-396 396q-5 5-8 11v-397q0-14-7-18t-18 8l-396 396q-5 5-7 11v-379q0-14-11-25t-25-11h-71q-15 0-25 11t-11 25z" horiz-adv-x="1000" /> +<glyph glyph-name="fast-fw" unicode="" d="m0-61v822q0 14 7 18t18-8l396-396q5-4 8-11v397q0 14 7 18t18-8l396-396q10-11 10-25t-10-25l-396-396q-11-11-18-8t-7 18v396q-3-5-8-10l-396-396q-10-11-18-8t-7 18z" horiz-adv-x="928.6" /> +<glyph glyph-name="fast-bw" unicode="" d="m68 350q0 15 11 25l396 396q11 11 18 8t7-18v-396q3 6 7 10l396 396q11 11 18 8t8-18v-822q0-14-8-18t-18 8l-396 396q-4 5-7 11v-397q0-14-7-18t-18 8l-396 396q-11 11-11 25z" horiz-adv-x="928.6" /> +<glyph glyph-name="eject" unicode="" d="m1 29v142q0 15 10 26t25 10h786q14 0 25-10t11-26v-142q0-15-11-26t-25-10h-786q-14 0-25 10t-10 26z m0 257q-4 7 7 18l396 396q11 10 25 10t25-10l396-396q11-11 8-18t-18-8h-822q-14 0-17 8z" horiz-adv-x="858.3" /> +<glyph glyph-name="target" unicode="" d="m521 407l0 162q60-16 103-60t59-102l-162 0z m0-113l162 0q-16-59-59-103t-103-59l0 162z m-113 113l-162 0q16 59 59 102t103 60l0-162z m0-113l0-162q-60 16-103 59t-59 103l162 0z m113 390l0 113q152-19 261-128t129-262l-113 0q-18 107-95 183t-182 94z m-390-277l-113 0q19 152 128 261t262 129l0-113q-106-18-182-94t-95-183z m277-390l0-114q-154 19-262 129t-128 262l113 0q18-107 95-183t182-94z m390 277l113 0q-21-153-129-262t-261-129l0 114q105 18 182 94t95 183z" horiz-adv-x="928" /> +<glyph glyph-name="signal" unicode="" d="m0-61v107q0 8 5 13t13 5h107q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-107q-8 0-13 5t-5 13z m214 0v179q0 8 5 13t13 5h107q8 0 13-5t5-13v-179q0-8-5-13t-13-5h-107q-8 0-13 5t-5 13z m215 0v322q0 8 5 13t12 5h108q7 0 12-5t5-13v-322q0-8-5-13t-12-5h-108q-7 0-12 5t-5 13z m214 0v536q0 8 5 13t13 5h107q8 0 13-5t5-13v-536q0-8-5-13t-13-5h-107q-8 0-13 5t-5 13z m214 0v822q0 8 5 13t13 5h107q8 0 13-5t5-13v-822q0-8-5-13t-13-5h-107q-8 0-13 5t-5 13z" horiz-adv-x="1000" /> +<glyph glyph-name="mobile" unicode="" d="m0 64v572q0 29 21 50t50 21h286q29 0 50-21t22-50v-572q0-29-22-50t-50-21h-286q-29 0-50 21t-21 50z m54 90q0-8 5-13t12-5h286q7 0 13 5t5 13v392q0 8-5 13t-13 5h-286q-7 0-12-5t-5-13v-392z m107 473q0-9 9-9h89q9 0 9 9t-9 9h-89q-9 0-9-9z m9-563q0-18 13-31t31-13 32 13 13 31-13 32-32 13-31-13-13-32z" horiz-adv-x="428.6" /> +<glyph glyph-name="inbox" unicode="" d="m0 29v269q0 34 14 68l133 308q5 14 20 24t29 9h465q14 0 29-9t20-24l133-308q14-34 14-68v-269q0-15-10-26t-26-10h-785q-15 0-25 10t-11 26z m110 285h176l53-107h179l53 107h176q0 2-1 5t-2 4l-118 277h-395l-118-277q-1-1-2-4t-1-5z" horiz-adv-x="857.1" /> +<glyph glyph-name="globe" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m126 189q4-4 7-4 2-1 3-5t1-6 6 1q5-4 2-10 1 0 25-15 10-10 11-12 2-6-5-10-1 1-5 5t-5 2q-2-3 0-10t6-7q-4 0-5-9t-2-20 0-13l1-1q-2-6 3-19t12-11q-7-1 11-24 3-4 4-5 2-1 7-4t9-6 5-5q2-3 6-13t8-13q-2-3 5-11t6-13q-1 0-2-1t-1 0q2-4 9-8t8-7q1-2 1-6t2-6 4-1q2 11-13 34-8 14-9 17-2 2-4 8t-2 8q1 0 3 0t5-2 4-3 1-1q-1-4 1-10t7-10 10-11 6-7q4-4 8-11t0-8q5 0 11-5t10-11q3-5 4-15t3-13q1-4 5-8t7-5l9-5t7-3q3-2 10-6t12-7q6-2 9-2t8 1 8 2q8 1 16-8t12-12q20-10 30-6-1 0 1-4t4-9 5-8 3-5q3-3 10-8t10-8q4 2 4 5-1-5 4-11t10-6q8 2 8 18-17-9-27 10 0 0-2 3t-2 5-1 4 0 5 2 1q5 0 6 2t-1 7-2 8q-1 4-6 11t-7 8q-3-5-9-4t-9 5q0-1-1-3t-1-4q-7 0-8 0 1 2 1 10t2 13q1 2 3 6t5 9 2 7-3 5-9 1q-11 0-15-11-1-2-2-6t-2-6-5-4q-4-2-14-1t-13 3q-8 4-13 16t-5 20q0 6 1 15t2 14-3 14q2 1 5 5t5 6q2 1 3 1t2 0 3 1 1 3q0 1-2 2-2 1-2 1 4-1 16 1t15-1q9-6 12 1 0 1-1 6t0 7q3-15 16-5 2-1 9-3t9-2q2-1 4-3t3-3 3 0 5 4q5-8 7-13 6-23 10-25 4-2 6-1t3 5 0 8-1 7l-1 4v11l0 4q-8 2-10 7t0 10 9 10q0 1 4 2t9 4 7 4q12 11 8 20 4 0 6 5 0 0-2 2t-5 2-2 2q5 2 1 8 3 2 4 7t4 5q5-7 12-1 4 5 1 9 2 4 11 6t10 5q4-1 5 1t0 7 2 7q2 2 8 5t8 2l9 7q2 2 0 2 10-1 18 6 5 6-4 11 2 3-2 5t-8 3q2 1 7 1t5 1q9 5-4 9-9 2-24-7-1-1-5-5t-7-6q1 0 2 3t3 6 2 4q3 4 12 8 8 4 29 7 19 5 29-6-1 1 5 7t8 7q2 1 8 2t9 5l1 12q-7-1-10 4t-3 12q0-2-4-5 0 4-2 5t-7-1-5-1q-5 2-8 5t-5 9-2 8q-1 3-5 6t-5 6q-1 1-2 3t-2 4-2 3-3 1-4-3-4-5-2-3q-2 1-4 1t-2-1-3-1-3-2q-1-2-4-2t-5-1q8 3-1 6-5 2-9 2 5 2 5 6t-5 8h3q-1 2-5 5t-10 5-7 3q-5 3-19 5t-18 1q-3-4-3-6t2-8 2-7q1-3-3-7t-3-7q0-4 7-9t6-12q-2-4-9-9t-9-6q-3-5-1-11t6-9q1-1 1-2t-2-3-3-2-4-2l-1-1q-7-3-12 3t-7 15q-4 14-9 17-13 4-17-1-2 7-22 15-14 5-33 2 4 0 0 8-4 9-10 7 1 3 2 10t0 7q2 7 7 13 1 1 4 5t5 7 1 4q19-3 28 6 2 3 6 9t6 10q5 3 8 3t8-3 8-3q8-1 8 6t-4 11q7 0 2 10-3 4-5 5-6 2-15-3-4-2 2-4-1 0-6-6t-9-10-9 3q0 0-3 7t-5 8q-5 0-9-9 1 5-6 9t-14 4q11 7-4 15-4 3-12 3t-11-2q-2-4-3-7t3-4 6-3 6-2 5-2q8-6 5-8-1 0-5-2t-6-2-4-3q-2-2 0-7t-1-8q-3 3-5 10t-4 9q4-5-14-4l-5 1q-3 0-9-1t-12-1-7 5q-3 4 0 11 0 2 2 1-2 2-6 5t-6 5q-25-8-52-23 3 0 6 1 3 1 8 3t5 4q19 7 24 3l3 3q7-9 11-14-4 3-17 1-11-4-12-7 4-7 2-10-2 2-6 6t-8 6-8 3q-9 0-13-1-81-45-131-124z m363-532q0-3 2-9 114 21 195 106-1 2-7 2t-7 2q-10 4-13 5 1 4-1 7t-5 5-7 5-6 4q-1 1-4 3t-4 3-4 2-5 2-5-1l-2-1q-2 0-3-1t-3-2-2-1 0-2q-12 10-20 13-3 0-7 3t-5 4-6 0-6-4q-3-2-4-8t-1-7q-4 3 0 10t1 10q-1 3-6 2t-6-2-7-5-5-3-4-3-5-5q-2-2-4-6t-2-7q-1 3-7 4t-5 3q1-5 2-19t3-22q4-17-7-26-15-14-16-23-2-12 7-14 0-4-5-12t-4-12z" horiz-adv-x="857.1" /> +<glyph glyph-name="sun" unicode="" d="m25 195q-3 10 2 17l100 138-100 138q-5 8-2 17 2 8 11 11l163 53v171q0 9 7 15 8 5 16 2l163-53 101 139q5 6 14 6t15-6l100-139 163 53q8 3 16-2 7-6 7-15v-171l163-53q9-3 11-12 3-8-2-16l-100-138 100-138q5-7 2-17-2-8-11-11l-163-53v-171q0-9-7-15-8-5-16-2l-163 53-100-139q-6-7-15-7t-14 7l-101 139-163-53q-8-3-16 2-7 6-7 15v171l-163 53q-9 3-11 11z m154 155q0-65 25-125t69-102 102-69 125-25 125 25 102 69 69 102 25 125-25 125-69 102-102 69-125 25-125-25-102-69-69-102-25-125z" horiz-adv-x="1000" /> +<glyph glyph-name="cloud" unicode="" d="m0 243q0 74 40 135t104 91q-1 15-1 24 0 118 84 202t202 84q88 0 159-50t105-128q39 35 93 35 59 0 101-42t42-101q0-42-23-77 72-17 119-75t46-134q0-89-62-151t-152-63h-607q-103 0-177 73t-73 177z" horiz-adv-x="1071.4" /> +<glyph glyph-name="flash" unicode="" d="m1 300l112 461q2 8 9 13t15 5h183q11 0 18-7t7-17q0-4-2-10l-96-258 221 54q5 2 7 2 11 0 19-9 10-11 4-24l-302-646q-7-14-23-14-2 0-8 1-9 3-14 11t-3 16l110 451-226-56q-2-1-7-1-10 0-17 7-10 8-7 21z" horiz-adv-x="500" /> +<glyph glyph-name="moon" unicode="" d="m0 350q0 85 32 163t87 135 132 92 161 38q25 1 34-22 10-23-8-40-48-43-73-101t-26-122q0-83 41-152t111-111 152-41q66 0 127 29 23 10 40-7 8-8 10-19t-2-22q-53-113-159-181t-230-68q-87 0-167 35t-136 91-92 137-34 166z m71 0q0-73 29-139t76-113 114-77 139-28q80 0 152 34t123 96q-30-5-61-5-102 0-188 50t-137 137-50 188q0 107 58 199-112-33-183-128t-72-214z" horiz-adv-x="857.1" /> +<glyph glyph-name="umbrella" unicode="" d="m0 373q0 3 1 4 25 102 96 178t166 114 201 38q78 0 153-22t138-64 109-104 64-140q1-1 1-4 0-7-6-13t-12-5q-6 0-13 6-27 25-52 38t-57 13q-38 0-71-21t-58-54q-4-5-10-15t-8-14q-6-9-15-9-10 0-16 9-3 4-9 14t-9 15q-24 34-58 54t-71 21-71-21-57-54q-4-5-10-15t-8-14q-6-9-16-9-10 0-16 9-2 4-8 14t-10 15q-24 34-57 54t-71 21q-33 0-57-13t-52-38q-7-6-13-6-7 0-13 5t-5 13z m214-309q0 15 11 25t25 11 25-11 11-25q0-28 22-49t49-22 50 22 22 49v324q18 6 35 6t36-6v-324q0-58-42-100t-101-43-100 43-43 100z m215 660v55q0 14 10 25t25 10 25-10 11-25v-55q-23 1-36 1t-35-1z" horiz-adv-x="928.6" /> +<glyph glyph-name="flight" unicode="" d="m0 259q-1 7 5 14l54 54q5 5 12 5 4 0 5 0l108-30 145 145-284 155q-8 5-9 14-1 9 5 15l71 71q8 7 17 5l371-89 89 89q43 42 96 60t83-6q24-29 7-83t-61-96l-90-90 90-388q3-11-7-19l-71-53q-4-3-11-3-2 0-4 0-8 2-12 9l-155 283-145-144 30-108q3-10-5-18l-53-53q-5-5-13-5h-1q-9 1-14 7l-105 141-141 105q-6 4-7 13z" horiz-adv-x="785.7" /> +<glyph glyph-name="fighter-jet" unicode="" d="m0 279v71l107 13v5h-71v18h-18v107l18 18h53l107-125h90v232h-36v18h179q14 0 25-3t10-6-10-7-25-2h-39l164-197h35l125-35 197-18q145-33 160-52l0-2q0-18-160-53l-197-18-125-36h-35l-164-196h39q14 0 25-3t10-6-10-7-25-2h-179v18h36v232h-90l-107-125h-53l-18 18v107h18v18h71v4z" horiz-adv-x="1071.4" /> +<glyph glyph-name="leaf" unicode="" d="m0 60q0 20 17 41t38 37 38 31 18 27q0 2-8 21t-9 25q-5 28-5 58 0 64 24 123t66 103 96 77 113 53q31 10 81 15t100 5 100 3 91 13 64 32l16 16t17 16 15 11 20 9 24 3q22 0 40-26t26-63 14-69 4-53q0-53-11-108-26-125-103-214t-200-149q-119-61-244-61-83 0-160 27-8 2-49 23t-53 21q-9 0-22-18t-25-39-30-39-33-18q-17 0-29 6t-17 13-15 24q-1 2-3 6t-3 6-2 5-1 7z m214 183q0-15 11-25t25-11q13 0 25 11 15 13 41 39t38 37q76 69 150 98t175 29q14 0 25 11t10 25-10 25-25 11q-96 0-178-28t-145-75-131-122q-11-12-11-25z" horiz-adv-x="1000" /> +<glyph glyph-name="italic" unicode="" d="m0-78l10 48q3 1 45 12t62 21q16 19 23 56 1 4 35 162t63 303 29 165v14q-13 7-30 11t-39 4-32 3l10 58q19-2 67-4t84-4 67-1q27 0 55 1t67 4 55 4q-2-22-10-50-17-6-57-16t-60-19q-5-10-8-23t-5-23-4-25-4-24q-15-82-49-234t-43-198q-1-5-7-32t-11-51-9-46-4-32l1-10q9-3 103-18-2-24-9-55-6 0-18-1t-18-1q-16 0-49 6t-48 6q-77 1-115 1-28 0-79-5t-68-6z" horiz-adv-x="571.4" /> +<glyph glyph-name="bold" unicode="" d="m0-79l1 53q9 2 48 9t59 15q4 7 7 15t4 19 4 18 1 21 0 19v36q0 548-12 572-2 5-12 8t-25 6-28 4-27 3-17 2l-2 46q55 1 190 6t208 5q13 0 38 0t38 0q39 0 76-7t72-24 60-39 41-59 16-76q0-29-9-54t-22-40-36-32-41-25-47-22q86-20 144-75t57-139q0-55-20-100t-52-73-77-47-91-27-98-8q-25 0-74 2t-74 1q-59 0-171-6t-129-7z m297 793q0-28 3-84t2-85q0-15 0-45t-1-44q0-26 1-38 23-4 61-4 46 0 80 7t61 25 41 50 15 79q0 39-16 68t-45 46-60 24-69 8q-28 0-73-7z m4-629q0-21 2-47t7-37q41-18 78-18 210 0 210 187 0 64-23 101-15 24-35 41t-37 26-45 14-47 6-53 1q-40 0-56-6 0-29 0-88t-1-89q0-4 0-37t0-54z" horiz-adv-x="785.7" /> +<glyph glyph-name="font" unicode="" d="m0-79l1 44q13 4 31 7t32 6 28 8 25 17 17 28l132 344 156 404h72q4-8 6-12l114-268q19-44 60-144t63-153q9-19 33-81t40-94q11-25 19-31 11-9 49-17t47-11q4-22 4-32 0-2-1-7t0-8q-35 0-106 5t-107 4q-42 0-120-4t-99-4q0 24 2 43l73 16q1 0 7 1t9 2 8 3 9 4 6 4 5 6 1 8q0 9-17 54t-40 99-24 56l-251 1q-14-33-43-109t-28-91q0-12 8-21t24-14 27-7 32-5 23-2q1-11 1-32 0-5-2-16-32 0-97 6t-97 6q-5 0-15-3t-12-2q-45-8-105-8z m310 366q18 0 76-1t89-1q11 0 32 1-48 141-102 252z" horiz-adv-x="928.6" /> +<glyph glyph-name="text-height" unicode="" d="m0 564v213l45 1 30-15q7-3 118-3 25 0 74 1t73 1q21 0 60 0t60 0h164q3 0 12 0t11 0 9 1 10 5 8 10l24 1q2 0 7-1t8 0q1-62 1-187 0-45-2-61-22-8-38-10-14 24-31 71-1 5-6 27t-8 41-4 20q-3 4-7 7t-8 3-8 1-10 1-9-1q-9 0-37 1t-42 0-35-1-40-4q-5-45-4-75 0-53 1-217t1-254q0-9-1-40t0-51 7-38q22-12 69-24t67-21q2-22 2-28 0-8-1-16l-19-1q-43-1-122 5t-115 6q-28 0-85-6t-84-5q-2 29-2 29v6q9 15 34 24t55 16 44 15q10 23 10 213 0 57-1 170t-2 169v65q0 1 0 9t1 14-1 14-2 13-3 8q-6 7-90 7-18 0-52-7t-44-15q-11-7-19-40t-18-62-24-30q-23 15-31 25z m789-510q5 10 23 10h45v572h-45q-18 0-23 10t6 25l71 90q11 15 27 15t27-15l70-90q12-15 7-25t-24-10h-44v-572h44q19 0 24-10t-7-25l-70-90q-11-15-27-15t-27 15l-71 90q-11 15-6 25z" horiz-adv-x="1000" /> +<glyph glyph-name="text-width" unicode="" d="m0 564v213l45 1 30-15q7-3 118-3 25 0 74 1t73 1q39 0 138 1t170 0 138-2q18-1 31 17l23 1q3 0 8-1t8 0q1-62 1-187 0-45-3-61-21-8-38-10-14 24-30 71-1 5-6 27t-8 41-4 20q-6 7-15 10-3 1-37 1-17 0-52 1t-57 1-53-2-53-4q-5-45-5-75l1-85v29q0-31 0-86t1-101 0-85q0-9-1-40t0-51 7-38q22-12 69-24t67-21q3-22 3-28 0-8-2-16l-19-1q-42-1-121 5t-116 5q-28 0-84-5t-85-5q-2 29-2 29v5q10 15 35 24t55 17 43 15q4 9 7 41t3 81 1 87-1 85 0 50q0 4-1 12t-2 12q0 4 1 25t0 41 0 42-1 38-4 18q-6 7-90 7-23 0-91-8t-77-14q-11-6-19-39t-18-63-24-30q-23 15-31 25z m3-607q0 16 14 27 3 2 20 17t34 28 32 23 23 11q7 0 12-6t5-16 2-19-1-18-1-11h571q0 1-1 11t0 18 1 19 6 16 11 6q7 0 23-11t33-23 33-28 20-17q14-11 14-27t-14-27q-2-2-20-17t-33-27-33-23-23-11q-7 0-11 5t-6 16-1 19 0 18 1 11h-571q0-1 1-11t1-18-2-19-5-16-12-5q-7 0-23 11t-32 23-34 27-20 17q-14 11-14 27z" horiz-adv-x="857.1" /> +<glyph glyph-name="list" unicode="" d="m0 11v107q0 7 5 12t13 6h107q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-107q-7 0-13 5t-5 13z m0 214v107q0 7 5 13t13 5h107q7 0 13-5t5-13v-107q0-7-5-13t-13-5h-107q-7 0-13 5t-5 13z m0 214v107q0 8 5 13t13 5h107q7 0 13-5t5-13v-107q0-7-5-12t-13-6h-107q-7 0-13 6t-5 12z m0 215v107q0 7 5 12t13 6h107q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-107q-7 0-13 5t-5 13z m214-643v107q0 7 6 12t12 6h750q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-750q-7 0-12 5t-6 13z m0 214v107q0 7 6 13t12 5h750q7 0 13-5t5-13v-107q0-7-5-13t-13-5h-750q-7 0-12 5t-6 13z m0 214v107q0 8 6 13t12 5h750q7 0 13-5t5-13v-107q0-7-5-12t-13-6h-750q-7 0-12 6t-6 12z m0 215v107q0 7 6 12t12 6h750q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-750q-7 0-12 5t-6 13z" horiz-adv-x="1000" /> +<glyph glyph-name="indent-left" unicode="" d="m0 11v107q0 7 5 12t13 6h964q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-964q-7 0-13 5t-5 13z m0 643v107q0 7 5 12t13 6h964q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-964q-7 0-13 5t-5 13z m18-268q0 8 5 13l161 160q5 5 12 5 8 0 13-5t5-13v-321q0-7-5-13t-13-5q-7 0-12 5l-161 161q-5 5-5 13z m339-161v107q0 7 5 13t13 5h607q7 0 13-5t5-13v-107q0-7-5-13t-13-5h-607q-7 0-13 5t-5 13z m0 214v107q0 8 5 13t13 5h607q7 0 13-5t5-13v-107q0-7-5-12t-13-6h-607q-7 0-13 6t-5 12z" horiz-adv-x="1000" /> +<glyph glyph-name="indent-right" unicode="" d="m0 11v107q0 7 5 12t13 6h964q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-964q-7 0-13 5t-5 13z m0 214v321q0 8 5 13t13 5q8 0 13-5l160-160q5-5 5-13t-5-13l-160-161q-5-5-13-5-7 0-13 5t-5 13z m0 429v107q0 7 5 12t13 6h964q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-964q-7 0-13 5t-5 13z m357-429v107q0 7 5 13t13 5h607q7 0 13-5t5-13v-107q0-7-5-13t-13-5h-607q-7 0-13 5t-5 13z m0 214v107q0 8 5 13t13 5h607q7 0 13-5t5-13v-107q0-7-5-12t-13-6h-607q-7 0-13 6t-5 12z" horiz-adv-x="1000" /> +<glyph glyph-name="list-bullet" unicode="" d="m0 64q0 45 31 76t76 31 76-31 31-76-31-76-76-31-76 31-31 76z m0 286q0 45 31 76t76 31 76-31 31-76-31-76-76-31-76 31-31 76z m0 286q0 44 31 76t76 31 76-31 31-76-31-76-76-31-76 31-31 76z m286-625v107q0 7 5 12t13 6h678q7 0 13-6t5-12v-107q0-7-5-13t-13-5h-678q-8 0-13 5t-5 13z m0 285v108q0 7 5 12t13 5h678q7 0 13-5t5-12v-108q0-7-5-12t-13-5h-678q-8 0-13 5t-5 12z m0 286v107q0 8 5 13t13 5h678q7 0 13-5t5-13v-107q0-7-5-12t-13-6h-678q-8 0-13 6t-5 12z" horiz-adv-x="1000" /> +<glyph glyph-name="list-numbered" unicode="" d="m8 237q0 29 14 52t31 38 37 27 31 24 14 25q0 14-9 22t-22 7q-25 0-45-32l-47 33q13 28 40 44t59 16q40 0 68-23t28-63q0-28-19-51t-42-36-42-28-20-30h71v34h59v-89h-202q-4 20-4 30z m3-350l31 49q28-25 60-25 16 0 28 8t12 24q0 35-59 31l-14 31q4 6 18 24t24 31 20 21v1q-9 0-27-1t-27 0v-30h-59v85h186v-49l-53-65q28-6 45-27t17-49q0-45-31-70t-75-26q-60 0-96 37z m8 887l76 71h59v-225h60v-56h-187v56h60q0 22 0 68t1 67v7h-1q-5-10-28-30z m267-763v107q0 8 5 13t13 5h678q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-678q-8 0-13 5t-5 13z m0 285v108q0 7 5 12t13 5h678q7 0 13-5t5-12v-108q0-7-5-12t-13-5h-678q-8 0-13 5t-5 12z m0 286v107q0 8 5 13t13 5h678q7 0 13-5t5-13v-107q0-7-5-12t-13-6h-678q-8 0-13 6t-5 12z" horiz-adv-x="1000" /> +<glyph glyph-name="strike" unicode="" d="m0 296v36q0 8 5 13t13 5h964q8 0 13-5t5-13v-36q0-7-5-12t-13-5h-964q-8 0-13 5t-5 12z m214 239q0 101 75 173 74 71 219 71 28 0 94-11 36-7 98-27 6-21 12-66 8-68 8-102 0-10-3-25l-7-2-46 4-8 1q-28 83-58 114-49 51-117 51-64 0-102-33-37-32-37-81 0-41 37-79t156-72q38-11 96-36 33-16 53-29h-414q-16 19-29 44-27 54-27 105z m17-456q0 17 0 38l1 20v25l57 1q8-19 17-40t12-31 7-15q20-32 45-52 24-20 59-32 33-12 73-12 36 0 78 15 43 14 68 48 26 34 26 72 0 47-45 87-19 16-77 40h230q4-22 4-51 0-62-23-119-13-30-40-58-20-19-61-45-44-27-85-37-45-12-113-12-64 0-109 13l-78 23q-32 9-40 15-5 5-5 13v7q0 60-1 87z" horiz-adv-x="1000" /> +<glyph glyph-name="underline" unicode="" d="m0-25v-36q0-8 5-13t13-5h821q8 0 13 5t5 13v36q0 8-5 13t-13 5h-821q-8 0-13-5t-5-13z m0 802q7 0 22 0 34 0 63-2 74-4 92-4 48 0 94 2 65 2 82 3 31 0 48 1l-1-8 1-36v-5q-33-5-69-5-33 0-44-14-7-7-7-73 0-8 0-18t0-15l1-128 8-156q3-69 28-112 20-33 54-52 49-26 98-26 58 0 107 16 31 10 55 28 27 20 37 36 20 31 29 63 12 41 12 128 0 44-2 72t-6 68-8 89l-2 33q-3 37-13 49-19 20-43 19l-56-1-8 2 1 48h47l114-6q43-2 110 6l10-2q3-21 3-28 0-4-2-17-25-7-47-8-41-6-44-9-8-9-8-23 0-4 0-15t1-17q5-11 13-221 3-109-9-170-8-42-23-68-21-36-62-69-42-32-102-49-61-19-142-19-93 0-159 26-66 26-99 68-34 42-47 109-9 44-9 132v186q0 105-9 119-14 20-82 21-21 2-25 3z" horiz-adv-x="857.1" /> +<glyph glyph-name="superscript" unicode="" d="m3-7v93h71l110 162-103 152h-76v94h154l77-127q1-2 13-24 4-5 6-11h2q1 5 6 11l14 24 78 127h143v-94h-69l-103-149 114-165h61v-93h-139l-89 141-13 23q-4 5-6 12h-2l-5-12q-5-11-14-25l-86-139h-144z m562 398q0 35 15 65t36 48 47 37 47 30 36 30 15 36q0 21-17 35t-39 13q-29 0-54-21-8-7-20-22l-59 52q15 20 35 37 46 36 105 36 61 0 99-33t38-89q0-31-13-57t-35-43-45-33-46-28-37-29-17-35h130v45h70v-115h-287l-1 15q-3 16-3 26z" horiz-adv-x="857.1" /> +<glyph glyph-name="subscript" unicode="" d="m3-7v93h71l110 162-103 152h-76v94h154l77-127q1-2 13-24 4-5 6-11h2q1 5 6 11l14 24 78 127h143v-94h-69l-103-149 114-165h61v-93h-139l-89 141-13 23q-4 5-6 12h-2l-5-12q-5-11-14-25l-86-139h-144z m563-102q0 35 15 65t36 48 47 37 47 30 36 30 15 36q0 21-17 35t-39 13q-29 0-54-21-8-6-20-22l-59 52q15 20 35 37 45 36 105 36 62 0 99-33t38-89q0-37-19-66t-47-48-55-35-49-35-23-41h130v45h70v-115h-287l-2 15q-2 25-2 26z" horiz-adv-x="857.1" /> +<glyph glyph-name="table" unicode="" d="m0 82v607q0 37 26 63t63 27h750q37 0 63-27t27-63v-607q0-37-27-63t-63-26h-750q-36 0-63 26t-26 63z m71 0q0-8 5-13t13-5h179q8 0 13 5t5 13v107q0 8-5 13t-13 5h-179q-7 0-13-5t-5-13v-107z m0 214q0-7 5-12t13-5h179q8 0 13 5t5 12v108q0 7-5 12t-13 5h-179q-7 0-13-5t-5-12v-108z m0 215q0-8 5-13t13-5h179q8 0 13 5t5 13v107q0 8-5 13t-13 5h-179q-7 0-13-5t-5-13v-107z m286-429q0-8 5-13t13-5h179q7 0 12 5t5 13v107q0 8-5 13t-12 5h-179q-8 0-13-5t-5-13v-107z m0 214q0-7 5-12t13-5h179q7 0 12 5t5 12v108q0 7-5 12t-12 5h-179q-8 0-13-5t-5-12v-108z m0 215q0-8 5-13t13-5h179q7 0 12 5t5 13v107q0 8-5 13t-12 5h-179q-8 0-13-5t-5-13v-107z m286-429q0-8 5-13t13-5h178q8 0 13 5t5 13v107q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-107z m0 214q0-7 5-12t13-5h178q8 0 13 5t5 12v108q0 7-5 12t-13 5h-178q-8 0-13-5t-5-12v-108z m0 215q0-8 5-13t13-5h178q8 0 13 5t5 13v107q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-107z" horiz-adv-x="928.6" /> +<glyph glyph-name="columns" unicode="" d="m0 11v678q0 37 26 63t63 27h750q37 0 63-27t27-63v-678q0-37-27-63t-63-27h-750q-36 0-63 27t-26 63z m71 0q0-8 6-13t12-5h340v643h-358v-625z m429-18h339q8 0 13 5t5 13v625h-357v-643z" horiz-adv-x="928.6" /> +<glyph glyph-name="crop" unicode="" d="m0 511v107q0 8 5 13t13 5h125v125q0 7 5 12t13 5h107q8 0 13-5t5-12v-125h475l137 138q5 5 13 5t13-5q5-6 5-13t-5-13l-138-137v-475h125q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-125v-125q0-8-5-13t-13-5h-107q-8 0-13 5t-5 13v125h-482q-8 0-13 5t-5 13v482h-125q-8 0-13 5t-5 13z m286-350l332 332h-332v-332z m25-25h332v332z" horiz-adv-x="928.6" /> +<glyph glyph-name="scissors" unicode="" d="m1 81q4 42 31 82t73 69q74 47 155 47 46 0 84-18 5 8 13 13l68 40-68 41q-8 5-13 12-38-17-84-17-81 0-155 47-46 29-73 69t-31 82q-3 33 8 63t36 52q47 44 124 44 80 0 154-47 46-29 74-68t31-83q2-27-6-54 3-1 7-3l62-37 385 216q7 5 17 5 9 0 16-4l71-36q17-9 20-28 2-20-14-32l-283-222 283-222q16-11 14-31-3-20-20-29l-71-35q-7-4-16-4-10 0-17 4l-385 216-62-37q-4-2-7-2 8-28 6-55-4-43-31-82t-74-69q-74-47-154-47-76 0-124 44-51 47-44 115z m93 10q-14-37 12-60 21-20 63-20 55 0 107 33 45 28 59 65t-12 60q-22 20-63 20-56 0-107-33-45-28-59-65z m0 447q14-37 59-66 51-33 107-33 41 0 63 20 26 24 12 61t-59 65q-52 33-107 33-42 0-63-20-26-24-12-60z m281-295l5-5q1-1 4-3 2-2 6-7t6-6l15-15 89 54 54-18 410 321-71 36-429-240v-64z m0 143l54-33v7q0 20 18 31l8 4-44 26-15-14q-1-2-5-6t-7-7q-1-1-2-2t-2-1z m125-72q0 15 11 25t25 11 25-11 10-25-10-25-25-10-25 10-11 25z m68-103l325-182 71 35-290 228-99-77q-1-2-7-4z" horiz-adv-x="1000" /> +<glyph glyph-name="paste" unicode="" d="m0 46v750q0 23 16 38t38 16h607q22 0 38-16t15-38v-183q12-7 20-15l228-228q16-16 27-42t11-50v-374q0-23-16-38t-38-16h-535q-23 0-38 16t-16 38v89h-303q-23 0-38 15t-16 38z m143 679q0-7 5-13t13-5h393q7 0 12 5t5 13v36q0 7-5 12t-12 5h-393q-7 0-13-5t-5-12v-36z m286-804h500v358h-233q-22 0-38 15t-15 38v232h-214v-643z m285 429h167l-167 167v-167z" horiz-adv-x="1000" /> +<glyph glyph-name="briefcase" unicode="" d="m0 82v268h375v-89q0-15 11-25t25-11h178q15 0 25 11t11 25v89h375v-268q0-37-26-63t-63-26h-822q-36 0-63 26t-26 63z m0 322v214q0 37 26 63t63 26h197v89q0 23 15 38t38 16h322q22 0 38-16t15-38v-89h197q37 0 63-26t26-63v-215h-1000z m357 303h286v72h-286v-72z m72-428v71h142v-71h-142z" horiz-adv-x="1000" /> +<glyph glyph-name="suitcase" unicode="" d="m0 46v465q0 51 37 88t88 37h36v-715h-36q-51 0-88 37t-37 88z m214-125v715h72v89q0 22 15 38t38 16h322q22 0 38-16t15-38v-89h72v-715h-572z m143 715h286v71h-286v-71z m482-715v715h36q51 0 88-37t37-88v-465q0-51-37-88t-88-37h-36z" horiz-adv-x="1000" /> +<glyph glyph-name="list-alt" unicode="" d="m0 82v607q0 37 26 63t63 27h822q37 0 63-27t26-63v-607q0-37-26-63t-63-26h-822q-36 0-63 26t-26 63z m71 0q0-7 6-12t12-6h822q7 0 12 6t6 12v464q0 8-6 13t-12 5h-822q-7 0-12-5t-6-13v-464z m72 72v35q0 8 5 13t13 5h35q8 0 13-5t5-13v-35q0-8-5-13t-13-5h-35q-7 0-13 5t-5 13z m0 142v36q0 7 5 13t13 5h35q8 0 13-5t5-13v-36q0-7-5-12t-13-5h-35q-7 0-13 5t-5 12z m0 143v36q0 7 5 13t13 5h35q8 0 13-5t5-13v-36q0-7-5-12t-13-6h-35q-7 0-13 6t-5 12z m143-285v35q0 8 5 13t13 5h535q8 0 13-5t5-13v-35q0-8-5-13t-13-5h-535q-8 0-13 5t-5 13z m0 142v36q0 7 5 13t13 5h535q8 0 13-5t5-13v-36q0-7-5-12t-13-5h-535q-8 0-13 5t-5 12z m0 143v36q0 7 5 13t13 5h535q8 0 13-5t5-13v-36q0-7-5-12t-13-6h-535q-8 0-13 6t-5 12z" horiz-adv-x="1000" /> +<glyph glyph-name="qrcode" unicode="" d="m0-7v357h357v-357h-357z m0 428v358h357v-358h-357z m71-356h215v214h-215v-214z m0 428h215v214h-215v-214z m72-357v71h71v-71h-71z m0 428v72h71v-72h-71z m286-571v357h214v-71h71v71h72v-214h-215v71h-71v-214h-71z m0 428v358h357v-358h-357z m71 72h214v214h-214v-214z m71-500v71h72v-71h-72z m0 571v72h72v-72h-72z m143-571v71h72v-71h-72z" horiz-adv-x="785.7" /> +<glyph glyph-name="barcode" unicode="" d="m0-7v786h35v-786h-35z m53 0v786h17v-786h-17z m53 0v786h17v-786h-17z m87 0v786h17v-786h-17z m70 0v786h35v-786h-35z m88 0v786h17v-786h-17z m35 0v786h17v-786h-17z m35 0v786h18v-786h-18z m70 0v786h35v-786h-35z m88 0v786h35v-786h-35z m70 0v786h35v-786h-35z m70 0v786h35v-786h-35z m53 0v786h35v-786h-35z m88 0v786h52v-786h-52z m70 0v786h18v-786h-18z m35 0v786h35v-786h-35z" horiz-adv-x="1000" /> +<glyph glyph-name="book" unicode="" d="m6 96q0 2 1 15t3 20q0 5-2 12t-2 11q1 6 5 12t9 13 9 13q13 21 25 51t17 51q2 6 0 17t0 16q2 6 9 15t10 13q12 20 23 51t14 51q1 5-1 17t0 16q2 7 12 17t13 13q10 14 23 47t16 54q0 4-2 14t-1 15q1 4 5 10t10 13 10 11q4 7 9 17t8 20 9 20 11 18 15 13 20 6 26-3l0-1q21 5 28 5h425q41 0 63-32t10-72l-152-506q-20-66-40-86t-72-19h-485q-15 0-21-8-6-9-1-24 14-39 81-39h515q16 0 31 8t19 24l168 550q4 13 3 32 21-8 33-24 22-32 10-72l-154-505q-10-36-42-60t-69-25h-515q-43 0-83 30t-55 74q-14 37-1 70z m269 343q-3-7 1-12t11-6h339q7 0 14 6t10 12l11 36q3 7-1 13t-11 5h-339q-8 0-14-5t-10-13z m46 143q-2-7 1-12t11-6h339q8 0 15 6t9 12l12 36q2 7-2 12t-11 6h-339q-7 0-14-6t-9-12z" horiz-adv-x="928.6" /> +<glyph glyph-name="ajust" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41v608q-83 0-153-41t-110-111-41-152z" horiz-adv-x="857.1" /> +<glyph glyph-name="tint" unicode="" d="m0 279q0 81 45 153 4 5 35 51t56 84 56 99 46 112q5 17 19 27t29 9 28-9 19-27q16-51 46-112t56-99 56-85 35-50q45-71 45-154 0-118-83-202t-202-83-202 83-84 202z m143-72q0-29 21-50t50-21 51 21 21 50q0 20-11 39-1 0-9 12t-14 21-14 25-12 28q-2 9-12 9t-11-9q-4-13-12-28t-14-25-14-21-9-12q-11-19-11-39z" horiz-adv-x="571.4" /> +<glyph glyph-name="check" unicode="" d="m0 154v464q0 66 47 113t114 48h464q35 0 65-14 9-4 10-13 2-10-5-16l-27-28q-6-5-13-5-2 0-5 1-13 3-25 3h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v141q0 8 5 13l36 35q6 6 13 6 3 0 7-2 11-4 11-16v-177q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114z m143 267q0 19 14 32l61 62q14 13 32 13t32-13l147-147 361 361q13 13 31 13t32-13l62-61q13-14 13-32t-13-32l-455-454q-13-14-31-14t-32 14l-240 240q-14 13-14 31z" horiz-adv-x="928.6" /> +<glyph glyph-name="check-empty" unicode="" d="m0 154v464q0 66 47 113t114 48h464q66 0 114-48t47-113v-464q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114z m71 0q0-37 27-63t63-27h464q37 0 63 27t26 63v464q0 37-26 63t-63 26h-464q-37 0-63-26t-27-63v-464z" horiz-adv-x="785.7" /> +<glyph glyph-name="circle" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z" horiz-adv-x="857.1" /> +<glyph glyph-name="circle-empty" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41-153-41-110-111-41-152z" horiz-adv-x="857.1" /> +<glyph glyph-name="asterisk" unicode="" d="m68 221q8 29 34 43l148 86-148 86q-26 14-34 43t7 55l36 61q15 26 43 33t55-7l148-85v171q0 29 21 50t51 22h71q29 0 50-22t21-50v-171l149 85q26 15 54 7t44-33l35-61q15-26 7-55t-33-43l-148-86 148-86q26-15 33-43t-7-55l-35-61q-15-26-44-33t-54 7l-149 85v-171q0-29-21-50t-50-22h-71q-29 0-51 22t-21 50v171l-148-85q-26-15-55-7t-43 33l-36 61q-14 26-7 55z" horiz-adv-x="928.6" /> +<glyph glyph-name="gift" unicode="" d="m0 296v179q0 8 5 13t13 5h245q-51 0-88 36t-37 89 37 88 88 37q60 0 94-43l72-92 71 92q34 43 94 43 52 0 88-37t37-88-37-89-88-36h245q8 0 13-5t5-13v-179q0-7-5-12t-13-6h-53v-232q0-22-16-38t-38-15h-607q-22 0-38 15t-16 38v232h-53q-8 0-13 6t-5 12z m210 322q0-22 15-38t38-16h109l-70 90q-15 17-39 17-22 0-38-15t-15-38z m129-525q0-14 10-21t26-8h107q16 0 26 8t10 21v400h-179v-400z m147 471h108q22 0 38 16t15 38-15 38-38 15q-24 0-39-17z" horiz-adv-x="857.1" /> +<glyph glyph-name="fire" unicode="" d="m0-96q0 7 5 12t13 5h750q7 0 12-5t6-12v-36q0-7-6-13t-12-5h-750q-7 0-13 5t-5 13v36z m143 446q0 44 14 80t35 63 49 49 54 43 48 41 36 45 14 54q0 52-37 125l2-1-1 1q50-23 89-46t78-56 63-68 41-84 15-103q0-44-14-80t-36-63-48-49-54-44-49-40-35-45-14-54q0-54 37-125l-2 0 1 0q-51 23-90 46t-77 56-63 68-41 84-15 103z" horiz-adv-x="785.7" /> +<glyph glyph-name="magnet" unicode="" d="m0 314v72q0 14 11 25t25 10h214q15 0 25-10t11-25v-72q0-29 13-50t30-32 39-16 36-8 25-1 24 1 36 8 39 16 30 32 13 50v72q0 14 11 25t25 10h214q15 0 26-10t10-25v-72q0-112-55-202t-153-140-220-51-221 51-153 140-55 202z m0 215v214q0 14 11 25t25 11h214q15 0 25-11t11-25v-214q0-15-11-26t-25-10h-214q-15 0-25 10t-11 26z m571 0v214q0 14 11 25t25 11h214q15 0 26-11t10-25v-214q0-15-10-26t-26-10h-214q-14 0-25 10t-11 26z" horiz-adv-x="857.1" /> +<glyph glyph-name="folder" unicode="" d="m0-52l0 715 139 0 68 90 217 0 68-90 508 0 0-715-1000 0z" horiz-adv-x="1000" /> +<glyph glyph-name="ticket" unicode="" d="m30 243q0 30 21 51l506 505q21 21 50 21t51-21l70-70q-32-31-32-75t32-76 76-32 75 32l71-70q20-21 20-51t-20-50l-506-507q-21-20-51-20t-50 20l-71 71q32 31 32 75t-32 76-76 32-75-32l-70 71q-21 20-21 50z m161 36q0-15 10-26l202-202q11-10 26-10t25 10l345 345q10 11 10 25t-10 26l-202 202q-10 10-26 10t-25-10l-345-345q-10-11-10-25z m61 0l319 319 177-177-319-319z" horiz-adv-x="1000" /> +<glyph glyph-name="key" unicode="" d="m0 413q0 89 53 174t138 139 175 53q91 0 148-58t57-148q0-105-73-204l198-198 54 54q-2 2-15 14t-22 21-18 20-9 16q0 10 27 37t37 28q7 0 13-6 3-3 26-25t45-44 49-48 40-44 16-23q0-9-27-36t-37-28q-5 0-16 9t-20 19-22 22-13 14l-54-53 123-123q15-16 15-38 0-23-21-45t-46-22q-22 0-38 16l-374 374q-98-73-204-73-91 0-148 57t-57 148z m107 8q0-44 31-75t76-32 76 32 31 75q0 24-10 47 23-11 46-11 45 0 76 31t31 76-31 76-76 31-76-31-31-76q0-23 11-46-23 11-47 11-44 0-76-32t-31-76z" horiz-adv-x="1000" /> +<glyph glyph-name="fork" unicode="" d="m0 29q0 29 15 53t39 39v458q-25 14-39 39t-15 53q0 45 31 76t76 32 76-32 31-76q0-29-14-53t-39-39v-278q30 15 86 32 30 10 49 17t39 17 33 22 22 29 16 38 5 51q-25 14-39 39t-15 54q0 45 31 76t76 31 76-31 31-76q0-29-14-54t-39-39q-1-160-126-231-38-21-114-45-71-22-94-39t-23-56v-15q24-14 39-39t14-53q0-45-31-76t-76-32-76 32-31 76z m54 0q0-23 15-38t38-16 38 16 16 38-16 38-38 15-38-15-15-38z m0 642q0-22 15-38t38-15 38 15 16 38-16 38-38 16-38-16-15-38z m357-71q0-22 15-38t38-16 38 16 16 38-16 38-38 16-38-16-15-38z" horiz-adv-x="571.4" /> +<glyph glyph-name="rocket" unicode="" d="m20 252l125 214q6 8 15 9l211 11q54 64 98 109 105 104 200 144t241 40q7 0 13-6t6-12q0-139-43-241t-141-201q-45-44-109-98l-11-211q-1-9-9-15l-214-125q-4-2-9-2-7 0-13 5l-36 36q-7 7-4 17l47 155-156 156-155-47q-1-1-5-1-7 0-12 5l-36 36q-10 11-3 22z m676 348q0-22 16-38t38-16 38 16 16 38-16 38-38 16-38-16-16-38z" horiz-adv-x="928.6" /> +<glyph glyph-name="bug" unicode="" d="m18 314q0 15 11 25t25 11h125v164l-97 97q-11 10-11 25t11 25 25 10 25-10l97-97h471l96 97q11 10 25 10t26-10 10-25-10-25l-97-97v-164h125q15 0 25-11t11-25-11-25-25-10h-125q0-96-37-162l116-117q10-11 10-25t-10-25q-10-11-25-11t-26 11l-110 110q-3-3-8-7t-24-16-36-21-46-16-54-7v500h-71v-500q-29 0-57 7t-49 19-36 22-25 18l-8 8-102-116q-11-12-27-12-13 0-24 9-11 10-11 25t8 26l113 127q-32 63-32 153h-125q-15 0-25 10t-11 25z m268 322q0 74 52 126t126 52 127-52 52-126h-357z" horiz-adv-x="928.6" /> +<glyph glyph-name="certificate" unicode="" d="m1 236q-6 23 11 39l77 75-77 75q-17 16-11 39 7 23 29 29l105 27-29 103q-7 23 10 39 16 18 39 11l104-29 27 104q5 23 28 29 23 7 39-11l76-77 75 77q16 17 39 11 23-6 28-29l27-104 104 29q23 7 39-11 17-16 11-39l-30-103 105-27q22-6 29-29 6-23-11-39l-77-75 77-75q17-16 11-39-7-23-29-29l-105-27 30-103q6-23-11-39-16-18-39-11l-104 30-27-105q-5-23-28-30-7-1-11-1-17 0-28 13l-75 77-76-77q-15-17-39-12-23 7-28 30l-27 105-104-30q-23-7-39 11-17 16-10 39l29 103-105 27q-22 6-29 29z" horiz-adv-x="857.1" /> +<glyph glyph-name="tasks" unicode="" d="m0 29v142q0 15 11 26t25 10h928q15 0 25-10t11-26v-142q0-15-11-26t-25-10h-928q-15 0-25 10t-11 26z m0 285v143q0 15 11 25t25 11h928q15 0 25-11t11-25v-143q0-14-11-25t-25-10h-928q-15 0-25 10t-11 25z m0 286v143q0 14 11 25t25 11h928q15 0 25-11t11-25v-143q0-15-11-25t-25-11h-928q-15 0-25 11t-11 25z m357-250h572v71h-572v-71z m214-286h358v72h-358v-72z m143 572h215v71h-215v-71z" horiz-adv-x="1000" /> +<glyph glyph-name="filter" unicode="" d="m3 685q9 22 33 22h714q23 0 33-22 9-23-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 10-10 25v271l-275 275q-18 16-8 39z" horiz-adv-x="785.7" /> +<glyph glyph-name="beaker" unicode="" d="m64-43q-19 35 12 85l281 442v223h-36q-14 0-25 11t-10 25 10 25 25 11h286q15 0 25-11t11-25-11-25-25-11h-36v-223l281-442q31-50 12-85t-78-36h-643q-59 0-79 36z m202 250h397l-152 240-11 17v243h-71v-243l-12-17z" horiz-adv-x="928.6" /> +<glyph glyph-name="magic" unicode="" d="m15 82q0 15 10 25l718 718q10 10 25 10t25-10l110-111q10-10 10-25t-10-25l-717-718q-10-10-25-10t-25 10l-111 111q-10 10-10 25z m56 697l55 16 17 55 17-55 54-16-54-17-17-55-17 55z m108-108l109 34 33 109 34-109 109-34-109-33-34-109-33 109z m250 108l54 16 17 55 17-55 54-16-54-17-17-55-17 55z m175-194l60-59 164 163-60 60z m182-164l54 17 17 55 17-55 55-17-55-16-17-55-17 55z" horiz-adv-x="928.6" /> +<glyph glyph-name="truck" unicode="" d="m36 100q0 15 10 25t25 11v178q0 5 0 20t0 21 2 19 3 21 8 17 13 17l110 110q11 11 28 18t33 7h89v107q0 15 11 26t25 10h571q15 0 25-10t11-26v-571q0-8-2-15t-8-10-9-6-13-4-13-1-14 0-12 0q0-59-42-101t-101-42-101 42-42 101h-214q0-59-42-101t-101-42-101 42-42 101h-36q-1 0-12 0t-15 0-12 1-13 4-9 6-8 10-2 15z m107 250h214v143h-88q-7 0-12-5l-109-109q-5-5-5-12v-17z m71-286q0-29 22-50t50-21 50 21 21 50-21 51-50 21-50-21-22-51z m500 0q0-29 21-50t51-21 50 21 21 50-21 51-50 21-51-21-21-51z" horiz-adv-x="1000" /> +<glyph glyph-name="money" unicode="" d="m0 29v642q0 15 11 26t25 10h1000q14 0 25-10t10-26v-642q0-15-10-26t-25-10h-1000q-15 0-25 10t-11 26z m71 178q60 0 101-42t42-101h643q0 59 42 101t101 42v286q-59 0-101 42t-42 101h-643q0-59-42-101t-101-42v-286z m286 143q0 39 12 79t33 75 57 56 77 22 77-22 56-56 34-75 11-79-11-79-34-75-56-56-77-22-77 22-57 56-33 75-12 79z m68 84l43-44q24 20 31 31h1v-160h-71v-54h214v54h-72v250h-63z" horiz-adv-x="1071.4" /> +<glyph glyph-name="euro" unicode="" d="m0 280v63q0 7 5 12t13 6h37q-1 31 0 58h-37q-8 0-13 5t-5 13v64q0 7 5 13t13 5h55q37 117 135 188t224 72q57 0 108-13 6-2 11-9 4-6 2-13l-24-89q-2-7-8-11t-13-1l-2 1q-3 0-7 1l-10 2t-12 2-15 2-16 1-16 0q-71 0-126-35t-84-98h261q9 0 14-7 6-7 4-15l-13-63q-3-15-18-15h-273q-1-20 0-58h256q9 0 14-7 5-7 4-15l-14-63q-1-6-6-10t-11-4h-216q27-65 84-104t127-38q10 0 20 1t19 2 16 2 14 3 10 3l7 1 3 2q7 2 14-2 7-4 9-11l19-89q2-7-1-13t-10-8l-3 0q-2-1-6-2t-9-3-12-3-14-3-17-2-18-3-21-2-21 0q-131 0-228 73t-133 196h-53q-7 0-13 5t-5 13z" horiz-adv-x="571.4" /> +<glyph glyph-name="pound" unicode="" d="m0 11v83q0 8 5 13t13 5h54v214h-53q-8 0-13 5t-5 13v73q0 8 5 13t13 5h53v124q0 96 69 158t175 62q104 0 187-70 5-5 6-12t-4-12l-57-71q-5-6-13-7-7-1-13 4-2 3-14 11t-39 18-51 10q-48 0-77-27t-29-68v-120h170q8 0 13-5t5-13v-73q0-7-5-13t-13-5h-170v-212h231v101q0 8 5 13t13 5h90q8 0 13-5t5-13v-204q0-8-5-13t-13-5h-533q-8 0-13 5t-5 13z" horiz-adv-x="571.4" /> +<glyph glyph-name="dollar" unicode="" d="m29 88l58 76q3 5 12 6 9 1 14-5l1-1q63-55 135-70 21-4 42-4 45 0 79 24t35 68q0 16-9 30t-18 23-33 21-37 18-45 18q-21 9-34 14t-34 15-35 17-32 20-29 24-25 27-20 32-11 37-5 44q0 77 55 135t142 75v100q0 7 5 13t13 5h75q8 0 13-5t5-13v-98q32-4 62-13t48-19 36-21 21-16 9-8q9-10 3-21l-46-81q-4-9-12-9-8-2-16 4-1 1-8 6t-21 15-33 18-42 15-47 6q-53 0-87-24t-33-62q0-14 4-27t17-23 22-18 31-18 34-15 39-15q30-11 45-18t43-19 42-24 34-28 30-35 18-43 7-52q0-86-56-147t-144-77v-97q0-8-5-13t-13-5h-75q-7 0-13 5t-5 13v97q-37 5-71 18t-57 25-41 26-26 21-10 10q-9 12-1 23z" horiz-adv-x="571.4" /> +<glyph glyph-name="rupee" unicode="" d="m0 330v71q0 8 5 13t13 5h62q74 0 119 24t57 70h-238q-8 0-13 5t-5 13v57q0 8 5 13t13 5h230q-31 63-149 63h-81q-7 0-13 5t-5 12v75q0 8 5 13t13 5h464q8 0 13-5t5-13v-57q0-8-5-13t-13-5h-130q26-34 36-80h95q8 0 13-5t5-13v-57q0-8-5-13t-13-5h-93q-13-80-72-131t-154-61q93-99 256-299 7-9 2-19-5-10-16-10h-109q-9 0-14 7-171 204-278 318-5 5-5 12z" horiz-adv-x="501.1" /> +<glyph glyph-name="yen" unicode="" d="m2 752q-4 9 0 18 6 9 16 9h108q11 0 16-10l120-238q11-21 32-69 5 13 17 37t15 35l107 234q4 10 16 10h106q10 0 15-8 5-8 1-18l-175-323h120q7 0 13-5t5-13v-58q0-8-5-13t-13-5h-162v-47h162q7 0 13-5t5-13v-57q0-8-5-13t-13-5h-162v-184q0-8-5-13t-12-5h-96q-8 0-13 5t-5 13v184h-161q-7 0-13 5t-5 13v57q0 7 5 13t13 5h161v47h-161q-7 0-13 5t-5 13v58q0 8 5 13t13 5h119z" horiz-adv-x="573.1" /> +<glyph glyph-name="renminbi" unicode="" d="m0 136v71q0 8 5 13t13 5h125v66h-125q-8 0-13 5t-5 13v83q0 7 5 12t13 6h125v351q0 8 5 13t13 5h301q111 0 182-69t70-175-70-176-182-68h-190v-66h282q7 0 12-5t5-13v-71q0-8-5-13t-12-5h-282v-107q0-8-6-13t-12-5h-93q-8 0-13 5t-5 13v107h-125q-8 0-13 5t-5 13z m272 274h178q60 0 96 34t36 91-36 90-96 35h-178v-250z" horiz-adv-x="714.3" /> +<glyph glyph-name="won" unicode="" d="m0 368v36q0 7 5 12t13 5h98l-19 72h-79q-8 0-13 5t-5 13v35q0 8 5 13t13 5h61l-50 192q-3 9 3 16 5 7 14 7h77q14 0 17-14l50-201h201l54 201q4 14 17 14h70q14 0 18-14l54-201h204l52 201q3 14 17 14h77q9 0 14-7 6-7 3-16l-51-192h62q8 0 13-5t5-13v-35q0-8-5-13t-13-5h-81l-19-72h100q8 0 13-5t5-12v-36q0-8-5-13t-13-5h-119l-91-344q-4-13-18-13h-88q-14 0-18 13l-92 344h-117l-93-344q-4-13-17-13h-89q-6 0-11 4t-6 9l-89 344h-116q-8 0-13 5t-5 13z m208 125l18-72h126l19 72h-163z m35-143l42-167q1-1 1-2t0-2q0 1 1 2t0 2l45 167h-89z m216 71h77l-19 72h-39z m165 72l19-72h128l19 72h-166z m38-143l46-167q0 0 0-2t1-2q0 1 0 2t0 2l44 167h-91z" horiz-adv-x="1000" /> +<glyph glyph-name="bitcoin" unicode="" d="m31-7l18 102h62q27 0 32 28v225h9q-4 0-9 0v160q-7 38-50 38h-62v92l119-1q35 0 54 1v141h86v-138q45 1 68 1v137h86v-141q44-4 78-13t63-25 46-43 20-64q10-102-73-144 65-16 98-58t25-119q-4-40-18-70t-36-49-54-33-68-19-81-9v-142h-86v140q-45 0-68 1v-141h-86v142q-10 0-30 1t-31 0h-112z m260 101q5 0 21 0t27 0 29 1 33 2 32 5 31 8 26 11 22 17 14 22 5 29q0 20-8 35t-21 26-32 17-36 10-42 6-38 1-36 0-27-1v-189z m0 275q3 0 20 0t26 0 27 1 31 3 29 6 27 10 21 15 15 22 5 28q0 19-7 33t-17 23-27 16-31 9-34 5-33 1-30 0-22-1v-171z" horiz-adv-x="714.3" /> +<glyph glyph-name="sort" unicode="" d="m0 243q0 14 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 10-11 25z m0 214q0 15 11 25l250 250q10 11 25 11t25-11l250-250q10-10 10-25t-10-25-25-11h-500q-15 0-25 11t-11 25z" horiz-adv-x="571.4" /> +<glyph glyph-name="sort-down" unicode="" d="m0 243q0 14 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 10-11 25z" horiz-adv-x="571.4" /> +<glyph glyph-name="sort-up" unicode="" d="m0 457q0 15 11 25l250 250q10 11 25 11t25-11l250-250q10-10 10-25t-10-25-25-11h-500q-15 0-25 11t-11 25z" horiz-adv-x="571.4" /> +<glyph glyph-name="sort-alt-up" unicode="" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13z" horiz-adv-x="1000" /> +<glyph glyph-name="sort-alt-down" unicode="" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m481-78q0 8 5 13t13 5h143q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-143q-8 0-13 5t-5 13v107z m0 179v107q0 8 5 13t13 5h250q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-250q-8 0-13 5t-5 13z m0 285v107q0 8 5 13t13 5h357q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-357q-8 0-13 5t-5 13z m0 286v107q0 8 5 13t13 5h464q8 0 13-5t5-13v-107q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13z" horiz-adv-x="1000" /> +<glyph glyph-name="sort-name-up" unicode="" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m483 368v60h39l128 369h90l129-369h39v-60h-161v60h42l-26 80h-136l-26-80h42v-60h-160z m49-521l206 295q7 10 12 16l6 5v1q-1 0-4 0t-4 0q-6-2-16-2h-130v-64h-67v128h317v-50l-206-296q-4-4-12-14l-6-7v-1l8 1q5 2 16 2h139v66h67v-130h-326v50z m114 722h98l-40 122-6 26q-2 9-2 11h-2l-2-11q0 0-1-10t-5-16z" horiz-adv-x="928.6" /> +<glyph glyph-name="sort-name-down" unicode="" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m483-144h39l128 370h90l129-370h39v-59h-161v59h42l-26 80h-136l-26-80h42v-59h-160v59z m49 512v51l206 295q7 10 12 15l6 5v2q-1 0-4-1t-4 0q-6-2-16-2h-130v-64h-67v128h317v-50l-206-295q-4-5-12-15l-6-6v-1l8 1q5 1 16 1h139v66h67v-130h-326z m114-370h98l-40 122-6 26q-2 9-2 11h-2l-2-11q0-1-1-10t-5-16z" horiz-adv-x="928.6" /> +<glyph glyph-name="sort-number-up" unicode="" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m509 86q0 58 40 99t101 41q69 0 114-53t46-141q0-35-7-68t-23-64-38-53-55-36-71-14q-35 0-60 9-14 4-24 8l22 63q8-4 17-6 21-7 42-7 47 0 75 33t37 81h-1q-11-13-34-21t-47-8q-59 0-97 40t-37 97z m17 608l107 103h68v-365h92v-64h-261v64h93v241q0 4 0 11t1 9v9h-2l-3-7q-5-7-15-17l-35-32z m60-608q0-32 21-53t58-22q28 0 48 15t19 38q0 35-24 65t-58 30q-29 0-46-21t-18-52z" horiz-adv-x="857.1" /> +<glyph glyph-name="sort-number-down" unicode="" d="m19 53q4 11 17 11h107v768q0 8 5 13t13 5h107q8 0 13-5t5-13v-768h107q8 0 13-5t5-13q0-6-6-13l-178-178q-5-5-13-5-6 0-13 5l-178 179q-8 9-4 19z m509 657q0 59 40 99t101 41q69 0 114-53t46-141q0-34-7-67t-23-64-38-53-55-37-71-14q-35 0-60 9-14 5-24 9l22 63q8-4 17-6 21-8 42-8 47 0 75 33t37 81h-1q-11-13-34-20t-47-8q-59 0-97 40t-37 96z m17-535l107 104h68v-365h92v-64h-261v64h93v241q0 4 0 10t1 10v9h-2l-3-7q-5-7-15-17l-35-33z m60 535q0-32 21-53t58-21q28 0 48 15t19 38q0 35-24 64t-58 30q-29 0-46-21t-18-52z" horiz-adv-x="857.1" /> +<glyph glyph-name="hammer" unicode="" d="m22 404q0 7 3 14t5 12 9 13 9 10 11 11 10 9q17 15 38 15 6 0 10 0t9-4 8-3 8-5 6-6 7-7 7-7q-8 8-8 19t8 19l194 194q8 8 19 8t19-8q-1 1-7 7t-7 7-6 7-5 7-3 8-4 9 0 10q0 21 15 38 2 1 9 10t11 11 10 9 13 9 12 5 14 3q23 0 38-16l228-228q16-15 16-38 0-7-3-14t-5-12-9-13-9-10-11-11-10-9q-17-15-38-15-6 0-10 0t-9 4-8 3-7 5-7 6-7 7-7 7q8-8 8-19t-8-19l-70-70 143-143q24 24 53 24 29 0 51-21l203-202q20-22 20-51 0-30-20-50l-60-61q-22-20-51-20-29 0-50 20l-203 204q-21 20-21 50 0 29 24 53l-143 143-70-70q-8-8-19-8t-19 8q1-1 7-7t7-7 6-7 5-7 4-8 3-9 0-10q0-21-15-38-2-1-9-10t-11-11-10-9-13-9-12-5-14-3q-23 0-38 16l-228 228q-16 15-16 38z" horiz-adv-x="1000" /> +<glyph glyph-name="gauge" unicode="" d="m0 207q0 102 40 194t106 160 160 107 194 39 194-39 160-107 106-160 40-194q0-145-79-269-10-17-30-17h-782q-20 0-30 17-79 123-79 269z m71 0q0-29 21-50t51-21 50 21 21 50-21 51-50 21-51-21-21-51z m108 250q0-29 21-50t50-21 51 21 20 50-20 51-51 21-50-21-21-51z m217-330q-11-43 11-81t66-50 81 11 50 66q9 33-4 65t-40 51l57 213q3 14-5 27t-21 16-27-3-17-22l-56-213q-33-3-60-25t-35-55z m33 437q0-29 21-50t50-21 51 21 20 50-20 51-51 21-50-21-21-51z m250-107q0-29 21-50t50-21 51 21 20 50-20 51-51 21-50-21-21-51z m107-250q0-29 21-50t50-21 51 21 21 50-21 51-51 21-50-21-21-51z" horiz-adv-x="1000" /> +<glyph glyph-name="sitemap" unicode="" d="m0-25v179q0 22 16 38t38 15h53v107q0 29 21 51t51 21h285v107h-53q-23 0-38 15t-16 38v179q0 22 16 38t38 16h178q23 0 38-16t16-38v-179q0-22-16-38t-38-15h-53v-107h285q29 0 51-21t21-51v-107h53q23 0 38-15t16-38v-179q0-22-16-38t-38-16h-178q-22 0-38 16t-16 38v179q0 22 16 38t38 15h53v107h-285v-107h53q23 0 38-15t16-38v-179q0-22-16-38t-38-16h-178q-23 0-38 16t-16 38v179q0 22 16 38t38 15h53v107h-285v-107h53q22 0 38-15t16-38v-179q0-22-16-38t-38-16h-178q-23 0-38 16t-16 38z" horiz-adv-x="1000" /> +<glyph glyph-name="spinner" unicode="" d="m0 350q0 37 26 63t63 26 63-26 27-63-27-63-63-26-63 26-26 63z m98 250q0 41 29 69t69 29 70-29 29-69-29-69-70-29-69 29-29 69z m18-500q0 34 24 57t56 23q33 0 57-23t24-57-24-57-57-23q-33 0-56 23t-24 57z m223 607q0 45 32 76t75 31 76-31 32-76-32-76-76-31-75 31-32 76z m36-714q0 29 21 50t50 21 51-21 21-50-21-51-51-21-50 21-21 51z m259 107q0 26 18 44t44 19 45-19 18-44-18-44-45-18-44 18-18 44z m18 500q0 18 13 32t31 13 32-13 13-32-13-32-32-13-31 13-13 32z m98-250q0 22 16 38t38 16 38-16 15-38-15-38-38-16-38 16-16 38z" horiz-adv-x="875" /> +<glyph glyph-name="coffee" unicode="" d="m0 64h1000q0-59-42-101t-101-42h-714q-59 0-101 42t-42 101z m143 197v410q0 15 11 26t25 10h642q89 0 152-63t63-151-63-152-152-62h-35v-18q0-52-37-88t-88-37h-393q-51 0-88 37t-37 88z m643 125h35q45 0 76 31t32 76-32 76-76 31h-35v-214z" horiz-adv-x="1071.4" /> +<glyph glyph-name="food" unicode="" d="m0 457v357q0 15 11 25t25 11 25-11 10-25v-232q0-14 11-25t25-11 25 11 11 25v232q0 15 11 25t25 11 25-11 10-25v-232q0-14 11-25t25-11 25 11 11 25v232q0 15 10 25t25 11 26-11 10-25v-357q0-34-20-62t-51-39v-435q0-29-21-50t-51-21h-71q-29 0-50 21t-22 50v435q-31 11-51 39t-20 62z m429-232v446q0 74 52 127t126 52h143q15 0 25-11t11-25v-893q0-29-21-50t-51-21h-71q-29 0-50 21t-22 50v286h-125q-7 0-12 5t-5 13z" horiz-adv-x="785.7" /> +<glyph glyph-name="beer" unicode="" d="m36 636l18 71h267l18 72h536l18-108-36-17v-447l72-107v-107h-643v107l71 107h-71q-89 0-152 63t-63 151v179z m178-215q0-29 21-50t51-21h71v214h-143v-143z" horiz-adv-x="928.6" /> +<glyph glyph-name="user-md" unicode="" d="m0 66q0 38 3 73t14 77 26 74 45 58 67 33q-12-29-12-67v-113q-32-11-52-39t-20-62q0-45 32-76t76-31 75 31 32 76q0 34-20 62t-52 39v113q0 35 14 52 74-58 165-58t164 58q14-17 14-52v-35q-59 0-101-42t-41-101v-50q-18-16-18-40 0-22 15-37t38-16 38 16 16 37q0 24-18 40v50q0 29 21 50t50 21 51-21 21-50v-50q-18-16-18-40 0-22 16-37t38-16 38 16 15 37q0 24-18 40v50q0 38-19 71t-52 52q0 6 0 24t0 27-1 23-4 26-7 22q38-8 67-33t45-58 26-74 14-77 3-73q0-68-41-106t-108-39h-488q-67 0-108 39t-41 106z m143 34q0 15 11 25t25 11 25-11 10-25-10-25-25-11-26 11-10 25z m36 464q0 89 62 152t152 63 151-63 63-152-63-151-151-63-152 63-62 151z" horiz-adv-x="785.7" /> +<glyph glyph-name="stethoscope" unicode="" d="m0 421v286q0 15 11 25t25 11q3 0 9-1 9 16 26 27t36 10q30 0 51-21t21-51-21-50-51-21q-18 0-36 10v-225q0-59 53-101t126-41 126 41 53 101v225q-18-10-36-10-30 0-51 21t-21 50 21 51 51 21q19 0 36-10t26-27q6 1 9 1 15 0 25-11t11-25v-286q0-80-61-140t-153-72v-73q0-59 52-101t126-42 126 42 53 101v220q-32 12-52 39t-20 62q0 45 32 76t76 31 75-31 32-76q0-34-20-62t-52-39v-220q0-89-73-152t-177-63-176 63-74 152v73q-91 12-153 72t-61 140z m643 36q0-14 10-25t26-11 25 11 10 25-10 25-25 11-26-11-10-25z" horiz-adv-x="785.7" /> +<glyph glyph-name="ambulance" unicode="" d="m36 100q0 15 10 25t25 11v232q0 14 8 32t18 29l110 110q11 11 29 18t32 7h89v179q0 14 11 25t25 11h643q14 0 25-11t10-25v-643q0-14-10-25t-25-11h-107q0-59-42-101t-101-42-101 42-42 101h-214q0-59-42-101t-101-42-101 42-42 101h-72q-14 0-25 11t-10 25z m107 250h214v143h-88q-8-1-12-5l-109-109q-4-7-5-12v-17z m71-286q0-29 21-50t51-21 50 21 21 50-21 51-50 21-51-21-21-51z m286 375q0-8 5-13t13-5h125v-125q0-7 5-12t13-5h107q8 0 13 5t5 12v125h125q8 0 13 5t5 13v107q0 8-5 13t-13 5h-125v125q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-125h-125q-8 0-13-5t-5-13v-107z m214-375q0-29 21-50t51-21 50 21 21 50-21 51-50 21-51-21-21-51z" horiz-adv-x="1071.4" /> +<glyph glyph-name="medkit" unicode="" d="m0 46v465q0 51 37 88t88 37h18v-715h-18q-51 0-88 37t-37 88z m196-125v715h90v89q0 22 15 38t38 16h322q22 0 38-16t15-38v-89h90v-715h-608z m90 304q0-8 5-13t13-5h125v-125q0-8 5-13t12-5h108q7 0 12 5t5 13v125h125q8 0 13 5t5 13v107q0 8-5 13t-13 5h-125v125q0 8-5 13t-12 5h-108q-7 0-12-5t-5-13v-125h-125q-8 0-13-5t-5-13v-107z m71 411h286v71h-286v-71z m500-715v715h18q51 0 88-37t37-88v-465q0-51-37-88t-88-37h-18z" horiz-adv-x="1000" /> +<glyph glyph-name="h-sigh" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 18q0-14 11-25t25-11h71q15 0 25 11t11 25v179h285v-179q0-14 11-25t25-11h72q14 0 25 11t10 25v500q0 15-10 25t-25 11h-72q-14 0-25-11t-11-25v-179h-285v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-500z" horiz-adv-x="857.1" /> +<glyph glyph-name="hospital" unicode="" d="m0-114v714q0 15 11 25t25 11h178v160q0 23 16 38t38 16h250q22 0 38-16t15-38v-160h179q15 0 25-11t11-25v-714q0-15-11-25t-25-11h-714q-15 0-25 11t-11 25z m71 35h215v125q0 8 5 13t13 5h178q7 0 13-5t5-13v-125h214v643h-143v-18q0-22-15-38t-38-15h-250q-22 0-38 15t-16 38v18h-143v-643z m72 161v36q0 7 5 12t13 6h35q8 0 13-6t5-12v-36q0-7-5-12t-13-6h-35q-7 0-13 6t-5 12z m0 143v36q0 7 5 12t13 6h35q8 0 13-6t5-12v-36q0-7-5-13t-13-5h-35q-7 0-13 5t-5 13z m0 143v36q0 7 5 12t13 5h35q8 0 13-5t5-12v-36q0-7-5-13t-13-5h-35q-7 0-13 5t-5 13z m143-143v36q0 7 5 12t13 6h35q8 0 13-6t5-12v-36q0-7-5-13t-13-5h-35q-8 0-13 5t-5 13z m0 143v36q0 7 5 12t13 5h35q8 0 13-5t5-12v-36q0-7-5-13t-13-5h-35q-8 0-13 5t-5 13z m0 214q0-7 5-12t13-6h35q8 0 13 6t5 12v54h72v-54q0-7 5-12t12-6h36q7 0 13 6t5 12v179q0 7-5 12t-13 6h-36q-7 0-12-6t-5-12v-54h-72v54q0 7-5 12t-13 6h-35q-8 0-13-6t-5-12v-179z m143-357v36q0 7 5 12t12 6h36q7 0 13-6t5-12v-36q0-7-5-13t-13-5h-36q-7 0-12 5t-5 13z m0 143v36q0 7 5 12t12 5h36q7 0 13-5t5-12v-36q0-7-5-13t-13-5h-36q-7 0-12 5t-5 13z m142-286v36q0 7 6 12t12 6h36q7 0 13-6t5-12v-36q0-7-5-12t-13-6h-36q-7 0-12 6t-6 12z m0 143v36q0 7 6 12t12 6h36q7 0 13-6t5-12v-36q0-7-5-13t-13-5h-36q-7 0-12 5t-6 13z m0 143v36q0 7 6 12t12 5h36q7 0 13-5t5-12v-36q0-7-5-13t-13-5h-36q-7 0-12 5t-6 13z" horiz-adv-x="785.7" /> +<glyph glyph-name="building" unicode="" d="m0-114v928q0 15 11 25t25 11h714q15 0 25-11t11-25v-928q0-15-11-25t-25-11h-714q-15 0-25 11t-11 25z m71 35h215v125q0 8 5 13t13 5h178q7 0 13-5t5-13v-125h214v858h-643v-858z m72 161v36q0 7 5 12t13 6h35q8 0 13-6t5-12v-36q0-7-5-12t-13-6h-35q-7 0-13 6t-5 12z m0 143v36q0 7 5 12t13 6h35q8 0 13-6t5-12v-36q0-7-5-13t-13-5h-35q-7 0-13 5t-5 13z m0 143v36q0 7 5 12t13 5h35q8 0 13-5t5-12v-36q0-7-5-13t-13-5h-35q-7 0-13 5t-5 13z m0 143v35q0 8 5 13t13 5h35q8 0 13-5t5-13v-35q0-8-5-13t-13-5h-35q-7 0-13 5t-5 13z m0 143v35q0 8 5 13t13 5h35q8 0 13-5t5-13v-35q0-8-5-13t-13-5h-35q-7 0-13 5t-5 13z m143-429v36q0 7 5 12t13 6h35q8 0 13-6t5-12v-36q0-7-5-13t-13-5h-35q-8 0-13 5t-5 13z m0 143v36q0 7 5 12t13 5h35q8 0 13-5t5-12v-36q0-7-5-13t-13-5h-35q-8 0-13 5t-5 13z m0 143v35q0 8 5 13t13 5h35q8 0 13-5t5-13v-35q0-8-5-13t-13-5h-35q-8 0-13 5t-5 13z m0 143v35q0 8 5 13t13 5h35q8 0 13-5t5-13v-35q0-8-5-13t-13-5h-35q-8 0-13 5t-5 13z m143-429v36q0 7 5 12t12 6h36q7 0 13-6t5-12v-36q0-7-5-13t-13-5h-36q-7 0-12 5t-5 13z m0 143v36q0 7 5 12t12 5h36q7 0 13-5t5-12v-36q0-7-5-13t-13-5h-36q-7 0-12 5t-5 13z m0 143v35q0 8 5 13t12 5h36q7 0 13-5t5-13v-35q0-8-5-13t-13-5h-36q-7 0-12 5t-5 13z m0 143v35q0 8 5 13t12 5h36q7 0 13-5t5-13v-35q0-8-5-13t-13-5h-36q-7 0-12 5t-5 13z m142-572v36q0 7 6 12t12 6h36q7 0 13-6t5-12v-36q0-7-5-12t-13-6h-36q-7 0-12 6t-6 12z m0 143v36q0 7 6 12t12 6h36q7 0 13-6t5-12v-36q0-7-5-13t-13-5h-36q-7 0-12 5t-6 13z m0 143v36q0 7 6 12t12 5h36q7 0 13-5t5-12v-36q0-7-5-13t-13-5h-36q-7 0-12 5t-6 13z m0 143v35q0 8 6 13t12 5h36q7 0 13-5t5-13v-35q0-8-5-13t-13-5h-36q-7 0-12 5t-6 13z m0 143v35q0 8 6 13t12 5h36q7 0 13-5t5-13v-35q0-8-5-13t-13-5h-36q-7 0-12 5t-6 13z" horiz-adv-x="785.7" /> +<glyph glyph-name="smile" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m71 0q0-73 29-139t76-113 114-77 139-28 138 28 114 77 76 113 29 139-29 139-76 114-114 76-138 28-139-28-114-76-76-114-29-139z m143 143q0 29 21 50t51 21 50-21 21-50-21-51-50-21-51 21-21 51z m10-243q-4 14 3 27t21 18q14 4 27-2t17-22q14-44 52-72t85-28 84 28 52 72q4 15 18 22t27 2 21-18 2-27q-21-67-77-109t-127-41-128 41-77 109z m276 243q0 29 21 50t50 21 51-21 21-50-21-51-51-21-50 21-21 51z" horiz-adv-x="857.1" /> +<glyph glyph-name="frown" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m71 0q0-73 29-139t76-113 114-77 139-28 138 28 114 77 76 113 29 139-29 139-76 114-114 76-138 28-139-28-114-76-76-114-29-139z m143 143q0 29 21 50t51 21 50-21 21-50-21-51-50-21-51 21-21 51z m10-329q21 68 77 109t128 41 127-41 77-109q4-14-2-27t-21-17-27 2-18 21q-14 45-52 72t-84 28-85-28-52-72q-4-15-17-21t-27-2q-15 4-21 17t-3 27z m276 329q0 29 21 50t50 21 51-21 21-50-21-51-51-21-50 21-21 51z" horiz-adv-x="857.1" /> +<glyph glyph-name="meh" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m71 0q0-73 29-139t76-113 114-77 139-28 138 28 114 77 76 113 29 139-29 139-76 114-114 76-138 28-139-28-114-76-76-114-29-139z m143-107q0 14 11 25t25 11h357q15 0 25-11t11-25-11-25-25-11h-357q-14 0-25 11t-11 25z m0 250q0 29 21 50t51 21 50-21 21-50-21-51-50-21-51 21-21 51z m286 0q0 29 21 50t50 21 51-21 21-50-21-51-51-21-50 21-21 51z" horiz-adv-x="857.1" /> +<glyph glyph-name="anchor" unicode="" d="m0-7v196q0 8 5 13t13 5h196q13 0 17-11 5-11-4-20l-56-55q38-51 106-86t152-46v361h-108q-14 0-25 11t-10 25v71q0 15 10 25t25 11h108v91q-33 19-52 51t-20 72q0 59 42 101t101 42 101-42 42-101q0-39-20-72t-52-51v-91h108q14 0 25-11t10-25v-71q0-15-10-25t-25-11h-108v-361q84 11 152 46t106 86l-56 55q-8 9-4 20 4 11 17 11h196q8 0 13-5t5-13v-196q0-12-11-17-5-1-7-1-7 0-13 5l-52 52q-66-80-177-127t-240-46-240 46-177 127l-52-52q-5-5-13-5-2 0-7 1-11 5-11 17z m464 714q0-14 11-25t25-11 25 11 11 25-11 25-25 11-25-11-11-25z" horiz-adv-x="1000" /> +<glyph glyph-name="terminal" unicode="" d="m7 82q0 7 6 13l219 219-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l260-260q6-5 6-13t-6-13l-260-260q-5-5-12-5t-13 5l-28 28q-6 6-6 13z m350-71v35q0 8 5 13t13 5h536q8 0 13-5t5-13v-35q0-8-5-13t-13-5h-536q-8 0-13 5t-5 13z" horiz-adv-x="928.6" /> +<glyph glyph-name="eraser" unicode="" d="m1 75q3 21 17 36l500 572q21 24 53 24h429q21 0 39-11t26-31q9-19 6-40t-17-36l-500-572q-22-24-54-24h-429q-21 0-38 11t-27 31q-8 19-5 40z m70-11h429l188 215h-429z" horiz-adv-x="1071.4" /> +<glyph glyph-name="puzzle" unicode="" d="m0-7v571q1 0 10-2t19-2 12-2q83-14 136-14 45 0 66 20 25 24 25 49 0 13-8 29t-19 29-18 36-9 46q0 46 33 72t81 25q44 0 74-25t30-69q0-23-9-43t-21-33-22-31-9-40q0-32 23-47t57-14q36 0 101 8t91 9v-1q-1-1-2-9t-3-19-2-12q-13-84-13-137 0-45 19-65 25-26 50-26 12 0 28 8t30 19 36 19 46 8q46 0 71-33t26-80q0-45-25-75t-69-30q-23 0-43 10t-33 21-32 21-39 10q-62 0-62-69 0-22 9-65t8-64v-3q-12 0-18 0-19-2-54-7t-65-7-55-3q-34 0-57 15t-23 47q0 20 9 39t22 32 21 33 9 43q0 44-30 69t-75 25q-47 0-80-26t-33-71q0-24 9-46t18-36 19-30 8-28q0-25-25-50-21-19-66-19-53 0-136 13-5 1-16 2t-15 3l-7 1q-1 0-2 0-1 0-1 1z" horiz-adv-x="928.6" /> +<glyph glyph-name="shield" unicode="" d="m0 314v429q0 14 11 25t25 11h643q14 0 25-11t10-25v-429q0-48-18-95t-47-84-66-71-70-57-68-43-50-28-23-11q-7-4-15-4t-14 4q-9 4-24 11t-50 28-68 43-70 57-66 71-46 84-19 95z m357-277q67 35 119 76 131 103 131 201v357h-250v-634z" horiz-adv-x="714.3" /> +<glyph glyph-name="extinguisher" unicode="" d="m2 517q-5 14 2 28 3 5 8 14t21 30 34 39 47 38 61 29q-14 23-14 48 0 37 26 63t63 26 63-26 26-63q0-19-7-36h168q0 6 4 11t10 6l250 54q2 1 4 1 7 0 11-4 7-5 7-14v-179q0-9-7-14-4-4-11-4-2 0-4 1l-250 53q-6 2-10 7t-4 11h-143v-57q62-13 103-62t40-113v-447q0-14-11-25t-25-11h-285q-15 0-26 11t-10 25v447q0 59 35 106t90 64v62h-18q-33 0-64-13t-51-30-37-37-23-30-7-14q-10-19-32-19-9 0-16 4-13 6-18 20z m212 226q0-15 11-25t25-11 25 11 11 25-11 25-25 11-25-11-11-25z" horiz-adv-x="785.7" /> +<glyph glyph-name="bullseye" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m71 0q0-73 29-139t76-113 114-77 139-28 138 28 114 77 76 113 29 139-29 139-76 114-114 76-138 28-139-28-114-76-76-114-29-139z m72 0q0 118 84 202t202 84 202-84 83-202-83-202-202-84-202 84-84 202z m71 0q0-89 63-151t152-63 151 63 63 151-63 152-151 62-152-62-63-152z m72 0q0 59 42 101t101 42 101-42 41-101-41-101-101-42-101 42-42 101z" horiz-adv-x="857.1" /> +<glyph glyph-name="resize-full" unicode="" d="m784 111l127 128 0-336-335 0 128 130-128 127 79 79z m-431 686l-129-127 128-127-80-80-126 128-128-129 0 335 335 0z m0-637l-129-127 129-130-335 0 0 336 128-128 128 128z m558 637l0-335-127 129-128-128-79 80 127 127-128 127 335 0z" horiz-adv-x="928" /> +<glyph glyph-name="laptop" unicode="" d="m0 46v54h1071v-54q0-22-26-37t-63-16h-893q-36 0-63 16t-26 37z m143 179v393q0 37 26 63t63 26h607q37 0 63-26t27-63v-393q0-37-27-63t-63-26h-607q-37 0-63 26t-26 63z m71 0q0-7 6-13t12-5h607q8 0 13 5t5 13v393q0 7-5 12t-13 6h-607q-7 0-12-6t-6-12v-393z m268-170q0-9 9-9h89q9 0 9 9t-9 9h-89q-9 0-9-9z" horiz-adv-x="1071.4" /> +<glyph glyph-name="chart-bar" unicode="" d="m688-97l0 894 223 0 0-894-223 0z m-335 0l0 671 223 0 0-671-223 0z m-335 0l0 448 223 0 0-448-223 0z" horiz-adv-x="928" /> +<glyph glyph-name="download-cloud" unicode="" d="m0 274q2 54 23 103t63 87 95 61q64 28 154 15 39 79 113 127t164 49q83 0 152-41t109-111 40-148v-29h7q80 32 159-4t112-113q31-81-4-159t-113-113l-17-4t-16-4-13-3-15-2-13-1h-724q-84 0-154 49t-102 134q-23 52-20 107z m448 103q-6-9 4-20l131-219q8-8 15-8 3 0 7 2t6 4l1 2 140 219q6 12 0 21t-22 9h-52v102h-153v-102h-59q-12 0-18-10z" horiz-adv-x="1205.6" /> +<glyph glyph-name="upload-cloud" unicode="" d="m0 251q-2 45 10 86t34 78 58 65 77 44q77 30 156 13 36 81 111 130t166 49q62 0 118-24t97-65 65-97 25-119q0-9-2-27 1 0 3 1t3 2q80 31 159-4t110-116q20-55 12-108t-43-96-88-65q-35-13-73-14h-298v168h68q19 0 25 11t-4 26l-171 275q-6 10-16 10-4 0-8-3t-6-5l-2-2-171-275q-10-15-3-26t25-11h67v-168h-224v1q-86 0-158 48t-103 131q-17 42-19 87z" horiz-adv-x="1205.1" /> +<glyph glyph-name="share" unicode="" d="m0 90v490q0 70 50 119t119 50h129q29 0 48-20t20-46q0-29-20-48t-48-20h-129q-15 0-25-10t-10-25v-490q0-14 10-25t25-10h588q15 0 25 10t10 25v60q0 27 20 47t46 20q28 0 48-20t19-47v-60q0-70-49-119t-119-50h-588q-70 0-119 50t-50 119z m244 90q45 81 121 132t167 59q42 3 74-2v-103q0-22 11-30t27 4l283 207q10 8 10 19 0 6-2 11t-6 7l-2 2-283 207q-15 12-27 4t-11-30v-84q-7 0-20-1-73-7-137-41t-109-89-72-124-24-148z" horiz-adv-x="937.5" /> +<glyph glyph-name="link" unicode="" d="m8 96q-17 66 0 132t67 115l131 131q49 49 115 67t131 0 116-67q20-20 20-49t-20-50-50-20-49 20q-35 34-82 34t-81-34l-132-131q-33-34-33-82t33-82q34-33 82-33t81 33l27 28q78-38 164-36l-91-91q-49-49-115-66t-132 0-115 66-67 115z m291 180q0 29 21 49 20 21 49 21t50-21q33-34 81-34t82 34l131 132q34 34 34 81t-34 81q-33 34-81 34t-82-34l-27-26q-77 36-164 35l91 91q50 49 116 66t131 0 115-66q49-49 67-115t0-132-67-115l-131-131q-49-49-115-67t-132 0-114 67q-21 21-21 50z" horiz-adv-x="887.2" /> +<glyph glyph-name="help-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m233 167q-9-14 4-24l74-55q4-4 10-4 9 0 14 7 30 38 48 51 19 14 48 14 27 0 48-15t21-33q0-21-11-34t-38-25q-35-16-65-48t-29-70v-20q0-8 5-13t13-5h107q8 0 13 5t5 13q0 10 12 27t30 28q18 10 28 16t25 19 25 27 16 34 7 45q0 49-31 91t-77 65-95 23q-136 0-207-119z m124-435q0-8 5-13t13-5h107q8 0 13 5t5 13v107q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-107z" horiz-adv-x="857.1" /> +<glyph glyph-name="info-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m286-268q0-8 5-13t13-5h250q7 0 12 5t5 13v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89z m71 500q0-8 5-13t13-5h107q8 0 13 5t5 13v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89z" horiz-adv-x="857.1" /> +<glyph glyph-name="info" unicode="" d="m0 29v71q0 15 11 25t25 11h35v214h-35q-15 0-25 11t-11 25v71q0 15 11 25t25 11h214q15 0 25-11t11-25v-321h35q15 0 26-11t10-25v-71q0-15-10-26t-26-10h-285q-15 0-25 10t-11 26z m71 607v107q0 14 11 25t25 11h143q15 0 25-11t11-25v-107q0-15-11-25t-25-11h-143q-14 0-25 11t-11 25z" horiz-adv-x="357.1" /> +<glyph glyph-name="home" unicode="" d="m15 348q0 8 6 12l401 334q18 15 42 15t43-15l136-114v109q0 8 5 13t13 5h107q8 0 13-5t5-13v-227l122-102q5-5 6-12t-4-13l-34-41q-5-5-12-7h-2q-7 0-12 4l-386 322-386-322q-7-4-13-4-7 2-12 7l-35 41q-4 5-3 13z m128-319v267q0 1 0 2t0 2l321 264 321-264q1-1 1-4v-267q0-15-11-26t-25-10h-214v214h-143v-214h-214q-15 0-25 10t-11 26z" horiz-adv-x="928.6" /> +<glyph glyph-name="flag-empty" unicode="" d="m36 707q0 30 21 51t50 21 51-21 21-51q0-19-10-36t-26-25v-707q0-8-5-13t-13-5h-36q-7 0-13 5t-5 13v707q-16 9-25 25t-10 36z m143-536v414q0 20 17 31 19 12 44 24t63 29 85 28 87 10q62 0 117-17t116-48q21-11 50-11 68 0 173 63 12 6 17 9 17 9 35-1 17-11 17-31v-425q0-22-20-32-5-3-9-5-122-65-206-65-49 0-88 20l-16 7q-35 19-55 27t-51 16-63 8q-57 0-132-24t-127-57q-9-5-19-5-9 0-18 4-17 11-17 31z m71 60q137 63 242 63 30 0 57-5t55-14 43-17 46-22l16-8q24-12 56-12 67 0 164 51v344q-95-51-171-51-46 0-81 18-56 27-103 42t-99 16q-97 0-225-71v-334z" horiz-adv-x="1000" /> +<glyph glyph-name="flag-checkered" unicode="" d="m36 707q0 30 21 51t50 21 51-21 21-51q0-19-10-36t-26-25v-707q0-8-5-13t-13-5h-36q-7 0-13 5t-5 13v707q-16 9-25 25t-10 36z m143-536v414q0 20 17 31 19 12 44 24t63 29 85 28 87 10q62 0 117-17t116-48q21-11 50-11 68 0 173 63 12 6 17 9 17 9 35-1 17-11 17-31v-425q0-22-20-32-5-3-9-5-122-65-206-65-49 0-88 20l-16 7q-35 19-55 27t-51 16-63 8q-57 0-132-24t-127-57q-9-5-19-5-9 0-18 4-17 11-17 31z m71 60q114 53 214 61v107q-101-9-214-65v-103z m0 228q120 62 214 66v110q-96-4-214-70v-106z m214-59h11q57 0 107-16t111-46q10-5 21-8v-105q24-9 51-9 67 0 164 51v103q-132-65-215-40v125q-11 3-21 8-3 2-19 10t-19 9-18 9-19 8-18 8-20 7-20 4-22 4-22 3-24 1q-13 0-28-2v-124z m250 55q83-24 215 50v106q-95-51-171-51-25 0-44 4v-109z" horiz-adv-x="1000" /> +<glyph glyph-name="thumbs-up" unicode="" d="m0 64v357q0 30 21 51t50 21h153q20 13 77 86 32 42 60 72 13 14 19 47t17 71 35 60q22 21 50 21 47 0 84-18t57-57 20-104q0-51-27-107h98q58 0 101-42t42-100q0-50-27-91 5-18 5-39 0-43-21-80 1-12 1-24 0-56-33-99 0-78-48-123t-126-45h-72q-54 0-106 13t-121 36q-65 23-77 23h-161q-29 0-50 21t-21 50z m71 36q0-14 11-25t25-11 25 11 11 25-11 25-25 11-25-11-11-25z m143-36h18q7 0 18-1t18-4 21-6 20-7 20-7 16-5q118-41 191-41h67q107 0 107 93 0 15-2 31 16 9 26 30t10 41-10 38q29 28 29 67 0 13-5 31t-14 26q18 1 30 26t12 45q0 29-22 50t-50 22h-196q0 32 27 89t26 89q0 55-17 81t-72 27q-14-15-21-48t-17-70-33-61q-13-13-43-51-2-3-13-17t-18-22-19-24-22-25-22-19-22-16-20-5h-18v-357z" horiz-adv-x="857.1" /> +<glyph glyph-name="thumbs-down" unicode="" d="m0 279v357q0 29 21 50t50 21h161q12 0 77 22 72 25 125 37t111 13h63q78 0 126-45t48-120v-3q33-43 33-99 0-13-1-24 21-38 21-81 0-20-5-38 27-41 27-91 0-58-42-100t-101-42h-98q27-56 27-107 0-66-20-104-19-39-57-57t-84-18q-28 0-50 21-19 18-30 45t-14 51-10 47-17 36q-27 28-60 71-57 73-77 86h-153q-29 0-50 21t-21 50z m71 321q0-15 11-25t25-11 25 11 11 25-11 25-25 11-25-11-11-25z m143-321h18q9 0 20-5t22-15 22-20 22-25 19-24 18-22 13-17q30-38 43-51 23-24 33-61t17-70 21-48q54 0 72 27t17 81q0 33-26 89t-27 89h196q28 0 50 22t22 50q0 19-12 45t-30 26q8 10 14 27t5 30q0 39-29 67 10 18 10 38t-10 41-26 30q2 16 2 31 0 47-27 70t-76 23h-71q-73 0-191-41-3-1-16-6t-20-7-20-6-21-6-18-4-18-1h-18v-358z" horiz-adv-x="857.1" /> +<glyph glyph-name="edit" unicode="" d="m0 154v464q0 66 47 113t114 48h464q35 0 65-14 9-4 10-13 2-10-5-16l-27-28q-8-8-18-4-13 3-25 3h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v70q0 7 5 12l36 36q8 8 20 4t11-16v-106q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114z m357-18v160l375 375 161-160-375-375h-161z m54 107h53v-54h32l64 65-85 85-64-65v-31z m116 134q9-9 18 0l196 196q9 9 0 18t-18 0l-196-196q-9-9 0-18z m241 330l51 51q16 16 38 16t38-16l85-84q16-16 16-38t-16-38l-51-52z" horiz-adv-x="1000" /> +<glyph glyph-name="print" unicode="" d="m0 82v232q0 44 32 76t75 31h36v304q0 22 16 38t37 16h375q23 0 50-12t42-26l85-85q15-16 27-43t11-49v-143h35q45 0 76-31t32-76v-232q0-7-6-12t-12-6h-125v-89q0-22-16-38t-38-16h-536q-22 0-37 16t-16 38v89h-125q-7 0-13 6t-5 12z m214-89h500v143h-500v-143z m0 357h500v214h-89q-22 0-38 16t-16 38v89h-357v-357z m572-36q0-14 10-25t25-10 26 10 10 25-10 25-26 11-25-11-10-25z" horiz-adv-x="928.6" /> +<glyph glyph-name="retweet" unicode="" d="m0 386q0 13 8 23l179 214q11 12 27 12t28-12l178-214q9-10 9-23 0-15-11-25t-25-11h-107v-214h321q9 0 14-6l89-108q4-6 4-11 0-8-5-13t-13-5h-535q-5 0-8 1t-5 4-3 4-2 7 0 6v335h-107q-15 0-25 11t-11 25z m357 232q0 7 5 12t13 6h536q4 0 7-1t5-4 3-5 2-6 1-7v-334h107q14 0 25-11t10-25q0-14-8-23l-179-214q-11-13-27-13t-27 13l-179 214q-8 9-8 23 0 14 10 25t26 11h107v214h-322q-9 0-14 7l-89 107q-4 5-4 11z" horiz-adv-x="1071.4" /> +<glyph glyph-name="keyboard" unicode="" d="m0 64v500q0 30 21 51t50 21h929q30 0 50-21t21-51v-500q0-29-21-50t-50-21h-929q-29 0-50 21t-21 50z m71 0h929v500h-929v-500z m72 81v53q0 9 9 9h53q9 0 9-9v-53q0-9-9-9h-53q-9 0-9 9z m0 143v53q0 9 9 9h125q9 0 9-9v-53q0-9-9-9h-125q-9 0-9 9z m0 142v54q0 9 9 9h53q9 0 9-9v-54q0-9-9-9h-53q-9 0-9 9z m143-285v53q0 9 9 9h482q9 0 9-9v-53q0-9-9-9h-482q-9 0-9 9z m0 285v54q0 9 9 9h53q9 0 9-9v-54q0-9-9-9h-53q-9 0-9 9z m71-142v53q0 9 9 9h54q9 0 9-9v-53q0-9-9-9h-54q-9 0-9 9z m72 142v54q0 9 9 9h53q9 0 9-9v-54q0-9-9-9h-53q-9 0-9 9z m71-142v53q0 9 9 9h54q8 0 8-9v-53q0-9-8-9h-54q-9 0-9 9z m71 142v54q0 9 9 9h54q9 0 9-9v-54q0-9-9-9h-54q-9 0-9 9z m72-142v53q0 9 9 9h53q9 0 9-9v-53q0-9-9-9h-53q-9 0-9 9z m71 142v54q0 9 9 9h54q9 0 9-9v-54q0-9-9-9h-54q-9 0-9 9z m72-142v53q0 9 9 9h62v134q0 9 9 9h54q9 0 9-9v-196q0-9-9-9h-125q-9 0-9 9z m71-143v53q0 9 9 9h54q9 0 9-9v-53q0-9-9-9h-54q-9 0-9 9z" horiz-adv-x="1071.4" /> +<glyph glyph-name="doc-text" unicode="" d="m0-96v892q0 23 16 38t38 16h500q22 0 49-11t42-27l174-174q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38z m71 17h715v572h-232q-23 0-38 15t-16 38v233h-429v-858z m143 161v36q0 8 5 13t13 5h393q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13z m0 143v36q0 8 5 13t13 5h393q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13z m0 143v36q0 7 5 12t13 5h393q8 0 13-5t5-12v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13z m357 196h210q-5 16-12 23l-175 175q-6 7-23 12v-210z" horiz-adv-x="857.1" /> +<glyph glyph-name="file" unicode="" d="m0-96v892q0 23 16 38t38 16h446v-304q0-22 16-38t38-15h303v-589q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38z m571 660v264q13-8 21-16l227-228q8-7 16-20h-264z" horiz-adv-x="857.1" /> +<glyph glyph-name="doc-text-inv" unicode="" d="m0-96v892q0 23 16 38t38 16h446v-304q0-22 16-38t38-15h303v-589q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38z m214 178q0-8 5-13t13-5h393q8 0 13 5t5 13v36q0 8-5 13t-13 5h-393q-8 0-13-5t-5-13v-36z m0 143q0-8 5-13t13-5h393q8 0 13 5t5 13v36q0 8-5 13t-13 5h-393q-8 0-13-5t-5-13v-36z m0 143q0-8 5-13t13-5h393q8 0 13 5t5 13v36q0 7-5 12t-13 5h-393q-8 0-13-5t-5-12v-36z m357 196v264q13-8 21-16l227-228q8-7 16-20h-264z" horiz-adv-x="857.1" /> +<glyph glyph-name="logout" unicode="" d="m0 154v392q0 67 47 114t114 47h178q8 0 13-5t5-13q0-2 1-11t0-15-2-13-5-11-12-3h-178q-37 0-63-27t-27-63v-392q0-37 27-63t63-27h174t6 0 7-2 4-3 4-5 1-8q0-2 1-11t0-14-2-14-5-11-12-3h-178q-67 0-114 47t-47 114z m214 89v214q0 15 11 25t25 11h250v161q0 14 11 25t25 10 25-10l303-304q11-10 11-25t-11-25l-303-304q-11-10-25-10t-25 10-11 25v161h-250q-14 0-25 11t-11 25z" horiz-adv-x="928.6" /> +<glyph glyph-name="mic" unicode="" d="m0 386v71q0 15 11 25t25 11 25-11 10-25v-71q0-103 74-177t176-73 177 73 73 177v71q0 15 11 25t25 11 25-11 11-25v-71q0-124-82-215t-204-104v-74h143q15 0 25-11t11-25-11-25-25-11h-357q-15 0-25 11t-11 25 11 25 25 11h143v74q-121 13-204 104t-82 215z m143 0v285q0 74 52 127t126 52 127-52 52-127v-285q0-74-52-126t-127-53-126 53-52 126z" horiz-adv-x="642.9" /> +<glyph glyph-name="mute" unicode="" d="m7 29q0 7 6 12l688 689q6 6 13 6t13-6l46-46q5-5 5-13t-5-12l-202-202v-71q0-74-52-126t-126-53q-31 0-61 11l-54-54q55-28 115-28 103 0 176 73t74 177v71q0 15 10 25t26 11 25-11 10-25v-71q0-124-82-215t-203-104v-74h142q15 0 26-11t10-25-10-25-26-11h-357q-14 0-25 11t-10 25 10 25 25 11h143v74q-70 7-131 45l-142-142q-5-6-13-6t-12 6l-46 46q-6 5-6 13z m64 357v71q0 15 11 25t25 11 25-11 11-25v-71q0-30 8-63l-56-57q-24 58-24 120z m143 0v285q0 74 53 127t126 52q57 0 103-33t65-85z" horiz-adv-x="785.7" /> +<glyph glyph-name="volume-off" unicode="" d="m0 243v214q0 15 11 25t25 11h146l186 186q10 10 25 10t25-10 11-25v-608q0-14-11-25t-25-10-25 10l-186 186h-146q-15 0-25 11t-11 25z" horiz-adv-x="428.6" /> +<glyph glyph-name="down-dir" unicode="" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" /> +<glyph glyph-name="up-dir" unicode="" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" /> +<glyph glyph-name="left-dir" unicode="" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" /> +<glyph glyph-name="right-dir" unicode="" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" /> +<glyph glyph-name="down" unicode="" d="m2 125q5 11 16 11h125v696q0 8 5 13t13 5h107q8 0 13-5t5-13v-696h125q11 0 16-11t-3-19l-195-215q-6-5-13-5-8 0-13 5l-198 215q-8 9-3 19z" horiz-adv-x="428.6" /> +<glyph glyph-name="left" unicode="" d="m0 296v108q0 7 5 12t13 5h696v125q0 12 11 17t19-3l215-196q5-5 5-12 0-8-5-14l-215-197q-9-8-19-4-11 5-11 17v124h-696q-8 0-13 6t-5 12z" horiz-adv-x="1000" /> +<glyph glyph-name="right" unicode="" d="m36 348q0 8 5 14l215 197q9 8 19 4 11-5 11-17v-125h696q8 0 13-5t5-12v-108q0-7-5-12t-13-5h-696v-125q0-12-11-17t-19 3l-215 196q-5 5-5 12z" horiz-adv-x="1000" /> +<glyph glyph-name="up" unicode="" d="m2 575q-5 10 3 19l195 215q5 5 13 5 7 0 13-5l198-215q7-9 3-19-5-11-16-11h-125v-696q0-8-5-13t-13-5h-107q-8 0-13 5t-5 13v696h-125q-12 0-16 11z" horiz-adv-x="428.6" /> +<glyph glyph-name="level-down" unicode="" d="m2 697q5 10 16 10h393q7 0 12-5t6-13v-482h107q22 0 32-20t-5-39l-178-214q-11-13-28-13t-27 13l-179 214q-14 17-5 39 10 20 33 20h107v357h-179q-8 0-14 6l-89 108q-7 7-2 19z" horiz-adv-x="571.4" /> +<glyph glyph-name="shuffle" unicode="" d="m0 82v107q0 8 5 13t13 5h125q27 0 48 9t39 25 28 34 26 43q17 35 43 96 16 36 28 62t30 58 36 56 41 46 50 38 59 24 72 9h143v107q0 8 5 13t13 5q6 0 13-5l178-178q5-5 5-13t-5-13l-179-179q-5-5-12-5-8 0-13 6t-5 12v107h-143q-27 0-49-8t-38-25-29-35-25-43q-18-34-43-95-16-37-28-62t-30-59-36-55-41-47-50-38-60-23-71-10h-125q-8 0-13 5t-5 13z m0 500v107q0 8 5 13t13 5h125q139 0 229-125-34-52-77-153-12 25-20 41t-23 35-28 32-36 19-45 8h-125q-8 0-13 5t-5 13z m415-392q33 52 76 152 12-25 20-40t23-36 28-31 35-20 46-8h143v107q0 8 5 13t13 5q6 0 13-5l178-178q5-5 5-13t-5-13l-179-179q-5-5-12-5-8 0-13 6t-5 12v107q-18 0-48 0t-45-1-41 1-39 3-36 6-35 10-32 16-33 22-31 30-31 39z" horiz-adv-x="1000" /> +<glyph glyph-name="exchange" unicode="" d="m0 136q0 8 5 13l179 178q5 5 12 5 8 0 13-5t5-13v-107h768q7 0 13-5t5-13v-107q0-7-5-12t-13-6h-768v-107q0-7-5-12t-13-6q-6 0-13 6l-178 178q-5 5-5 13z m0 303v107q0 8 5 13t13 5h768v107q0 8 5 13t13 5q6 0 13-5l178-178q5-5 5-13t-5-13l-179-179q-5-5-12-5-8 0-13 6t-5 12v107h-768q-7 0-13 6t-5 12z" horiz-adv-x="1000" /> +<glyph glyph-name="collapse" unicode="" d="m0 82v536q0 66 47 113t114 48h535q67 0 114-48t47-113v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113z m143 0q0-7 5-12t13-6h535q8 0 13 6t5 12v536q0 7-5 12t-13 6h-535q-7 0-13-6t-5-12v-536z m75 391q10 20 32 20h357q22 0 32-20 10-19-3-36l-178-250q-11-16-29-16t-29 16l-179 250q-13 17-3 36z" horiz-adv-x="857.1" /> +<glyph glyph-name="award" unicode="" d="m0 511v71q0 22 16 38t38 16h160v53q0 37 27 63t63 27h321q37 0 63-27t26-63v-53h161q22 0 38-16t16-38v-71q0-40-24-80t-62-73-97-54-120-25q-23-30-53-53-21-19-29-40t-8-50q0-30 17-51t54-21q42 0 75-25t32-64v-36q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v36q0 39 33 64t74 25q38 0 55 21t17 51q0 28-8 50t-30 40q-29 23-53 53-63 3-120 25t-96 54-63 73-23 80z m71 0q0-44 53-91t132-63q-42 91-42 207h-143v-53z m602-154q79 16 131 63t53 91v53h-143q0-116-41-207z" horiz-adv-x="928.6" /> +<glyph glyph-name="desktop" unicode="" d="m0 154v607q0 37 26 63t63 26h893q37 0 63-26t26-63v-607q0-37-26-63t-63-27h-303q0-20 9-43t17-40 9-24q0-14-10-25t-25-11h-286q-15 0-25 11t-11 25q0 8 9 25t18 39 9 43h-304q-36 0-63 27t-26 63z m71 142q0-7 6-12t12-5h893q7 0 13 5t5 12v465q0 7-5 12t-13 6h-893q-7 0-12-6t-6-12v-465z" horiz-adv-x="1071.4" /> +<glyph glyph-name="tablet" unicode="" d="m0 82v607q0 37 26 63t63 27h465q36 0 63-27t26-63v-607q0-37-26-63t-63-26h-465q-36 0-63 26t-26 63z m71 72q0-8 6-13t12-5h465q7 0 12 5t5 13v535q0 8-5 13t-12 5h-465q-7 0-12-5t-6-13v-535z m215-90q0-14 10-25t25-10 26 10 10 25-10 25-26 11-25-11-10-25z" horiz-adv-x="642.9" /> +<glyph glyph-name="align-left" unicode="" d="m0 29v71q0 15 11 25t25 11h928q15 0 25-11t11-25v-71q0-15-11-26t-25-10h-928q-15 0-25 10t-11 26z m0 214v71q0 15 11 25t25 11h714q15 0 25-11t11-25v-71q0-15-11-25t-25-11h-714q-15 0-25 11t-11 25z m0 214v72q0 14 11 25t25 10h857q14 0 25-10t11-25v-72q0-14-11-25t-25-11h-857q-15 0-25 11t-11 25z m0 214v72q0 14 11 25t25 11h643q14 0 25-11t10-25v-72q0-14-10-25t-25-10h-643q-15 0-25 10t-11 25z" horiz-adv-x="1000" /> +<glyph glyph-name="align-center" unicode="" d="m0 29v71q0 15 11 25t25 11h928q15 0 25-11t11-25v-71q0-15-11-26t-25-10h-928q-15 0-25 10t-11 26z m71 428v72q0 14 11 25t25 10h786q14 0 25-10t11-25v-72q0-14-11-25t-25-11h-786q-14 0-25 11t-11 25z m143-214v71q0 15 11 25t25 11h500q15 0 25-11t11-25v-71q0-15-11-25t-25-11h-500q-14 0-25 11t-11 25z m72 428v72q0 14 10 25t25 11h358q14 0 25-11t10-25v-72q0-14-10-25t-25-10h-358q-14 0-25 10t-10 25z" horiz-adv-x="1000" /> +<glyph glyph-name="align-right" unicode="" d="m0 29v71q0 15 11 25t25 11h928q15 0 25-11t11-25v-71q0-15-11-26t-25-10h-928q-15 0-25 10t-11 26z m71 428v72q0 14 11 25t25 10h857q15 0 25-10t11-25v-72q0-14-11-25t-25-11h-857q-14 0-25 11t-11 25z m143-214v71q0 15 11 25t25 11h714q15 0 25-11t11-25v-71q0-15-11-25t-25-11h-714q-14 0-25 11t-11 25z m72 428v72q0 14 10 25t25 11h643q15 0 25-11t11-25v-72q0-14-11-25t-25-10h-643q-14 0-25 10t-10 25z" horiz-adv-x="1000" /> +<glyph glyph-name="align-justify" unicode="" d="m0 29v71q0 15 11 25t25 11h928q15 0 25-11t11-25v-71q0-15-11-26t-25-10h-928q-15 0-25 10t-11 26z m0 214v71q0 15 11 25t25 11h928q15 0 25-11t11-25v-71q0-15-11-25t-25-11h-928q-15 0-25 11t-11 25z m0 214v72q0 14 11 25t25 10h928q15 0 25-10t11-25v-72q0-14-11-25t-25-11h-928q-15 0-25 11t-11 25z m0 214v72q0 14 11 25t25 11h928q15 0 25-11t11-25v-72q0-14-11-25t-25-10h-928q-15 0-25 10t-11 25z" horiz-adv-x="1000" /> +<glyph glyph-name="ellipsis" unicode="" d="m0 332v107q0 23 16 38t38 16h107q22 0 38-16t15-38v-107q0-22-15-38t-38-15h-107q-23 0-38 15t-16 38z m286 0v107q0 23 15 38t38 16h107q23 0 38-16t16-38v-107q0-22-16-38t-38-15h-107q-22 0-38 15t-15 38z m285 0v107q0 23 16 38t38 16h107q22 0 38-16t16-38v-107q0-22-16-38t-38-15h-107q-22 0-38 15t-16 38z" horiz-adv-x="785.7" /> +<glyph glyph-name="ellipsis-vert" unicode="" d="m0 46v108q0 22 16 38t38 15h107q22 0 38-15t15-38v-108q0-22-15-37t-38-16h-107q-23 0-38 16t-16 37z m0 286v107q0 23 16 38t38 16h107q22 0 38-16t15-38v-107q0-22-15-38t-38-15h-107q-23 0-38 15t-16 38z m0 286v107q0 22 16 38t38 16h107q22 0 38-16t15-38v-107q0-22-15-38t-38-16h-107q-23 0-38 16t-16 38z" horiz-adv-x="214.3" /> +<glyph glyph-name="off" unicode="" d="m0 350q0 102 45 191t126 151q24 18 54 14t46-28q18-23 14-53t-28-47q-54-41-84-101t-30-127q0-58 22-111t62-91 91-61 111-23 110 23 92 61 61 91 22 111q0 68-30 127t-84 101q-24 18-28 47t14 53q17 24 47 28t53-14q81-61 126-151t45-191q0-87-34-166t-91-137-137-92-166-34-167 34-136 92-92 137-34 166z m357 71v358q0 29 21 50t51 21 50-21 21-50v-358q0-29-21-50t-50-21-51 21-21 50z" horiz-adv-x="857.1" /> +<glyph glyph-name="road" unicode="" d="m28 34q0 30 14 64l233 583q5 11 15 18t21 8h189q-7 0-13-5t-6-13l-8-107q-1-8 4-13t12-5h93q7 0 12 5t5 13l-9 107q0 7-6 13t-13 5h190q11 0 21-8t14-18l233-583q15-34 15-64 0-41-26-41h-393q7 0 12 5t5 13l-11 143q-1 7-7 12t-12 5h-152q-7 0-13-5t-6-12l-11-143q-1-8 4-13t12-5h-392q-26 0-26 41z m423 260q0-6 5-11t12-4h136q7 0 12 4t4 11v2l-13 179q-1 7-7 13t-12 5h-104q-7 0-13-5t-6-13l-14-179v-2z" horiz-adv-x="1071.4" /> +<glyph glyph-name="credit-card" unicode="" d="m0 11v678q0 37 26 63t63 27h893q37 0 63-27t26-63v-678q0-37-26-63t-63-27h-893q-36 0-63 27t-26 63z m71 0q0-8 6-13t12-5h893q7 0 13 5t5 13v339h-929v-339z m0 553h929v125q0 8-5 13t-13 5h-893q-7 0-12-5t-6-13v-125z m72-500v72h143v-72h-143z m214 0v72h214v-72h-214z" horiz-adv-x="1071.4" /> +<glyph glyph-name="floppy" unicode="" d="m0-25v750q0 22 16 38t38 16h517q23 0 50-12t42-26l156-157q16-15 27-42t11-49v-518q0-22-15-38t-38-16h-750q-23 0-38 16t-16 38z m71 18h72v232q0 22 16 38t37 16h465q22 0 38-16t15-38v-232h72v500q0 8-6 21t-11 20l-157 156q-5 6-19 12t-22 5v-232q0-22-15-38t-38-16h-322q-22 0-37 16t-16 38v232h-72v-714z m143 0h429v214h-429v-214z m143 518q0-8 5-13t13-5h107q7 0 13 5t5 13v178q0 8-5 13t-13 5h-107q-7 0-13-5t-5-13v-178z" horiz-adv-x="857.1" /> +<glyph glyph-name="megaphone" unicode="" d="m0 368v107q0 37 26 63t63 26h268q243 0 500 215 29 0 50-22t22-50v-214q29 0 50-21t21-51-21-50-50-21v-214q0-29-22-51t-50-21q-233 194-453 212-32-10-51-37t-17-56 22-51q-11-19-13-37t4-32 18-31 27-28 35-28q-17-32-63-46t-94-7-73 31q-4 13-17 49t-18 53-12 50-9 56 2 55 12 61h-68q-36 0-63 27t-26 63z m429-22q210-23 428-190v532q-220-168-428-191v-151z" horiz-adv-x="1000" /> +</font> +</defs> +</svg> \ No newline at end of file diff --git a/public/font/fontello.woff b/public/font/fontello.woff new file mode 100644 index 0000000000000000000000000000000000000000..658ab82961aee0515dd4cae8e9e6de0bed67096c Binary files /dev/null and b/public/font/fontello.woff differ diff --git a/public/fonts/glyphicons-halflings-regular.eot b/public/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..423bd5d3a20b804f596e04e5cd02fb4f16cfcbc1 Binary files /dev/null and b/public/fonts/glyphicons-halflings-regular.eot differ diff --git a/public/fonts/glyphicons-halflings-regular.svg b/public/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 0000000000000000000000000000000000000000..4469488747892e5d72de3752a17705b0f02bec91 --- /dev/null +++ b/public/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,229 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="glyphicons_halflingsregular" horiz-adv-x="1200" > +<font-face units-per-em="1200" ascent="960" descent="-240" /> +<missing-glyph horiz-adv-x="500" /> +<glyph /> +<glyph /> +<glyph unicode="
" /> +<glyph unicode=" " /> +<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" /> +<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" /> +<glyph unicode=" " /> +<glyph unicode=" " horiz-adv-x="652" /> +<glyph unicode=" " horiz-adv-x="1304" /> +<glyph unicode=" " horiz-adv-x="652" /> +<glyph unicode=" " horiz-adv-x="1304" /> +<glyph unicode=" " horiz-adv-x="434" /> +<glyph unicode=" " horiz-adv-x="326" /> +<glyph unicode=" " horiz-adv-x="217" /> +<glyph unicode=" " horiz-adv-x="217" /> +<glyph unicode=" " horiz-adv-x="163" /> +<glyph unicode=" " horiz-adv-x="260" /> +<glyph unicode=" " horiz-adv-x="72" /> +<glyph unicode=" " horiz-adv-x="260" /> +<glyph unicode=" " horiz-adv-x="326" /> +<glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" /> +<glyph unicode="−" d="M200 400h900v300h-900v-300z" /> +<glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" /> +<glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" /> +<glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" /> +<glyph unicode="" horiz-adv-x="500" d="M0 0z" /> +<glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" /> +<glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q17 -55 85.5 -75.5t147.5 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" /> +<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" /> +<glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" /> +<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" /> +<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" /> +<glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" /> +<glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" /> +<glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" /> +<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" /> +<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" /> +<glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 299q-120 -77 -261 -77q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" /> +<glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" /> +<glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" /> +<glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" /> +<glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" /> +<glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" /> +<glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" /> +<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" /> +<glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" /> +<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" /> +<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" /> +<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" /> +<glyph unicode="" d="M0 25v475l200 700h800q199 -700 200 -700v-475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" /> +<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" /> +<glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" /> +<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" /> +<glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" /> +<glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" /> +<glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" /> +<glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" /> +<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" /> +<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" /> +<glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" /> +<glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" /> +<glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" /> +<glyph unicode="" d="M1 700v475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" /> +<glyph unicode="" d="M2 700v475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" /> +<glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" /> +<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" /> +<glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" /> +<glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" /> +<glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" /> +<glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v70h471q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" /> +<glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" /> +<glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " /> +<glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" /> +<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" /> +<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" /> +<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" /> +<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" /> +<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" /> +<glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" /> +<glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" /> +<glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" /> +<glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " /> +<glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" /> +<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" /> +<glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 138.5t-64 210.5zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" /> +<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" /> +<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" /> +<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l566 567l-136 137l-430 -431l-147 147z" /> +<glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" /> +<glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" /> +<glyph unicode="" d="M200 0l900 550l-900 550v-1100z" /> +<glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" /> +<glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" /> +<glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" /> +<glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" /> +<glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" /> +<glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" /> +<glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" /> +<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" /> +<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" /> +<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM300 500h600v200h-600v-200z" /> +<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141z" /> +<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" /> +<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM363 700h144q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5q19 0 30 -10t11 -26 q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-105 0 -172 -56t-67 -183zM500 300h200v100h-200v-100z" /> +<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" /> +<glyph unicode="" d="M0 500v200h194q15 60 36 104.5t55.5 86t88 69t126.5 40.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200 v-206q149 48 201 206h-201v200h200q-25 74 -76 127.5t-124 76.5v-204h-200v203q-75 -24 -130 -77.5t-79 -125.5h209v-200h-210z" /> +<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" /> +<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" /> +<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" /> +<glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z" /> +<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" /> +<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" /> +<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" /> +<glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" /> +<glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" /> +<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" /> +<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-33 14.5h-207q-20 0 -32 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" /> +<glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111v6t-1 15t-3 18l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6h-111v-100z M100 0h400v400h-400v-400zM200 900q-3 0 14 48t35 96l18 47l214 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" /> +<glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" /> +<glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" /> +<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" /> +<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" /> +<glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 33 -48 36t-48 -29l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" /> +<glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -21 -13 -29t-32 1l-94 78h-222l-94 -78q-19 -9 -32 -1t-13 29v64 q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" /> +<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" /> +<glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" /> +<glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" /> +<glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" /> +<glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" /> +<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" /> +<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" /> +<glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" /> +<glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" /> +<glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" /> +<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" /> +<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" /> +<glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" /> +<glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM99 500v250v5q0 13 0.5 18.5t2.5 13t8 10.5t15 3h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35q-56 337 -56 351z M1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" /> +<glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-22 -9 -63 -23t-167.5 -37 t-251.5 -23t-245.5 20.5t-178.5 41.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" /> +<glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" /> +<glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q123 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 212l100 213h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" /> +<glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q123 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" /> +<glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" /> +<glyph unicode="" d="M-101 651q0 72 54 110t139 37h302l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 16.5 -10.5t26 -26t16.5 -36.5v-526q0 -13 -85.5 -93.5t-93.5 -80.5h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l106 89v502l-342 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM999 201v600h200v-600h-200z" /> +<glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6v7.5v7v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" /> +<glyph unicode="" d="M1 585q-15 -31 7 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85l-1 -302q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM76 565l237 339h503l89 -100v-294l-340 -130 q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" /> +<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 500h300l-2 -194l402 294l-402 298v-197h-298v-201z" /> +<glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l400 -294v194h302v201h-300v197z" /> +<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" /> +<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" /> +<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -34 5.5 -93t7.5 -87q0 -9 17 -44t16 -60q12 0 23 -5.5 t23 -15t20 -13.5q20 -10 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55.5t-20 -57.5q12 -21 22.5 -34.5t28 -27t36.5 -17.5q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q101 -2 221 111q31 30 47 48t34 49t21 62q-14 9 -37.5 9.5t-35.5 7.5q-14 7 -49 15t-52 19 q-9 0 -39.5 -0.5t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q8 16 22 22q6 -1 26 -1.5t33.5 -4.5t19.5 -13q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5 t5.5 57.5q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 41 1 44q31 -13 58.5 -14.5t39.5 3.5l11 4q6 36 -17 53.5t-64 28.5t-56 23 q-19 -3 -37 0q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -46 0t-45 -3q-20 -6 -51.5 -25.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79zM518 915q3 12 16 30.5t16 25.5q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -18 8 -42.5t16.5 -44 t9.5 -23.5q-6 1 -39 5t-53.5 10t-36.5 16z" /> +<glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" /> +<glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" /> +<glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" /> +<glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" /> +<glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" /> +<glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM513 609q0 32 21 56.5t52 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-16 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5q-37 0 -62.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" /> +<glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -79.5 -17t-67.5 -51l-388 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23q38 0 53 -36 q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60l517 511 q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" /> +<glyph unicode="" d="M79 784q0 131 99 229.5t230 98.5q144 0 242 -129q103 129 245 129q130 0 227 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100l-84.5 84.5t-68 74t-60 78t-33.5 70.5t-15 78z M250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-106 48.5q-73 0 -131 -83l-118 -171l-114 174q-51 80 -124 80q-59 0 -108.5 -49.5t-49.5 -118.5z" /> +<glyph unicode="" d="M57 353q0 -94 66 -160l141 -141q66 -66 159 -66q95 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-12 12 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141l19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -18q46 -46 77 -99l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" /> +<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" /> +<glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" /> +<glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335l-27 7q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5v-307l64 -14 q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5zM700 237 q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" /> +<glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -11 2.5 -24.5t5.5 -24t9.5 -26.5t10.5 -25t14 -27.5t14 -25.5 t15.5 -27t13.5 -24h242v-100h-197q8 -50 -2.5 -115t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q32 1 102 -16t104 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10 t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5t-30 142.5h-221z" /> +<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" /> +<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" /> +<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" /> +<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" /> +<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" /> +<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" /> +<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" /> +<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" /> +<glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" /> +<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" /> +<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" /> +<glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" /> +<glyph unicode="" d="M216 519q10 -19 32 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8l9 -1q13 0 26 16l538 630q15 19 6 36q-8 18 -32 16h-300q1 4 78 219.5t79 227.5q2 17 -6 27l-8 8h-9q-16 0 -25 -15q-4 -5 -98.5 -111.5t-228 -257t-209.5 -238.5q-17 -19 -7 -40z" /> +<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " /> +<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" /> +<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" /> +<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" /> +<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" /> +<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" /> +<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 401h700v699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" /> +<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l248 -237v700h-699zM900 150h100v50h-100v-50z" /> +<glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" /> +<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" /> +<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" /> +<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" /> +<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" /> +<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" /> +<glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" /> +<glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" /> +<glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -117q-25 -16 -43.5 -50.5t-18.5 -65.5v-359z" /> +<glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" /> +<glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" /> +<glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q16 17 13 40.5t-22 37.5l-192 136q-19 14 -45 12t-42 -19l-119 -118q-143 103 -267 227q-126 126 -227 268l118 118q17 17 20 41.5 t-11 44.5l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" /> +<glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -15 -35.5t-35 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" /> +<glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" /> +<glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" /> +<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" /> +<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" /> +<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" /> +<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" /> +<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" /> +<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" /> +<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" /> +<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" /> +<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" /> +<glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" /> +<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300 h200l-300 -300z" /> +<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104t60.5 178q0 121 -85 207.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" /> +<glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" /> +<glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -12t1 -11q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" /> +</font> +</defs></svg> \ No newline at end of file diff --git a/public/fonts/glyphicons-halflings-regular.ttf b/public/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a498ef4e7c8b556fc36f580c5ff524025bb11c84 Binary files /dev/null and b/public/fonts/glyphicons-halflings-regular.ttf differ diff --git a/public/fonts/glyphicons-halflings-regular.woff b/public/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..d83c539b8266366dc331c5f746714caefb84c47d Binary files /dev/null and b/public/fonts/glyphicons-halflings-regular.woff differ diff --git a/public/images/.keep b/public/images/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c9c7c01f30b90e009de2d15952ae83230f8e37a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,5 @@ +# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-agent: * +# Disallow: / diff --git a/scripts/copy_client_vendor_scripts.sh b/scripts/copy_client_vendor_scripts.sh new file mode 100755 index 0000000000000000000000000000000000000000..a8b00c95bd09c0ed1a7f1d41f4b350b62d64bacd --- /dev/null +++ b/scripts/copy_client_vendor_scripts.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -e + +mkdir -p public/vendor +mkdir -p public/assets +mkdir -p vendor/assets/components/socket.io + +pushd vendor/assets/components/html2canvas +npm install +npm run build +rm -rf node_modules +popd + +cp -R node_modules/socket.io-client/dist/* vendor/assets/components/socket.io +cp -R vendor/assets/components public/vendor/ + +mkdir vendor/assets/components/feedback +cp -R deps/feedbackjs/dist/* vendor/assets/components/feedback + diff --git a/scripts/gen-build-info.sh b/scripts/gen-build-info.sh new file mode 100755 index 0000000000000000000000000000000000000000..fea264f64d9b9a33b1dc10c84664955c6904ffff --- /dev/null +++ b/scripts/gen-build-info.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +function get_version() { + current_branch=$(git branch | grep -v HEAD | grep \* | cut -d ' ' -f2) + current_branch=${CI_COMMIT_SHORT_SHA:-$current_branch} + branches=(master develop $current_branch) + + for branch_idx in "${!branches[@]}"; do + [[ "${branches[$branch_idx]}" = "${current_branch}" ]] && break + done + + version="" +# echo $branch_idx + + while (( branch_idx >= 1 )); do +# echo "${branches[branch_idx]} ^${branches[branch_idx - 1]}" + commit_distance=$(git log --oneline ${branches[branch_idx]} ^${branches[branch_idx - 1]} | wc -l) + version=".${commit_distance// /}${version}" + (( branch_idx-- )) + done + + master_commit=$(git log master --pretty=oneline | wc -l) + full_version="${master_commit}${version}" + echo ${full_version} +} + +function emit_info() { + component_name=$1 + component_dir=$2 + + #ISO 8601 + builddate=`date "+%Y-%m-%dT%H:%M:%S%z"` + + echo "${component_name}:" + branch=`git --git-dir=$component_dir/.git --work-tree=$PWD/$component_dir rev-parse --abbrev-ref HEAD` + echo " version: $(get_version)" + echo " build_date: ${builddate}" + echo " branch: \"${branch}\"" + commit=`git --git-dir=$component_dir/.git --work-tree=$PWD/$component_dir rev-parse HEAD` + echo " commit: \"${commit}\"" + origin_url=`git --git-dir=$component_dir/.git --work-tree=$PWD/$component_dir remote show origin | grep Fetch | sed 's/ Fetch URL: //g'` + echo " origin_url: ${origin_url}" + commit_details=`git --git-dir=$component_dir/.git --work-tree=$PWD/$component_dir log --pretty=format:'%ad %h %d %cn -- %s' --abbrev-commit --date=short -1 | sed 's/\: /; /g'` + commit_details_clean=$(echo "${commit_details}" | sed s/\"/''/g | sed 's/:/;/g' ) + echo " commit_details: ${commit_details_clean}" + echo " recent_commit_details: " + git --git-dir=$component_dir/.git --work-tree=$PWD/$component_dir log --pretty=format:'%ad %h %d %cn -- %s' --abbrev-commit --date=short -10 | while read recent_commit_detail; do + line=$(echo $recent_commit_detail | sed s/\"/''/g | sed 's/:/;/g' ) + echo " - \"${line}\"" + done +} + +sed=sed +if type gsed >/dev/null 2>&1; then + sed=gsed +fi +component=$(git config --local remote.origin.url | ${sed} -r 's/.*[:/]([^/]+)(\.git)?$/\1/' | ${sed} -r 's/\//-/') + +emit_info ${component} . + diff --git a/scripts/run-lint.sh b/scripts/run-lint.sh new file mode 100755 index 0000000000000000000000000000000000000000..34154fce40e989ed8150b43a0e0f908dc7c6daf5 --- /dev/null +++ b/scripts/run-lint.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +script_dir=$(dirname ${BASH_SOURCE[0]}) +root=$(realpath ${script_dir}/..) + +echo ${root} + +docker run --interactive --tty --rm \ + --env CODECLIMATE_CODE=${root} \ + --volume ${root}:/code \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + --volume /tmp/cc:/tmp/cc \ + codeclimate/codeclimate analyze diff --git a/scripts/run-server.sh b/scripts/run-server.sh new file mode 100755 index 0000000000000000000000000000000000000000..31f73257f3970cfe214fe3c486152428f162b9c9 --- /dev/null +++ b/scripts/run-server.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +timestamp() { date "+%FT%T%z"; } + +log() { echo "[$(timestamp)] ${@}"; } + +public=/data/website-public +CHOWN=${CHOWN:-dtuuser:dtugroup} + +log "RUNNING WEBSITE SERVER AS $(whoami) (${CHOWN})" + +log "RUNNING WEBSITE IN TIMEZONE ${TZ}" + +log "STARTING SERVER FOR STARTUP MESSAGE" + +export PORT=3000 +indexpage=_rails_starting.html bundle exec thin -R ./maintenance.ru -p ${PORT} start & + +ruby -v | grep "2\.5\.1" +if [[ $? != 0 ]]; then + echo "Wrong version of Ruby installed!" + ruby -v + exit ${?}; +fi + +RAILS_ENV=${RAILS_ENV:="development"} +export RAILS_ENV + +sleep 5 +jobs +curl http://localhost:${PORT} + +# generate a new secret key on every startup +SECRET_KEY_BASE=${SECRET_KEY_BASE:=`cat ~/secret-key-base.txt`} +export SECRET_KEY_BASE=${SECRET_KEY_BASE} + +log "REMOVING TMP" + +rm -rf tmp/* +rm -rf ${APP_ROOT}/log/* +mkdir -p ${APP_ROOT}/log/ + +log "LINKING SHARED ASSETS AND LOG FILES" + +# gross! https://github.com/docker/docker/issues/2259 +sudo chown -R ${CHOWN} /data/* + +sshdir=/home/$(whoami)/.ssh +[[ -d ${sshdir} ]] || mkdir ${sshdir} +sudo sh -c "cp /get-pdf-keys/* ${sshdir} && chown -R ${CHOWN} ${sshdir}/*" +sudo chmod 0600 ${sshdir}/* + +log "COPYING PRECOMPILED APP ASSETS" + +# make these available for nginx to serve statically +cp -R ./public/* ${public} + +echo "<html><body>NGINX -- NOT RAILS</body></html>" > ${public}/nginx-text.html +echo "<html><body>NGINX -- NOT RAILS</body></html>" > ${public}/images/nginx-text.html +echo "<html><body>NGINX -- NOT RAILS</body></html>" > ${public}/assets/nginx-text.html + +mkdir -p ${public}/assets/pdfjs-viewer +cp -R deps/pdfjs/build/generic/web/* ${public}/assets/pdfjs-viewer/ +cp -R deps/pdfjs/build/generic/web ${public}/assets/pdfjs-viewer/ +cp -R deps/pdfjs/build/generic/build ${public}/assets/pdfjs-viewer/ + +log "FLUSHING REDIS SOFT-STATE CACHE" + +redis-cli -h redis -n 1 flushdb + +# echo [$(timestamp)] COMPILE PAGES TO STATIC ASSETS + +# bundle exec rake update:all + +echo [$(timestamp)] DONE PRECOMPILING ASSETS + +log "MIGRATING DB" + +bundle exec rake db:migrate + +log "KILLING SERVER FOR STARTUP MESSAGE" + +kill $(jobs -p) +wait + +log "STARTING RAILS WITH RAILS_ENV=${RAILS_ENV}" + +foreman start + +log "RAILS DIED!" + +log "STARTING SERVER FOR FAIL MESSAGE" +indexpage=_rails_failed.html bundle exec thin -R ./maintenance.ru -p ${PORT} start + +log "WAITING FOREVER SO CONTAINER STAYS ACTIVE FOR DEBUGGING" +tail -F -n0 /etc/hosts + diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh new file mode 100755 index 0000000000000000000000000000000000000000..5d8f7ea771a1a8abad5b5644260e0354ec6a23f1 --- /dev/null +++ b/scripts/run-tests.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +test_arg=${1:-spec} +shift + +export RAILS_ENV=test +export PRECOMPILE=1 +export DTU_DATA_ROOT=spec/files/data + +bundle exec rake db:migrate +bin/rails webpacker:compile +bundle exec rspec ${test_arg} $@ + diff --git a/spec/controllers/admin/admin_controller_spec.rb b/spec/controllers/admin/admin_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..5fc48b88b3d3e35cbd01b31ca7207c93edf70bce --- /dev/null +++ b/spec/controllers/admin/admin_controller_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'fakefs/safe' +require 'fakefs/spec_helpers' + +RSpec.describe Admin::AdminPagesController, type: :controller do + describe 'GET #index' do + DTUAuth2.populate Rails.root.join('spec', 'files', 'config').to_s, Rails.root.join('spec', 'files', 'user_config').to_s + admin_user = DTUAuth2::CachedAuthorizationManager.user_by_id('testadmin') + author_user = DTUAuth2::CachedAuthorizationManager.user_by_id('testauthor') + student_user = DTUAuth2::CachedAuthorizationManager.user_by_id('teststudent') + + before(:each) do + DTUAuth2.populate Rails.root.join('spec', 'files', 'config').to_s, Rails.root.join('spec', 'files', 'user_config').to_s + end + + # it "returns http success for admin" do + # subject.send(:log_in, admin_user) + + # allow(DTUFileManagement::FileManager.instance).to receive(:uploads_folder).and_return("./spec/files/uploads") + + # get :index, params: {:course_id => @test_course_id } + # expect(response).to have_http_status(:ok) + # end + + it 'returns http success for author' do + subject.send(:log_in, author_user) + + get :index, params: { course_id: @test_course_id } + # expect(response).to have_http_status(:ok) + expect(subject).to redirect_to(course_home_url) + end + + it 'returns redirect to home for student' do + subject.send(:log_in, student_user) + + get :index, params: { course_id: @test_course_id } + expect(subject).to redirect_to(course_home_url) + end + + it 'returns redirect success for no logged in user' do + subject.send(:log_out) + get :index, params: { course_id: @test_course_id } + expect(response).to have_http_status(:redirect) + expect(subject).to redirect_to(DtuCoreApp::Engine.routes.url_helpers.login_path) + end + end + +end diff --git a/spec/controllers/admin/admin_enotes_controller_spec.rb b/spec/controllers/admin/admin_enotes_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..2ecf4b8f0f388234c8b86e0d44038ac02c07bf66 --- /dev/null +++ b/spec/controllers/admin/admin_enotes_controller_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'fakefs/safe' +require 'fakefs/spec_helpers' + +RSpec.describe Admin::AdminEnotesController, type: :controller do + describe 'GET #publish_enotes' do + config_path = Rails.root.join('spec', 'files', 'config').to_s + user_config_path = Rails.root.join('spec', 'files', 'user_config').to_s + DTUAuth2.populate config_path, user_config_path + admin_user = DTUAuth2::CachedAuthorizationManager.user_by_id('testadmin') + # author_user = DTUAuth2::CachedAuthorizationManager.user_by_id('testauthor') + # student_user = DTUAuth2::CachedAuthorizationManager.user_by_id('teststudent') + + before(:each) do + config_path = Rails.root.join('spec', 'files', 'config').to_s + user_config_path = Rails.root.join('spec', 'files', 'user_config').to_s + DTUAuth2.populate config_path, user_config_path + end + + it 'returns redirect to home for student' do + subject.send(:log_in, admin_user) + # get :publish_enotes, params: { course_id: @test_course_id, format: :json } + # expect(response).to have_http_status(:ok) + # + # Enotes.instance.get(@test_course_id) + # EnotesStaging.instance.get(@test_course_id) + FakeFS do + # these 3: + # https://github.com/fakefs/fakefs/issues/136 + FakeFS::FileSystem.clone(File.join(Rails.root, 'app', 'models')) + FakeFS::FileSystem.clone(File.join(Rails.root, 'app', 'views')) + FakeFS::FileSystem.clone(File.join(Rails.root, 'app', 'services')) + content_path = File.join(Rails.root, 'spec', 'files', 'content', @test_course_id) + FakeFS::FileSystem.clone(File.join(Rails.root, 'spec', 'files')) + staging_files_before = Dir.glob(File.join(content_path, 'sharelatex-private', '**/*')) + + get :publish_enotes, params: { course_id: @test_course_id, format: :json } + + expect(response).to have_http_status(:ok) + staging_files_after = Dir.glob(File.join(content_path, 'sharelatex-private', '**/*')) + published_files_after = Dir.glob(File.join(content_path, 'sharelatex-public', '**/*')) + expect(staging_files_after).to eq([]) + basename_compare = ->(file) { File.basename(file) } + expect(published_files_after.map(&basename_compare)).to eq(staging_files_before.map(&basename_compare)) + end + end + end +end diff --git a/spec/controllers/enotes_controller_spec.rb b/spec/controllers/enotes_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..1ba52f00e7d9a6859b8c9fab6b5f9d57f0e281b5 --- /dev/null +++ b/spec/controllers/enotes_controller_spec.rb @@ -0,0 +1,25 @@ +require 'rails_helper' + +RSpec.describe EnotesController, type: :controller do + + describe 'GET #index' do + render_views + it 'returns http success index' do + get :index, params: { course_id: @test_course_id, format: :json } + expect(response).to have_http_status(:success) + response_wrapper = JSON.parse(response.body) + response_object = JSON.parse(response_wrapper['json']) + expect(response_object).to have_key('enotes') + expect(response_object['enotes']).to eq(["01-Talrum"]) + end + + it 'returns http success index on staging' do + get :index, params: { course_id: @test_course_id, format: :json, kind: 'staging' } + expect(response).to have_http_status(:success) + response_wrapper = JSON.parse(response.body) + response_object = JSON.parse(response_wrapper['json']) + expect(response_object).to have_key('enotes') + expect(response_object['enotes']).to eq(["01-Talrum-staging"]) + end + end +end diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..338c3f62e2648ec84c888e27cae43ba487608fe5 --- /dev/null +++ b/spec/controllers/home_controller_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe MdSinglePageController, type: :controller do + def page_params + { course_id: @test_course_id, page: 'Frontpage' } + end + + describe 'GET #index' do + it 'returns http success' do + get :show, params: page_params + expect(response).to have_http_status(:success) + end + end + + describe 'GET #index shows the admin menu' do + render_views + + admin_user = DTUAuth2::CachedAuthorizationManager.user_by_id('testadmin') + author_user = DTUAuth2::CachedAuthorizationManager.user_by_id('testauthor') + student_user = DTUAuth2::CachedAuthorizationManager.user_by_id('teststudent') + + before(:each) do + DTUAuth2.populate Rails.root.join('spec', 'files', 'config').to_s, Rails.root.join('spec', 'files', 'user_config').to_s + end + + it 'shows the admin menu item if the user is an admin' do + subject.send(:log_in, admin_user) + get :show, params: page_params + expect(response.body).to have_tag(:a, text: 'Admin', href: '/admin') + end + + it 'shows no admin menu item if the user is a student' do + subject.send(:log_in, student_user) + get :show, params: page_params + expect(response.body).to_not have_tag(:a, text: 'Admin', href: '/admin') + end + + it 'shows no admin menu item if the user is a author' do + subject.send(:log_in, author_user) + get :show, params: page_params + expect(response.body).to_not have_tag(:a, text: 'Admin', href: '/admin') + end + end +end diff --git a/spec/controllers/md_single_page_controller_spec.rb b/spec/controllers/md_single_page_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..01c9e7e94b5372ed21a06921ca1e7955079821e8 --- /dev/null +++ b/spec/controllers/md_single_page_controller_spec.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'pp' # https://devhub.io/zh/repos/fakefs-fakefs +require 'fakefs/safe' +require 'fakefs/spec_helpers' +require 'markdown_service' + +RSpec.describe MdSinglePageController, type: :controller do + files = File.expand_path(File.join('../../files'), __FILE__) + pages_files = File.expand_path(File.join('../../files', 'basic_pages'), __FILE__) + + describe 'GET #show' do + render_views + it 'returns http success for non-existant page' do + get :show, params: { course_id: @test_course_id, page: 'Fake' } + expect(response).to have_http_status(:success) + expect(response.body).to include('Page \"Fake\" or \"Fake-right\" does not exist. Maybe update from the admin page?') + end + it 'returns http success existing page' do + ap "Outside FAKEFS: #{Webpacker.manifest.lookup('styles.css')}" + ap "Outside FAKEFS: #{Webpacker.manifest.lookup('styles.css')}" + FakeFS do + FakeFS::FileSystem.clone(pages_files) + FakeFS::FileSystem.clone(File.join(Rails.root, 'app/views')) # https://github.com/fakefs/fakefs/issues/136 + FakeFS::FileSystem.clone(File.join(Rails.root, 'spec/files')) + FakeFS::FileSystem.clone(File.join(Rails.root, 'public')) + FakeFS::FileSystem.clone(File.join(Rails.root, 'config')) + ap "In FAKEFS: #{Webpacker.manifest.ai}" + #ap "In FAKEFS: #{Webpacker.manifest.lookup('styles.css')}" + allow_any_instance_of(PagesService).to receive(:raw_md_folder).and_return(pages_files) + allow_any_instance_of(PagesService).to receive(:compiled_folder).and_return(pages_files) + get :show, params: { course_id: @test_course_id, page: 'TestPage', mode: 'view' } + expect(response).to have_http_status(:success) + expect(response).to render_template(:show) + expect(response.body).to include('Test file loaded successfully!') + end + end + end + + DTUAuth2.populate Rails.root.join('spec', 'files', 'config').to_s, Rails.root.join('spec', 'files', 'user_config').to_s + admin_user = DTUAuth2::CachedAuthorizationManager.user_by_id('testadmin') + author_user = DTUAuth2::CachedAuthorizationManager.user_by_id('testauthor') + student_user = DTUAuth2::CachedAuthorizationManager.user_by_id('teststudent') + + describe 'GET #show with edit' do + render_views + + before(:each) do + DTUAuth2.populate Rails.root.join('spec', 'files', 'config').to_s, Rails.root.join('spec', 'files', 'user_config').to_s + allow_any_instance_of(PagesService).to receive(:raw_md_folder).and_return(pages_files) + allow_any_instance_of(PagesService).to receive(:compiled_folder).and_return(pages_files) + end + + after(:all) do + FileUtils.rm Dir.glob(File.join(pages_files, '*.lock')) + end + + it "shows error page if you're not logged in" do + get :show, params: { course_id: @test_course_id, page: 'TestPage', mode: 'edit' } + expect(response).to have_http_status(:success) + expect(response).to render_template(:edit) + expect(response.body).to include('You cannot edit this page. You must be logged in to edit.') + end + + it 'allows an admin to edit' do + # note: ideally we'd use the fakeFS here to prevent permanent alterations to our test files, + # but it messes up the view files. + # FakeFS do + # FakeFS::FileSystem.clone(files) + subject.send(:log_in, admin_user) + get :show, params: { course_id: @test_course_id, page: 'TestPage', mode: 'edit' } + expect(response).to have_http_status(:success) + expect(response).to render_template(:edit) + expect(response.body).to include('Test file loaded successfully!') + # end + end + + it 'shows an error if another user tries to edit a locked file' do + # FakeFS do + # FakeFS::FileSystem.clone(files) + subject.send(:log_in, author_user) + get :show, params: { course_id: @test_course_id, page: 'TestPage', mode: 'edit' } + expect(response).to have_http_status(:success) + expect(response).to render_template(:edit_locked) + expect(response.body).to include('You cannot edit this page, it is locked by testadmin.') + # end + end + + it 'shows an error if a student tries to edit' do + # FakeFS do + # FakeFS::FileSystem.clone(files) + FileUtils.rm File.join(pages_files, 'TestPage.md.lock') + subject.send(:log_in, student_user) + get :show, params: { course_id: @test_course_id, page: 'TestPage', mode: 'edit' } + expect(response).to have_http_status(:success) + expect(response.body).to include('You cannot edit this page. You must be an author or an administrator to edits') + # end + end + + it 'allows an author to edit' do + subject.send(:log_in, author_user) + get :show, params: { course_id: @test_course_id, page: 'TestPage', mode: 'edit' } + expect(response).to have_http_status(:success) + expect(response).to render_template(:edit) + expect(response.body).to include('Test file loaded successfully!') + end + end +end diff --git a/spec/controllers/pages_controller_spec.rb b/spec/controllers/pages_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..9aa4f63f6ea629a4a4e2bbba7544cabfb668fc6a --- /dev/null +++ b/spec/controllers/pages_controller_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe PagesController, type: :controller do + files = File.expand_path(File.join('../../files'), __FILE__) + pages_files = File.expand_path(File.join('../../files', 'basic_pages'), __FILE__) + + describe 'GET #index' do + render_views + it 'returns http success index' do + allow_any_instance_of(WebsiteCourseConfig).to receive(:pages_source_path).and_return(pages_files) + allow_any_instance_of(WebsiteCourseConfig).to receive(:pages_compiled_path).and_return(pages_files) + + Pages.refresh @test_course_id + + get :index, params: { course_id: @test_course_id, format: :json } + expect(response).to have_http_status(:success) + response_wrapper = JSON.parse(response.body) + response_object = JSON.parse(response_wrapper['json']) + ap response_object + expect(response_object).to have_key('valid_page_names') + expect(response_object['valid_page_names']).to eq(['TestPage']) + end + end +end diff --git a/spec/files/basic_pages/TestPage.md b/spec/files/basic_pages/TestPage.md new file mode 100644 index 0000000000000000000000000000000000000000..ca8f32bea47a75b8c46491fdf3d93303148f0ce4 --- /dev/null +++ b/spec/files/basic_pages/TestPage.md @@ -0,0 +1 @@ +Test file loaded successfully! \ No newline at end of file diff --git a/spec/files/config/couchdb.yaml b/spec/files/config/couchdb.yaml new file mode 100644 index 0000000000000000000000000000000000000000..946fd2fe63ddc701548b31a50b512845d5012dbd --- /dev/null +++ b/spec/files/config/couchdb.yaml @@ -0,0 +1,8 @@ +'_admin': + db: https://dtuadmin:Aevee7Le@couchdb.docker.local +'00000': + db: https://user00000:Die2Imae@couchdb.docker.local/db00000 +'01005': + db: https://user01005:uloh2ieH@couchdb.docker.local/db01005 +'02402': + db: https://user02402:Meil8sha@couchdb.docker.local/db02402 diff --git a/spec/files/config/courses.yaml b/spec/files/config/courses.yaml new file mode 100644 index 0000000000000000000000000000000000000000..15864b339dd4307e1c970740e32d65fbd200ae5b --- /dev/null +++ b/spec/files/config/courses.yaml @@ -0,0 +1,9 @@ +'00000': + name: Test zero + branch: local_test + members: 00000-users.yaml + groups: 00000-groups.yaml + website_enabled: true + askbot_enabled: true + sharelatex_enabled: false + diff --git a/spec/files/config/sharelatex.yaml b/spec/files/config/sharelatex.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8ed86094005d1f49549b94f9c8cfd65c7ca4f70a --- /dev/null +++ b/spec/files/config/sharelatex.yaml @@ -0,0 +1,20 @@ +'00000': + host: sharelatex-00000 + username: test@dtu.dk + password: test@dtu.dk + enote_project_id: 579b4ec056432e5b00742d93 +'01005': + host: sharelatex-01005 + username: test@dtu.dk + password: test@dtu.dk + enote_project_id: 579b4ec056432e5b00742d93 +'01006': + host: sharelatex-01006 + username: test@dtu.dk + password: test@dtu.dk + enote_project_id: 579b4ec056432e5b00742d93 +'02402': + host: sharelatex-02402 + username: test@dtu.dk + password: test@dtu.dk + enote_project_id: 579b4ec056432e5b00742d93 diff --git a/spec/files/config/website-00000-content.yaml b/spec/files/config/website-00000-content.yaml new file mode 100644 index 0000000000000000000000000000000000000000..62948b9d6736da6340884f229d8e02b9c65a8bba --- /dev/null +++ b/spec/files/config/website-00000-content.yaml @@ -0,0 +1,3 @@ +--- +mode: editor +last_commit: diff --git a/spec/files/config/website.yaml b/spec/files/config/website.yaml new file mode 100644 index 0000000000000000000000000000000000000000..798eda9be85f0eaf8b6622967df761db4a80dae7 --- /dev/null +++ b/spec/files/config/website.yaml @@ -0,0 +1,8 @@ +getpdf-server-url: http://get-pdf:8080 +quiz-url: http://quiz.test +courses: + '00000': + files-repo: git@github.com:dtu-compute/00000-files.git + pages-repo: git@github.com:dtu-compute/00000-pages.git + branch: local_test + course_external_url: http://0000.test diff --git a/spec/files/content/00000/sharelatex-private/01-Talrum-staging.pdf b/spec/files/content/00000/sharelatex-private/01-Talrum-staging.pdf new file mode 100644 index 0000000000000000000000000000000000000000..45d333c7c857ba4fe00089e9a54704ea111b3e88 Binary files /dev/null and b/spec/files/content/00000/sharelatex-private/01-Talrum-staging.pdf differ diff --git a/spec/files/content/00000/sharelatex-public/01-Talrum.pdf b/spec/files/content/00000/sharelatex-public/01-Talrum.pdf new file mode 100644 index 0000000000000000000000000000000000000000..45d333c7c857ba4fe00089e9a54704ea111b3e88 Binary files /dev/null and b/spec/files/content/00000/sharelatex-public/01-Talrum.pdf differ diff --git a/spec/files/content/00000/uploads/foo.txt b/spec/files/content/00000/uploads/foo.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c6ded14ecffa0341f8dc68fb674d4ae26d34644 --- /dev/null +++ b/spec/files/content/00000/uploads/foo.txt @@ -0,0 +1 @@ +foo.txt diff --git a/spec/files/menu/simple.md b/spec/files/menu/simple.md new file mode 100644 index 0000000000000000000000000000000000000000..75998580ab4a0d74450774ab8f3f8028d6bdd781 --- /dev/null +++ b/spec/files/menu/simple.md @@ -0,0 +1,5 @@ +Agendas, Agendas +Book, eNotes/ +Course Material, Material +Podcast, podcast +Quiz, https://quiz.compute.dtu.dk/ diff --git a/spec/files/pages_service/00000/Agendas.md b/spec/files/pages_service/00000/Agendas.md new file mode 100644 index 0000000000000000000000000000000000000000..0807ef927c0d063651f8a0295d2278ae729bc20c --- /dev/null +++ b/spec/files/pages_service/00000/Agendas.md @@ -0,0 +1,7 @@ +# Agendas + +## Bug 72 + +[test](Invalid_INTERNAL_LINK) +[valid link to bug page](bug67) + diff --git a/spec/files/pages_service/00000/Frontpage-left.md b/spec/files/pages_service/00000/Frontpage-left.md new file mode 100644 index 0000000000000000000000000000000000000000..d10490e0448a78fc80a66b60bbfe1d6efcefc39e --- /dev/null +++ b/spec/files/pages_service/00000/Frontpage-left.md @@ -0,0 +1,24 @@ +#### Alle Mat1 eNoter + +Du kan nu pÃ¥ kursets fildeling (CN) hente en samlet pdf med alle Mat1-eNoterne. Fortsat god fornøjelse med eksamenslæsningen + +#### Projektarbejde mv. +Starter for alvor efter pÃ¥ske, vi ønsker god fornøjelse! Hvis du fÃ¥r tid, er du velkommen til at kigge forbi Hjemmeopgavesæt 8 og Pensumlisten som er klar pÃ¥ dagsordensoversigten. + +#### Mat1-projektet +PÃ¥ Store Dag i semuge 4 giver klasselæreren første orientering om forÃ¥rets projektarbejde. Deadline for tilmelding er Store Dag i semuge 5, kl. 16. + +#### Hjemmeopgavesæt 6 +Sæt 6 er i luften. Revideret 17/2, 14:10. God fornøjelse! + +#### Hjemmeopgavesæt 5 +Sæt 5 er i luften. Revideret 7/2, 9:30. God fornøjelse! + +#### Velkommen til forÃ¥rssemesteret! +Skema, lærere, lokaler, alt er som i E15. Men vi har masser af nyt, spændende mat1-stof: Funktioner af flere variable, integration og vektoranalyse! God fornøjelse med undervisningen og læringen! + +#### Skriv forklaringer i Maple! +I denne video kan du fÃ¥ nogle tips til hvordan man kan lave tekstbehandling i Maple med formler og forklaringer. + +#### At gÃ¥ pÃ¥ to ben +I uge 5 starter introduktionen til Maple. Fremover skal du gÃ¥ pÃ¥ to ben: Du skal fortsat beherske hvert enkelt step i metoder/beregninger. Og du skal kunne eksperimentere og visualisere ved hjælp af Maple. Sæt dig hurtigt ind i Maple's editeringsfaciliteter sÃ¥ du kan dokumentere/forklare alt hvad du foretager dig i dine Maple-ark. diff --git a/spec/files/pages_service/00000/Frontpage-right.md b/spec/files/pages_service/00000/Frontpage-right.md new file mode 100644 index 0000000000000000000000000000000000000000..d535c3d292e90f5c72e6e6b9e9aeca3587ebf874 --- /dev/null +++ b/spec/files/pages_service/00000/Frontpage-right.md @@ -0,0 +1,35 @@ +# Velkommen til Matematik 1 ver. 2015-2016! +01005-Matematik 1 er et obligatorisk helÃ¥rskursus for alle civilingeniørstuderende. Denne hjemmeside indeholder de væsentligste oplysninger om kursets indhold og opbygning, og den opdateres løbende, sÃ¥ hold godt øje med den. NÃ¥r du skal bruge hjemmesidens daglige undervisningsaktiviteter, skal du først logge pÃ¥ med dit sædvanlige DTU login. + +## table example + +| Tables | Are | Cool | +| ------------- |:-------------:| -----:| +| col 3 is | right-aligned | $1600 | +| col 2 is | centered | $12 | +| zebra stripes | are neat | $1 | + + +## Math + +Inline: $E=mc^2$ . + + +$$ x^n = y^n + z^n $$ + + +# Webbaseret undervisning +PÃ¥ Matematik 1 forsøger vi helhjertet at udnytte de muligheder for fornyelse af undervisningen, som it og nettet giver. Vi tror stadig at fremmøde, forelæsninger og gruppearbejde er helt afgørende bidrag til læring af matematik. Men vi ved ogsÃ¥ at kurset rummer 17 meget forskellige studieretninger, og at vores studerende ønsker at finde de arbejdsformer som passer bedst til hver enkelt. + +Dette ønsker vi at understøtte med en bred vifte af webbaserede læringsobjekter og aktiviteter. Derfor er traditionelle undervisningsmaterialer som lærebøger og trykte ugesedler erstattet af eNoter, video-instruktion og elektroniske opgaver, der udnytter link-teknologier og lægger op til en mindre lineær læringsstil. + +For at gøre undervisningen endnu bedre har vi brug for jeres reaktion og holdninger. Derfor vil undervisningen løbende blive evalueret. Giv venligst dit bidrag til forbedring af matematikundervisningen, sÃ¥dan at matematik kan blive et endnu vigtigere element i din og dine studiekammeraters udforskning af dit ingeniørfag og jeres verden. + +# Om matematikprogrammet Maple +Det professionelle program Maple er en vigtig del af undervisningen pÃ¥ Matematik 1! Det tages i brug efter det indledende 4-ugers kursus i komplekse tal. + +Om brug af it i matematik generelt: Vi mener stadig at matematik skal bygges op fra bunden, og at det er afgørende at du har sat dig grundigt ind i de metoder og mellemregninger der fører frem til de ønskede resultater. Men ligesÃ¥ vigtigt er det at fÃ¥ en oplevelse af hvad matematik kan bruges til i den virkelige verden, hvor komplicerede modeller og omfattende beregninger indgÃ¥r. + +Maple understøtter begge dele! Maple er et univers af muligheder for at dyrke matematik, bÃ¥de nÃ¥r det drejer sig om at forstÃ¥ de grundlæggende begreber, og nÃ¥r opgaven er at udforske aspekter af verden gennem visualiseringer, analytiske modeller og numeriske beregninger. + +Derfor er det vigtigt at du altid er opmærksom pÃ¥ hvordan du udnytter de muligheder Maple stiller til rÃ¥dighed. Hvad er læringsmÃ¥let for den aktivitet du er i gang med netop nu? Og hvilke Maple-kommandoer og stilarter understøtter bedst muligt dette mÃ¥l? diff --git a/spec/files/pages_service/00000/Information.md b/spec/files/pages_service/00000/Information.md new file mode 100644 index 0000000000000000000000000000000000000000..7d96b6024b603c2f0b164bb132d110f18a1ec981 --- /dev/null +++ b/spec/files/pages_service/00000/Information.md @@ -0,0 +1,58 @@ +# Kursets opbygning + +En kursusuge indeholder følgende elementer: En Stor Dag med forelæsning, fællestimer med klasselærer og selvstudium med konsulent, samt en Lille Dag med forelæsning, selvstudium og fællestime med klasselærer. Det er vigtigt, at deltager i alle disse aktiviteter, og det er dit udbytte heraf, der vil blive testet til prøverne. Du skal ogsÃ¥ pÃ¥regne hjemmearbejde. Hjemmeopgaverne er en del af karaktergrundlaget. + +Der er tre skema-varianter for kombinationen Store Dag + Lille Dag: + +### Skema A (BioTek, Design&Inn, Kemi, MedTek, TekBioMed, VandMiljø): + +Store Dag: Mandag 10:00-17:00 indeholder: +: Forelæsning 10:00-12:00. Selvstudium 12:30-13:00. Fællestimer med klasselærer 13.00-16.00. Selvstudium (med konsulent) 16:00-17:00. + +Lille Dag: Torsdag 8:00-12:00 indeholder: +: Forelæsning 8:00-10:00. Selvstudium 10:00-10:30. Fællestimer med klasselærer 10:30-12:00. + + + +### Skema B (BygTek, BygDesign, FysNan, GeoFys, ProdKon): + +Store Dag: Tirsdag 10:00-17:00 indeholder: +: Forelæsning 10:00-12:00. Selvstudium 12:30-13:00. Fællestimer med klasselærer 13.00-16.00. Selvstudium (med konsulent) 16:00 - 17:00. + +Lille Dag: Fredag 8:00-12:00 indeholder: +: Forelæsning 8:00-10:00. Selvstudium 10:00-10:30. Fællestimer med klasselærer 10:30-12:00. + + + +### Skema C (Elektro, MatTek, Netværk, Software, Strategisk analyse): + +Store Dag: Onsdag 10:00-17:00 indeholder: +: Forelæsning 10:00-12:00. Selvstudium 12:30-13:00. Fællestimer med klasselærer 13.00-16.00. Selvstudium (med konsulent) 16:00-17:00. + +Lille Dag: Fredag 13:00-17.00 indeholder: +: Forelæsning 13:00-15:00. Fællestime med klasselærer 15:00-16:30. Selvstudium 16:30-17:00. + + +# Undervisningen +Ved forelæsningerne bliver vigtige og centrale emner trukket frem og sat i perspektiv for kurset som helhed. Vær dog opmærksom pÃ¥, at hvad der har været gennemgÃ¥et ved forelæsningerne ikke definerer pensum i kurset. Der kan til prøverne blive stillet spørgsmÃ¥l i dele af pensum, som ikke nødvendigvis har været gennemgÃ¥et ved forelæsningerne. + +Store Dag starter med forelæsningen hvorefter der er gruppeøvelser. Bemærk at jeres klasselokale er til rÃ¥dighed allerede fra kl. 12:00. PÃ¥ dagsordnen (se senere) er der anført informationer og aktiviteter for dagen, herunder opgaver til regning dels med papir og blyant, dels med matematikprogrammet MAPLE. Brug selvstudiums-tiden 12:30-13:00 at orientere dig i dagsordnens udfordringer sÃ¥ du er klar til de efterfølgende fællestimer med klasselæreren. Her vil du og din gruppe, under vejledning af klasselæreren, arbejde videre med stoffet fra dagens forelæsning og øvelserne fra dagsordnen. NÃ¥r fællestimerne er slut har du timen 16:00-17:00 til at færdiggøre dagens arbejde, fx regne de opgaver fra dagsordnen, du ikke har nÃ¥et endnu, eller gÃ¥ i gang med hjemmeopgaverne. Dette er selvstudium, men to-tre af klasselærerne vil fungere som konsulent for hele skemagruppen SÃ¥ find og spørg konsulenten, hvis du har problemer. Du er ogsÃ¥ velkommen hos konsulenterne pÃ¥ de dage, hvor du ikke selv har fællestime. + +Lille dag starter med en forelæsning, hvorefter der er tid til selvstudium inden fællestimerne, hvor du og din gruppe i klasselokalet sammen med klasselæreren følger op pÃ¥ ugens emner samt regner opgaver. + +Dagsordnerne er kursets rygrad. De udgør et vigtigt middel i kommunikationen fra lærerne til dig. PÃ¥ dagsordnerne anføres mange centrale begreber i ugens pensum, og de indeholder introduktioner, eNoter, opgaver, aktiviteter og diskussionsoplæg til selvstudium og fællestimer. Desuden indeholder dagsordnerne information om hjemmeopgaver. + +Kurset giver 17.5 point og er normeret til 16 timers arbejde ugentligt. Derfor er det nødvendigt for dig at bruge tid hver uge pÃ¥ forberedelse og efterbehandling hjemme. + +# Projektbaserede øvelser +Flere gange i løbet af kurset afbrydes den sædvanlige undervisning af projekt forløb. + +ForÃ¥rets store projektopgave gennemføres i kalenderugerne 13, 14 og 15 (NB: Skemagruppe A har kick off torsdag d. 17. marts) og afsluttes med projektfremlæggelse og mundtlig eksamen pÃ¥ den efterfølgende Store Dag, i kalenderuge 16. Her skal du i en gruppe arbejde pÃ¥ en opgave, der med udgangspunkt i en ingeniørmæssig problemstilling benytter den matematik, du har lært i kurset. Der kommer flere praktiske oplysninger om projektperioderne senere. + +Alle studieretninger pÃ¥nær KemiTek og TekBioMed har det selvstændige kursus Temøvelser i Matematik 1, som tæller 2.5 ECTS point. Her fÃ¥r du lejlighed til at arbejde med mindre anvendelsesorienterede øvelser der hver udfolder et matematisk emne, straks efter det er gennemgÃ¥et pÃ¥ Matematik 1. +Materialer + +Undervisningsmaterialet til kurset bestÃ¥r af: dagsordnerne og de øvrige materialer pÃ¥ kursets hjemmeside, herunder eNoter, et bredt spektrum af opgaver, videoer af forskellig type, MapleDemo'er med videre. +Hjemmeopgaver + +Otte hjemmeopgavesæt fordeles med 4 pÃ¥ hvert semester. Hjemmeopgaver skal altid, uanset hvor meget forudgÃ¥ende gruppearbejde der evt. ligger bag løsningen, formuleres endeligt af dig selv, idet aflevering af enslydende besvarelser bliver betragtet som eksamenssnyd. diff --git a/spec/files/pages_service/00000/Material.md b/spec/files/pages_service/00000/Material.md new file mode 100644 index 0000000000000000000000000000000000000000..7d4359486ab7d2d2d2701996ef3de76b0d9082d9 --- /dev/null +++ b/spec/files/pages_service/00000/Material.md @@ -0,0 +1,18 @@ +# Material +Here I have just copied the eNotes page, as this page just contains a large table similar to the eNotes page. + +| Number | Title | Updated | +| -----: | :---------------------------------------| :------------ | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | + diff --git a/spec/files/pages_service/00000/Podcast-left.md b/spec/files/pages_service/00000/Podcast-left.md new file mode 100644 index 0000000000000000000000000000000000000000..d6be656ea7a4f143587daa60b516db995490ea7e --- /dev/null +++ b/spec/files/pages_service/00000/Podcast-left.md @@ -0,0 +1 @@ +podcast left test diff --git a/spec/files/pages_service/00000/Podcast.md b/spec/files/pages_service/00000/Podcast.md new file mode 100644 index 0000000000000000000000000000000000000000..ae3107b5aed5a6de774fc274f3f43b85e611b0bb --- /dev/null +++ b/spec/files/pages_service/00000/Podcast.md @@ -0,0 +1,9 @@ + +[google][http://google.com] + +[_Podcast link](http://podcast.llab.dtu.dk/feeds/02402-introduction-to-statistics-e15/?tx_enotepodcast_pi1[data]=true) +# First podcast link +[Podcast link](http://podcast.llab.dtu.dk/feeds/02402-introduction-to-statistics-e15/?tx_enotepodcast_pi1[data]=true) +[Podcast link](http://google.com) + +## SECOND podcast link diff --git a/spec/files/pages_service/00000/README.md b/spec/files/pages_service/00000/README.md new file mode 100644 index 0000000000000000000000000000000000000000..942e535661b50c00b9c70cfeb28d267faaeeb168 --- /dev/null +++ b/spec/files/pages_service/00000/README.md @@ -0,0 +1 @@ +# 00000-files \ No newline at end of file diff --git a/spec/files/pages_service/00000/bug60.md b/spec/files/pages_service/00000/bug60.md new file mode 100644 index 0000000000000000000000000000000000000000..291c146c46c6d01692f52c7fb92b1d880e19d1d9 --- /dev/null +++ b/spec/files/pages_service/00000/bug60.md @@ -0,0 +1,25 @@ +####### begin:only FakeGroun +Here is content that only students in the classes `A, B, biotek1` can see. +####### end:only + +#title + +[laalall][1] + +> ghghg + + 1. hjh + + +---------- + + +$e^{\pi i} = -1$ + +$$e^{ \pm i\theta } = \cos \theta \pm i\sin \theta$$ + +**klklk** + +####### begin:only A, B +only main +####### end:only diff --git a/spec/files/pages_service/00000/bug67.md b/spec/files/pages_service/00000/bug67.md new file mode 100644 index 0000000000000000000000000000000000000000..bad3a5e34246cfcfd81d75653161b9e32de5c26e --- /dev/null +++ b/spec/files/pages_service/00000/bug67.md @@ -0,0 +1,23 @@ +#Exercise 1 Approximating Polynomials + + +a) Maple-opgave: +Use Maple to find the approximating polynomial of degree 9, $P_9(x)$ with the development point $x_0 = 0$ for the function $\sin(x)$. Draw in the same coordinate system $\sin(x)$ and $P_9(x)$. How far out can you make the approximating poynomial follow the function? (Experiment wit the degree of the polynomial). +####### begin:answer +The higher the degree of the approximating polynomial the larger the interval around $x_0 = 0$ there will be agreement between $\sin(x)$ and the appoximating poynomial $P_9(x)$. One can make the approximating poynomial $P_9(x)$ follow $\sin(x)$ as long as you like, because $\sin(x)$ is analytic for all $x$. For $n = 17$ it agrees with $\sin(x)$ in the interval $[-2\pi;2\pi]$ and for $n = 25$it is even better. +####### end:answer + +b) Exercise by hand followed by a maple plot: +Find for every of the following functions their approximating poynomials of first and second degree with the development point $x_0 = 0$ and plot each of the functions together with the two approximating polynomials found: + +1. $f(x) = e^x$, +2. $f(x) = \cos(x)$, +3. $f(x) = e^{\sin(x)}$, +4. $f(x) = \cosh(x)$. + +####### begin:answer +1. $P_1(x) = 1+x$ and $P_2(x) = 1+x+\frac{1}{2}x^2$, +2. $P_1(x) = 1$ and $P_2(x) = 1-\frac{1}{2}x^2$, +3. $P_1(x) = 1+x$ and $P_2(x) = 1+x+\frac{1}{2}x^2$, +4. $P_1(x) = 1$ and $P_2(x) = 1+\frac{1}{2}x^2$. +####### end:answer \ No newline at end of file diff --git a/spec/files/pages_service/00000/bug67_2.md b/spec/files/pages_service/00000/bug67_2.md new file mode 100644 index 0000000000000000000000000000000000000000..8f7a3aaed64bfa74ff43f72722aea65b0d5ee819 --- /dev/null +++ b/spec/files/pages_service/00000/bug67_2.md @@ -0,0 +1,33 @@ +#Exercise 1 Approximating Polynomials + + +a) Maple-opgave: +Use Maple to find the approximating polynomial of degree 9, $P_9(x)$ with the development point $x_0 = 0$ for the function $\sin(x)$. Draw in the same coordinate system $\sin(x)$ and $P_9(x)$. How far out can you make the approximating poynomial follow the function? (Experiment wit the degree of the polynomial). +####### begin:answer +The higher the degree of the approximating polynomial the larger the interval around $x_0 = 0$ there will be agreement between $\sin(x)$ and the appoximating poynomial $P_9(x)$. One can make the approximating poynomial $P_9(x)$ follow $\sin(x)$ as long as you like, because $\sin(x)$ is analytic for all $x$. For $n = 17$ it agrees with $\sin(x)$ in the interval $[-2\pi;2\pi]$ and for $n = 25$it is even better. +####### end:answer + +--- + + +b) Exercise by hand followed by a maple plot: +Find for every of the following functions their approximating poynomials of first and second degree with the development point $x_0 = 0$ and plot each of the functions together with the two approximating polynomials found: + +1. $f(x) = e^x$, +2. $f(x) = \cos(x)$, +3. $f(x) = e^{\sin(x)}$, +4. $f(x) = \cosh(x)$. + +####### begin:answer + +## answer? + +1. $P_1(x) = 1+x$ and $P_2(x) = 1+x+\frac{1}{2}x^2$, + +2. $P_1(x) = 1$ and $P_2(x) = 1-\frac{1}{2}x^2$, + +3. $P_1(x) = 1+x$ and $P_2(x) = 1+x+\frac{1}{2}x^2$, + +4. $P_1(x) = 1$ and $P_2(x) = 1+\frac{1}{2}x^2$. + +####### end:answer diff --git a/spec/files/pages_service/00000/eNotes.md b/spec/files/pages_service/00000/eNotes.md new file mode 100644 index 0000000000000000000000000000000000000000..815e99a41cce4c09047d2ad12314697c70226e26 --- /dev/null +++ b/spec/files/pages_service/00000/eNotes.md @@ -0,0 +1,16 @@ +# eNotes + +| Number | Title | Updated | +| -----: | :---------------------------------------| :------------ | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | +| 1 | [Taylor 1 variable Funktioner 2 variable](https://google.com) | 9. august 2015 | diff --git a/spec/files/pages_service/00000/exercise1.md b/spec/files/pages_service/00000/exercise1.md new file mode 100644 index 0000000000000000000000000000000000000000..31b0a7d88b75a7b2b889b80629f851fa7468f3a3 --- /dev/null +++ b/spec/files/pages_service/00000/exercise1.md @@ -0,0 +1,8 @@ +## Outer + +####### begin:question + +## Exercise 1 + +####### end:question + diff --git a/spec/files/pages_service/00000/macros.tex b/spec/files/pages_service/00000/macros.tex new file mode 100644 index 0000000000000000000000000000000000000000..8ccafb210a2d79746acc7ac06ed509f8e87ddf4c --- /dev/null +++ b/spec/files/pages_service/00000/macros.tex @@ -0,0 +1,3 @@ +test + + diff --git a/spec/files/podcasts/bug_172.json b/spec/files/podcasts/bug_172.json new file mode 100644 index 0000000000000000000000000000000000000000..d592e658ebea83ccf54c6f006226fe4d98d525e5 --- /dev/null +++ b/spec/files/podcasts/bug_172.json @@ -0,0 +1,2564 @@ +{ + "metadata": { + "title": "27411 Biological data analysis and chemometrics", + "TYPO3_SITE_URL": "http:\/\/podcast.llab.dtu.dk\/", + "copyright": "DTU 2015", + "description": "", + "subtitle": "", + "author": "Technical University of Denmark", + "author_email": "kaska@llab.dtu.dk", + "image": "", + "category": "Education", + "language": "en" + }, + "feeds": { + "HD": { + "version": "720p", + "label": "HD" + } + }, + "episodes": [ + { + "uniqueHash": "ea0e328505fbf41e77164503056c76a2", + "description": "Lecture by Jens Chr. Frisvad on Cluster Analysis.", + "pubDate": 1431438300, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Cluster Analysis", + "startOffset": "{0}", + "hits": "134", + "bandwidth": "72072913301", + "hits-480p": "39", + "bandwidth-480p": "4105385252", + "hitspartial": "713", + "hitspartial-480p": "61", + "hits-720p": "134", + "hitspartial-720p": "713", + "bandwidth-720p": "72072913301", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/ClusterAnalysis-20150512154502-720p.mp4", + "extension": "mp4", + "filesize": "206811318", + "_lastWrite": 903, + "mimetype": "video\/mp4", + "duration": "00:23:42", + "avgBitrate": "1.16 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0f86399227.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/029fcdcfba.jpg" + } + ] + } + }, + { + "uniqueHash": "58469b35fedf6d8565a6304e5b33e415", + "description": "Correspondence analysis_lecture for DTU course 27411", + "pubDate": 1425484560, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Correspondence analysis_chemometrics", + "startOffset": "{0}", + "hits": "155", + "hits-720p": "155", + "hitspartial-720p": "822", + "bandwidth": "105060542582", + "hitspartial": "822", + "bandwidth-720p": "105060542582", + "hits-480p": "52", + "bandwidth-480p": "7152001404", + "hitspartial-480p": "94", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Correspondenceanalysischemometrics-20150304165602-720p.mp4", + "extension": "mp4", + "filesize": "227730411", + "_lastWrite": 954, + "mimetype": "video\/mp4", + "duration": "00:26:03", + "avgBitrate": "1.16 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9b6a7b1b90.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8675e12f85.jpg" + } + ] + } + }, + { + "uniqueHash": "be63a15a98ec2c353947b8d16b03f144", + "description": "And practical information.", + "pubDate": 1422888120, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1A: Course welcome.", + "startOffset": "{0}", + "hits": "145", + "hits-720p": "145", + "hitspartial-720p": "281", + "bandwidth": "8703279431", + "hitspartial": "281", + "bandwidth-720p": "8703279431", + "hits-480p": "48", + "bandwidth-480p": "1609969693", + "hitspartial-480p": "57", + "media": { + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/673ba28592.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8af7ccae51.jpg" + } + ] + } + }, + { + "uniqueHash": "4b99c3ab2bdc2881214838a06ebb1cfc", + "description": "By Jens Chr. Frisvad", + "pubDate": 1422888180, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1B: Introduction to Chemometrics, part 1", + "startOffset": "{0}", + "hits": "158", + "hits-720p": "158", + "hitspartial-720p": "367", + "bandwidth": "14495252622", + "hitspartial": "367", + "bandwidth-720p": "14495252622", + "hits-480p": "66", + "bandwidth-480p": "3134479393", + "hitspartial-480p": "82", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1BIntroductiontoChemometricspart1-20150202154301-720p.mp4", + "extension": "mp4", + "filesize": "52356783", + "_lastWrite": 1580, + "mimetype": "video\/mp4", + "duration": "00:20:10", + "avgBitrate": "341 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/7f481f251d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/a8b2d1c230.jpg" + } + ] + } + }, + { + "uniqueHash": "a0e45343fbcd81568c7027da1297f629", + "description": "By Jens Chr. Frisvad", + "pubDate": 1422888240, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec1C: Introduction to Chemometrics, part 2", + "startOffset": "{0}", + "hits": "147", + "hits-720p": "147", + "hitspartial-720p": "260", + "bandwidth": "11136556544", + "hitspartial": "260", + "bandwidth-720p": "11136556544", + "hits-480p": "44", + "bandwidth-480p": "1580301979", + "hitspartial-480p": "9", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1CIntroductiontoChemometricspart2-20150202154401-720p.mp4", + "extension": "mp4", + "filesize": "46551226", + "_lastWrite": 1458, + "mimetype": "video\/mp4", + "duration": "00:18:01", + "avgBitrate": "340 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/4435d5739e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/b5dc05d4fe.jpg" + } + ] + } + }, + { + "uniqueHash": "c98a22137a02822fd6dd029a0e1d7de6", + "description": "PBB example of Sensory (and other) data on frozen peas.", + "pubDate": 1422888840, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1D: Food example.", + "startOffset": "{0}", + "hits": "139", + "hits-720p": "139", + "hitspartial-720p": "216", + "bandwidth": "6400541407", + "hitspartial": "216", + "bandwidth-720p": "6400541407", + "hits-480p": "50", + "bandwidth-480p": "1182512171", + "hitspartial-480p": "13", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1DFoodexample-20150202155401-720p.mp4", + "extension": "mp4", + "filesize": "28577837", + "_lastWrite": 1627, + "mimetype": "video\/mp4", + "duration": "00:12:01", + "avgBitrate": "312 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/31044b64b3.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c360258441.jpg" + } + ] + } + }, + { + "uniqueHash": "0944e25bc6c700bb6ff33233b82bb622", + "description": "Permeability discrimination of drug candidates.", + "pubDate": 1422889020, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1E: QSAR example", + "startOffset": "{0}", + "hits": "123", + "hits-720p": "123", + "hitspartial-720p": "152", + "bandwidth": "5212100402", + "hitspartial": "152", + "bandwidth-720p": "5212100402", + "hits-480p": "42", + "bandwidth-480p": "847260960", + "hitspartial-480p": "6", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1EQSARexample-20150202155701-720p.mp4", + "extension": "mp4", + "filesize": "29465717", + "_lastWrite": 817, + "mimetype": "video\/mp4", + "duration": "00:08:26", + "avgBitrate": "461 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/819fbd948f.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/619523d1bc.jpg" + } + ] + } + }, + { + "uniqueHash": "9898df38e40862e25d86d6e01422c6f1", + "description": "Link between multivariate data and simple correlations.", + "pubDate": 1422889200, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec1G: Correlation and covariance", + "startOffset": "{0}", + "hits": "139", + "hits-720p": "139", + "hitspartial-720p": "209", + "bandwidth": "5583763254", + "hitspartial": "209", + "bandwidth-720p": "5583763254", + "hits-480p": "47", + "bandwidth-480p": "1075803865", + "hitspartial-480p": "19", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1GCorrelationandcovariance-20150202160001-720p.mp4", + "extension": "mp4", + "filesize": "26633616", + "_lastWrite": 585, + "mimetype": "video\/mp4", + "duration": "00:10:49", + "avgBitrate": "324 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d152d2b9d6.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/fe5968e5e8.jpg" + } + ] + } + }, + { + "uniqueHash": "5e9bab8dae7a4aa1a3786c9b3c05a5d9", + "description": "A little recap of linear algebra(matrices).", + "pubDate": 1422889080, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1F: Lattin Chapter2", + "startOffset": "{0}", + "hits": "131", + "hits-720p": "131", + "hitspartial-720p": "221", + "bandwidth": "11497894298", + "hitspartial": "221", + "bandwidth-720p": "11497894298", + "hits-480p": "46", + "bandwidth-480p": "1811561711", + "hitspartial-480p": "11", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1FLattinChapter2-20150202155801-720p.mp4", + "extension": "mp4", + "filesize": "52304113", + "_lastWrite": 335, + "mimetype": "video\/mp4", + "duration": "00:17:31", + "avgBitrate": "393 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/dcaf77d06c.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/f335ec53a6.jpg" + } + ] + } + }, + { + "uniqueHash": "88a5849c9ac0d8e4a5ae0dee1376dc6c", + "description": "Using R for initial explorative data analysis.", + "pubDate": 1424249640, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3A: Exploring the Leslie Salt data", + "startOffset": "{0}", + "hits": "143", + "hits-720p": "143", + "bandwidth": "15988122638", + "hitspartial-720p": "374", + "hits-480p": "47", + "bandwidth-480p": "2480848366", + "hitspartial": "374", + "hitspartial-480p": "38", + "bandwidth-720p": "15988122638", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3AExploringtheLeslieSaltdata-20150218095401-720p.mp4", + "extension": "mp4", + "filesize": "52050769", + "_lastWrite": 4010, + "mimetype": "video\/mp4", + "duration": "00:19:39", + "avgBitrate": "349 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c2f1392d7a.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/17627d5b36.jpg" + } + ] + } + }, + { + "uniqueHash": "3a5920c035acf311eaba06c4ad5f4e9c", + "description": "Basics: The model and approach.", + "pubDate": 1424250420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3B: Multiple Linear Regression", + "startOffset": "{0}", + "hits": "159", + "hits-720p": "159", + "bandwidth": "20131174706", + "hits-480p": "4", + "bandwidth-480p": "2989357475", + "hitspartial-480p": "52", + "bandwidth-720p": "20131174706", + "hitspartial": "667", + "hitspartial-720p": "667", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3BMultipleLinearRegression-20150218100701-720p.mp4", + "extension": "mp4", + "filesize": "49603069", + "_lastWrite": 1741, + "mimetype": "video\/mp4", + "duration": "00:21:01", + "avgBitrate": "310 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ae002d9b0e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8d14010321.jpg" + } + ] + } + }, + { + "uniqueHash": "f582f676753ff0a2dbda1566c013850e", + "description": "Computations, Statistical inference and interpretation.", + "pubDate": 1424250540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3C: Multiple Linear Regression", + "startOffset": "{0}", + "hits": "145", + "hits-720p": "145", + "bandwidth": "15333982408", + "hitspartial-720p": "446", + "hits-480p": "49", + "bandwidth-480p": "3143644892", + "hitspartial": "446", + "hitspartial-480p": "66", + "bandwidth-720p": "15333982408", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3CMultipleLinearRegression-20150218100901-720p.mp4", + "extension": "mp4", + "filesize": "50911452", + "_lastWrite": 7568, + "mimetype": "video\/mp4", + "duration": "00:22:07", + "avgBitrate": "302 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/3421d58804.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8f8e06dfec.jpg" + } + ] + } + }, + { + "uniqueHash": "81891de34c42d1ddba95b7034d0d5741", + "description": "Start.", + "pubDate": 1424250660, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3D(part 1): Model validation.", + "startOffset": "{0}", + "hits": "133", + "hits-720p": "133", + "bandwidth": "845620065", + "hits-480p": "4", + "bandwidth-480p": "184370440", + "hitspartial-480p": "22", + "bandwidth-720p": "845620065", + "hitspartial": "170", + "hitspartial-720p": "170", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3Dpart1Modelvalidation-20150218101102-720p.mp4", + "extension": "mp4", + "filesize": "4105589", + "_lastWrite": 402, + "mimetype": "video\/mp4", + "duration": "00:01:41", + "avgBitrate": "318 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c785b92f8d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/6a4efc33fa.jpg" + } + ] + } + }, + { + "uniqueHash": "8cac37ec75e04bc6c31e2c1045cd7b68", + "description": "Residual plotting and modelling non-linearities and interactions.", + "pubDate": 1424250960, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3D(part 2): Model validation.", + "startOffset": "{0}", + "hits": "141", + "hits-720p": "141", + "hitspartial-720p": "232", + "bandwidth": "6279539615", + "bandwidth-720p": "6279539615", + "hits-480p": "46", + "bandwidth-480p": "1268391943", + "hitspartial-480p": "22", + "hitspartial": "232", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3Dpart2Modelvalidation-20150218101601-720p.mp4", + "extension": "mp4", + "filesize": "27356096", + "_lastWrite": 6538, + "mimetype": "video\/mp4", + "duration": "00:11:49", + "avgBitrate": "304 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/afde135688.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/a69d4f5cae.jpg" + } + ] + } + }, + { + "uniqueHash": "7910a9ce1592316a7a4d95bc04156981", + "description": "And a perspective towards the dimension reduction techniques later in the course.", + "pubDate": 1424251020, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3E: Multicollinearity", + "startOffset": "{0}", + "hits": "127", + "hits-720p": "127", + "bandwidth": "1658175145", + "hitspartial-720p": "140", + "hits-480p": "48", + "bandwidth-480p": "449141765", + "hitspartial-480p": "32", + "bandwidth-720p": "1658175145", + "hitspartial": "140", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3EMulticollinearity-20150218101701-720p.mp4", + "extension": "mp4", + "filesize": "8579714", + "_lastWrite": 6175, + "mimetype": "video\/mp4", + "duration": "00:03:44", + "avgBitrate": "302 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/688419c89e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/27c5645a74.jpg" + } + ] + } + }, + { + "uniqueHash": "b5ba518e53f7b227daaa0645b829ea51", + "description": "Running MLR, stepwise variable elimination and statistical inference.", + "pubDate": 1424251140, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3F: R-tutorial: MLR in R.", + "startOffset": "{0}", + "hits": "125", + "bandwidth": "9741534497", + "hits-480p": "47", + "bandwidth-480p": "3653315041", + "hitspartial-480p": "123", + "hits-720p": "125", + "hitspartial-720p": "197", + "bandwidth-720p": "9741534497", + "hitspartial": "197", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3FRtutorialMLRinR-20150218101902-720p.mp4", + "extension": "mp4", + "filesize": "44793654", + "_lastWrite": 4823, + "mimetype": "video\/mp4", + "duration": "00:16:36", + "avgBitrate": "355 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/166bd9d63a.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9d6870768f.jpg" + } + ] + } + }, + { + "uniqueHash": "d1723f006a50eaf52203bc5dfeeb3df4", + "description": "Model Validation: residual plotting and modelling non-linerarities and interactions. Predicting new observations in R.", + "pubDate": 1424251260, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3G: R-tutorial. MLR in R.", + "startOffset": "{0}", + "hits": "137", + "hits-720p": "137", + "bandwidth": "12982807479", + "hitspartial-720p": "244", + "hits-480p": "42", + "bandwidth-480p": "2754117326", + "hitspartial": "244", + "hitspartial-480p": "46", + "bandwidth-720p": "12982807479", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3GRtutorialMLRinR-20150218102101-720p.mp4", + "extension": "mp4", + "filesize": "52188727", + "_lastWrite": 3528, + "mimetype": "video\/mp4", + "duration": "00:20:46", + "avgBitrate": "331 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c8b5213111.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/07083c3ea5.jpg" + } + ] + } + }, + { + "uniqueHash": "99af7d7f7afc3f0355be863215b4d764", + "description": "A brief initial ' what is PCR?'", + "pubDate": 1424761980, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4A: What is Principal Component Analysis.", + "startOffset": "{0}", + "hits": "182", + "hits-720p": "182", + "bandwidth": "2558567101", + "hitspartial-720p": "311", + "hits-480p": "42", + "bandwidth-480p": "323228568", + "hitspartial-480p": "17", + "bandwidth-720p": "2558567101", + "hitspartial": "311", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4AWhatisPrincipalComponentAnalysis-20150224081301-720p.mp4", + "extension": "mp4", + "filesize": "8053754", + "_lastWrite": 1000, + "mimetype": "video\/mp4", + "duration": "00:03:27", + "avgBitrate": "306 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1a694a2c17.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c9a414f6bb.jpg" + } + ] + } + }, + { + "uniqueHash": "234ee49aa0c15f4866a8713f8bc41319", + "description": "See how PCR makes better sense than MLR when the x'es are highly correlated.", + "pubDate": 1424762100, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4B: Motivating example 1.", + "startOffset": "{0}", + "hits": "138", + "hits-720p": "138", + "bandwidth": "8425001886", + "hitspartial-720p": "290", + "hits-480p": "45", + "bandwidth-480p": "1641118607", + "hitspartial-480p": "38", + "bandwidth-720p": "8425001886", + "hitspartial": "290", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4BMotivatingexample1-20150224081503-720p.mp4", + "extension": "mp4", + "filesize": "31730876", + "_lastWrite": 38922, + "mimetype": "video\/mp4", + "duration": "00:13:50", + "avgBitrate": "301 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/f4ea380afc.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/40d1c78a61.jpg" + } + ] + } + }, + { + "uniqueHash": "937dcd0b0b507f5522153597dab0987a", + "description": "A recap of PCA of spectral type data.", + "pubDate": 1424762280, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4C: Spectral data motivation", + "startOffset": "{0}", + "hits": "155", + "hits-720p": "155", + "bandwidth": "4453781605", + "hitspartial-720p": "237", + "hits-480p": "42", + "bandwidth-480p": "713578826", + "hitspartial-480p": "21", + "bandwidth-720p": "4453781605", + "hitspartial": "237", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4CSpectraldatamotivation-20150224081802-720p.mp4", + "extension": "mp4", + "filesize": "17445535", + "_lastWrite": 39261, + "mimetype": "video\/mp4", + "duration": "00:07:40", + "avgBitrate": "299 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8cd5d262b8.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/a2e2306bc7.jpg" + } + ] + } + }, + { + "uniqueHash": "7254384fc361c268351325eccdac9753", + "description": "A final wrap up of this.", + "pubDate": 1424762340, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4D: What is PCR then.", + "startOffset": "{0}", + "hits": "152", + "hits-720p": "152", + "bandwidth": "1132768738", + "hitspartial-720p": "265", + "hits-480p": "41", + "bandwidth-480p": "162609019", + "hitspartial-480p": "16", + "bandwidth-720p": "1132768738", + "hitspartial": "265", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4DWhatisPCRthen-20150224081901-720p.mp4", + "extension": "mp4", + "filesize": "4249035", + "_lastWrite": 25112, + "mimetype": "video\/mp4", + "duration": "00:01:49", + "avgBitrate": "306 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/79b94d9978.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ed518e8e78.jpg" + } + ] + } + }, + { + "uniqueHash": "d57a539cff1eaf526e0f166ddcd84973", + "description": "A brief overview of the analysis approach.", + "pubDate": 1424762460, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4E: PCR - how to do it?", + "startOffset": "{0}", + "hits": "152", + "hits-720p": "152", + "bandwidth": "1825170139", + "hitspartial-720p": "236", + "hits-480p": "44", + "bandwidth-480p": "337119866", + "hitspartial-480p": "26", + "bandwidth-720p": "1825170139", + "hitspartial": "236", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4EPCRhowtodoit-20150224082102-720p.mp4", + "extension": "mp4", + "filesize": "7287343", + "_lastWrite": 38697, + "mimetype": "video\/mp4", + "duration": "00:03:11", + "avgBitrate": "301 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/49a0a68a94.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/2855446c5a.jpg" + } + ] + } + }, + { + "uniqueHash": "1907451e187054afc3464773624e02dd", + "description": "Cross validation and other validation and resampling techniques. Model selection. Bias and variance.", + "pubDate": 1424762580, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4F: Cross validation and friends.", + "startOffset": "{0}", + "hits": "157", + "hits-720p": "157", + "bandwidth": "27999803550", + "hitspartial-720p": "610", + "hits-480p": "44", + "bandwidth-480p": "3458692808", + "hitspartial-480p": "36", + "bandwidth-720p": "27999803550", + "hitspartial": "610", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4FCrossvalidationandfriends-20150224082301-720p.mp4", + "extension": "mp4", + "filesize": "70995122", + "_lastWrite": 36908, + "mimetype": "video\/mp4", + "duration": "00:28:20", + "avgBitrate": "330 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8a52efbccd.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/2ab32c13c1.jpg" + } + ] + } + }, + { + "uniqueHash": "d379b2c39ef84e129808b73f3bf108c7", + "description": "Motivating example: Leslie Salt data.", + "pubDate": 1426069080, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 6A. PLS. Motivation", + "startOffset": "{0}", + "hits": "166", + "hits-720p": "166", + "bandwidth": "10203294521", + "hitspartial-720p": "340", + "hits-480p": "42", + "bandwidth-480p": "1133168132", + "bandwidth-720p": "456731204", + "hitspartial": "340", + "hitspartial-480p": "10", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec6APLSMotivation-20150311111801-720p.mp4", + "extension": "mp4", + "filesize": "32537511", + "_lastWrite": 9176, + "mimetype": "video\/mp4", + "duration": "00:13:23", + "avgBitrate": "319 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c188ec5f9e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/e6f6c946e5.jpg" + } + ] + } + }, + { + "uniqueHash": "6d277cd11226e114588b7716264296f3", + "description": "What is pls?", + "pubDate": 1426069140, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 6B. PLS: What is it?", + "startOffset": "{0}", + "hits": "156", + "hits-720p": "156", + "bandwidth": "11328226838", + "hitspartial-720p": "362", + "hits-480p": "48", + "bandwidth-480p": "1532705889", + "hitspartial-480p": "20", + "bandwidth-720p": "11328226838", + "hitspartial": "362", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec6BPLSWhatisit-20150311111901-720p.mp4", + "extension": "mp4", + "filesize": "34673027", + "_lastWrite": 9118, + "mimetype": "video\/mp4", + "duration": "00:14:11", + "avgBitrate": "321 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/db311f19c9.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/3c6d345ff4.jpg" + } + ] + } + }, + { + "uniqueHash": "2ef9f47bdba4751c2629d0112ab19c0d", + "description": "A description of the analysis approach when using PLS-regression.", + "pubDate": 1426069200, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 6C. PLS - how to do it!", + "startOffset": "{0}", + "hits": "74", + "hits-720p": "74", + "bandwidth": "5324935269", + "hitspartial-720p": "241", + "hits-480p": "11", + "bandwidth-480p": "420077879", + "bandwidth-720p": "256347943", + "hitspartial": "241", + "hitspartial-480p": "10", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec6CPLShowtodoit-20150311112002-720p.mp4", + "extension": "mp4", + "filesize": "31939868", + "_lastWrite": 7914, + "mimetype": "video\/mp4", + "duration": "00:13:30", + "avgBitrate": "311 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/07cd9e62b0.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1641401809.jpg" + } + ] + } + }, + { + "uniqueHash": "89d6a91837bc1b3f7b27b0f1baa427cc", + "description": "A different description of PLS - a chemometrics perspective.", + "pubDate": 1426069320, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 6D. PLS - what is it?", + "startOffset": "{0}", + "hits": "159", + "hits-720p": "159", + "bandwidth": "39724700030", + "hitspartial-720p": "623", + "hits-480p": "44", + "bandwidth-480p": "1621833151", + "hitspartial-480p": "24", + "bandwidth-720p": "39724700030", + "hitspartial": "623", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec6DPLSwhatisit-20150311112201-720p.mp4", + "extension": "mp4", + "filesize": "89925208", + "_lastWrite": 7512, + "mimetype": "video\/mp4", + "duration": "00:12:20", + "avgBitrate": "967 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c0996a0b14.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d66c122500.jpg" + } + ] + } + }, + { + "uniqueHash": "655565926a2c047e7e47c7dfddab7685", + "description": "Finding optimal predictor by CV (cross validation): Bias, variance and model complexity.", + "pubDate": 1426514880, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7A: Optimal predictor?", + "startOffset": "{0}", + "hits": "137", + "hits-720p": "137", + "bandwidth": "9182129926", + "hitspartial-720p": "242", + "hits-480p": "45", + "bandwidth-480p": "1927151512", + "hitspartial-480p": "54", + "bandwidth-720p": "9182129926", + "hitspartial": "242", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7AOptimalpredictor-20150316150802-720p.mp4", + "extension": "mp4", + "filesize": "39758243", + "_lastWrite": 8172, + "mimetype": "video\/mp4", + "duration": "00:15:25", + "avgBitrate": "339 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/53e7a117fc.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9d277665df.jpg" + } + ] + } + }, + { + "uniqueHash": "8a94811a35a7fbc922b09dabe1dd5fa4", + "description": "MLR produces solutions with too large coefficients.", + "pubDate": 1426515060, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7B: MLR and the problem.", + "startOffset": "{0}", + "hits": "131", + "hits-720p": "131", + "bandwidth": "4966323237", + "hitspartial-720p": "190", + "hits-480p": "40", + "bandwidth-480p": "865418778", + "hitspartial-480p": "16", + "bandwidth-720p": "4966323237", + "hitspartial": "190", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7BMLRandtheproblem-20150316151101-720p.mp4", + "extension": "mp4", + "filesize": "23365254", + "_lastWrite": 8227, + "mimetype": "video\/mp4", + "duration": "00:10:05", + "avgBitrate": "304 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/68b027aac3.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/58bb2597b2.jpg" + } + ] + } + }, + { + "uniqueHash": "1bb9dfcf209b1f1d24194e55b59075f6", + "description": "Definition of Ridge Regression", + "pubDate": 1426515180, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7C: Ridge Regression", + "startOffset": "{0}", + "hits": "138", + "hits-720p": "138", + "bandwidth": "19408402522", + "hitspartial-720p": "272", + "hits-480p": "45", + "bandwidth-480p": "1201300917", + "hitspartial-480p": "22", + "bandwidth-720p": "19408402522", + "hitspartial": "272", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7CRidgeRegression-20150316151305-720p.mp4", + "extension": "mp4", + "filesize": "76212747", + "_lastWrite": 7524, + "mimetype": "video\/mp4", + "duration": "00:07:36", + "avgBitrate": "1.33 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/252a0fdb77.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/dfff74ad15.jpg" + } + ] + } + }, + { + "uniqueHash": "d2b573a332884700ae3a686a34c20a6a", + "description": "Definition of Lasso regression.", + "pubDate": 1426515180, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7D: Lasso Regression", + "startOffset": "{0}", + "hits": "136", + "hits-720p": "136", + "bandwidth": "4831075872", + "hitspartial-720p": "178", + "hits-480p": "42", + "bandwidth-480p": "304109047", + "hitspartial-480p": "10", + "bandwidth-720p": "4831075872", + "hitspartial": "178", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7DLassoRegression-20150316151301-720p.mp4", + "extension": "mp4", + "filesize": "22318945", + "_lastWrite": 7859, + "mimetype": "video\/mp4", + "duration": "00:02:16", + "avgBitrate": "1.3 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/bfbedb8c86.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8e4c98e93f.jpg" + } + ] + } + }, + { + "uniqueHash": "c54a598773021ac19a90d3815daa2716", + "description": "The solution", + "pubDate": 1426515300, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7E: Ridge Regression", + "startOffset": "{0}", + "hits": "137", + "hits-720p": "137", + "bandwidth": "7333966785", + "hitspartial-720p": "164", + "hits-480p": "37", + "bandwidth-480p": "421834993", + "hitspartial-480p": "9", + "bandwidth-720p": "7333966785", + "hitspartial": "164", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7ERidgeRegression-20150316151520-720p.mp4", + "extension": "mp4", + "filesize": "35553938", + "_lastWrite": 7622, + "mimetype": "video\/mp4", + "duration": "00:03:34", + "avgBitrate": "1.32 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/f6bfb8ea6e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/851a6e4107.jpg" + } + ] + } + }, + { + "uniqueHash": "2ce0c4169d0687a15226dd5b23512d95", + "description": "L2 and L1 regression methods - an overview.", + "pubDate": 1426515420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7F: Ridge and Lasso", + "startOffset": "{0}", + "hits": "130", + "hits-720p": "130", + "bandwidth": "30147487524", + "hitspartial-720p": "254", + "hits-480p": "40", + "bandwidth-480p": "1519755150", + "hitspartial-480p": "11", + "bandwidth-720p": "30147487524", + "hitspartial": "254", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7FRidgeandLasso-20150316151710-720p.mp4", + "extension": "mp4", + "filesize": "122875330", + "_lastWrite": 4694, + "mimetype": "video\/mp4", + "duration": "00:11:52", + "avgBitrate": "1.37 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/04e03e2444.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/69417e5b9a.jpg" + } + ] + } + }, + { + "uniqueHash": "8a15f7c583635601098a89f22d1f6576", + "description": "A small example.", + "pubDate": 1426515420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7G: Rddge Regression", + "startOffset": "{0}", + "hits": "127", + "bandwidth": "7201996898", + "hits-480p": "45", + "bandwidth-480p": "605313873", + "hitspartial": "158", + "hitspartial-480p": "19", + "hits-720p": "127", + "hitspartial-720p": "158", + "bandwidth-720p": "7201996898", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7GRddgeRegression-20150316151701-720p.mp4", + "extension": "mp4", + "filesize": "37292088", + "_lastWrite": 7382, + "mimetype": "video\/mp4", + "duration": "00:03:45", + "avgBitrate": "1.32 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/86044aab7e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/74816ea595.jpg" + } + ] + } + }, + { + "uniqueHash": "1a29b54c87c7de6234523be76cda4122", + "description": "k-Nearest Neighbour", + "pubDate": 1427313720, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8F: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "11480842861", + "hits-480p": "44", + "bandwidth-480p": "1379442463", + "hitspartial": "255", + "hitspartial-480p": "71", + "hits": "153", + "hits-720p": "153", + "hitspartial-720p": "255", + "bandwidth-720p": "11480842861", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8FDiscriminantAnalysis-20150325210201-720p.mp4", + "extension": "mp4", + "filesize": "43091782", + "_lastWrite": 42090, + "mimetype": "video\/mp4", + "duration": "00:07:34", + "avgBitrate": "753 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ae7cc82410.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/22be474b80.jpg" + } + ] + } + }, + { + "uniqueHash": "ee1dc0c3c5ad57a93a397e84422e640c", + "description": "Question to small example.", + "pubDate": 1426515540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7H: Ridge Regression", + "startOffset": "{0}", + "hits": "120", + "hits-720p": "120", + "bandwidth": "4220989959", + "hitspartial-720p": "118", + "hits-480p": "44", + "bandwidth-480p": "386123311", + "hitspartial-480p": "18", + "bandwidth-720p": "4220989959", + "hitspartial": "118", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7HRidgeRegression-20150316151914-720p.mp4", + "extension": "mp4", + "filesize": "24625251", + "_lastWrite": 6931, + "mimetype": "video\/mp4", + "duration": "00:02:29", + "avgBitrate": "1.31 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/839cfb07c3.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/5eab76a980.jpg" + } + ] + } + }, + { + "uniqueHash": "0b1e6122d66aab92dabaee6d9351c7ed", + "description": "How to analyze data by Ridge and Lasso Regression - the overall approach.", + "pubDate": 1426515540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7I: Ridge and Lasso.", + "startOffset": "{0}", + "hits": "130", + "hits-720p": "130", + "bandwidth": "6628451869", + "hitspartial-720p": "158", + "hits-480p": "41", + "bandwidth-480p": "443015128", + "hitspartial-480p": "11", + "bandwidth-720p": "6628451869", + "hitspartial": "158", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7IRidgeandLasso-20150316151901-720p.mp4", + "extension": "mp4", + "filesize": "34174210", + "_lastWrite": 6828, + "mimetype": "video\/mp4", + "duration": "00:03:28", + "avgBitrate": "1.31 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ebe4353168.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8e89060247.jpg" + } + ] + } + }, + { + "uniqueHash": "94c4487ffcae3e566d87053fe4c12942", + "description": "An introduction", + "pubDate": 1427313300, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8A: Discriminant Analysis", + "startOffset": "{0}", + "hits": "173", + "hits-720p": "173", + "bandwidth": "30940781245", + "hitspartial-720p": "649", + "hits-480p": "48", + "bandwidth-480p": "1887104320", + "hitspartial-480p": "22", + "bandwidth-720p": "30940781245", + "hitspartial": "649", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8ADiscriminantAnalysis-20150325205501-720p.mp4", + "extension": "mp4", + "filesize": "76542144", + "_lastWrite": 44971, + "mimetype": "video\/mp4", + "duration": "00:13:52", + "avgBitrate": "731 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/380e19b3ce.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0a9f00d93f.jpg" + } + ] + } + }, + { + "uniqueHash": "8faf2bc056dbe897a2ac1043862e8366", + "description": "Different priors and miss classification costs", + "pubDate": 1427313420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8B: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "14695642164", + "hits-480p": "43", + "bandwidth-480p": "1326260111", + "hitspartial": "308", + "hitspartial-480p": "39", + "hits": "150", + "hits-720p": "150", + "hitspartial-720p": "308", + "bandwidth-720p": "14695642164", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8BDiscriminantAnalysis-20150325205701-720p.mp4", + "extension": "mp4", + "filesize": "54807070", + "_lastWrite": 43154, + "mimetype": "video\/mp4", + "duration": "00:09:27", + "avgBitrate": "768 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/2376b7f898.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/12a76b69bb.jpg" + } + ] + } + }, + { + "uniqueHash": "86aa7aba2d37d9b1ecad45ada1083fe9", + "description": "LDA and QDA: Linear and Quadratic DA.", + "pubDate": 1427313540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8C: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "16584740464", + "hits-480p": "43", + "bandwidth-480p": "2806513615", + "hitspartial": "172", + "hitspartial-480p": "65", + "hits": "94", + "hits-720p": "94", + "hitspartial-720p": "172", + "bandwidth-720p": "16584740464", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8CDiscriminantAnalysis-20150325205901-720p.mp4", + "extension": "mp4", + "filesize": "96837443", + "_lastWrite": 42136, + "mimetype": "video\/mp4", + "duration": "00:16:56", + "avgBitrate": "758 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/02006c3e86.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/91f57be561.jpg" + } + ] + } + }, + { + "uniqueHash": "9f0220d531330aee6b18010c5f631685", + "description": "Fisher and CVA.", + "pubDate": 1427313600, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8D: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "18040634367", + "hits-480p": "43", + "bandwidth-480p": "1515812934", + "hitspartial": "412", + "hitspartial-480p": "43", + "hits": "157", + "hits-720p": "157", + "hitspartial-720p": "412", + "bandwidth-720p": "18040634367", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8DDiscriminantAnalysis-20150325210002-720p.mp4", + "extension": "mp4", + "filesize": "58610186", + "_lastWrite": 43028, + "mimetype": "video\/mp4", + "duration": "00:10:19", + "avgBitrate": "752 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/2a03e3bcd5.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0aa868caef.jpg" + } + ] + } + }, + { + "uniqueHash": "3f6fc06e5b06e7d3952f3b4f6774ed32", + "description": "Relations between Bayes, LDA, QDA and CVA.", + "pubDate": 1427313660, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8E: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "6579108276", + "hits-480p": "43", + "bandwidth-480p": "600247926", + "hitspartial": "274", + "hitspartial-480p": "39", + "hits": "156", + "hits-720p": "156", + "hitspartial-720p": "274", + "bandwidth-720p": "6579108276", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8EDiscriminantAnalysis-20150325210101-720p.mp4", + "extension": "mp4", + "filesize": "23810626", + "_lastWrite": 39605, + "mimetype": "video\/mp4", + "duration": "00:04:07", + "avgBitrate": "765 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9f6be61f9d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/cdf5967b90.jpg" + } + ] + } + }, + { + "uniqueHash": "94232baf2e9fbba75a7ba1ddf7197b76", + "description": "Regression and PLS", + "pubDate": 1427313840, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8G: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "8585839885", + "hits-480p": "40", + "bandwidth-480p": "839526201", + "hitspartial": "250", + "hitspartial-480p": "50", + "hits": "149", + "hits-720p": "149", + "hitspartial-720p": "250", + "bandwidth-720p": "8585839885", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8GDiscriminantAnalysis-20150325210401-720p.mp4", + "extension": "mp4", + "filesize": "33585452", + "_lastWrite": 42227, + "mimetype": "video\/mp4", + "duration": "00:05:04", + "avgBitrate": "878 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/121e3e5b8a.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c858fee56e.jpg" + } + ] + } + }, + { + "uniqueHash": "8017fcd866b5b8f8a61b3ff1ce096034", + "description": "Supervised learning and classical statistics", + "pubDate": 1428931020, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 9A: S\u00f8ren Havelund Welling(SHW): Supervised learning", + "startOffset": "{0}", + "hits": "121", + "hits-720p": "121", + "hitspartial-720p": "129", + "bandwidth": "5857709117", + "hitspartial": "129", + "bandwidth-720p": "5857709117", + "hits-480p": "37", + "bandwidth-480p": "584899873", + "hitspartial-480p": "13", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec9ASrenHavelundWellingSHWSupervisedlearning-20150413151701-720p.mp4", + "extension": "mp4", + "filesize": "33623568", + "_lastWrite": 3095, + "mimetype": "video\/mp4", + "duration": "00:04:23", + "avgBitrate": "1.02 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/6e5ac1771d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/310ce4efb8.jpg" + } + ] + } + }, + { + "uniqueHash": "ca4c7ad215249218f52d963b0d1a4660", + "description": "Regression, PLS and summary.", + "pubDate": 1427313900, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8H: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "11215134521", + "hits-480p": "41", + "bandwidth-480p": "894745380", + "hitspartial": "297", + "hitspartial-480p": "30", + "hits": "144", + "hits-720p": "144", + "hitspartial-720p": "297", + "bandwidth-720p": "11215134521", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8HDiscriminantAnalysis-20150325210504-720p.mp4", + "extension": "mp4", + "filesize": "41366571", + "_lastWrite": 41252, + "mimetype": "video\/mp4", + "duration": "00:06:48", + "avgBitrate": "805 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/33d9929568.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/a6e581d66c.jpg" + } + ] + } + }, + { + "uniqueHash": "2202d00752867e2af3ee06ed3b4c7722", + "description": "The Tree model, bagging and random forests.", + "pubDate": 1428931080, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 9B: (SHW): Random Forests", + "startOffset": "{0}", + "hits": "125", + "hits-720p": "125", + "bandwidth": "43786951210", + "hitspartial-720p": "392", + "hits-480p": "39", + "bandwidth-480p": "4119552800", + "hitspartial": "392", + "hitspartial-480p": "58", + "bandwidth-720p": "43786951210", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec9BSHWRandomForests-20150413151801-720p.mp4", + "extension": "mp4", + "filesize": "156609164", + "_lastWrite": 5101, + "mimetype": "video\/mp4", + "duration": "00:19:12", + "avgBitrate": "1.08 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1a3e1ed63e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/13d78ec332.jpg" + } + ] + } + }, + { + "uniqueHash": "0a19affd9cdb9c359f0cbb9d3380ecfa", + "description": "Learning from the model: Interpretation. Using ForestFloor - an R-package developed by SHW.", + "pubDate": 1428932760, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 9C (SHW): Random Forests", + "startOffset": "{0}", + "hits": "121", + "hits-720p": "121", + "hitspartial-720p": "145", + "bandwidth": "26263032119", + "hitspartial": "145", + "bandwidth-720p": "26263032119", + "hits-480p": "38", + "bandwidth-480p": "2616717019", + "hitspartial-480p": "19", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec9CSHWRandomForests-20150413154601-720p.mp4", + "extension": "mp4", + "filesize": "141554891", + "_lastWrite": 3325, + "mimetype": "video\/mp4", + "duration": "00:16:51", + "avgBitrate": "1.11 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/abff0330a6.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/01a24e23d0.jpg" + } + ] + } + }, + { + "uniqueHash": "55c312322107fa27674e011801d9b803", + "description": "Multidimensional scaling_PCO_MDS_NMS in general", + "pubDate": 1430822940, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Multidimensional scaling_27411_Chemometrics", + "startOffset": "{0}", + "hits": "131", + "hits-720p": "131", + "bandwidth": "76563924994", + "hitspartial-720p": "635", + "hits-480p": "33", + "bandwidth-480p": "3043819278", + "hitspartial-480p": "10", + "bandwidth-720p": "76563924994", + "hitspartial": "635", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Multidimensionalscaling27411Chemometrics-20150505124901-720p.mp4", + "extension": "mp4", + "filesize": "241954890", + "_lastWrite": 10053, + "mimetype": "video\/mp4", + "duration": "00:25:52", + "avgBitrate": "1.24 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0048cc6c04.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d7a6dd148a.jpg" + } + ] + } + }, + { + "uniqueHash": "54ce0965acfb91e654f29a3a800a808a", + "description": "Multidimensional scaling_27411_PCO-NMS_MST_DTU_27411", + "pubDate": 1431440040, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Multidimensional scaling_27411_Chemometrics", + "startOffset": "{0}", + "hits": "150", + "bandwidth": "104288583996", + "hits-480p": "42", + "bandwidth-480p": "5155732789", + "hitspartial": "1535", + "hitspartial-480p": "60", + "hits-720p": "150", + "hitspartial-720p": "1535", + "bandwidth-720p": "104288583996", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Multidimensionalscaling27411Chemometrics-20150512161401-720p.mp4", + "extension": "mp4", + "filesize": "241954966", + "_lastWrite": 11338, + "mimetype": "video\/mp4", + "duration": "00:25:52", + "avgBitrate": "1.24 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ab2dbf22a1.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d7ac7c55a4.jpg" + } + ] + } + }, + { + "uniqueHash": "87e1d85e84c1c252961ada4c504b1f5f", + "description": "Overview of classification in Chemometrics, by Jens Chr. Frisvad.", + "pubDate": 1431438420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 1", + "startOffset": "{0}", + "hits": "137", + "bandwidth": "32280531152", + "hits-480p": "40", + "bandwidth-480p": "2337462046", + "hitspartial": "345", + "hitspartial-480p": "39", + "hits-720p": "137", + "hitspartial-720p": "345", + "bandwidth-720p": "32280531152", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture1-20150512154702-720p.mp4", + "extension": "mp4", + "filesize": "123714756", + "_lastWrite": 2482, + "mimetype": "video\/mp4", + "duration": "00:13:57", + "avgBitrate": "1.18 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1e4e1b0900.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/b214aeca4a.jpg" + } + ] + } + }, + { + "uniqueHash": "132b131ad23fe0ef3c8b3d46e5701cba", + "description": "Regression and discrimination, by Per B.B.", + "pubDate": 1431438480, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2A", + "startOffset": "{0}", + "hits": "126", + "hits-720p": "126", + "bandwidth": "8869351311", + "hitspartial-720p": "240", + "hits-480p": "33", + "bandwidth-480p": "1349420891", + "hitspartial-480p": "23", + "bandwidth-720p": "8869351311", + "hitspartial": "240", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2A-20150512154801-720p.mp4", + "extension": "mp4", + "filesize": "40554399", + "_lastWrite": 1009, + "mimetype": "video\/mp4", + "duration": "00:17:24", + "avgBitrate": "306 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/367f9c51ae.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9339c6624c.jpg" + } + ] + } + }, + { + "uniqueHash": "7d0dc0f3a1c7058d12ce47ff4b49b455", + "description": "Bias and Variance in prediction, optimal predictor.", + "pubDate": 1431438540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2B", + "startOffset": "{0}", + "hits": "140", + "hits-720p": "140", + "bandwidth": "4169753106", + "hitspartial-720p": "143", + "hits-480p": "30", + "bandwidth-480p": "544771534", + "hitspartial-480p": "3", + "bandwidth-720p": "4169753106", + "hitspartial": "143", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2B-20150512154902-720p.mp4", + "extension": "mp4", + "filesize": "22463183", + "_lastWrite": 203, + "mimetype": "video\/mp4", + "duration": "00:09:57", + "avgBitrate": "296 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/961cf879ab.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ce08252cea.jpg" + } + ] + } + }, + { + "uniqueHash": "2da979237d0f83bb91eda09c2fdf7720", + "description": "MLR - the basic model.", + "pubDate": 1431438720, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2C", + "startOffset": "{0}", + "hits": "109", + "hits-720p": "109", + "bandwidth": "2013221279", + "hitspartial-720p": "108", + "hits-480p": "31", + "bandwidth-480p": "340923722", + "hitspartial-480p": "4", + "bandwidth-720p": "2013221279", + "hitspartial": "108", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2C-20150512155202-720p.mp4", + "extension": "mp4", + "filesize": "13547947", + "_lastWrite": 3370, + "mimetype": "video\/mp4", + "duration": "00:05:59", + "avgBitrate": "297 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/951f6a90a6.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/e2ef74442a.jpg" + } + ] + } + }, + { + "uniqueHash": "3a087e1eba98622a6efdc9aba9e9aee9", + "description": "Biased regression methods: Ridge, Lasso, PLS, PCR.", + "pubDate": 1431438780, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2D", + "startOffset": "{0}", + "hits": "114", + "bandwidth": "5419458884", + "hits-480p": "33", + "bandwidth-480p": "927272013", + "hitspartial": "179", + "hitspartial-480p": "9", + "hits-720p": "114", + "hitspartial-720p": "179", + "bandwidth-720p": "5419458884", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2D-20150512155301-720p.mp4", + "extension": "mp4", + "filesize": "32458294", + "_lastWrite": 2638, + "mimetype": "video\/mp4", + "duration": "00:14:29", + "avgBitrate": "294 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/979801a0b2.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/76145ec846.jpg" + } + ] + } + }, + { + "uniqueHash": "9dcb55330c51996a404f6cb620004b39", + "description": "All the methods are shrinking the MLR solution.", + "pubDate": 1431438840, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2E", + "startOffset": "{0}", + "hits": "108", + "hits-720p": "108", + "bandwidth": "2537727011", + "hitspartial-720p": "86", + "hits-480p": "32", + "bandwidth-480p": "495316448", + "hitspartial-480p": "4", + "bandwidth-720p": "2537727011", + "hitspartial": "86", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2E-20150512155401-720p.mp4", + "extension": "mp4", + "filesize": "19086899", + "_lastWrite": 2694, + "mimetype": "video\/mp4", + "duration": "00:08:18", + "avgBitrate": "302 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/35cdec4a0d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/e038746d18.jpg" + } + ] + } + }, + { + "uniqueHash": "08282afa7270a7c63d60fea0c36564b6", + "description": "See how to use the 'pcr' function of the 'pls' package.", + "pubDate": 1424762700, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, PCR", + "startOffset": "{0}", + "hits": "142", + "hits-720p": "142", + "bandwidth": "25701296679", + "hitspartial-720p": "432", + "hits-480p": "54", + "bandwidth-480p": "4452825004", + "hitspartial-480p": "30", + "bandwidth-720p": "25701296679", + "hitspartial": "432", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialPCR-20150224082501-720p.mp4", + "extension": "mp4", + "filesize": "85606314", + "_lastWrite": 35498, + "mimetype": "video\/mp4", + "duration": "00:35:23", + "avgBitrate": "318 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/30c03f57b5.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/11594cef4d.jpg" + } + ] + } + }, + { + "uniqueHash": "3561bdc5bd6815697fd8f30cedca2fb9", + "description": "All the methods are shrinking the MLR solution.", + "pubDate": 1431438900, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2E", + "startOffset": "{0}", + "hits": "101", + "bandwidth": "2599224004", + "hits-480p": "31", + "bandwidth-480p": "499197524", + "hitspartial": "93", + "hitspartial-480p": "20", + "hits-720p": "101", + "hitspartial-720p": "93", + "bandwidth-720p": "2599224004", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2E-20150512155502-720p.mp4", + "extension": "mp4", + "filesize": "19086899", + "_lastWrite": 2069, + "mimetype": "video\/mp4", + "duration": "00:08:18", + "avgBitrate": "302 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0ba1a19aa2.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/fa0217811d.jpg" + } + ] + } + }, + { + "uniqueHash": "b3a9190524c2cdb3e83ee91a2e9b7358", + "description": "The overall modelling approach: Cross validation etc.", + "pubDate": 1431438960, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2F", + "startOffset": "{0}", + "hits": "123", + "bandwidth": "3865434654", + "hits-480p": "37", + "bandwidth-480p": "907002958", + "hitspartial": "195", + "hitspartial-480p": "697", + "hits-720p": "123", + "hitspartial-720p": "195", + "bandwidth-720p": "3865434654", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2F-20150512155601-720p.mp4", + "extension": "mp4", + "filesize": "20344645", + "_lastWrite": 1947, + "mimetype": "video\/mp4", + "duration": "00:08:39", + "avgBitrate": "309 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/3406199efe.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/e485195484.jpg" + } + ] + } + }, + { + "uniqueHash": "a12b87658ced4472152a7e1d19566c62", + "description": "PCA, first lecture for DTU course 27411", + "pubDate": 1423558740, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Principal Component Analysis_1", + "startOffset": "{0}", + "hits": "248", + "bandwidth": "190378424337", + "hits-480p": "52", + "bandwidth-480p": "6033361562", + "hitspartial": "1623", + "hitspartial-480p": "62", + "hits-720p": "248", + "bandwidth-720p": "928935940", + "hitspartial-720p": "1623", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/PrincipalComponentAnalysis1-20150210095901-720p.mp4", + "extension": "mp4", + "filesize": "232233985", + "_lastWrite": 624, + "mimetype": "video\/mp4", + "duration": "00:25:18", + "avgBitrate": "1.22 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/943de55787.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/4f60e0b6e0.jpg" + } + ] + } + }, + { + "uniqueHash": "3320f5b573ca98f4bea13918c64a911c", + "description": "PCA_part_2, DTU course 27411", + "pubDate": 1423558860, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Principal Component Analysis_2", + "startOffset": "{0}", + "hits": "176", + "bandwidth": "170057364518", + "hits-480p": "53", + "bandwidth-480p": "8684901773", + "hitspartial": "1131", + "hitspartial-480p": "61", + "hits-720p": "176", + "bandwidth-720p": "1576753555", + "hitspartial-720p": "1131", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/PrincipalComponentAnalysis2-20150210100102-720p.mp4", + "extension": "mp4", + "filesize": "315350711", + "_lastWrite": 1499, + "mimetype": "video\/mp4", + "duration": "00:34:49", + "avgBitrate": "1.2 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/568817708c.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ff111d0772.jpg" + } + ] + } + }, + { + "uniqueHash": "90914f76b1e8118e8903a6cdc8f8730e", + "description": "Iris data example. Various methods, part 1.", + "pubDate": 1427314140, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "24990734855", + "hits-480p": "40", + "bandwidth-480p": "2217805269", + "hitspartial": "244", + "hitspartial-480p": "24", + "hits": "132", + "hits-720p": "132", + "hitspartial-720p": "244", + "bandwidth-720p": "24990734855", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialDiscriminantAnalysis-20150325210901-720p.mp4", + "extension": "mp4", + "filesize": "108566456", + "_lastWrite": 39852, + "mimetype": "video\/mp4", + "duration": "00:17:12", + "avgBitrate": "836 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/4cecc755fd.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d5577a40e7.jpg" + } + ] + } + }, + { + "uniqueHash": "49cd537b5ac1768de4ac3c5af18d53ce", + "description": "Iris data example. Various methods, part 1.", + "pubDate": 1427314140, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "12180598086", + "hits-480p": "40", + "bandwidth-480p": "1316227654", + "hitspartial": "192", + "hitspartial-480p": "29", + "hits": "131", + "hits-720p": "131", + "hitspartial-720p": "192", + "bandwidth-720p": "12180598086", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialDiscriminantAnalysis-20150325210929-720p.mp4", + "extension": "mp4", + "filesize": "58816309", + "_lastWrite": 40647, + "mimetype": "video\/mp4", + "duration": "00:09:46", + "avgBitrate": "797 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/b1c7f97d30.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/35b74cc469.jpg" + } + ] + } + }, + { + "uniqueHash": "be9a6538ac5c47a5dbb24a260ba8a371", + "description": "How to do it in R.", + "pubDate": 1426515720, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Lasso Regression.", + "startOffset": "{0}", + "hits": "129", + "hits-720p": "129", + "bandwidth": "14199455391", + "hitspartial-720p": "161", + "hits-480p": "41", + "bandwidth-480p": "1180833642", + "bandwidth-720p": "525394652", + "hitspartial": "161", + "hitspartial-480p": "21", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialLassoRegression-20150316152201-720p.mp4", + "extension": "mp4", + "filesize": "74669707", + "_lastWrite": 5909, + "mimetype": "video\/mp4", + "duration": "00:07:29", + "avgBitrate": "1.32 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1c04ed9c8d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/838284ba84.jpg" + } + ] + } + }, + { + "uniqueHash": "36a108823adc1d1873082e830119cbc3", + "description": "How to use R to analyse data by PLS-regression.", + "pubDate": 1426069380, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, PLS.", + "startOffset": "{0}", + "hits": "142", + "hits-720p": "142", + "bandwidth": "21691962707", + "hitspartial-720p": "390", + "hits-480p": "41", + "bandwidth-480p": "3046328752", + "bandwidth-720p": "1014125188", + "hitspartial": "390", + "hitspartial-480p": "77", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialPLS-20150311112302-720p.mp4", + "extension": "mp4", + "filesize": "63228338", + "_lastWrite": 7135, + "mimetype": "video\/mp4", + "duration": "00:20:55", + "avgBitrate": "398 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1be9809c52.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/5d29e871ac.jpg" + } + ] + } + }, + { + "uniqueHash": "f6e973c9eacfcb58cfd609b672870efa", + "description": "How to do it in R.", + "pubDate": 1426515600, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Ridge Regression.", + "startOffset": "{0}", + "hits": "66", + "bandwidth": "29445034093", + "hits-480p": "12", + "bandwidth-480p": "990455037", + "hitspartial": "307", + "hitspartial-480p": "22", + "hits-720p": "66", + "hitspartial-720p": "307", + "bandwidth-720p": "29445034093", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialRidgeRegression-20150316152001-720p.mp4", + "extension": "mp4", + "filesize": "153671174", + "_lastWrite": 5573, + "mimetype": "video\/mp4", + "duration": "00:15:14", + "avgBitrate": "1.34 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/07fce7173e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/59ef71d8a1.jpg" + } + ] + } + }, + { + "uniqueHash": "836e4334ae4b6d0c0b446e7df586a68f", + "description": "How to predict in R.", + "pubDate": 1426515840, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Ridge and Lasso Regression.", + "startOffset": "{0}", + "hits": "126", + "hits-720p": "126", + "bandwidth": "5223320228", + "hitspartial-720p": "153", + "hits-480p": "43", + "bandwidth-480p": "450966680", + "hitspartial-480p": "19", + "bandwidth-720p": "5223320228", + "hitspartial": "153", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialRidgeandLassoRegression-20150316152401-720p.mp4", + "extension": "mp4", + "filesize": "28096240", + "_lastWrite": 6339, + "mimetype": "video\/mp4", + "duration": "00:02:52", + "avgBitrate": "1.3 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/4b2b69928e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/812bf4adc6.jpg" + } + ] + } + }, + { + "uniqueHash": "0dab12bc7f26d5eaae8a1498b1bc1296", + "description": "How to run Random forests in R. An example.", + "pubDate": 1428931260, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "R-tutorial (SHW):; Random forests", + "startOffset": "{0}", + "hits": "133", + "hits-720p": "133", + "bandwidth": "11793833430", + "hitspartial-720p": "138", + "hits-480p": "35", + "bandwidth-480p": "1061566470", + "hitspartial": "138", + "hitspartial-480p": "41", + "bandwidth-720p": "11793833430", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RtutorialSHWRandomforests-20150413152101-720p.mp4", + "extension": "mp4", + "filesize": "62894886", + "_lastWrite": 30, + "mimetype": "video\/mp4", + "duration": "00:07:53", + "avgBitrate": "1.06 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d48903c9b2.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ce4870fe26.jpg" + } + ] + } + }, + { + "uniqueHash": "abe381b90a0fa8afa5041a1d3bae66c4", + "description": "Presenting the two data sets for the exercises.", + "pubDate": 1428933420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "R-tutorial - exercise data (SHW)", + "startOffset": "{0}", + "hits": "100", + "hits-720p": "100", + "hitspartial-720p": "71", + "bandwidth": "23175005703", + "hitspartial": "71", + "bandwidth-720p": "23175005703", + "hits-480p": "37", + "bandwidth-480p": "2495282008", + "hitspartial-480p": "11", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RtutorialexercisedataSHW-20150413155701-720p.mp4", + "extension": "mp4", + "filesize": "178429871", + "_lastWrite": 3069, + "mimetype": "video\/mp4", + "duration": "00:15:25", + "avgBitrate": "1.54 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/3e89c658f6.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/996dcc77c8.jpg" + } + ] + } + }, + { + "uniqueHash": "262acb006972830cc4a084951946513e", + "description": "Random Forests in R.", + "pubDate": 1428931380, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "R-tutorial, part 2 (SHW).", + "startOffset": "{0}", + "hits": "114", + "hits-720p": "114", + "bandwidth": "21965656468", + "hitspartial-720p": "341", + "hits-480p": "34", + "bandwidth-480p": "2038581575", + "hitspartial": "341", + "hitspartial-480p": "147", + "bandwidth-720p": "21965656468", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Rtutorialpart2SHW-20150413152302-720p.mp4", + "extension": "mp4", + "filesize": "118013235", + "_lastWrite": 5706, + "mimetype": "video\/mp4", + "duration": "00:15:27", + "avgBitrate": "1.01 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/f3a2ecf82a.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c9d6cb1a75.jpg" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/spec/files/podcasts/bug_172_1.json b/spec/files/podcasts/bug_172_1.json new file mode 100644 index 0000000000000000000000000000000000000000..b8bc9a93e071db658c9c11a37f1adc7894b05919 --- /dev/null +++ b/spec/files/podcasts/bug_172_1.json @@ -0,0 +1,2562 @@ +{ + "metadata": { + "title": "27411 Biological data analysis and chemometrics", + "TYPO3_SITE_URL": "http:\/\/podcast.llab.dtu.dk\/", + "copyright": "DTU 2015", + "description": "", + "subtitle": "", + "author": "Technical University of Denmark", + "author_email": "kaska@llab.dtu.dk", + "image": "", + "category": "Education", + "language": "en" + }, + "feeds": { + "HD": { + "version": "720p", + "label": "HD" + } + }, + "episodes": [ + { + "uniqueHash": "ea0e328505fbf41e77164503056c76a2", + "description": "Lecture by Jens Chr. Frisvad on Cluster Analysis.", + "pubDate": 1431438300, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Cluster Analysis", + "startOffset": "{0}", + "hits": "134", + "bandwidth": "72072913301", + "hits-480p": "39", + "bandwidth-480p": "4105385252", + "hitspartial": "713", + "hitspartial-480p": "61", + "hits-720p": "134", + "hitspartial-720p": "713", + "bandwidth-720p": "72072913301", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/ClusterAnalysis-20150512154502-720p.mp4", + "extension": "mp4", + "filesize": "206811318", + "_lastWrite": 903, + "mimetype": "video\/mp4", + "avgBitrate": "1.16 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0f86399227.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/029fcdcfba.jpg" + } + ] + } + }, + { + "uniqueHash": "58469b35fedf6d8565a6304e5b33e415", + "description": "Correspondence analysis_lecture for DTU course 27411", + "pubDate": 1425484560, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Correspondence analysis_chemometrics", + "startOffset": "{0}", + "hits": "155", + "hits-720p": "155", + "hitspartial-720p": "822", + "bandwidth": "105060542582", + "hitspartial": "822", + "bandwidth-720p": "105060542582", + "hits-480p": "52", + "bandwidth-480p": "7152001404", + "hitspartial-480p": "94", + "media": { + "720p": { + "extension": "mp4", + "filesize": "227730411", + "_lastWrite": 954, + "mimetype": "video\/mp4", + "duration": "00:26:03", + "avgBitrate": "1.16 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9b6a7b1b90.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8675e12f85.jpg" + } + ] + } + }, + { + "uniqueHash": "be63a15a98ec2c353947b8d16b03f144", + "description": "And practical information.", + "pubDate": 1422888120, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1A: Course welcome.", + "startOffset": "{0}", + "hits": "145", + "hits-720p": "145", + "hitspartial-720p": "281", + "bandwidth": "8703279431", + "hitspartial": "281", + "bandwidth-720p": "8703279431", + "hits-480p": "48", + "bandwidth-480p": "1609969693", + "hitspartial-480p": "57", + "media": { + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/673ba28592.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8af7ccae51.jpg" + } + ] + } + }, + { + "uniqueHash": "4b99c3ab2bdc2881214838a06ebb1cfc", + "description": "By Jens Chr. Frisvad", + "pubDate": 1422888180, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1B: Introduction to Chemometrics, part 1", + "startOffset": "{0}", + "hits": "158", + "hits-720p": "158", + "hitspartial-720p": "367", + "bandwidth": "14495252622", + "hitspartial": "367", + "bandwidth-720p": "14495252622", + "hits-480p": "66", + "bandwidth-480p": "3134479393", + "hitspartial-480p": "82", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1BIntroductiontoChemometricspart1-20150202154301-720p.mp4", + "extension": "mp4", + "filesize": "52356783", + "_lastWrite": 1580, + "mimetype": "video\/mp4", + "duration": "00:20:10", + "avgBitrate": "341 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/7f481f251d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/a8b2d1c230.jpg" + } + ] + } + }, + { + "uniqueHash": "a0e45343fbcd81568c7027da1297f629", + "description": "By Jens Chr. Frisvad", + "pubDate": 1422888240, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec1C: Introduction to Chemometrics, part 2", + "startOffset": "{0}", + "hits": "147", + "hits-720p": "147", + "hitspartial-720p": "260", + "bandwidth": "11136556544", + "hitspartial": "260", + "bandwidth-720p": "11136556544", + "hits-480p": "44", + "bandwidth-480p": "1580301979", + "hitspartial-480p": "9", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1CIntroductiontoChemometricspart2-20150202154401-720p.mp4", + "extension": "mp4", + "filesize": "46551226", + "_lastWrite": 1458, + "mimetype": "video\/mp4", + "duration": "00:18:01", + "avgBitrate": "340 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/4435d5739e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/b5dc05d4fe.jpg" + } + ] + } + }, + { + "uniqueHash": "c98a22137a02822fd6dd029a0e1d7de6", + "description": "PBB example of Sensory (and other) data on frozen peas.", + "pubDate": 1422888840, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1D: Food example.", + "startOffset": "{0}", + "hits": "139", + "hits-720p": "139", + "hitspartial-720p": "216", + "bandwidth": "6400541407", + "hitspartial": "216", + "bandwidth-720p": "6400541407", + "hits-480p": "50", + "bandwidth-480p": "1182512171", + "hitspartial-480p": "13", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1DFoodexample-20150202155401-720p.mp4", + "extension": "mp4", + "filesize": "28577837", + "_lastWrite": 1627, + "mimetype": "video\/mp4", + "duration": "00:12:01", + "avgBitrate": "312 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/31044b64b3.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c360258441.jpg" + } + ] + } + }, + { + "uniqueHash": "0944e25bc6c700bb6ff33233b82bb622", + "description": "Permeability discrimination of drug candidates.", + "pubDate": 1422889020, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1E: QSAR example", + "startOffset": "{0}", + "hits": "123", + "hits-720p": "123", + "hitspartial-720p": "152", + "bandwidth": "5212100402", + "hitspartial": "152", + "bandwidth-720p": "5212100402", + "hits-480p": "42", + "bandwidth-480p": "847260960", + "hitspartial-480p": "6", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1EQSARexample-20150202155701-720p.mp4", + "extension": "mp4", + "filesize": "29465717", + "_lastWrite": 817, + "mimetype": "video\/mp4", + "duration": "00:08:26", + "avgBitrate": "461 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/819fbd948f.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/619523d1bc.jpg" + } + ] + } + }, + { + "uniqueHash": "9898df38e40862e25d86d6e01422c6f1", + "description": "Link between multivariate data and simple correlations.", + "pubDate": 1422889200, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec1G: Correlation and covariance", + "startOffset": "{0}", + "hits": "139", + "hits-720p": "139", + "hitspartial-720p": "209", + "bandwidth": "5583763254", + "hitspartial": "209", + "bandwidth-720p": "5583763254", + "hits-480p": "47", + "bandwidth-480p": "1075803865", + "hitspartial-480p": "19", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1GCorrelationandcovariance-20150202160001-720p.mp4", + "extension": "mp4", + "filesize": "26633616", + "_lastWrite": 585, + "mimetype": "video\/mp4", + "duration": "00:10:49", + "avgBitrate": "324 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d152d2b9d6.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/fe5968e5e8.jpg" + } + ] + } + }, + { + "uniqueHash": "5e9bab8dae7a4aa1a3786c9b3c05a5d9", + "description": "A little recap of linear algebra(matrices).", + "pubDate": 1422889080, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 1F: Lattin Chapter2", + "startOffset": "{0}", + "hits": "131", + "hits-720p": "131", + "hitspartial-720p": "221", + "bandwidth": "11497894298", + "hitspartial": "221", + "bandwidth-720p": "11497894298", + "hits-480p": "46", + "bandwidth-480p": "1811561711", + "hitspartial-480p": "11", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec1FLattinChapter2-20150202155801-720p.mp4", + "extension": "mp4", + "filesize": "52304113", + "_lastWrite": 335, + "mimetype": "video\/mp4", + "duration": "00:17:31", + "avgBitrate": "393 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/dcaf77d06c.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/f335ec53a6.jpg" + } + ] + } + }, + { + "uniqueHash": "88a5849c9ac0d8e4a5ae0dee1376dc6c", + "description": "Using R for initial explorative data analysis.", + "pubDate": 1424249640, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3A: Exploring the Leslie Salt data", + "startOffset": "{0}", + "hits": "143", + "hits-720p": "143", + "bandwidth": "15988122638", + "hitspartial-720p": "374", + "hits-480p": "47", + "bandwidth-480p": "2480848366", + "hitspartial": "374", + "hitspartial-480p": "38", + "bandwidth-720p": "15988122638", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3AExploringtheLeslieSaltdata-20150218095401-720p.mp4", + "extension": "mp4", + "filesize": "52050769", + "_lastWrite": 4010, + "mimetype": "video\/mp4", + "duration": "00:19:39", + "avgBitrate": "349 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c2f1392d7a.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/17627d5b36.jpg" + } + ] + } + }, + { + "uniqueHash": "3a5920c035acf311eaba06c4ad5f4e9c", + "description": "Basics: The model and approach.", + "pubDate": 1424250420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3B: Multiple Linear Regression", + "startOffset": "{0}", + "hits": "159", + "hits-720p": "159", + "bandwidth": "20131174706", + "hits-480p": "4", + "bandwidth-480p": "2989357475", + "hitspartial-480p": "52", + "bandwidth-720p": "20131174706", + "hitspartial": "667", + "hitspartial-720p": "667", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3BMultipleLinearRegression-20150218100701-720p.mp4", + "extension": "mp4", + "filesize": "49603069", + "_lastWrite": 1741, + "mimetype": "video\/mp4", + "duration": "00:21:01", + "avgBitrate": "310 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ae002d9b0e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8d14010321.jpg" + } + ] + } + }, + { + "uniqueHash": "f582f676753ff0a2dbda1566c013850e", + "description": "Computations, Statistical inference and interpretation.", + "pubDate": 1424250540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3C: Multiple Linear Regression", + "startOffset": "{0}", + "hits": "145", + "hits-720p": "145", + "bandwidth": "15333982408", + "hitspartial-720p": "446", + "hits-480p": "49", + "bandwidth-480p": "3143644892", + "hitspartial": "446", + "hitspartial-480p": "66", + "bandwidth-720p": "15333982408", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3CMultipleLinearRegression-20150218100901-720p.mp4", + "extension": "mp4", + "filesize": "50911452", + "_lastWrite": 7568, + "mimetype": "video\/mp4", + "duration": "00:22:07", + "avgBitrate": "302 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/3421d58804.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8f8e06dfec.jpg" + } + ] + } + }, + { + "uniqueHash": "81891de34c42d1ddba95b7034d0d5741", + "description": "Start.", + "pubDate": 1424250660, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3D(part 1): Model validation.", + "startOffset": "{0}", + "hits": "133", + "hits-720p": "133", + "bandwidth": "845620065", + "hits-480p": "4", + "bandwidth-480p": "184370440", + "hitspartial-480p": "22", + "bandwidth-720p": "845620065", + "hitspartial": "170", + "hitspartial-720p": "170", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3Dpart1Modelvalidation-20150218101102-720p.mp4", + "extension": "mp4", + "filesize": "4105589", + "_lastWrite": 402, + "mimetype": "video\/mp4", + "duration": "00:01:41", + "avgBitrate": "318 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c785b92f8d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/6a4efc33fa.jpg" + } + ] + } + }, + { + "uniqueHash": "8cac37ec75e04bc6c31e2c1045cd7b68", + "description": "Residual plotting and modelling non-linearities and interactions.", + "pubDate": 1424250960, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3D(part 2): Model validation.", + "startOffset": "{0}", + "hits": "141", + "hits-720p": "141", + "hitspartial-720p": "232", + "bandwidth": "6279539615", + "bandwidth-720p": "6279539615", + "hits-480p": "46", + "bandwidth-480p": "1268391943", + "hitspartial-480p": "22", + "hitspartial": "232", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3Dpart2Modelvalidation-20150218101601-720p.mp4", + "extension": "mp4", + "filesize": "27356096", + "_lastWrite": 6538, + "mimetype": "video\/mp4", + "duration": "00:11:49", + "avgBitrate": "304 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/afde135688.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/a69d4f5cae.jpg" + } + ] + } + }, + { + "uniqueHash": "7910a9ce1592316a7a4d95bc04156981", + "description": "And a perspective towards the dimension reduction techniques later in the course.", + "pubDate": 1424251020, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3E: Multicollinearity", + "startOffset": "{0}", + "hits": "127", + "hits-720p": "127", + "bandwidth": "1658175145", + "hitspartial-720p": "140", + "hits-480p": "48", + "bandwidth-480p": "449141765", + "hitspartial-480p": "32", + "bandwidth-720p": "1658175145", + "hitspartial": "140", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3EMulticollinearity-20150218101701-720p.mp4", + "extension": "mp4", + "filesize": "8579714", + "_lastWrite": 6175, + "mimetype": "video\/mp4", + "duration": "00:03:44", + "avgBitrate": "302 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/688419c89e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/27c5645a74.jpg" + } + ] + } + }, + { + "uniqueHash": "b5ba518e53f7b227daaa0645b829ea51", + "description": "Running MLR, stepwise variable elimination and statistical inference.", + "pubDate": 1424251140, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3F: R-tutorial: MLR in R.", + "startOffset": "{0}", + "hits": "125", + "bandwidth": "9741534497", + "hits-480p": "47", + "bandwidth-480p": "3653315041", + "hitspartial-480p": "123", + "hits-720p": "125", + "hitspartial-720p": "197", + "bandwidth-720p": "9741534497", + "hitspartial": "197", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3FRtutorialMLRinR-20150218101902-720p.mp4", + "extension": "mp4", + "filesize": "44793654", + "_lastWrite": 4823, + "mimetype": "video\/mp4", + "duration": "00:16:36", + "avgBitrate": "355 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/166bd9d63a.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9d6870768f.jpg" + } + ] + } + }, + { + "uniqueHash": "d1723f006a50eaf52203bc5dfeeb3df4", + "description": "Model Validation: residual plotting and modelling non-linerarities and interactions. Predicting new observations in R.", + "pubDate": 1424251260, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 3G: R-tutorial. MLR in R.", + "startOffset": "{0}", + "hits": "137", + "hits-720p": "137", + "bandwidth": "12982807479", + "hitspartial-720p": "244", + "hits-480p": "42", + "bandwidth-480p": "2754117326", + "hitspartial": "244", + "hitspartial-480p": "46", + "bandwidth-720p": "12982807479", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec3GRtutorialMLRinR-20150218102101-720p.mp4", + "extension": "mp4", + "filesize": "52188727", + "_lastWrite": 3528, + "mimetype": "video\/mp4", + "duration": "00:20:46", + "avgBitrate": "331 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c8b5213111.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/07083c3ea5.jpg" + } + ] + } + }, + { + "uniqueHash": "99af7d7f7afc3f0355be863215b4d764", + "description": "A brief initial ' what is PCR?'", + "pubDate": 1424761980, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4A: What is Principal Component Analysis.", + "startOffset": "{0}", + "hits": "182", + "hits-720p": "182", + "bandwidth": "2558567101", + "hitspartial-720p": "311", + "hits-480p": "42", + "bandwidth-480p": "323228568", + "hitspartial-480p": "17", + "bandwidth-720p": "2558567101", + "hitspartial": "311", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4AWhatisPrincipalComponentAnalysis-20150224081301-720p.mp4", + "extension": "mp4", + "filesize": "8053754", + "_lastWrite": 1000, + "mimetype": "video\/mp4", + "duration": "00:03:27", + "avgBitrate": "306 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1a694a2c17.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c9a414f6bb.jpg" + } + ] + } + }, + { + "uniqueHash": "234ee49aa0c15f4866a8713f8bc41319", + "description": "See how PCR makes better sense than MLR when the x'es are highly correlated.", + "pubDate": 1424762100, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4B: Motivating example 1.", + "startOffset": "{0}", + "hits": "138", + "hits-720p": "138", + "bandwidth": "8425001886", + "hitspartial-720p": "290", + "hits-480p": "45", + "bandwidth-480p": "1641118607", + "hitspartial-480p": "38", + "bandwidth-720p": "8425001886", + "hitspartial": "290", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4BMotivatingexample1-20150224081503-720p.mp4", + "extension": "mp4", + "filesize": "31730876", + "_lastWrite": 38922, + "mimetype": "video\/mp4", + "duration": "00:13:50", + "avgBitrate": "301 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/f4ea380afc.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/40d1c78a61.jpg" + } + ] + } + }, + { + "uniqueHash": "937dcd0b0b507f5522153597dab0987a", + "description": "A recap of PCA of spectral type data.", + "pubDate": 1424762280, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4C: Spectral data motivation", + "startOffset": "{0}", + "hits": "155", + "hits-720p": "155", + "bandwidth": "4453781605", + "hitspartial-720p": "237", + "hits-480p": "42", + "bandwidth-480p": "713578826", + "hitspartial-480p": "21", + "bandwidth-720p": "4453781605", + "hitspartial": "237", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4CSpectraldatamotivation-20150224081802-720p.mp4", + "extension": "mp4", + "filesize": "17445535", + "_lastWrite": 39261, + "mimetype": "video\/mp4", + "duration": "00:07:40", + "avgBitrate": "299 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8cd5d262b8.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/a2e2306bc7.jpg" + } + ] + } + }, + { + "uniqueHash": "7254384fc361c268351325eccdac9753", + "description": "A final wrap up of this.", + "pubDate": 1424762340, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4D: What is PCR then.", + "startOffset": "{0}", + "hits": "152", + "hits-720p": "152", + "bandwidth": "1132768738", + "hitspartial-720p": "265", + "hits-480p": "41", + "bandwidth-480p": "162609019", + "hitspartial-480p": "16", + "bandwidth-720p": "1132768738", + "hitspartial": "265", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4DWhatisPCRthen-20150224081901-720p.mp4", + "extension": "mp4", + "filesize": "4249035", + "_lastWrite": 25112, + "mimetype": "video\/mp4", + "duration": "00:01:49", + "avgBitrate": "306 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/79b94d9978.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ed518e8e78.jpg" + } + ] + } + }, + { + "uniqueHash": "d57a539cff1eaf526e0f166ddcd84973", + "description": "A brief overview of the analysis approach.", + "pubDate": 1424762460, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4E: PCR - how to do it?", + "startOffset": "{0}", + "hits": "152", + "hits-720p": "152", + "bandwidth": "1825170139", + "hitspartial-720p": "236", + "hits-480p": "44", + "bandwidth-480p": "337119866", + "hitspartial-480p": "26", + "bandwidth-720p": "1825170139", + "hitspartial": "236", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4EPCRhowtodoit-20150224082102-720p.mp4", + "extension": "mp4", + "filesize": "7287343", + "_lastWrite": 38697, + "mimetype": "video\/mp4", + "duration": "00:03:11", + "avgBitrate": "301 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/49a0a68a94.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/2855446c5a.jpg" + } + ] + } + }, + { + "uniqueHash": "1907451e187054afc3464773624e02dd", + "description": "Cross validation and other validation and resampling techniques. Model selection. Bias and variance.", + "pubDate": 1424762580, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 4F: Cross validation and friends.", + "startOffset": "{0}", + "hits": "157", + "hits-720p": "157", + "bandwidth": "27999803550", + "hitspartial-720p": "610", + "hits-480p": "44", + "bandwidth-480p": "3458692808", + "hitspartial-480p": "36", + "bandwidth-720p": "27999803550", + "hitspartial": "610", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec4FCrossvalidationandfriends-20150224082301-720p.mp4", + "extension": "mp4", + "filesize": "70995122", + "_lastWrite": 36908, + "mimetype": "video\/mp4", + "duration": "00:28:20", + "avgBitrate": "330 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8a52efbccd.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/2ab32c13c1.jpg" + } + ] + } + }, + { + "uniqueHash": "d379b2c39ef84e129808b73f3bf108c7", + "description": "Motivating example: Leslie Salt data.", + "pubDate": 1426069080, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 6A. PLS. Motivation", + "startOffset": "{0}", + "hits": "166", + "hits-720p": "166", + "bandwidth": "10203294521", + "hitspartial-720p": "340", + "hits-480p": "42", + "bandwidth-480p": "1133168132", + "bandwidth-720p": "456731204", + "hitspartial": "340", + "hitspartial-480p": "10", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec6APLSMotivation-20150311111801-720p.mp4", + "extension": "mp4", + "filesize": "32537511", + "_lastWrite": 9176, + "mimetype": "video\/mp4", + "duration": "00:13:23", + "avgBitrate": "319 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c188ec5f9e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/e6f6c946e5.jpg" + } + ] + } + }, + { + "uniqueHash": "6d277cd11226e114588b7716264296f3", + "description": "What is pls?", + "pubDate": 1426069140, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 6B. PLS: What is it?", + "startOffset": "{0}", + "hits": "156", + "hits-720p": "156", + "bandwidth": "11328226838", + "hitspartial-720p": "362", + "hits-480p": "48", + "bandwidth-480p": "1532705889", + "hitspartial-480p": "20", + "bandwidth-720p": "11328226838", + "hitspartial": "362", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec6BPLSWhatisit-20150311111901-720p.mp4", + "extension": "mp4", + "filesize": "34673027", + "_lastWrite": 9118, + "mimetype": "video\/mp4", + "duration": "00:14:11", + "avgBitrate": "321 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/db311f19c9.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/3c6d345ff4.jpg" + } + ] + } + }, + { + "uniqueHash": "2ef9f47bdba4751c2629d0112ab19c0d", + "description": "A description of the analysis approach when using PLS-regression.", + "pubDate": 1426069200, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 6C. PLS - how to do it!", + "startOffset": "{0}", + "hits": "74", + "hits-720p": "74", + "bandwidth": "5324935269", + "hitspartial-720p": "241", + "hits-480p": "11", + "bandwidth-480p": "420077879", + "bandwidth-720p": "256347943", + "hitspartial": "241", + "hitspartial-480p": "10", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec6CPLShowtodoit-20150311112002-720p.mp4", + "extension": "mp4", + "filesize": "31939868", + "_lastWrite": 7914, + "mimetype": "video\/mp4", + "duration": "00:13:30", + "avgBitrate": "311 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/07cd9e62b0.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1641401809.jpg" + } + ] + } + }, + { + "uniqueHash": "89d6a91837bc1b3f7b27b0f1baa427cc", + "description": "A different description of PLS - a chemometrics perspective.", + "pubDate": 1426069320, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 6D. PLS - what is it?", + "startOffset": "{0}", + "hits": "159", + "hits-720p": "159", + "bandwidth": "39724700030", + "hitspartial-720p": "623", + "hits-480p": "44", + "bandwidth-480p": "1621833151", + "hitspartial-480p": "24", + "bandwidth-720p": "39724700030", + "hitspartial": "623", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec6DPLSwhatisit-20150311112201-720p.mp4", + "extension": "mp4", + "filesize": "89925208", + "_lastWrite": 7512, + "mimetype": "video\/mp4", + "duration": "00:12:20", + "avgBitrate": "967 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c0996a0b14.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d66c122500.jpg" + } + ] + } + }, + { + "uniqueHash": "655565926a2c047e7e47c7dfddab7685", + "description": "Finding optimal predictor by CV (cross validation): Bias, variance and model complexity.", + "pubDate": 1426514880, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7A: Optimal predictor?", + "startOffset": "{0}", + "hits": "137", + "hits-720p": "137", + "bandwidth": "9182129926", + "hitspartial-720p": "242", + "hits-480p": "45", + "bandwidth-480p": "1927151512", + "hitspartial-480p": "54", + "bandwidth-720p": "9182129926", + "hitspartial": "242", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7AOptimalpredictor-20150316150802-720p.mp4", + "extension": "mp4", + "filesize": "39758243", + "_lastWrite": 8172, + "mimetype": "video\/mp4", + "duration": "00:15:25", + "avgBitrate": "339 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/53e7a117fc.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9d277665df.jpg" + } + ] + } + }, + { + "uniqueHash": "8a94811a35a7fbc922b09dabe1dd5fa4", + "description": "MLR produces solutions with too large coefficients.", + "pubDate": 1426515060, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7B: MLR and the problem.", + "startOffset": "{0}", + "hits": "131", + "hits-720p": "131", + "bandwidth": "4966323237", + "hitspartial-720p": "190", + "hits-480p": "40", + "bandwidth-480p": "865418778", + "hitspartial-480p": "16", + "bandwidth-720p": "4966323237", + "hitspartial": "190", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7BMLRandtheproblem-20150316151101-720p.mp4", + "extension": "mp4", + "filesize": "23365254", + "_lastWrite": 8227, + "mimetype": "video\/mp4", + "duration": "00:10:05", + "avgBitrate": "304 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/68b027aac3.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/58bb2597b2.jpg" + } + ] + } + }, + { + "uniqueHash": "1bb9dfcf209b1f1d24194e55b59075f6", + "description": "Definition of Ridge Regression", + "pubDate": 1426515180, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7C: Ridge Regression", + "startOffset": "{0}", + "hits": "138", + "hits-720p": "138", + "bandwidth": "19408402522", + "hitspartial-720p": "272", + "hits-480p": "45", + "bandwidth-480p": "1201300917", + "hitspartial-480p": "22", + "bandwidth-720p": "19408402522", + "hitspartial": "272", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7CRidgeRegression-20150316151305-720p.mp4", + "extension": "mp4", + "filesize": "76212747", + "_lastWrite": 7524, + "mimetype": "video\/mp4", + "duration": "00:07:36", + "avgBitrate": "1.33 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/252a0fdb77.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/dfff74ad15.jpg" + } + ] + } + }, + { + "uniqueHash": "d2b573a332884700ae3a686a34c20a6a", + "description": "Definition of Lasso regression.", + "pubDate": 1426515180, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7D: Lasso Regression", + "startOffset": "{0}", + "hits": "136", + "hits-720p": "136", + "bandwidth": "4831075872", + "hitspartial-720p": "178", + "hits-480p": "42", + "bandwidth-480p": "304109047", + "hitspartial-480p": "10", + "bandwidth-720p": "4831075872", + "hitspartial": "178", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7DLassoRegression-20150316151301-720p.mp4", + "extension": "mp4", + "filesize": "22318945", + "_lastWrite": 7859, + "mimetype": "video\/mp4", + "duration": "00:02:16", + "avgBitrate": "1.3 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/bfbedb8c86.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8e4c98e93f.jpg" + } + ] + } + }, + { + "uniqueHash": "c54a598773021ac19a90d3815daa2716", + "description": "The solution", + "pubDate": 1426515300, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7E: Ridge Regression", + "startOffset": "{0}", + "hits": "137", + "hits-720p": "137", + "bandwidth": "7333966785", + "hitspartial-720p": "164", + "hits-480p": "37", + "bandwidth-480p": "421834993", + "hitspartial-480p": "9", + "bandwidth-720p": "7333966785", + "hitspartial": "164", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7ERidgeRegression-20150316151520-720p.mp4", + "extension": "mp4", + "filesize": "35553938", + "_lastWrite": 7622, + "mimetype": "video\/mp4", + "duration": "00:03:34", + "avgBitrate": "1.32 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/f6bfb8ea6e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/851a6e4107.jpg" + } + ] + } + }, + { + "uniqueHash": "2ce0c4169d0687a15226dd5b23512d95", + "description": "L2 and L1 regression methods - an overview.", + "pubDate": 1426515420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7F: Ridge and Lasso", + "startOffset": "{0}", + "hits": "130", + "hits-720p": "130", + "bandwidth": "30147487524", + "hitspartial-720p": "254", + "hits-480p": "40", + "bandwidth-480p": "1519755150", + "hitspartial-480p": "11", + "bandwidth-720p": "30147487524", + "hitspartial": "254", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7FRidgeandLasso-20150316151710-720p.mp4", + "extension": "mp4", + "filesize": "122875330", + "_lastWrite": 4694, + "mimetype": "video\/mp4", + "duration": "00:11:52", + "avgBitrate": "1.37 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/04e03e2444.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/69417e5b9a.jpg" + } + ] + } + }, + { + "uniqueHash": "8a15f7c583635601098a89f22d1f6576", + "description": "A small example.", + "pubDate": 1426515420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7G: Rddge Regression", + "startOffset": "{0}", + "hits": "127", + "bandwidth": "7201996898", + "hits-480p": "45", + "bandwidth-480p": "605313873", + "hitspartial": "158", + "hitspartial-480p": "19", + "hits-720p": "127", + "hitspartial-720p": "158", + "bandwidth-720p": "7201996898", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7GRddgeRegression-20150316151701-720p.mp4", + "extension": "mp4", + "filesize": "37292088", + "_lastWrite": 7382, + "mimetype": "video\/mp4", + "duration": "00:03:45", + "avgBitrate": "1.32 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/86044aab7e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/74816ea595.jpg" + } + ] + } + }, + { + "uniqueHash": "1a29b54c87c7de6234523be76cda4122", + "description": "k-Nearest Neighbour", + "pubDate": 1427313720, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8F: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "11480842861", + "hits-480p": "44", + "bandwidth-480p": "1379442463", + "hitspartial": "255", + "hitspartial-480p": "71", + "hits": "153", + "hits-720p": "153", + "hitspartial-720p": "255", + "bandwidth-720p": "11480842861", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8FDiscriminantAnalysis-20150325210201-720p.mp4", + "extension": "mp4", + "filesize": "43091782", + "_lastWrite": 42090, + "mimetype": "video\/mp4", + "duration": "00:07:34", + "avgBitrate": "753 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ae7cc82410.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/22be474b80.jpg" + } + ] + } + }, + { + "uniqueHash": "ee1dc0c3c5ad57a93a397e84422e640c", + "description": "Question to small example.", + "pubDate": 1426515540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7H: Ridge Regression", + "startOffset": "{0}", + "hits": "120", + "hits-720p": "120", + "bandwidth": "4220989959", + "hitspartial-720p": "118", + "hits-480p": "44", + "bandwidth-480p": "386123311", + "hitspartial-480p": "18", + "bandwidth-720p": "4220989959", + "hitspartial": "118", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7HRidgeRegression-20150316151914-720p.mp4", + "extension": "mp4", + "filesize": "24625251", + "_lastWrite": 6931, + "mimetype": "video\/mp4", + "duration": "00:02:29", + "avgBitrate": "1.31 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/839cfb07c3.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/5eab76a980.jpg" + } + ] + } + }, + { + "uniqueHash": "0b1e6122d66aab92dabaee6d9351c7ed", + "description": "How to analyze data by Ridge and Lasso Regression - the overall approach.", + "pubDate": 1426515540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 7I: Ridge and Lasso.", + "startOffset": "{0}", + "hits": "130", + "hits-720p": "130", + "bandwidth": "6628451869", + "hitspartial-720p": "158", + "hits-480p": "41", + "bandwidth-480p": "443015128", + "hitspartial-480p": "11", + "bandwidth-720p": "6628451869", + "hitspartial": "158", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec7IRidgeandLasso-20150316151901-720p.mp4", + "extension": "mp4", + "filesize": "34174210", + "_lastWrite": 6828, + "mimetype": "video\/mp4", + "duration": "00:03:28", + "avgBitrate": "1.31 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ebe4353168.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/8e89060247.jpg" + } + ] + } + }, + { + "uniqueHash": "94c4487ffcae3e566d87053fe4c12942", + "description": "An introduction", + "pubDate": 1427313300, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8A: Discriminant Analysis", + "startOffset": "{0}", + "hits": "173", + "hits-720p": "173", + "bandwidth": "30940781245", + "hitspartial-720p": "649", + "hits-480p": "48", + "bandwidth-480p": "1887104320", + "hitspartial-480p": "22", + "bandwidth-720p": "30940781245", + "hitspartial": "649", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8ADiscriminantAnalysis-20150325205501-720p.mp4", + "extension": "mp4", + "filesize": "76542144", + "_lastWrite": 44971, + "mimetype": "video\/mp4", + "duration": "00:13:52", + "avgBitrate": "731 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/380e19b3ce.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0a9f00d93f.jpg" + } + ] + } + }, + { + "uniqueHash": "8faf2bc056dbe897a2ac1043862e8366", + "description": "Different priors and miss classification costs", + "pubDate": 1427313420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8B: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "14695642164", + "hits-480p": "43", + "bandwidth-480p": "1326260111", + "hitspartial": "308", + "hitspartial-480p": "39", + "hits": "150", + "hits-720p": "150", + "hitspartial-720p": "308", + "bandwidth-720p": "14695642164", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8BDiscriminantAnalysis-20150325205701-720p.mp4", + "extension": "mp4", + "filesize": "54807070", + "_lastWrite": 43154, + "mimetype": "video\/mp4", + "duration": "00:09:27", + "avgBitrate": "768 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/2376b7f898.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/12a76b69bb.jpg" + } + ] + } + }, + { + "uniqueHash": "86aa7aba2d37d9b1ecad45ada1083fe9", + "description": "LDA and QDA: Linear and Quadratic DA.", + "pubDate": 1427313540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8C: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "16584740464", + "hits-480p": "43", + "bandwidth-480p": "2806513615", + "hitspartial": "172", + "hitspartial-480p": "65", + "hits": "94", + "hits-720p": "94", + "hitspartial-720p": "172", + "bandwidth-720p": "16584740464", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8CDiscriminantAnalysis-20150325205901-720p.mp4", + "extension": "mp4", + "filesize": "96837443", + "_lastWrite": 42136, + "mimetype": "video\/mp4", + "duration": "00:16:56", + "avgBitrate": "758 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/02006c3e86.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/91f57be561.jpg" + } + ] + } + }, + { + "uniqueHash": "9f0220d531330aee6b18010c5f631685", + "description": "Fisher and CVA.", + "pubDate": 1427313600, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8D: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "18040634367", + "hits-480p": "43", + "bandwidth-480p": "1515812934", + "hitspartial": "412", + "hitspartial-480p": "43", + "hits": "157", + "hits-720p": "157", + "hitspartial-720p": "412", + "bandwidth-720p": "18040634367", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8DDiscriminantAnalysis-20150325210002-720p.mp4", + "extension": "mp4", + "filesize": "58610186", + "_lastWrite": 43028, + "mimetype": "video\/mp4", + "duration": "00:10:19", + "avgBitrate": "752 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/2a03e3bcd5.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0aa868caef.jpg" + } + ] + } + }, + { + "uniqueHash": "3f6fc06e5b06e7d3952f3b4f6774ed32", + "description": "Relations between Bayes, LDA, QDA and CVA.", + "pubDate": 1427313660, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8E: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "6579108276", + "hits-480p": "43", + "bandwidth-480p": "600247926", + "hitspartial": "274", + "hitspartial-480p": "39", + "hits": "156", + "hits-720p": "156", + "hitspartial-720p": "274", + "bandwidth-720p": "6579108276", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8EDiscriminantAnalysis-20150325210101-720p.mp4", + "extension": "mp4", + "filesize": "23810626", + "_lastWrite": 39605, + "mimetype": "video\/mp4", + "duration": "00:04:07", + "avgBitrate": "765 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9f6be61f9d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/cdf5967b90.jpg" + } + ] + } + }, + { + "uniqueHash": "94232baf2e9fbba75a7ba1ddf7197b76", + "description": "Regression and PLS", + "pubDate": 1427313840, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8G: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "8585839885", + "hits-480p": "40", + "bandwidth-480p": "839526201", + "hitspartial": "250", + "hitspartial-480p": "50", + "hits": "149", + "hits-720p": "149", + "hitspartial-720p": "250", + "bandwidth-720p": "8585839885", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8GDiscriminantAnalysis-20150325210401-720p.mp4", + "extension": "mp4", + "filesize": "33585452", + "_lastWrite": 42227, + "mimetype": "video\/mp4", + "duration": "00:05:04", + "avgBitrate": "878 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/121e3e5b8a.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c858fee56e.jpg" + } + ] + } + }, + { + "uniqueHash": "8017fcd866b5b8f8a61b3ff1ce096034", + "description": "Supervised learning and classical statistics", + "pubDate": 1428931020, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 9A: S\u00f8ren Havelund Welling(SHW): Supervised learning", + "startOffset": "{0}", + "hits": "121", + "hits-720p": "121", + "hitspartial-720p": "129", + "bandwidth": "5857709117", + "hitspartial": "129", + "bandwidth-720p": "5857709117", + "hits-480p": "37", + "bandwidth-480p": "584899873", + "hitspartial-480p": "13", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec9ASrenHavelundWellingSHWSupervisedlearning-20150413151701-720p.mp4", + "extension": "mp4", + "filesize": "33623568", + "_lastWrite": 3095, + "mimetype": "video\/mp4", + "duration": "00:04:23", + "avgBitrate": "1.02 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/6e5ac1771d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/310ce4efb8.jpg" + } + ] + } + }, + { + "uniqueHash": "ca4c7ad215249218f52d963b0d1a4660", + "description": "Regression, PLS and summary.", + "pubDate": 1427313900, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 8H: Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "11215134521", + "hits-480p": "41", + "bandwidth-480p": "894745380", + "hitspartial": "297", + "hitspartial-480p": "30", + "hits": "144", + "hits-720p": "144", + "hitspartial-720p": "297", + "bandwidth-720p": "11215134521", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec8HDiscriminantAnalysis-20150325210504-720p.mp4", + "extension": "mp4", + "filesize": "41366571", + "_lastWrite": 41252, + "mimetype": "video\/mp4", + "duration": "00:06:48", + "avgBitrate": "805 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/33d9929568.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/a6e581d66c.jpg" + } + ] + } + }, + { + "uniqueHash": "2202d00752867e2af3ee06ed3b4c7722", + "description": "The Tree model, bagging and random forests.", + "pubDate": 1428931080, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 9B: (SHW): Random Forests", + "startOffset": "{0}", + "hits": "125", + "hits-720p": "125", + "bandwidth": "43786951210", + "hitspartial-720p": "392", + "hits-480p": "39", + "bandwidth-480p": "4119552800", + "hitspartial": "392", + "hitspartial-480p": "58", + "bandwidth-720p": "43786951210", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec9BSHWRandomForests-20150413151801-720p.mp4", + "extension": "mp4", + "filesize": "156609164", + "_lastWrite": 5101, + "mimetype": "video\/mp4", + "duration": "00:19:12", + "avgBitrate": "1.08 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1a3e1ed63e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/13d78ec332.jpg" + } + ] + } + }, + { + "uniqueHash": "0a19affd9cdb9c359f0cbb9d3380ecfa", + "description": "Learning from the model: Interpretation. Using ForestFloor - an R-package developed by SHW.", + "pubDate": 1428932760, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Lec 9C (SHW): Random Forests", + "startOffset": "{0}", + "hits": "121", + "hits-720p": "121", + "hitspartial-720p": "145", + "bandwidth": "26263032119", + "hitspartial": "145", + "bandwidth-720p": "26263032119", + "hits-480p": "38", + "bandwidth-480p": "2616717019", + "hitspartial-480p": "19", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Lec9CSHWRandomForests-20150413154601-720p.mp4", + "extension": "mp4", + "filesize": "141554891", + "_lastWrite": 3325, + "mimetype": "video\/mp4", + "duration": "00:16:51", + "avgBitrate": "1.11 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/abff0330a6.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/01a24e23d0.jpg" + } + ] + } + }, + { + "uniqueHash": "55c312322107fa27674e011801d9b803", + "description": "Multidimensional scaling_PCO_MDS_NMS in general", + "pubDate": 1430822940, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Multidimensional scaling_27411_Chemometrics", + "startOffset": "{0}", + "hits": "131", + "hits-720p": "131", + "bandwidth": "76563924994", + "hitspartial-720p": "635", + "hits-480p": "33", + "bandwidth-480p": "3043819278", + "hitspartial-480p": "10", + "bandwidth-720p": "76563924994", + "hitspartial": "635", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Multidimensionalscaling27411Chemometrics-20150505124901-720p.mp4", + "extension": "mp4", + "filesize": "241954890", + "_lastWrite": 10053, + "mimetype": "video\/mp4", + "duration": "00:25:52", + "avgBitrate": "1.24 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0048cc6c04.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d7a6dd148a.jpg" + } + ] + } + }, + { + "uniqueHash": "54ce0965acfb91e654f29a3a800a808a", + "description": "Multidimensional scaling_27411_PCO-NMS_MST_DTU_27411", + "pubDate": 1431440040, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Multidimensional scaling_27411_Chemometrics", + "startOffset": "{0}", + "hits": "150", + "bandwidth": "104288583996", + "hits-480p": "42", + "bandwidth-480p": "5155732789", + "hitspartial": "1535", + "hitspartial-480p": "60", + "hits-720p": "150", + "hitspartial-720p": "1535", + "bandwidth-720p": "104288583996", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Multidimensionalscaling27411Chemometrics-20150512161401-720p.mp4", + "extension": "mp4", + "filesize": "241954966", + "_lastWrite": 11338, + "mimetype": "video\/mp4", + "duration": "00:25:52", + "avgBitrate": "1.24 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ab2dbf22a1.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d7ac7c55a4.jpg" + } + ] + } + }, + { + "uniqueHash": "87e1d85e84c1c252961ada4c504b1f5f", + "description": "Overview of classification in Chemometrics, by Jens Chr. Frisvad.", + "pubDate": 1431438420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 1", + "startOffset": "{0}", + "hits": "137", + "bandwidth": "32280531152", + "hits-480p": "40", + "bandwidth-480p": "2337462046", + "hitspartial": "345", + "hitspartial-480p": "39", + "hits-720p": "137", + "hitspartial-720p": "345", + "bandwidth-720p": "32280531152", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture1-20150512154702-720p.mp4", + "extension": "mp4", + "filesize": "123714756", + "_lastWrite": 2482, + "mimetype": "video\/mp4", + "duration": "00:13:57", + "avgBitrate": "1.18 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1e4e1b0900.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/b214aeca4a.jpg" + } + ] + } + }, + { + "uniqueHash": "132b131ad23fe0ef3c8b3d46e5701cba", + "description": "Regression and discrimination, by Per B.B.", + "pubDate": 1431438480, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2A", + "startOffset": "{0}", + "hits": "126", + "hits-720p": "126", + "bandwidth": "8869351311", + "hitspartial-720p": "240", + "hits-480p": "33", + "bandwidth-480p": "1349420891", + "hitspartial-480p": "23", + "bandwidth-720p": "8869351311", + "hitspartial": "240", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2A-20150512154801-720p.mp4", + "extension": "mp4", + "filesize": "40554399", + "_lastWrite": 1009, + "mimetype": "video\/mp4", + "duration": "00:17:24", + "avgBitrate": "306 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/367f9c51ae.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/9339c6624c.jpg" + } + ] + } + }, + { + "uniqueHash": "7d0dc0f3a1c7058d12ce47ff4b49b455", + "description": "Bias and Variance in prediction, optimal predictor.", + "pubDate": 1431438540, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2B", + "startOffset": "{0}", + "hits": "140", + "hits-720p": "140", + "bandwidth": "4169753106", + "hitspartial-720p": "143", + "hits-480p": "30", + "bandwidth-480p": "544771534", + "hitspartial-480p": "3", + "bandwidth-720p": "4169753106", + "hitspartial": "143", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2B-20150512154902-720p.mp4", + "extension": "mp4", + "filesize": "22463183", + "_lastWrite": 203, + "mimetype": "video\/mp4", + "duration": "00:09:57", + "avgBitrate": "296 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/961cf879ab.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ce08252cea.jpg" + } + ] + } + }, + { + "uniqueHash": "2da979237d0f83bb91eda09c2fdf7720", + "description": "MLR - the basic model.", + "pubDate": 1431438720, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2C", + "startOffset": "{0}", + "hits": "109", + "hits-720p": "109", + "bandwidth": "2013221279", + "hitspartial-720p": "108", + "hits-480p": "31", + "bandwidth-480p": "340923722", + "hitspartial-480p": "4", + "bandwidth-720p": "2013221279", + "hitspartial": "108", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2C-20150512155202-720p.mp4", + "extension": "mp4", + "filesize": "13547947", + "_lastWrite": 3370, + "mimetype": "video\/mp4", + "duration": "00:05:59", + "avgBitrate": "297 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/951f6a90a6.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/e2ef74442a.jpg" + } + ] + } + }, + { + "uniqueHash": "3a087e1eba98622a6efdc9aba9e9aee9", + "description": "Biased regression methods: Ridge, Lasso, PLS, PCR.", + "pubDate": 1431438780, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2D", + "startOffset": "{0}", + "hits": "114", + "bandwidth": "5419458884", + "hits-480p": "33", + "bandwidth-480p": "927272013", + "hitspartial": "179", + "hitspartial-480p": "9", + "hits-720p": "114", + "hitspartial-720p": "179", + "bandwidth-720p": "5419458884", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2D-20150512155301-720p.mp4", + "extension": "mp4", + "filesize": "32458294", + "_lastWrite": 2638, + "mimetype": "video\/mp4", + "duration": "00:14:29", + "avgBitrate": "294 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/979801a0b2.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/76145ec846.jpg" + } + ] + } + }, + { + "uniqueHash": "9dcb55330c51996a404f6cb620004b39", + "description": "All the methods are shrinking the MLR solution.", + "pubDate": 1431438840, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2E", + "startOffset": "{0}", + "hits": "108", + "hits-720p": "108", + "bandwidth": "2537727011", + "hitspartial-720p": "86", + "hits-480p": "32", + "bandwidth-480p": "495316448", + "hitspartial-480p": "4", + "bandwidth-720p": "2537727011", + "hitspartial": "86", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2E-20150512155401-720p.mp4", + "extension": "mp4", + "filesize": "19086899", + "_lastWrite": 2694, + "mimetype": "video\/mp4", + "duration": "00:08:18", + "avgBitrate": "302 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/35cdec4a0d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/e038746d18.jpg" + } + ] + } + }, + { + "uniqueHash": "08282afa7270a7c63d60fea0c36564b6", + "description": "See how to use the 'pcr' function of the 'pls' package.", + "pubDate": 1424762700, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, PCR", + "startOffset": "{0}", + "hits": "142", + "hits-720p": "142", + "bandwidth": "25701296679", + "hitspartial-720p": "432", + "hits-480p": "54", + "bandwidth-480p": "4452825004", + "hitspartial-480p": "30", + "bandwidth-720p": "25701296679", + "hitspartial": "432", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialPCR-20150224082501-720p.mp4", + "extension": "mp4", + "filesize": "85606314", + "_lastWrite": 35498, + "mimetype": "video\/mp4", + "duration": "00:35:23", + "avgBitrate": "318 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/30c03f57b5.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/11594cef4d.jpg" + } + ] + } + }, + { + "uniqueHash": "3561bdc5bd6815697fd8f30cedca2fb9", + "description": "All the methods are shrinking the MLR solution.", + "pubDate": 1431438900, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2E", + "startOffset": "{0}", + "hits": "101", + "bandwidth": "2599224004", + "hits-480p": "31", + "bandwidth-480p": "499197524", + "hitspartial": "93", + "hitspartial-480p": "20", + "hits-720p": "101", + "hitspartial-720p": "93", + "bandwidth-720p": "2599224004", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2E-20150512155502-720p.mp4", + "extension": "mp4", + "filesize": "19086899", + "_lastWrite": 2069, + "mimetype": "video\/mp4", + "duration": "00:08:18", + "avgBitrate": "302 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/0ba1a19aa2.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/fa0217811d.jpg" + } + ] + } + }, + { + "uniqueHash": "b3a9190524c2cdb3e83ee91a2e9b7358", + "description": "The overall modelling approach: Cross validation etc.", + "pubDate": 1431438960, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Overview Lecture 2F", + "startOffset": "{0}", + "hits": "123", + "bandwidth": "3865434654", + "hits-480p": "37", + "bandwidth-480p": "907002958", + "hitspartial": "195", + "hitspartial-480p": "697", + "hits-720p": "123", + "hitspartial-720p": "195", + "bandwidth-720p": "3865434654", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/OverviewLecture2F-20150512155601-720p.mp4", + "extension": "mp4", + "filesize": "20344645", + "_lastWrite": 1947, + "mimetype": "video\/mp4", + "duration": "00:08:39", + "avgBitrate": "309 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/3406199efe.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/e485195484.jpg" + } + ] + } + }, + { + "uniqueHash": "a12b87658ced4472152a7e1d19566c62", + "description": "PCA, first lecture for DTU course 27411", + "pubDate": 1423558740, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Principal Component Analysis_1", + "startOffset": "{0}", + "hits": "248", + "bandwidth": "190378424337", + "hits-480p": "52", + "bandwidth-480p": "6033361562", + "hitspartial": "1623", + "hitspartial-480p": "62", + "hits-720p": "248", + "bandwidth-720p": "928935940", + "hitspartial-720p": "1623", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/PrincipalComponentAnalysis1-20150210095901-720p.mp4", + "extension": "mp4", + "filesize": "232233985", + "_lastWrite": 624, + "mimetype": "video\/mp4", + "duration": "00:25:18", + "avgBitrate": "1.22 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/943de55787.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/4f60e0b6e0.jpg" + } + ] + } + }, + { + "uniqueHash": "3320f5b573ca98f4bea13918c64a911c", + "description": "PCA_part_2, DTU course 27411", + "pubDate": 1423558860, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "Principal Component Analysis_2", + "startOffset": "{0}", + "hits": "176", + "bandwidth": "170057364518", + "hits-480p": "53", + "bandwidth-480p": "8684901773", + "hitspartial": "1131", + "hitspartial-480p": "61", + "hits-720p": "176", + "bandwidth-720p": "1576753555", + "hitspartial-720p": "1131", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/PrincipalComponentAnalysis2-20150210100102-720p.mp4", + "extension": "mp4", + "filesize": "315350711", + "_lastWrite": 1499, + "mimetype": "video\/mp4", + "duration": "00:34:49", + "avgBitrate": "1.2 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/568817708c.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ff111d0772.jpg" + } + ] + } + }, + { + "uniqueHash": "90914f76b1e8118e8903a6cdc8f8730e", + "description": "Iris data example. Various methods, part 1.", + "pubDate": 1427314140, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "24990734855", + "hits-480p": "40", + "bandwidth-480p": "2217805269", + "hitspartial": "244", + "hitspartial-480p": "24", + "hits": "132", + "hits-720p": "132", + "hitspartial-720p": "244", + "bandwidth-720p": "24990734855", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialDiscriminantAnalysis-20150325210901-720p.mp4", + "extension": "mp4", + "filesize": "108566456", + "_lastWrite": 39852, + "mimetype": "video\/mp4", + "duration": "00:17:12", + "avgBitrate": "836 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/4cecc755fd.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d5577a40e7.jpg" + } + ] + } + }, + { + "uniqueHash": "49cd537b5ac1768de4ac3c5af18d53ce", + "description": "Iris data example. Various methods, part 1.", + "pubDate": 1427314140, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Discriminant Analysis", + "startOffset": "{0}", + "bandwidth": "12180598086", + "hits-480p": "40", + "bandwidth-480p": "1316227654", + "hitspartial": "192", + "hitspartial-480p": "29", + "hits": "131", + "hits-720p": "131", + "hitspartial-720p": "192", + "bandwidth-720p": "12180598086", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialDiscriminantAnalysis-20150325210929-720p.mp4", + "extension": "mp4", + "filesize": "58816309", + "_lastWrite": 40647, + "mimetype": "video\/mp4", + "duration": "00:09:46", + "avgBitrate": "797 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/b1c7f97d30.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/35b74cc469.jpg" + } + ] + } + }, + { + "uniqueHash": "be9a6538ac5c47a5dbb24a260ba8a371", + "description": "How to do it in R.", + "pubDate": 1426515720, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Lasso Regression.", + "startOffset": "{0}", + "hits": "129", + "hits-720p": "129", + "bandwidth": "14199455391", + "hitspartial-720p": "161", + "hits-480p": "41", + "bandwidth-480p": "1180833642", + "bandwidth-720p": "525394652", + "hitspartial": "161", + "hitspartial-480p": "21", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialLassoRegression-20150316152201-720p.mp4", + "extension": "mp4", + "filesize": "74669707", + "_lastWrite": 5909, + "mimetype": "video\/mp4", + "duration": "00:07:29", + "avgBitrate": "1.32 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1c04ed9c8d.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/838284ba84.jpg" + } + ] + } + }, + { + "uniqueHash": "36a108823adc1d1873082e830119cbc3", + "description": "How to use R to analyse data by PLS-regression.", + "pubDate": 1426069380, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, PLS.", + "startOffset": "{0}", + "hits": "142", + "hits-720p": "142", + "bandwidth": "21691962707", + "hitspartial-720p": "390", + "hits-480p": "41", + "bandwidth-480p": "3046328752", + "bandwidth-720p": "1014125188", + "hitspartial": "390", + "hitspartial-480p": "77", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialPLS-20150311112302-720p.mp4", + "extension": "mp4", + "filesize": "63228338", + "_lastWrite": 7135, + "mimetype": "video\/mp4", + "duration": "00:20:55", + "avgBitrate": "398 kbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/1be9809c52.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/5d29e871ac.jpg" + } + ] + } + }, + { + "uniqueHash": "f6e973c9eacfcb58cfd609b672870efa", + "description": "How to do it in R.", + "pubDate": 1426515600, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Ridge Regression.", + "startOffset": "{0}", + "hits": "66", + "bandwidth": "29445034093", + "hits-480p": "12", + "bandwidth-480p": "990455037", + "hitspartial": "307", + "hitspartial-480p": "22", + "hits-720p": "66", + "hitspartial-720p": "307", + "bandwidth-720p": "29445034093", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialRidgeRegression-20150316152001-720p.mp4", + "extension": "mp4", + "filesize": "153671174", + "_lastWrite": 5573, + "mimetype": "video\/mp4", + "duration": "00:15:14", + "avgBitrate": "1.34 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/07fce7173e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/59ef71d8a1.jpg" + } + ] + } + }, + { + "uniqueHash": "836e4334ae4b6d0c0b446e7df586a68f", + "description": "How to predict in R.", + "pubDate": 1426515840, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "RTutorial, Ridge and Lasso Regression.", + "startOffset": "{0}", + "hits": "126", + "hits-720p": "126", + "bandwidth": "5223320228", + "hitspartial-720p": "153", + "hits-480p": "43", + "bandwidth-480p": "450966680", + "hitspartial-480p": "19", + "bandwidth-720p": "5223320228", + "hitspartial": "153", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RTutorialRidgeandLassoRegression-20150316152401-720p.mp4", + "extension": "mp4", + "filesize": "28096240", + "_lastWrite": 6339, + "mimetype": "video\/mp4", + "duration": "00:02:52", + "avgBitrate": "1.3 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/4b2b69928e.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/812bf4adc6.jpg" + } + ] + } + }, + { + "uniqueHash": "0dab12bc7f26d5eaae8a1498b1bc1296", + "description": "How to run Random forests in R. An example.", + "pubDate": 1428931260, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "R-tutorial (SHW):; Random forests", + "startOffset": "{0}", + "hits": "133", + "hits-720p": "133", + "bandwidth": "11793833430", + "hitspartial-720p": "138", + "hits-480p": "35", + "bandwidth-480p": "1061566470", + "hitspartial": "138", + "hitspartial-480p": "41", + "bandwidth-720p": "11793833430", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RtutorialSHWRandomforests-20150413152101-720p.mp4", + "extension": "mp4", + "filesize": "62894886", + "_lastWrite": 30, + "mimetype": "video\/mp4", + "duration": "00:07:53", + "avgBitrate": "1.06 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/d48903c9b2.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/ce4870fe26.jpg" + } + ] + } + }, + { + "uniqueHash": "abe381b90a0fa8afa5041a1d3bae66c4", + "description": "Presenting the two data sets for the exercises.", + "pubDate": 1428933420, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "R-tutorial - exercise data (SHW)", + "startOffset": "{0}", + "hits": "100", + "hits-720p": "100", + "hitspartial-720p": "71", + "bandwidth": "23175005703", + "hitspartial": "71", + "bandwidth-720p": "23175005703", + "hits-480p": "37", + "bandwidth-480p": "2495282008", + "hitspartial-480p": "11", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/RtutorialexercisedataSHW-20150413155701-720p.mp4", + "extension": "mp4", + "filesize": "178429871", + "_lastWrite": 3069, + "mimetype": "video\/mp4", + "duration": "00:15:25", + "avgBitrate": "1.54 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/3e89c658f6.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/996dcc77c8.jpg" + } + ] + } + }, + { + "uniqueHash": "262acb006972830cc4a084951946513e", + "description": "Random Forests in R.", + "pubDate": 1428931380, + "endOffset": "{0}", + "H264ProRecorderDynamicRangeCorrection": "true", + "title": "R-tutorial, part 2 (SHW).", + "startOffset": "{0}", + "hits": "114", + "hits-720p": "114", + "bandwidth": "21965656468", + "hitspartial-720p": "341", + "hits-480p": "34", + "bandwidth-480p": "2038581575", + "hitspartial": "341", + "hitspartial-480p": "147", + "bandwidth-720p": "21965656468", + "media": { + "720p": { + "filename": "http:\/\/podcast.llab.dtu.dk\/fileadmin\/podcasts\/2015\/27411\/Rtutorialpart2SHW-20150413152302-720p.mp4", + "extension": "mp4", + "filesize": "118013235", + "_lastWrite": 5706, + "mimetype": "video\/mp4", + "duration": "00:15:27", + "avgBitrate": "1.01 Mbps", + "imageWidth": "1280", + "imageHeight": "720" + }, + "thumbnail": [ + { + "135": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/f3a2ecf82a.jpg", + "250": "http:\/\/podcast.llab.dtu.dk\/typo3temp\/pics\/c9d6cb1a75.jpg" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/spec/files/user_config/00000-groups.yaml b/spec/files/user_config/00000-groups.yaml new file mode 100644 index 0000000000000000000000000000000000000000..35cbc25e7d1f67b968bf23077bc6757d92ad69e0 --- /dev/null +++ b/spec/files/user_config/00000-groups.yaml @@ -0,0 +1,9 @@ +A: + testauthor: Author + testadmin: Administrator +B: + testauthor: User + testadmin: User + testadmin: Administrator + teststudentandauthor: User + teststudentandauthor: Author diff --git a/spec/files/user_config/00000-users.yaml b/spec/files/user_config/00000-users.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5c7be5710143bcda5a4441ef822eae7840f42719 --- /dev/null +++ b/spec/files/user_config/00000-users.yaml @@ -0,0 +1,15 @@ +--- +testadmin: + email: enotema@dtu.dk + name: Test Admin +testauthor: + email: enotemb@dtu.dk + name: Test Author +teststudent: + email: enotemc@dtu.dk + name: Test Student +teststudentauthor: + email: enotemd@dtu.dk + name: Test Student and Author +--- + diff --git a/spec/helpers/home_helper_spec.rb b/spec/helpers/home_helper_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..454f4652e344ae584420bb404bdc71b258c21507 --- /dev/null +++ b/spec/helpers/home_helper_spec.rb @@ -0,0 +1,79 @@ +require 'rails_helper' + + +RSpec.describe HomeHelper, type: :helper do + + groups = [ DTUAuth2::UserRole2.new({:group => "A", :user_id=>"iaibrys", :course_id=>"00000", :acl=>"administrator" }) ] + + bug60 = <<-BUG60 +<div class='only' data-only-groups=' FakeGroun'> +Here is content that only students in the classes éA, B, biotek1é can see. +</div><!-- only --> + +<div class='only' data-only-groups=' A, B'> +only main +</div><!-- only --> +BUG60 + + embeded_div = <<-EDIV +<div class='only' data-only-groups=' FakeGroun'> +Here is content that only students in the classes éA, B, biotek1é can see. +<div class='hint'> +hint! +</div> +</div><!-- only --> + +<div class='only' data-only-groups=' A, B'> +only main +<div class='hint'> +hint! +</div> +</div><!-- only --> +EDIV + + describe "enforce_group_permissions works" do + it "doesn't disturb correct groups" do + in_md = <<-IN +<div class='only' data-only-groups=' A, B'> +only main +</div><!-- only --> +IN + out = helper.enforce_group_permissions(in_md, groups) + expect(out.strip).to eq(in_md.strip) + end + + it "strips invalid groups groups" do + in_md = <<-IN +<div class='only' data-only-groups='Main'> +only main +</div><!-- only --> +IN + out = helper.enforce_group_permissions(in_md, groups) + expect(out.strip).to eq("") + end + + it "handled both valid and restricted groups (Issue#60)" do + out_md = <<-IN +<div class='only' data-only-groups=' A, B'> +only main +</div><!-- only --> +IN + out = helper.enforce_group_permissions(bug60, groups) + expect(out.strip).to eq(out_md.strip) + end + + it "handled both valid and restricted groups with embeded divs " do + out_md = <<-IN +<div class='only' data-only-groups=' A, B'> +only main +<div class='hint'> +hint! +</div> +</div><!-- only --> +IN + out = helper.enforce_group_permissions(embeded_div, groups) + expect(out.strip).to eq(out_md.strip) + end + + end +end diff --git a/spec/models/enotes_spec.rb b/spec/models/enotes_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..74c3eb074b88235d74d95413e06e2e299484876d --- /dev/null +++ b/spec/models/enotes_spec.rb @@ -0,0 +1,53 @@ +require "rails_helper" +require "awesome_print" + +RSpec.describe Enotes, :type => :model do + + # https://github.com/dtu-compute/dtu-enote-website/issues/75 + describe "#menuize" do + it "produces the right menu name" do + examples = ["CamelCaseName", "camelCase2", "Chapter A", "test_file", "__another-example"] + menuized = examples.map { |enote| Enotes.menuize enote } + expect(menuized).to eq(["CamelCaseName", "camelCase2", "Chapter A", "test file", " another-example"]) + end + + it "produced the right menu titles for " do + examples = [ +"eNote 06.pdf", +"Kapitel 1.pdf", +"Kapitel 2 - Ikke lin. ligninger.pdf", +"kapitel 3 - Part. Diff..pdf", +"book-IntroStatistics.pdf", +"chapter1-DataVisualization.pdf", +"chapter2-ProbabilitySimulation.pdf", +"chapter3-StatisticsNormalAssumption.pdf", +"chapter4-SimulationBasedStatistics.pdf", +"chapter5-SimpleLinearRegression.pdf", +"chapter6-MultipleLinearRegression.pdf", +"chapter7-ProportionsFrequencyTables.pdf", +"chapter8-StatisticsMultigroupA_N_O_V_A.pdf", +"chapterA-formulas.pdf", +].map{|s| s.gsub("\.pdf",'')} + expected = [ +"eNote 06", +"Kapitel 1", +"Kapitel 2 - Ikke lin. ligninger", +"kapitel 3 - Part. Diff.", +"book-IntroStatistics", +"chapter1-DataVisualization", +"chapter2-ProbabilitySimulation", +"chapter3-StatisticsNormalAssumption", +"chapter4-SimulationBasedStatistics", +"chapter5-SimpleLinearRegression", +"chapter6-MultipleLinearRegression", +"chapter7-ProportionsFrequencyTables", +"chapter8-StatisticsMultigroupA N O V A", +"chapterA-formulas" +] + inout = examples.each_with_index.map{ |ex,idx| { :in => ex, :expected => expected[idx], :actual => Enotes.menuize(ex), :correct => expected[idx].eql?(Enotes.menuize(ex)) } } + ap inout + menuized = examples.map { |enote| Enotes.menuize enote } + expect(menuized).to eq(expected) + end + end +end diff --git a/spec/models/errors_spec.rb b/spec/models/errors_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..e182dda696e9cfe986733c2145c2f6d1d9429df8 --- /dev/null +++ b/spec/models/errors_spec.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'awesome_print' + +require 'rspec/expectations' + +RSpec::Matchers.define :be_same_error_list_as do |expected| + match do |actual| + error_to_string = ->(error) { "#{error[:page]}:#{error[:line]}" } + sorted_expected = expected.sort_by(&error_to_string) + sorted_actual = actual.sort_by(&error_to_string) + + sorted_actual == sorted_expected + end +end + +RSpec.describe Errors, type: :model do + def generate_expected_map(expected) + expected_map = {} + expected.each do |e| + if expected_map.key? e[:page] + expected_map[e[:page]] << e + else + expected_map[e[:page]] = [e] + end + end + expected_map + end + + def page_error_to_hash(page_errors) + page_errors.map { |x| JSON.parse(x.to_json).symbolize_keys! } + end + + def actual_error_list + page_error_to_hash(Errors.get(@test_course_id).error_list) + end + + def actual_error_map + Errors.get(@test_course_id).errors.map { |k, v| [k, page_error_to_hash(v)] }.to_h + end + + describe '#set' do + let(:examples) do + [{ page: 'info.md', err: [{ file: 'info.md', line: 3, text: 'test' }, + { file: 'info.md', line: 4, text: 'Missing file', refer_page: 'Missing' }] }, + { page: 'agendas.md', err: [{ file: 'agendas.md', line: 4, text: 'Blah', refer_page: 'Fugazi' }] }] + end + let(:expected) do + [{ file: 'info.md', page: 'info', refer_page: nil, error_type: nil, line: 3, text: 'test', course_id: @test_course_id }, + { file: 'info.md', page: 'info', refer_page: 'Missing', error_type: nil, line: 4, text: 'Missing file', course_id: @test_course_id }, + { file: 'agendas.md', page: 'agendas', refer_page: 'Fugazi', error_type: nil, line: 4, text: 'Blah', course_id: @test_course_id }] + end + + before(:each) do + Errors.clear_all! @test_course_id + examples.each { |e| Errors.set_page @test_course_id, e[:page], e[:err] } + end + + it 'handles adds correctly' do + expected_map = generate_expected_map expected + + expect(actual_error_list).to be_same_error_list_as(expected) + expect(actual_error_map).to eq(expected_map) + + Errors.get(@test_course_id).refresh + + expect(actual_error_list).to be_same_error_list_as(expected) + expect(actual_error_map).to eq(expected_map) + end + + it '#clear_missing_page_error' do + expected.delete_at 1 + expected_map = generate_expected_map expected + + Errors.get(@test_course_id).clear_missing_page_error 'Missing' + + expect(actual_error_list).to be_same_error_list_as(expected) + expect(actual_error_map).to eq(expected_map) + + Errors.get(@test_course_id).refresh + + expect(actual_error_list).to be_same_error_list_as(expected) + expect(actual_error_map).to eq(expected_map) + end + + it '#clear_all_missing!' do + expected_after_clear = expected.select { |e| e[:page].eql? 'agendas' } + expected_after_clear_map = generate_expected_map expected_after_clear + + Errors.get(@test_course_id).clear_all_missing! ['agendas'] + + expect(actual_error_list).to be_same_error_list_as(expected_after_clear) + expect(actual_error_map).to eq(expected_after_clear_map) + + Errors.get(@test_course_id).refresh + + expect(actual_error_list).to be_same_error_list_as(expected_after_clear) + expect(actual_error_map).to eq(expected_after_clear_map) + end + end +end diff --git a/spec/models/feedback_spec.rb b/spec/models/feedback_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..ef016398e3f1eaf55bd4c073eef6d75a3d721e2b --- /dev/null +++ b/spec/models/feedback_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Feedback, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/menu_spec.rb b/spec/models/menu_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..5b8ef22bc67bac81c87364a5f537594f3d4f8c2e --- /dev/null +++ b/spec/models/menu_spec.rb @@ -0,0 +1,37 @@ +require "rails_helper" +require 'pp' # https://devhub.io/zh/repos/fakefs-fakefs +require 'fakefs/safe' +require 'fakefs/spec_helpers' + +RSpec.describe Menu, :type => :model do + context "Parse line" do + it "Parses a valid line correctly" do + item, error = Menu.get(@test_course_id).parse_config_line("Agenda, /agenda") + expect(item).to eq({:menu => "Agenda", :url => "/agenda"}) + end + it "Returns an error if the url is missing" do + item, error = Menu.get(@test_course_id).parse_config_line("Agenda") + expect(item).to be_nil + expect(error).to eq({ :file => nil, :line => 0, :text => "exactly one comma, separating name from url, required" }) + end + end + + context "Parse file" do + file_path = File.expand_path('../../files/menu', __FILE__) + it "Parses a valid file correctly" do + Menu.refresh(@test_course_id, File.join(file_path, "simple.md")) + expect(Menu.get(@test_course_id).items).to eq([{:menu=>"Agendas", :url=>"/Agendas"}, + {:menu=>"Book", :url=>"/eNotes"}, + {:menu=>"Course Material", :url => "/Material"}, + {:menu=>"Podcast", :url=>"/podcast"}, + {:menu=>"Quiz", :url=>"https://quiz.compute.dtu.dk/"}]) + end + end + + context "#expected_menu_pages" do + it "expected_menu_pages returns correct defaults" do + exp = Menu.new.expected_menu_pages + expect(exp).to eq(Set.new(["Agendas", "Frontpage-right", "Frontpage-left", "Agendas", "Material", "podcast"])) + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..97eb92727827b84274cbb238e97785fc418230bc --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,48 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'spec_helper' +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +RSpec.configure do |config| + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, :type => :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end + +Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } + diff --git a/spec/services/page_compiler_service/all_that_apply_spec.rb b/spec/services/page_compiler_service/all_that_apply_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..2c91a7a88ce97942f8a1da09a1f2cc21e90ca052 --- /dev/null +++ b/spec/services/page_compiler_service/all_that_apply_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe PageCompilerService, type: :model do + include PageCompilerSpecHelper + + describe 'compile_lines' do + describe ':multiple_choice directives' do + it 'processes :multiple_choice directive' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + t = <<~BLOCK +####### begin:quiz +begin:all_that_apply + right "Democrats" + right "Republicans" + right "Greens" "Yes, they're a party!" + wrong "Tories" "They're British" + wrong "Social Democrats" +end:all_that_apply +####### end:quiz + BLOCK + + line_in = t.split(/\n/) + lines_out = [] + acc = lambda { |line_out| lines_out << line_out unless line_out.empty? } + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file', &acc) + expect(lines_out.first).to eq(VERBATIM_HTML_START) + expect(lines_out.last).to eq(VERBATIM_HTML_END) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + + it 'propagates quiz parsing errors to the quiz error list' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + t = <<~BLOCK +####### begin:quiz +begin:all_that_apply + right "Democrats" + right "Republicans" + right "Greens" "Yes, they're a party!" + wrong "Tories" "They're British" + wrong "Social Democrats" +end:multiple_choice +####### end:quiz + BLOCK + + line_in = t.split(/\n/) + lines_out = [] + acc = lambda { |line_out| lines_out << line_out unless line_out.empty? } + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file', &acc) + expect(err).to_not be_empty + expect(err).to eq([{file:"test file", + line:9, + text:"critical end with unexpected identifier 'multiple_choice'. \ +expected one of 'all_that_apply' to close begin started on line 1"} + ]) + expect(lines_out.first).to eq("<span class='quiz-error'>Error in quiz definition. See Admin panel for details.</span>") + expect(directive_stack).to be_empty + end + end + end +end diff --git a/spec/services/page_compiler_service/fill_in_the_blank_spec.rb b/spec/services/page_compiler_service/fill_in_the_blank_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..1715c72b8eaf44742d96fb810460548d5ca9aa46 --- /dev/null +++ b/spec/services/page_compiler_service/fill_in_the_blank_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe PageCompilerService, type: :model do + include PageCompilerSpecHelper + + describe 'compile_lines' do + + describe ':fill_in_the_blank directives' do + it 'processes :fill_in_the_blank directive' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + t = <<~BLOCK +####### begin:quiz +begin:fill_in_the_blank + text "Which %4% is missing?" +end:fill_in_the_blank +####### end:quiz + BLOCK + + line_in = t.split(/\n/) + lines_out = [] + acc = lambda { |line_out| lines_out << line_out unless line_out.blank? } + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file', &acc) + expect(err).to be_empty + expect(lines_out.first).to eq(VERBATIM_HTML_START) + expect(lines_out.last).to eq(VERBATIM_HTML_END) + expect(directive_stack).to be_empty + end + + it 'propagates quiz parsing errors to the quiz error list' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + t = <<~BLOCK +####### begin:quiz +begin:fill_in_the_blank + text "Which %4% is missing?" +end:all_that_apply +####### end:quiz + BLOCK + + line_in = t.split(/\n/) + lines_out = [] + acc = lambda { |line_out| lines_out << line_out unless line_out.blank? } + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file', &acc) + expect(err).to_not be_empty + expect(err).to eq([ + { + file: "test file", + line: 4, + text: "critical end with unexpected identifier 'all_that_apply'. \ +expected one of 'fill_in_the_blank' to close begin started on line 1" + } + ]) + expect(lines_out.first).to eq("<span class='quiz-error'>Error in quiz definition. See Admin panel for details.</span>") + expect(directive_stack).to be_empty + end + + + it 'processes correct answers and wrong text' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + t = <<~BLOCK +####### begin:quiz +begin:fill_in_the_blank + text 'Which %4% %2% missing %1%' + right 'word' 'is' '?' + wrong 'error' +end:fill_in_the_blank +####### end:quiz + BLOCK + + line_in = t.split(/\n/) + lines_out = [] + acc = lambda { |line_out| lines_out << line_out unless line_out.blank? } + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file', &acc) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + + end + end +end diff --git a/spec/services/page_compiler_service/include_spec.rb b/spec/services/page_compiler_service/include_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..eb00925c556056a95b1dafcb3bf800bf1d260e21 --- /dev/null +++ b/spec/services/page_compiler_service/include_spec.rb @@ -0,0 +1,45 @@ +require 'rails_helper' + +RSpec.describe PageCompilerService, type: :model do + + describe "compile_lines" do + describe "include directive" do + it "processes basic include directives" do + IncludedPages.get(@test_course_id).refresh + allow(IncludedPages).to receive(:get).and_return(IncludedPages.new({:pages => {'macros.tex' => "MACROS INCLUDED\nSECOND LINE"}})) + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = [ "####### include macros.tex" ] + lines_out = [ ] + lines_exp = ["<div class='hidden inline'>", "$$", "MACROS INCLUDED", "SECOND LINE", "$$", "</div>"] + directive_stack, err = page_compiler_service.compile_lines(line_in, "test file") { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + it "strips empty lines properly" do + IncludedPages.get(@test_course_id).refresh + allow(IncludedPages).to receive(:get).and_return(IncludedPages.new({:pages => {'macros.tex' => "MACROS INCLUDED\n \nSECOND LINE\n\n \n"}})) + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = [ "####### include macros.tex" ] + lines_out = [ ] + lines_exp = ["<div class='hidden inline'>", "$$", "MACROS INCLUDED", "SECOND LINE", "$$", "</div>"] + directive_stack, err = page_compiler_service.compile_lines(line_in, "test file") { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + it "raises an error if included file doesn't exist" do + IncludedPages.get(@test_course_id).refresh + allow(IncludedPages).to receive(:get).and_return(IncludedPages.new({:pages => {'macros.tex' => nil}})) + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = [ "####### include macros.tex" ] + lines_out = [ ] + lines_exp = ["<div class='error-directive'> macros.tex does not exist </div>"] + directive_stack, err = page_compiler_service.compile_lines(line_in, "test file") { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to eq([{:file=>"test file", :line=>1, :text=>"Missing included page macros.tex at 1"}]) + expect(directive_stack).to be_empty + end + end + end +end diff --git a/spec/services/page_compiler_service/links_spec.rb b/spec/services/page_compiler_service/links_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..5b25f8e141566017b59bd04fb76d025c1155fd49 --- /dev/null +++ b/spec/services/page_compiler_service/links_spec.rb @@ -0,0 +1,151 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe PageCompilerService, type: :model do + describe 'compile_lines' do + + describe "#process_link" do + it "doesn't process non 'Podcast link' links" do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = " [non podcast link](http://google.com) is a great link" + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_in) + expect(err).to be_empty + end + +# Seems this link no longer works? + it "Processes 'Podcast link' links" do + page_compiler_service = PageCompilerService.new(@test_course_id, File.join(Rails.root, 'spec', 'files', 'test_file.md')) + line_in = " [Podcast link](http://podcast.llab.dtu.dk/feeds/02402-introduction-to-statistics-f17/?tx_enotepodcast_pi1[data]=true) is a great podcast link" + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to_not eq(line_in) + expect(err).to be_empty + end + + it "Produces an error for invalid 'Podcast link' links" do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = " [Podcast link](http://google.com) is a great podcast link" + line_exp = "\n<span class='link-error'>Unreadable podcast link [http://google.com](http://google.com)</span>\n" + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_exp) + expect(err).to_not be_empty + end + +# https://github.com/dtu-compute/dtu-enote-website/issues/73 + it "Doesn't process simple parens as links" do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = "AFTER lecture: Complete the exercises listed below (2 hours)(click the link e.g. [E1.1] links to Chapter 1 Exercise 1)" + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_in) + expect(err).to be_empty + end + + it "processes external links" do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md', {"" => Set.new(['ValidInternal'])}) + line_in = " [non podcast link](http://google.com) is a great link" + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_in) + end + + it "processes internal links" do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md', {"" => Set.new(['ValidInternal'])}) + line_in = " [non podcast link](ValidInternal) is a great link" + line_exp = " [non podcast link](/ValidInternal) is a great link" + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_exp) + expect(err).to be_empty + end + + it "processes internal link with anchors" do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md', {"" => Set.new(['ValidInternal'])}) + line_in = " [non podcast link](ValidInternal#anchor) is a great link" + line_exp = " [non podcast link](/ValidInternal#anchor) is a great link" + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_exp) + expect(err).to be_empty + end + + it "processes internal enotes and uploads links" do + valid_links = { + "" => Set.new(['ValidPage']), + "/uploads" => Set.new(['ValidUpload']), + "/enotes" => Set.new(['ValidEnote']) + } + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md', valid_links) + line_in = " upload: [uploads link](/uploads/ValidUpload#anchorenote) enote: [enote link](/enotes/ValidEnote#anchor) page: [non podcast link](ValidPage#pageanchor) is a great link " + line_exp = " upload: [uploads link](/filemanager/uploads/00000/ValidUpload#anchorenote) enote: [enote link](/enotes/ValidEnote#anchor) page: [non podcast link](/ValidPage#pageanchor) is a great link " + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_exp) + expect(err).to be_empty, "#{err.ai}" + end + + it "processes uploads subfolder links (issue#134)" do + valid_links = { + "" => Set.new([]), + "/uploads" => Set.new(['folder/ValidUpload']), + "/enotes" => Set.new([]) + } + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md', valid_links) + line_in = " upload: [uploads link](/uploads/folder/ValidUpload#anchorenote)" + line_exp = " upload: [uploads link](/filemanager/uploads/00000/folder/ValidUpload#anchorenote)" + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_exp) + expect(err).to be_empty, "#{err.ai}" + end + + it "generates errors for missing enotes and uploads links" do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = " upload: [uploads link](/uploads/inValidUpload#anchorenote) enote: [enote link](/enotes/inValidEnote#anchor) page: [non podcast link](inValidPage#pageanchor) is a great link " + line_exp = " upload: <span class='link-error'>/uploads/inValidUpload#anchorenote</span> enote: <span class='link-error'>/enotes/inValidEnote#anchor</span> page: <span class='link-error'>inValidPage#pageanchor</span> is a great link " + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_exp) + expect(err).to eq([ + "Missing page referenced \"/uploads/inValidUpload#anchorenote\"", + "Missing page referenced \"/enotes/inValidEnote#anchor\"", + "Missing page referenced \"inValidPage#pageanchor\"" + ]) + end + + it "processes external links" do + page_compiler_service = PageCompilerService.new(@test_course_id, {"" => Set.new(['ValidInternal'])}) + line_in = " [non podcast link](InvalidInternal) is a great link" + line_exp = " <span class='link-error'>InvalidInternal</span> is a great link" + line_out, err = page_compiler_service.process_links(line_in) + expect(line_out).to eq(line_exp) + expect(err).to eq(["Missing page referenced \"InvalidInternal\""]) + end + + it "doesn't expand directives which don't start at the beginning of the line (Issue #131)" do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ["```", + "_####### begin:hint", "hint", "_####### begin:question", + "```"] + lines_out = [] + lines_exp = ["```", + "_####### begin:hint", "hint", "_####### begin:question", + "```"] + directive_stack, err = page_compiler_service.compile_lines(line_in, "test file") {|line_out| lines_out << line_out} + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack).to eq([]) + end + + it "doesn't expand directives which don't start at the beginning of the line (Issue #132)" do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ["```", + "%####### begin:hint", "hint", "%####### begin:question", + "```"] + lines_out = [] + lines_exp = ["```", + "hint", + "```"] + directive_stack, err = page_compiler_service.compile_lines(line_in, "test file") {|line_out| lines_out << line_out} + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack).to eq([]) + end + end + + end +end diff --git a/spec/services/page_compiler_service/multiple_choice_spec.rb b/spec/services/page_compiler_service/multiple_choice_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..7ee1dc859fd4452a8a9747f56eb8697149076206 --- /dev/null +++ b/spec/services/page_compiler_service/multiple_choice_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe PageCompilerService, type: :model do + include PageCompilerSpecHelper + + describe 'compile_lines' do + + describe ':multiple_choice directives' do + it 'processes :multiple_choice directive' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + t = <<~BLOCK + ####### begin:quiz + begin:multiple_choice + right 'Alaska' "You really know your stuff" + wrong 'Hawaii' "Not big enough." + wrong 'Texas' "That's pretty big, but think colder." + randomize false + end:multiple_choice + + + ####### end:quiz + BLOCK + + line_in = t.split(/\n/) + lines_out = [] + acc = lambda { |line_out| lines_out << line_out unless line_out.empty? } + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file', &acc) + expect(lines_out.first).to eq(VERBATIM_HTML_START) + expect(lines_out.last).to eq(VERBATIM_HTML_END) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + + it 'propagates quiz parsing errors to the quiz error list' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + t = <<~BLOCK + ####### begin:quiz + begin:multiple_choice + right 'Alaska' "You really know your stuff" + wrong 'Hawaii' "Not big enough." + wrong 'Texas' "That's pretty big, but think colder." + randomize false + end:all_that_apply + ####### end:quiz + BLOCK + + line_in = t.split(/\n/) + lines_out = [] + acc = lambda { |line_out| lines_out << line_out unless line_out.empty? } + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file', &acc) + expect(err).to_not be_empty + expect(err).to eq([ + { + file: "test file", + line: 8, + text: "critical end with unexpected identifier 'all_that_apply'. \ +expected one of 'multiple_choice' to close begin started on line 1" + } + ]) + expect(lines_out.first).to eq("<span class='quiz-error'>Error in quiz definition. See Admin panel for details.</span>") + expect(directive_stack).to be_empty + end + end + end +end diff --git a/spec/services/page_compiler_service/only_spec.rb b/spec/services/page_compiler_service/only_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..6b47108cd3c6acbf58ba3bcaef0b640aad8d2ae4 --- /dev/null +++ b/spec/services/page_compiler_service/only_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe PageCompilerService, type: :model do + include PageCompilerSpecHelper + + describe 'compile_lines' do + describe ':only directives' do + it 'processes begin:only directive' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ['####### begin:only grk'] + lines_out = [] + lines_exp = ["<div class='only' data-only-groups=' grk'>"] + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack.length).to eq(1) + expect(directive_stack[0][:beginend]).to eq('begin') + expect(directive_stack[0][:kind]).to eq('only') + expect(directive_stack[0][:line_no]).to eq(1) + end + + it 'processes begin:only directive in the presence of malformed headers (bug 102)' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ['##### Aktivitetsprogrammet', + '', + '####### begin:only A,B', + '**For studieretninger pÃ¥ Skema A og B:**', + '8.00 -- 10.00 Forelæsning', + '10.00 -- 12.00 Gruppeøvelser i klasselokalet', + '10.30 -- 12.00 Din klasselærer er til stede', + '####### end:only'] + lines_out = [] + lines_exp = ['##### Aktivitetsprogrammet', + '', + "<div class='only' data-only-groups=' A,B'>", + '**For studieretninger pÃ¥ Skema A og B:**', + '8.00 -- 10.00 Forelæsning', + '10.00 -- 12.00 Gruppeøvelser i klasselokalet', + '10.30 -- 12.00 Din klasselærer er til stede', + '</div><!-- only -->'] + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp), (lines_out - lines_exp).to_s + expect(err).to be_empty + expect(directive_stack).to be_empty + end + + it 'processes begin:only directive in the presence of blockquotes (bug 103)' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ['### Opgave 2: Mere om approksimerende polynomier (Maple)', + '', + ' > Bestem det approksimerende polynomium *P*<sub>5</sub>(*x*) og *P*<sub>6</sub>(*x*) af grad henholdsvis 5 og 6 for funktionen $f (x) =\frac{1}{1+x^2}$ med udviklingspunkt *x*<sub>0</sub> = 0.', + '', + '####### begin:hint', + '', + '*P*<sub>5</sub>(*x*)=1 - *x*<sup>2</sup> + *x*<sup>4</sup>, *P*<sub>6</sub>(*x*)=1 - *x*<sup>2</sup> + *x*<sup>4</sup> - *x*<sup>6</sup>.', + '', + '####### end:hint', # in the original bug, this was an error "end :hint" + '', + '> Tegn *f*(*x*), *P*<sub>5</sub>(*x*) og *P*<sub>6</sub>(*x*) i samme koordinatsystem.'] + lines_out = [] + lines_exp = ['### Opgave 2: Mere om approksimerende polynomier (Maple)', + '', + ' > Bestem det approksimerende polynomium *P*<sub>5</sub>(*x*) og *P*<sub>6</sub>(*x*) af grad henholdsvis 5 og 6 for funktionen $f (x) =\frac{1}{1+x^2}$ med udviklingspunkt *x*<sub>0</sub> = 0.', + '', + build_labelled_directive_start('hint', [0, 0], 0), + '', + '*P*<sub>5</sub>(*x*)=1 - *x*<sup>2</sup> + *x*<sup>4</sup>, *P*<sub>6</sub>(*x*)=1 - *x*<sup>2</sup> + *x*<sup>4</sup> - *x*<sup>6</sup>.', + '', + build_labelled_directive_end('hint'), + '', + '> Tegn *f*(*x*), *P*<sub>5</sub>(*x*) og *P*<sub>6</sub>(*x*) i samme koordinatsystem.'].flatten + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp), (lines_out - lines_exp).to_s + expect(err).to be_empty + expect(directive_stack).to be_empty + end + end + end +end diff --git a/spec/services/page_compiler_service/page_compiler_service_spec.rb b/spec/services/page_compiler_service/page_compiler_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..ef4aab59bd323ed48960fd0b6edbf29b6ed9a39f --- /dev/null +++ b/spec/services/page_compiler_service/page_compiler_service_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe PageCompilerService, type: :model do + + include PageCompilerSpecHelper + + describe 'compile_lines' do + describe '#process_links' do + it 'processes external links' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = [' [non podcast link](http://google.com) is a great link'] + lines_out = [] + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(line_in) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + it 'processes internal ascii links' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md', '' => Set.new(['foo'])) + line_in = [' [non podcast link](foo) is a great link'] + lines_exp = [' [non podcast link](/foo) is a great link'] + lines_out = [] + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + it 'processes internal non-ascii links' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md', '' => Set.new(['hovedsætningen'])) + line_in = [' [NUID21-tn8.ThAfbMatrix](hovedsætningen) is a great link'] + lines_exp = [' [NUID21-tn8.ThAfbMatrix](/hovedsætningen) is a great link'] + lines_out = [] + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + end + + describe ':answer directives' do + it 'processes begin:answer directive' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ['####### begin:answer'] + lines_out = [] + lines_exp = [build_labelled_directive_start('answer', [0, 0], 0)].flatten + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack.length).to eq(1) + expect(directive_stack[0]).to include_hash(beginend: 'begin', kind: 'answer', line_no: 1) + end + end + + describe ':hint directives' do + it 'processes begin:hint directive' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ['## h2', '', '####### begin:hint'] + lines_out = [] + lines_exp = ['## h2', '', + build_labelled_directive_start('hint', [0, 1], 0)].flatten + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack.length).to eq(1) + expect(directive_stack[0]).to include_hash(beginend: 'begin', kind: 'hint', line_no: 3) + end + end + + describe 'headings' do + it 'passes through non-directive headings' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ['####### not a directive', '###### not a directive', '###### not a directive'] + lines_out = [] + lines_exp = line_in + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + + it 'produces section/subsection/questions data elements' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ['# H1', '## H2', '### H3'] + lines_out = [] + lines_exp = line_in + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack).to be_empty + end + end + end +end diff --git a/spec/services/page_compiler_service/question_directive_spec.rb b/spec/services/page_compiler_service/question_directive_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..9a4d548d64b85e0cedcb33e77f1fe41dfb6d833a --- /dev/null +++ b/spec/services/page_compiler_service/question_directive_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe PageCompilerService, type: :model do + include PageCompilerSpecHelper + + describe 'compile_lines' do + describe ':question directives' do + it 'processes begin:question directive' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ['# h1', '', '####### begin:question'] + lines_out = [] + lines_exp = ['# h1', '', + build_labelled_directive_start('question', [1, 0], 1)].flatten + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack.length).to eq(1) + expect(directive_stack[0]).to include_hash(beginend: 'begin', kind: 'question', line_no: 3) + end + + it 'updates the question counter for multiple begin:question directive' do + page_compiler_service = PageCompilerService.new(@test_course_id, 'test_file.md') + line_in = ['# h1', '', '####### begin:question', '', '####### begin:question'] + lines_out = [] + lines_exp = ['# h1', '', + build_labelled_directive_start('question', [1, 0], 1), + '', + build_labelled_directive_start('question', [1, 0], 2)].flatten + directive_stack, err = page_compiler_service.compile_lines(line_in, 'test file') { |line_out| lines_out << line_out } + expect(lines_out).to eq(lines_exp) + expect(err).to be_empty + expect(directive_stack.length).to eq(2) + expect(directive_stack[0]).to include_hash(beginend: 'begin', kind: 'question', line_no: 3) + expect(directive_stack[1]).to include_hash(beginend: 'begin', kind: 'question', line_no: 5) + end + end + end +end diff --git a/spec/services/pages_service_spec.rb b/spec/services/pages_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..771db2c0480fce54b3fe93e1d74a90492094f495 --- /dev/null +++ b/spec/services/pages_service_spec.rb @@ -0,0 +1,54 @@ +require 'rails_helper' +require 'pp' # https://devhub.io/zh/repos/fakefs-fakefs +require 'fakefs/safe' +require 'fakefs/spec_helpers' + +RSpec.describe PagesService, type: :model do + include FakeFS::SpecHelpers + + describe "edit_page" do + it "allows editing a markdown file which exists" do + FakeFS do + files = File.expand_path(File.join('../../files', "pages_service", @test_course_id), __FILE__) + + allow_any_instance_of(PagesService).to receive(:raw_md_folder).and_return(files) + + user = DTUAuth2::CachedAuthorizationManager.system_user + + FakeFS::FileSystem.clone(files) + + expect(PagesService.new(@test_course_id).edit_page 'Agendas', user).to eq true + expect(PagesService.new(@test_course_id).who_is_editing? 'Agendas').to eq user._id + current_edits = (PagesService.new(@test_course_id).all_current_edits())[0] + expect(current_edits[:name]).to eq "Agendas" + expect(current_edits[:user]).to eq user._id + expect(current_edits[:locked_time].to_i).to be_within(1).of Time.zone.now.to_i + expect(PagesService.new(@test_course_id).edit_page 'Agendas', nil).to eq true + expect(PagesService.new(@test_course_id).who_is_editing? 'Agendas').to eq nil + expect(PagesService.new(@test_course_id).all_current_edits).to eq [] + end + end + + it "allows editing a macro file which exists" do + FakeFS do + files = File.expand_path(File.join('../../files', "pages_service", @test_course_id), __FILE__) + + allow_any_instance_of(PagesService).to receive(:raw_md_folder).and_return(files) + + user = DTUAuth2::CachedAuthorizationManager.system_user + + FakeFS::FileSystem.clone(files) + + expect(PagesService.new(@test_course_id).edit_page 'macros', user).to eq true + expect(PagesService.new(@test_course_id).who_is_editing? 'macros').to eq user._id + current_edits = (PagesService.new(@test_course_id).all_current_edits())[0] + expect(current_edits[:name]).to eq "macros" + expect(current_edits[:user]).to eq user._id + expect(current_edits[:locked_time].to_i).to be_within(1).of Time.zone.now.to_i + expect(PagesService.new(@test_course_id).edit_page 'macros', nil).to eq true + expect(PagesService.new(@test_course_id).who_is_editing? 'macros').to eq nil + expect(PagesService.new(@test_course_id).all_current_edits).to eq [] + end + end + end +end diff --git a/spec/services/podcast_service_spec.rb b/spec/services/podcast_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..3a256137b86eac56c5c4e2b60ade86ef85ed7c53 --- /dev/null +++ b/spec/services/podcast_service_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +RSpec.describe PodcastService, type: :model do + + describe "#new_podcasts?" do + it "returns false for identical feeds" do + end + end + + + describe "#new_podcast_episodes?" do + + it "returns false for identical feeds" do + podcast_json = JSON.parse(File.read(File.join(Rails.root, 'spec', 'files', 'podcasts', 'bug_172.json'))) + expect(PodcastService.new_podcast_episodes?(podcast_json, podcast_json)).to eq(false) + end + + it "returns true when a new episode is present" do + old_podcast_json = JSON.parse(File.read(File.join(Rails.root, 'spec', 'files', 'podcasts', 'bug_172.json'))) + new_podcast_json = JSON.parse(File.read(File.join(Rails.root, 'spec', 'files', 'podcasts', 'bug_172.json'))) + + old_podcast_json['episodes'].shift + + expect(PodcastService.new_podcast_episodes?(old_podcast_json, new_podcast_json)).to eq(true) + end + + end +end diff --git a/spec/services/update_service_spec.rb b/spec/services/update_service_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..66a89f441ee9e692f25fbe1d2dabb2c93af2d3ab --- /dev/null +++ b/spec/services/update_service_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe UpdateService, type: :model do + + + +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..5b77f263ba9b02bb627a99feef89fde804935736 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +require 'rspec-html-matchers' + +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + config.include RSpecHtmlMatchers + + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. + # # These two settings work together to allow you to limit a spec run + # # to individual examples or groups you care about by tagging them with + # # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # # get run. + # config.filter_run :focus + # config.run_all_when_everything_filtered = true + # + # # Allows RSpec to persist some state between runs in order to support + # # the `--only-failures` and `--next-failure` CLI options. We recommend + # # you configure your source control system to ignore this file. + # config.example_status_persistence_file_path = "spec/examples.txt" + # + # # Limits the available syntax to the non-monkey patched syntax that is + # # recommended. For more details, see: + # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + # config.disable_monkey_patching! + # + # # Many RSpec users commonly either run the entire suite or an individual + # # file, and it's useful to allow more verbose output when running an + # # individual spec file. + # if config.files_to_run.one? + # # Use the documentation formatter for detailed output, + # # unless a formatter has already been configured + # # (e.g. via a command-line flag). + # config.default_formatter = 'doc' + # end + # + # # Print the 10 slowest examples and example groups at the + # # end of the spec run, to help surface which specs are running + # # particularly slow. + # config.profile_examples = 10 + # + # # Run specs in random order to surface order dependencies. If you find an + # # order dependency and want to debug it, you can fix the order by providing + # # the seed, which is printed after each run. + # # --seed 1234 + # config.order = :random + # + # # Seed global randomization in this process using the `--seed` CLI option. + # # Setting this allows you to use `--seed` to deterministically reproduce + # # test failures related to randomization by passing the same `--seed` value + # # as the one that triggered the failure. + # Kernel.srand config.seed +end + +RSpec.configure do |config| + config.before(:example) do + @test_course_id = '00000' + + WebsiteConfig.data_root = File.join Rails.root, 'spec/files' + WebsiteConfig.config_root = File.join(WebsiteConfig.data_root, 'config') + + courses = WebsiteConfig.get.courses.keys + + file_manager = DTUFileManagement::FileManager.instance + file_manager.dtu_file_manager_root = File.join Rails.root, 'spec/files/content' + file_manager.update + + courses.each do |course| + Pages.refresh course + Errors.refresh course + IncludedPages.refresh course + end + end +end + +module CustomMatchers + RSpec::Matchers.define :include_hash do |expected| + match do |hash| + expected.keys.each do |key| + return false unless hash.key?(key) && hash[key] == expected[key] + end + end + end +end diff --git a/spec/support/fakeredis.rb b/spec/support/fakeredis.rb new file mode 100644 index 0000000000000000000000000000000000000000..61733812e3e78f4c23f0f413911e5ff315d19160 --- /dev/null +++ b/spec/support/fakeredis.rb @@ -0,0 +1,11 @@ +# spec/support/fakeredis.rb +require 'fakeredis' +require 'fakeredis/rspec' + +$redis = Redis.new(:port => 666) +$redis_course_website = Redis.new(:port => 667) + +DTUAuth2::populate Rails.root.join("spec", "files", "config").to_s, Rails.root.join("spec", "files", "user_config").to_s + +$redis.get("courses") + diff --git a/spec/support/page_compiler_spec_helper.rb b/spec/support/page_compiler_spec_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..a981ad2edef00b493ca3b822b21b4e38e32a1d03 --- /dev/null +++ b/spec/support/page_compiler_spec_helper.rb @@ -0,0 +1,35 @@ +module PageCompilerSpecHelper + + def accumulate_lines(line_out) + self.lines_out << line_out unless line_out.empty? + end + + def build_labelled_directive_start(kind, sec_no, q_no) + label_map = { + 'only' => '', + 'question' => q_no.alph, + 'hint' => 'Hint', + 'answer' => 'Answer' + } + + hide = '' + hide = ' hide' if kind == 'answer' || kind == 'hint' + + question_id = sec_no[0].to_s + '.' + sec_no[1].to_s + '.' + q_no.to_s + doc_attr = "data-section='#{sec_no[0]}'" \ + " data-subsection='#{sec_no[1]}'" \ + " data-question='#{question_id}'" + + "<div class='#{kind}#{hide} directive-region' #{doc_attr}>" \ + "<div class='directive-region-item-container'>" \ + "<div class='directive-region-label'>" \ + "<div class=' '>#{label_map[kind]}</div>" \ + "</div>" \ + "<div class='directive-region-item'>" + end + + def build_labelled_directive_end(kind) + "</div></div></div>"#<!-- #{kind} --> + end + +end diff --git a/spec/views/podcasts/index.html.erb_spec.rb b/spec/views/podcasts/index.html.erb_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..c1cfac75ee7611b545c5d82ce82c1446d22641ec --- /dev/null +++ b/spec/views/podcasts/index.html.erb_spec.rb @@ -0,0 +1,22 @@ +require "spec_helper" +require "rails_helper" + +describe "podcasts/index.html.erb" do + + describe "rendering podcasts" do + let(:params) { [:course_id => @test_course_id] } + _course_id = @test_course_id + it "handles bug 172: Handle missing links in podcasts" do + + _course_id = @test_course_id + + podcast_json = JSON.parse(File.read(File.join(Rails.root, 'spec', 'files', 'podcasts', 'bug_172_1.json'))) + + render :template => "podcasts/index", :locals => {:my_course_id => @test_course_id, :podcast_json => podcast_json} + + expect(rendered).to_not have_tag(:a, :text => "Admin", :href=>"/admin") + expect(rendered).to_not match /TESTCOURSE/ + end + end + +end diff --git a/spec/views/shared/_header.html.erb_spec.rb b/spec/views/shared/_header.html.erb_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..c4a9de9014e6540f5ffef5182e1fcdba2f7b93f8 --- /dev/null +++ b/spec/views/shared/_header.html.erb_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'rails_helper' + +describe 'shared/_header.html.erb' do + describe 'rendering the menu header' do + let(:params) { [course_id: @test_course_id] } + _course_id = @test_course_id + it "does not displays the course and doesn't show the admin menu" do + _course_id = @test_course_id + render 'shared/header', + is_admin: false, + my_course_id: @test_course_id, + course: 'TESTCOURSE', + always_shrunk: false, + menu_items: Menu.get(@test_course_id).items + + expect(rendered).to_not have_tag(:a, text: 'Admin', href: '/admin') + expect(rendered).to_not match(/TESTCOURSE/) + end + + it 'does show the admin menu' do + render 'shared/header', + is_admin: true, + my_course_id: @test_course_id, + course: 'TESTCOURSE', + always_shrunk: false, + menu_items: Menu.get(@test_course_id).items + expect(rendered).to have_tag(:a, text: 'Admin', href: '/admin') + end + + it 'does show a custom admin menu' do + items = [{ menu: 'testagendas', url: '/agendas_t' }, + { menu: 'Book', url: 'eNotes' }, + { menu: 'Course Matorial', url: 'Materialy' }, + { menu: 'Podcast', url: 'podcast' }, + { menu: 'Quiz', url: 'https://quiz.compute.dtu.dk/' }] + + render 'shared/header', + is_admin: true, + my_course_id: @test_course_id, + course: 'TESTCOURSE', + always_shrunk: false, + menu_items: items + expect(rendered).to have_tag(:a, text: 'testagendas', href: '/agendas_t') + expect(rendered).to have_tag(:a, text: 'Book', href: '/eNotes') + expect(rendered).to have_tag(:a, text: 'Podcast', href: '/admin') + expect(rendered).to have_tag(:a, text: 'Admin', href: '/podcast') + expect(rendered).to_not have_tag(:a, text: 'Course Material', href: '/Materialy') + expect(rendered).to have_tag(:a, text: 'testagendas', href: '/agendas_t') + end + end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/fixtures/.keep b/test/fixtures/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/helpers/.keep b/test/helpers/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..3acf9ae30d0d2f78cc21d3aee2d7f37e155193c0 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,7 @@ +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +require 'rails/test_help' + +class ActiveSupport::TestCase + # Add more helper methods to be used by all tests here... +end diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000000000000000000000000000000000000..fdcc184e8ea6b1f26b400ccdb23a8433dc6c0af7 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,8627 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" + integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== + dependencies: + "@babel/highlight" "^7.0.0" + +"@babel/core@^7.4.5": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.0.tgz#6ed6a2881ad48a732c5433096d96d1b0ee5eb734" + integrity sha512-6Isr4X98pwXqHvtigw71CKgmhL1etZjPs5A67jL/w0TkLM9eqmFR40YrnJvEc1WnMZFsskjsmid8bHZyxKEAnw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.5.0" + "@babel/helpers" "^7.5.0" + "@babel/parser" "^7.5.0" + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.5.0" + "@babel/types" "^7.5.0" + convert-source-map "^1.1.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.11" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a" + integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA== + dependencies: + "@babel/types" "^7.5.0" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-annotate-as-pure@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" + integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" + integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-call-delegate@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43" + integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ== + dependencies: + "@babel/helper-hoist-variables" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/helper-create-class-features-plugin@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.5.0.tgz#02edb97f512d44ba23b3227f1bf2ed43454edac5" + integrity sha512-EAoMc3hE5vE5LNhMqDOwB1usHvmRjCDAnH8CD4PVkX9/Yr3W/tcz8xE8QvdZxfsFBDICwZnF2UTHIqslRpvxmA== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.4.4" + "@babel/helper-split-export-declaration" "^7.4.4" + +"@babel/helper-define-map@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a" + integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/types" "^7.4.4" + lodash "^4.17.11" + +"@babel/helper-explode-assignable-expression@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" + integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== + dependencies: + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-hoist-variables@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" + integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w== + dependencies: + "@babel/types" "^7.4.4" + +"@babel/helper-member-expression-to-functions@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" + integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-imports@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" + integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8" + integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/template" "^7.4.4" + "@babel/types" "^7.4.4" + lodash "^4.17.11" + +"@babel/helper-optimise-call-expression@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" + integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== + +"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2" + integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q== + dependencies: + lodash "^4.17.11" + +"@babel/helper-remap-async-to-generator@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" + integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-wrap-function" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27" + integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/helper-simple-access@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" + integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== + dependencies: + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== + dependencies: + "@babel/types" "^7.4.4" + +"@babel/helper-wrap-function@^7.1.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" + integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.2.0" + +"@babel/helpers@^7.5.0": + version "7.5.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.1.tgz#65407c741a56ddd59dd86346cd112da3de912db3" + integrity sha512-rVOTDv8sH8kNI72Unenusxw6u+1vEepZgLxeV+jHkhsQlYhzVhzL1EpfoWT7Ub3zpWSv2WV03V853dqsnyoQzA== + dependencies: + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.5.0" + "@babel/types" "^7.5.0" + +"@babel/highlight@^7.0.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" + integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.4.4", "@babel/parser@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7" + integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA== + +"@babel/plugin-proposal-async-generator-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" + integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + +"@babel/plugin-proposal-class-properties@^7.4.4": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.0.tgz#5bc6a0537d286fcb4fd4e89975adbca334987007" + integrity sha512-9L/JfPCT+kShiiTTzcnBJ8cOwdKVmlC1RcCf9F0F9tERVrM4iWtWnXtjWCRqNm2la2BxO1MPArWNsU9zsSJWSQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.5.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-proposal-dynamic-import@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz#e532202db4838723691b10a67b8ce509e397c506" + integrity sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + +"@babel/plugin-proposal-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" + integrity sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + +"@babel/plugin-proposal-object-rest-spread@^7.4.4", "@babel/plugin-proposal-object-rest-spread@^7.5.0": + version "7.5.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.1.tgz#5788ab097c63135e4236548b4f112bfce09dd394" + integrity sha512-PVGXx5LYHcT7L4MdoE+rM5uq68IKlvU9lljVQ4OXY6aUEnGvezcGbM4VNY57Ug+3R2Zg/nYHlEdiWoIBoRA0mw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" + integrity sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz#501ffd9826c0b91da22690720722ac7cb1ca9c78" + integrity sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.5.4" + +"@babel/plugin-syntax-async-generators@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" + integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-dynamic-import@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612" + integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" + integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-object-rest-spread@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" + integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" + integrity sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-arrow-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" + integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-async-to-generator@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e" + integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + +"@babel/plugin-transform-block-scoped-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" + integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-block-scoping@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d" + integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.11" + +"@babel/plugin-transform-classes@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6" + integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-define-map" "^7.4.4" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.4.4" + "@babel/helper-split-export-declaration" "^7.4.4" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" + integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-destructuring@^7.4.4", "@babel/plugin-transform-destructuring@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a" + integrity sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3" + integrity sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.5.4" + +"@babel/plugin-transform-duplicate-keys@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853" + integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-exponentiation-operator@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" + integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-for-of@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" + integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-function-name@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad" + integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" + integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-member-expression-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz#fa10aa5c58a2cb6afcf2c9ffa8cb4d8b3d489a2d" + integrity sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-amd@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" + integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-commonjs@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz#425127e6045231360858eeaa47a71d75eded7a74" + integrity sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ== + dependencies: + "@babel/helper-module-transforms" "^7.4.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-systemjs@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249" + integrity sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg== + dependencies: + "@babel/helper-hoist-variables" "^7.4.4" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-umd@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" + integrity sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.4.5": + version "7.4.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz#9d269fd28a370258199b4294736813a60bbdd106" + integrity sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg== + dependencies: + regexp-tree "^0.1.6" + +"@babel/plugin-transform-new-target@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" + integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-object-super@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598" + integrity sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.1.0" + +"@babel/plugin-transform-parameters@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" + integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw== + dependencies: + "@babel/helper-call-delegate" "^7.4.4" + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-property-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz#03e33f653f5b25c4eb572c98b9485055b389e905" + integrity sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-regenerator@^7.4.5": + version "7.4.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz#629dc82512c55cee01341fb27bdfcb210354680f" + integrity sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA== + dependencies: + regenerator-transform "^0.14.0" + +"@babel/plugin-transform-reserved-words@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634" + integrity sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-runtime@^7.4.4": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.5.0.tgz#45242c2c9281158c5f06d25beebac63e498a284e" + integrity sha512-LmPIZOAgTLl+86gR9KjLXex6P/lRz1fWEjTz6V6QZMmKie51ja3tvzdwORqhHc4RWR8TcZ5pClpRWs0mlaA2ng== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + resolve "^1.8.1" + semver "^5.5.1" + +"@babel/plugin-transform-shorthand-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" + integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-spread@^7.2.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" + integrity sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-sticky-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" + integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + +"@babel/plugin-transform-template-literals@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" + integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-typeof-symbol@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" + integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-unicode-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f" + integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.5.4" + +"@babel/preset-env@^7.4.5": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.0.tgz#1122a751e864850b4dbce38bd9b4497840ee6f01" + integrity sha512-/5oQ7cYg+6sH9Dt9yx5IiylnLPiUdyMHl5y+K0mKVNiW2wJ7FpU5bg8jKcT8PcCbxdYzfv6OuC63jLEtMuRSmQ== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions" "^7.2.0" + "@babel/plugin-proposal-dynamic-import" "^7.5.0" + "@babel/plugin-proposal-json-strings" "^7.2.0" + "@babel/plugin-proposal-object-rest-spread" "^7.5.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/plugin-transform-arrow-functions" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.5.0" + "@babel/plugin-transform-block-scoped-functions" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.4.4" + "@babel/plugin-transform-classes" "^7.4.4" + "@babel/plugin-transform-computed-properties" "^7.2.0" + "@babel/plugin-transform-destructuring" "^7.5.0" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/plugin-transform-duplicate-keys" "^7.5.0" + "@babel/plugin-transform-exponentiation-operator" "^7.2.0" + "@babel/plugin-transform-for-of" "^7.4.4" + "@babel/plugin-transform-function-name" "^7.4.4" + "@babel/plugin-transform-literals" "^7.2.0" + "@babel/plugin-transform-member-expression-literals" "^7.2.0" + "@babel/plugin-transform-modules-amd" "^7.5.0" + "@babel/plugin-transform-modules-commonjs" "^7.5.0" + "@babel/plugin-transform-modules-systemjs" "^7.5.0" + "@babel/plugin-transform-modules-umd" "^7.2.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.5" + "@babel/plugin-transform-new-target" "^7.4.4" + "@babel/plugin-transform-object-super" "^7.2.0" + "@babel/plugin-transform-parameters" "^7.4.4" + "@babel/plugin-transform-property-literals" "^7.2.0" + "@babel/plugin-transform-regenerator" "^7.4.5" + "@babel/plugin-transform-reserved-words" "^7.2.0" + "@babel/plugin-transform-shorthand-properties" "^7.2.0" + "@babel/plugin-transform-spread" "^7.2.0" + "@babel/plugin-transform-sticky-regex" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.4.4" + "@babel/plugin-transform-typeof-symbol" "^7.2.0" + "@babel/plugin-transform-unicode-regex" "^7.4.4" + "@babel/types" "^7.5.0" + browserslist "^4.6.0" + core-js-compat "^3.1.1" + invariant "^2.2.2" + js-levenshtein "^1.1.3" + semver "^5.5.0" + +"@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5": + version "7.5.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.1.tgz#51b56e216e87103ab3f7d6040b464c538e242888" + integrity sha512-g+hmPKs16iewFSmW57NkH9xpPkuYD1RV3UE2BCkXx9j+nhhRb9hsiSxPmEa67j35IecTQdn4iyMtHMbt5VoREg== + dependencies: + regenerator-runtime "^0.13.2" + +"@babel/template@^7.1.0", "@babel/template@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" + integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.0.tgz#4216d6586854ef5c3c4592dab56ec7eb78485485" + integrity sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.5.0" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.5.0" + "@babel/types" "^7.5.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + +"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab" + integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + +"@csstools/convert-colors@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" + integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== + +"@fortawesome/fontawesome-common-types@^0.2.19": + version "0.2.19" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.19.tgz#754a0f85e1290858152e1c05700ab502b11197f1" + integrity sha512-nd2Ul/CUs8U9sjofQYAALzOGpgkVJQgEhIJnOHaoyVR/LeC3x2mVg4eB910a4kS6WgLPebAY0M2fApEI497raQ== + +"@fortawesome/fontawesome-svg-core@^1.2.17": + version "1.2.19" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.19.tgz#0eca1ce9285c3d99e6e340633ee8f615f9d1a2e0" + integrity sha512-D4ICXg9oU08eF9o7Or392gPpjmwwgJu8ecCFusthbID95CLVXOgIyd4mOKD9Nud5Ckz+Ty59pqkNtThDKR0erA== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.19" + +"@fortawesome/free-solid-svg-icons@^5.8.1": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.9.0.tgz#1c73e7bac17417d23f934d83f7fff5b100a7fda9" + integrity sha512-U8YXPfWcSozsCW0psCtlRGKjjRs5+Am5JJwLOUmVHFZbIEWzaz4YbP84EoPwUsVmSAKrisu3QeNcVOtmGml0Xw== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.19" + +"@rails/webpacker@^4.0.2": + version "4.0.7" + resolved "https://registry.yarnpkg.com/@rails/webpacker/-/webpacker-4.0.7.tgz#268571bf974e78ce57eca9fa478f5bd97fd5182c" + integrity sha512-nx3inMv7euO0UsD0voJ+n3/z1u56PuprW322b67TLuDmOHRpT7yUjBJULMisVKA6PVJw4DwiG9Kbf8ZGu53+tw== + dependencies: + "@babel/core" "^7.4.5" + "@babel/plugin-proposal-class-properties" "^7.4.4" + "@babel/plugin-proposal-object-rest-spread" "^7.4.4" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/plugin-transform-destructuring" "^7.4.4" + "@babel/plugin-transform-regenerator" "^7.4.5" + "@babel/plugin-transform-runtime" "^7.4.4" + "@babel/preset-env" "^7.4.5" + "@babel/runtime" "^7.4.5" + babel-loader "^8.0.6" + babel-plugin-dynamic-import-node "^2.2.0" + babel-plugin-macros "^2.5.0" + case-sensitive-paths-webpack-plugin "^2.2.0" + compression-webpack-plugin "^2.0.0" + core-js "^3.1.3" + css-loader "^2.1.1" + file-loader "^3.0.1" + flatted "^2.0.0" + glob "^7.1.4" + js-yaml "^3.13.1" + mini-css-extract-plugin "^0.7.0" + node-sass "^4.12.0" + optimize-css-assets-webpack-plugin "^5.0.1" + path-complete-extname "^1.0.0" + pnp-webpack-plugin "^1.4.3" + postcss-flexbugs-fixes "^4.1.0" + postcss-import "^12.0.1" + postcss-loader "^3.0.0" + postcss-preset-env "^6.6.0" + postcss-safe-parser "^4.0.1" + regenerator-runtime "^0.13.2" + sass-loader "^7.1.0" + style-loader "^0.23.1" + terser-webpack-plugin "^1.3.0" + webpack "^4.32.2" + webpack-assets-manifest "^3.1.1" + webpack-cli "^3.3.2" + webpack-sources "^1.3.0" + +"@types/caseless@*": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" + integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== + +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + +"@types/form-data@*": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" + integrity sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ== + dependencies: + "@types/node" "*" + +"@types/glob@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" + integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + +"@types/minimatch@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + +"@types/node@*": + version "12.0.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.12.tgz#cc791b402360db1eaf7176479072f91ee6c6c7ca" + integrity sha512-Uy0PN4R5vgBUXFoJrKryf5aTk3kJ8Rv3PdlHjl6UaX+Cqp1QE0yPQ68MPXGrZOfG7gZVNDIJZYyot0B9ubXUrQ== + +"@types/q@^1.5.1": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" + integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== + +"@types/request@^2.47.1": + version "2.48.1" + resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.1.tgz#e402d691aa6670fbbff1957b15f1270230ab42fa" + integrity sha512-ZgEZ1TiD+KGA9LiAAPPJL68Id2UWfeSO62ijSXZjFJArVV+2pKcsVHmrcu+1oiE3q6eDGiFiSolRc4JHoerBBg== + dependencies: + "@types/caseless" "*" + "@types/form-data" "*" + "@types/node" "*" + "@types/tough-cookie" "*" + +"@types/tough-cookie@*": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.5.tgz#9da44ed75571999b65c37b60c9b2b88db54c585d" + integrity sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg== + +"@webassemblyjs/ast@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" + integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== + dependencies: + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + +"@webassemblyjs/floating-point-hex-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" + integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== + +"@webassemblyjs/helper-api-error@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" + integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== + +"@webassemblyjs/helper-buffer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" + integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== + +"@webassemblyjs/helper-code-frame@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" + integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== + dependencies: + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/helper-fsm@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" + integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== + +"@webassemblyjs/helper-module-context@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" + integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== + dependencies: + "@webassemblyjs/ast" "1.8.5" + mamacro "^0.0.3" + +"@webassemblyjs/helper-wasm-bytecode@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" + integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== + +"@webassemblyjs/helper-wasm-section@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" + integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + +"@webassemblyjs/ieee754@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" + integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" + integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" + integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== + +"@webassemblyjs/wasm-edit@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" + integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/helper-wasm-section" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-opt" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/wasm-gen@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" + integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wasm-opt@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" + integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + +"@webassemblyjs/wasm-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" + integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wast-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" + integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/floating-point-hex-parser" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-code-frame" "1.8.5" + "@webassemblyjs/helper-fsm" "1.8.5" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" + integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-dynamic-import@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" + integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== + +acorn-jsx@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" + integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== + +acorn-walk@^6.1.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" + integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== + +acorn@^6.0.5, acorn@^6.0.7: + version "6.2.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3" + integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw== + +adjust-sourcemap-loader@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz#6471143af75ec02334b219f54bc7970c52fb29a4" + integrity sha512-4hFsTsn58+YjrU9qKzML2JSSDqKvN8mUGQ0nNIrfPi8hmIONT4L3uUaT6MKdMsZ9AjsU6D2xDkZxCkbQPxChrA== + dependencies: + assert "1.4.1" + camelcase "5.0.0" + loader-utils "1.2.3" + object-path "0.11.4" + regex-parser "2.2.10" + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d" + integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw== + +ajv@^6.1.0, ajv@^6.5.5, ajv@^6.9.1: + version "6.10.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" + integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +alphanum-sort@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arity-n@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745" + integrity sha1-2edrEXM+CFacCEeuezmyhgswt0U= + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + dependencies: + util "0.10.3" + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== + +async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= + +async@~2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" + integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== + dependencies: + lodash "^4.17.11" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@^9.4.9: + version "9.6.1" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47" + integrity sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw== + dependencies: + browserslist "^4.6.3" + caniuse-lite "^1.0.30000980" + chalk "^2.4.2" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.17" + postcss-value-parser "^4.0.0" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + +babel-loader@^8.0.6: + version "8.0.6" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" + integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== + dependencies: + find-cache-dir "^2.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + pify "^4.0.1" + +babel-plugin-dynamic-import-node@^2.2.0, babel-plugin-dynamic-import-node@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-macros@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.6.1.tgz#41f7ead616fc36f6a93180e89697f69f51671181" + integrity sha512-6W2nwiXme6j1n2erPOnmRiWfObUhWH7Qw1LMi9XZy8cj+KtESu3T6asZvtk5bMQQjX8te35o7CFueiSdL/2NmQ== + dependencies: + "@babel/runtime" "^7.4.2" + cosmiconfig "^5.2.0" + resolve "^1.10.0" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= + +base64-arraybuffer@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz#4b944fac0191aa5907afe2d8c999ccc57ce80f45" + integrity sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ== + +base64-js@^1.0.2, base64-js@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= + dependencies: + callsite "1.0.0" + +bfj@^6.1.1: + version "6.1.2" + resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.2.tgz#325c861a822bcb358a41c78a33b8e6e2086dde7f" + integrity sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw== + dependencies: + bluebird "^3.5.5" + check-types "^8.0.3" + hoopy "^0.1.4" + tryer "^1.0.1" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +bluebird@^3.5.5: + version "3.5.5" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" + integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +"bootstrap-treeview@git+https://github.com/iainbryson/bootstrap-treeview.git": + version "1.2.1" + resolved "git+https://github.com/iainbryson/bootstrap-treeview.git#10700fb50e97412c62d8900aec997bc78a28cd94" + +bootstrap@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.4.1.tgz#c3a347d419e289ad11f4033e3c4132b87c081d72" + integrity sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +brotli-webpack-plugin@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brotli-webpack-plugin/-/brotli-webpack-plugin-1.1.0.tgz#57168f1f109c07d45b412f52b287fc9dab50103c" + integrity sha512-byxKhV7L/OsN9urBgcD8Gkgq0OW61KYdSBwN249vT77VRl+9iz6TlWDXhg45rwYynZYetr+WRVuUvQ5WzwcYDQ== + dependencies: + async "~2.6.0" + webpack-sources "^1.0.2" + optionalDependencies: + brotli "^1.3.1" + iltorb "^2.0.1" + +brotli@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/brotli/-/brotli-1.3.2.tgz#525a9cad4fcba96475d7d388f6aecb13eed52f46" + integrity sha1-UlqcrU/LqWR119OI9q7LE+7VL0Y= + dependencies: + base64-js "^1.1.2" + +browser-request@~0.3.0: + version "0.3.3" + resolved "https://registry.yarnpkg.com/browser-request/-/browser-request-0.3.3.tgz#9ece5b5aca89a29932242e18bf933def9876cc17" + integrity sha1-ns5bWsqJopkyJC4Yv5M975h2zBc= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^4.0.0, browserslist@^4.4.2, browserslist@^4.6.0, browserslist@^4.6.2, browserslist@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.3.tgz#0530cbc6ab0c1f3fc8c819c72377ba55cf647f05" + integrity sha512-CNBqTCq22RKM8wKJNowcqihHJ4SkI8CGeK7KOR9tPboXUuS5Zk5lQgzzTbs4oxD8x+6HUshZUa2OyNI9lR93bQ== + dependencies: + caniuse-lite "^1.0.30000975" + electron-to-chromium "^1.3.164" + node-releases "^1.1.23" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cacache@^11.2.0, cacache@^11.3.2: + version "11.3.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc" + integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= + dependencies: + caller-callsite "^2.0.0" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" + integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= + +camelcase@^5.0.0, camelcase@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000697, caniuse-lite@^1.0.30000939, caniuse-lite@^1.0.30000975, caniuse-lite@^1.0.30000980: + version "1.0.30000980" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000980.tgz#0df53e4354b3111f83ac15b0bd4c71fe92994231" + integrity sha512-as0PRtWHaX3gl2gpC7qA7bX88lr+qLacMMXm1QKLLQtBCwT/Ljbgrv5EXKMNBoeEX6yFZ4vIsBb4Nh+PEwW2Rw== + +case-sensitive-paths-webpack-plugin@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.2.0.tgz#3371ef6365ef9c25fa4b81c16ace0e9c7dc58c3e" + integrity sha512-u5ElzokS8A1pm9vM3/iDgTcI3xqHxuCao94Oz8etI3cf0Tio0p8izkDYbTIn09uP3yUUr6+veaE6IkjnTYS46g== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@2.4.2, chalk@^2.0, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +check-types@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" + integrity sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ== + +chokidar@^2.0.2, chokidar@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" + integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chownr@^1.0.1, chownr@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" + integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== + +chrome-trace-event@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" + integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== + dependencies: + tslib "^1.9.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + +cli@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cli/-/cli-1.0.1.tgz#22817534f24bfa4950c34d532d48ecbc621b8c14" + integrity sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ= + dependencies: + exit "0.1.2" + glob "^7.1.1" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-deep@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" + integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== + dependencies: + for-own "^1.0.0" + is-plain-object "^2.0.4" + kind-of "^6.0.0" + shallow-clone "^1.0.0" + +cloudant-follow@^0.18.1: + version "0.18.2" + resolved "https://registry.yarnpkg.com/cloudant-follow/-/cloudant-follow-0.18.2.tgz#35dd7b29c5b9c58423d50691f848a990fbe2c88f" + integrity sha512-qu/AmKxDqJds+UmT77+0NbM7Yab2K3w0qSeJRzsq5dRWJTEJdWeb+XpG4OpKuTE9RKOa/Awn2gR3TTnvNr3TeA== + dependencies: + browser-request "~0.3.0" + debug "^4.0.1" + request "^2.88.0" + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0, color-convert@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" + integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.18.0, commander@^2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= + +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + +compose-function@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/compose-function/-/compose-function-3.0.3.tgz#9ed675f13cc54501d30950a486ff6a7ba3ab185f" + integrity sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8= + dependencies: + arity-n "^1.0.4" + +compressible@~2.0.16: + version "2.0.17" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" + integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== + dependencies: + mime-db ">= 1.40.0 < 2" + +compression-webpack-plugin@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-2.0.0.tgz#46476350c1eb27f783dccc79ac2f709baa2cffbc" + integrity sha512-bDgd7oTUZC8EkRx8j0sjyCfeiO+e5sFcfgaFcjVhfQf5lLya7oY2BczxcJ7IUuVjz5m6fy8IECFmVFew3xLk8Q== + dependencies: + cacache "^11.2.0" + find-cache-dir "^2.0.0" + neo-async "^2.5.0" + schema-utils "^1.0.0" + serialize-javascript "^1.4.0" + webpack-sources "^1.0.1" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +confusing-browser-globals@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.7.tgz#5ae852bd541a910e7ffb2dbb864a2d21a36ad29b" + integrity sha512-cgHI1azax5ATrZ8rJ+ODDML9Fvu67PimB6aNxBrc/QwSaDaM9eTfIEUHx3bBLJJ82ioSb+/5zfsMCCEJax3ByQ== + +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +console-browserify@1.1.x, console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@1.6.0, convert-source-map@^1.1.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@^0.3.3: + version "0.3.5" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190" + integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA= + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js-compat@^3.1.1: + version "3.1.4" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.1.4.tgz#e4d0c40fbd01e65b1d457980fe4112d4358a7408" + integrity sha512-Z5zbO9f1d0YrJdoaQhphVAnKPimX92D6z8lCGphH89MNRxlL1prI9ExJPqVwP0/kgkQCv8c4GJGT8X16yUncOg== + dependencies: + browserslist "^4.6.2" + core-js-pure "3.1.4" + semver "^6.1.1" + +core-js-pure@3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.4.tgz#5fa17dc77002a169a3566cc48dc774d2e13e3769" + integrity sha512-uJ4Z7iPNwiu1foygbcZYJsJs1jiXrTTCvxfLDXNhI/I+NHbSIEyr548y4fcsCEyWY0XgfAG/qqaunJ1SThHenA== + +core-js@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.0.1.tgz#1343182634298f7f38622f95e73f54e48ddf4738" + integrity sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew== + +core-js@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07" + integrity sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ== + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^5.0.0, cosmiconfig@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-blank-pseudo@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" + integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w== + dependencies: + postcss "^7.0.5" + +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= + +css-declaration-sorter@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" + integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== + dependencies: + postcss "^7.0.1" + timsort "^0.3.0" + +css-has-pseudo@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee" + integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^5.0.0-rc.4" + +css-line-break@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef" + integrity sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA== + dependencies: + base64-arraybuffer "^0.2.0" + +css-loader@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea" + integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w== + dependencies: + camelcase "^5.2.0" + icss-utils "^4.1.0" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.14" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^2.0.6" + postcss-modules-scope "^2.1.0" + postcss-modules-values "^2.0.0" + postcss-value-parser "^3.3.0" + schema-utils "^1.0.0" + +css-prefers-color-scheme@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" + integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg== + dependencies: + postcss "^7.0.5" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.0.2.tgz#ab4386cec9e1f668855564b17c3733b43b2a5ede" + integrity sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ== + dependencies: + boolbase "^1.0.0" + css-what "^2.1.2" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-tree@1.0.0-alpha.28: + version "1.0.0-alpha.28" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.28.tgz#8e8968190d886c9477bc8d61e96f61af3f7ffa7f" + integrity sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w== + dependencies: + mdn-data "~1.1.0" + source-map "^0.5.3" + +css-tree@1.0.0-alpha.29: + version "1.0.0-alpha.29" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39" + integrity sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg== + dependencies: + mdn-data "~1.1.0" + source-map "^0.5.3" + +css-unit-converter@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" + integrity sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY= + +css-url-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/css-url-regex/-/css-url-regex-1.1.0.tgz#83834230cc9f74c457de59eebd1543feeb83b7ec" + integrity sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w= + +css-what@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + +css@^2.0.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" + integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== + dependencies: + inherits "^2.0.3" + source-map "^0.6.1" + source-map-resolve "^0.5.2" + urix "^0.1.0" + +cssdb@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0" + integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ== + +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" + integrity sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA== + dependencies: + css-declaration-sorter "^4.0.1" + cssnano-util-raw-cache "^4.0.1" + postcss "^7.0.0" + postcss-calc "^7.0.1" + postcss-colormin "^4.0.3" + postcss-convert-values "^4.0.1" + postcss-discard-comments "^4.0.2" + postcss-discard-duplicates "^4.0.2" + postcss-discard-empty "^4.0.1" + postcss-discard-overridden "^4.0.1" + postcss-merge-longhand "^4.0.11" + postcss-merge-rules "^4.0.3" + postcss-minify-font-values "^4.0.2" + postcss-minify-gradients "^4.0.2" + postcss-minify-params "^4.0.2" + postcss-minify-selectors "^4.0.2" + postcss-normalize-charset "^4.0.1" + postcss-normalize-display-values "^4.0.2" + postcss-normalize-positions "^4.0.2" + postcss-normalize-repeat-style "^4.0.2" + postcss-normalize-string "^4.0.2" + postcss-normalize-timing-functions "^4.0.2" + postcss-normalize-unicode "^4.0.1" + postcss-normalize-url "^4.0.1" + postcss-normalize-whitespace "^4.0.2" + postcss-ordered-values "^4.1.2" + postcss-reduce-initial "^4.0.3" + postcss-reduce-transforms "^4.0.2" + postcss-svgo "^4.0.2" + postcss-unique-selectors "^4.0.1" + +cssnano-util-get-arguments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= + +cssnano-util-raw-cache@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" + integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== + dependencies: + postcss "^7.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" + integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== + +cssnano@^4.1.10: + version "4.1.10" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" + integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.7" + is-resolvable "^1.0.0" + postcss "^7.0.0" + +csso@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b" + integrity sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg== + dependencies: + css-tree "1.0.0-alpha.29" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + dependencies: + array-find-index "^1.0.1" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= + +d@1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.2.5, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +deep-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +default-gateway@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== + dependencies: + execa "^1.0.0" + ip-regex "^2.1.0" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@types/glob" "^7.1.1" + globby "^6.1.0" + is-path-cwd "^2.0.0" + is-path-in-cwd "^2.0.0" + p-map "^2.0.0" + pify "^4.0.1" + rimraf "^2.6.3" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= + +detect-libc@^1.0.2, detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-serializer@0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domelementtype@1, domelementtype@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domhandler@2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" + integrity sha1-LeWaCCLVAn+r/28DLCsloqir5zg= + dependencies: + domelementtype "1" + +domutils@1.5: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +dot-prop@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== + dependencies: + is-obj "^1.0.0" + +"dtu_core_assets@file:./deps/dtu-core/dtu_core_assets": + version "1.0.0" + +"dtu_core_js@file:./deps/dtu-core/dtu_core_assets": + version "1.0.0" + +duplexer@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +ejs@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.2.tgz#3a32c63d1cd16d11266cd4703b14fec4e74ab4f6" + integrity sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q== + +electron-to-chromium@^1.3.164: + version "1.3.188" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.188.tgz#e28e1afe4bb229989e280bfd3b395c7ec03c8b7a" + integrity sha512-tEQcughYIMj8WDMc59EGEtNxdGgwal/oLLTDw+NEqJRJwGflQvH3aiyiexrWeZOETP4/ko78PVr6gwNhdozvuQ== + +elliptic@^6.0.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.0.tgz#2b8ed4c891b7de3200e14412a5b8248c7af505ca" + integrity sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +engine.io-client@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" + integrity sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.3.2.tgz#18cbc8b6f36e9461c5c0f81df2b830de16058a59" + integrity sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w== + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~6.1.0" + +enhanced-resolve@4.1.0, enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +entities@1.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" + integrity sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY= + +entities@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +errs@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/errs/-/errs-0.3.2.tgz#798099b2dbd37ca2bc749e538a7c1307d0b50499" + integrity sha1-eYCZstvTfKK8dJ5TinwTB9C1BJk= + +es-abstract@^1.12.0, es-abstract@^1.5.1, es-abstract@^1.7.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" + integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-keys "^1.0.12" + +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@~0.10.14: + version "0.10.50" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.50.tgz#6d0e23a0abdb27018e5ac4fd09b412bc5517a778" + integrity sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.1" + next-tick "^1.0.0" + +es6-iterator@2.0.3, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc= + dependencies: + d "1" + es5-ext "~0.10.14" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-config-airbnb-base@^13.1.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.2.0.tgz#f6ea81459ff4dec2dda200c35f1d8f7419d57943" + integrity sha512-1mg/7eoB4AUeB0X1c/ho4vb2gYkNH8Trr/EgCT/aGmKhhG+F6vF5s8+iRBlWAzFIAphxIdp3YfEKgEl0f9Xg+w== + dependencies: + confusing-browser-globals "^1.0.5" + object.assign "^4.1.0" + object.entries "^1.1.0" + +eslint-import-resolver-node@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== + dependencies: + debug "^2.6.9" + resolve "^1.5.0" + +eslint-module-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a" + integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw== + dependencies: + debug "^2.6.8" + pkg-dir "^2.0.0" + +eslint-plugin-import@^2.17.2: + version "2.18.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.0.tgz#7a5ba8d32622fb35eb9c8db195c2090bd18a3678" + integrity sha512-PZpAEC4gj/6DEMMoU2Df01C5c50r7zdGIN52Yfi7CvvWaYssG7Jt5R9nFG5gmqodxNOz9vQS87xk6Izdtpdrig== + dependencies: + array-includes "^3.0.3" + contains-path "^0.1.0" + debug "^2.6.9" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.2" + eslint-module-utils "^2.4.0" + has "^1.0.3" + lodash "^4.17.11" + minimatch "^3.0.4" + read-pkg-up "^2.0.0" + resolve "^1.11.0" + +eslint-scope@^4.0.0, eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" + integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q== + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== + +eslint@^5.16.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" + integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.9.1" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^4.0.3" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^5.0.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.2.2" + js-yaml "^3.13.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.11" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^5.5.1" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^5.2.3" + text-table "^0.2.0" + +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" + integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== + dependencies: + acorn "^6.0.7" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + +events@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" + integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== + +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== + dependencies: + original "^1.0.0" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exit@0.1.2, exit@0.1.x: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= + dependencies: + homedir-polyfill "^1.0.1" + +express@^4.16.3, express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" + integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fallback@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fallback/-/fallback-1.0.1.tgz#ff53cadced129752a9c7a2108dd568f4c8e95d01" + integrity sha1-/1PK3O0Sl1Kpx6IQjdVo9MjpXQE= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.1: + version "0.11.3" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" + integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== + dependencies: + websocket-driver ">=0.5.1" + +"feedbackjs@file:./deps/feedbackjs": + version "1.0.0-alpha.1" + dependencies: + "@fortawesome/fontawesome-svg-core" "^1.2.17" + "@fortawesome/free-solid-svg-icons" "^5.8.1" + html2canvas "^1.0.0-rc.3" + +figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +file-loader@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" + integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== + dependencies: + loader-utils "^1.0.2" + schema-utils "^1.0.0" + +filesize@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +findup-sync@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" + integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I= + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@^1.0.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" + integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== + dependencies: + debug "^3.2.6" + +for-in@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" + integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-minipass@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" + integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== + dependencies: + minipass "^2.2.1" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.9" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" + integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== + dependencies: + nan "^2.12.1" + node-pre-gyp "^0.12.0" + +fstream@^1.0.0, fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^6.0.1: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI= + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0, globals@^11.7.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globule@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" + integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ== + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== + +gzip-size@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" + integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== + dependencies: + duplexer "^0.1.1" + pify "^4.0.1" + +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.0, has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +hoopy@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" + integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== + +hosted-git-info@^2.1.4: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= + +html-comment-regex@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" + integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== + +html-entities@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= + +html2canvas@^1.0.0-rc.3: + version "1.0.0-rc.3" + resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.0.0-rc.3.tgz#1de88b073f6bcaa6954ca1edfb46da13b258b038" + integrity sha512-nWRk34IO3QopcDYpiPAbRW6VoI10H7uxEhcSFjox0JB6wZOMd6Mak+NqHPLljSFFEOvBjPafyRgcHnuWcFpWvg== + dependencies: + css-line-break "1.1.1" + +htmlparser2@3.8.x: + version "3.8.3" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" + integrity sha1-mWwosZFRaovoZQGn15dX5ccMEGg= + dependencies: + domelementtype "1" + domhandler "2.3" + domutils "1.5" + entities "1.0" + readable-stream "1.1" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +"http-parser-js@>=0.4.0 <0.4.11": + version "0.4.10" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" + integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q= + +http-proxy-middleware@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + +http-proxy@^1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== + dependencies: + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= + +icss-utils@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" + integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== + dependencies: + postcss "^7.0.14" + +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +iltorb@^2.0.1: + version "2.4.3" + resolved "https://registry.yarnpkg.com/iltorb/-/iltorb-2.4.3.tgz#b489689d24c8a25a2cf170c515f97954edd45577" + integrity sha512-cr/kC07Cf9sW3TWH7yUxV2QkNjby4LMCsXGmxPCQs5x//QzTpF3GLPNY7L66G+DkNGaTRCgY+vYZ+dyAcuDOnQ== + dependencies: + detect-libc "^1.0.3" + nan "^2.13.2" + npmlog "^4.1.2" + prebuild-install "^5.3.0" + which-pm-runs "^1.0.0" + +import-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= + dependencies: + import-from "^2.1.0" + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +import-fresh@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" + integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-from@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" + integrity sha1-M1238qev/VOqpHHUuAId7ja387E= + dependencies: + resolve-from "^3.0.0" + +import-local@2.0.0, import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + integrity sha1-4g/146KvwmkDILbcVSaCqcf631E= + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + dependencies: + repeating "^2.0.0" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +inquirer@^6.2.2: + version "6.4.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.4.1.tgz#7bd9e5ab0567cd23b41b0180b68e0cfa82fc3c0b" + integrity sha512-/Jw+qPZx4EDYsaT6uz7F4GJRNFMRdKNeUZw3ZnKV8lyuUgz/YWRCSUAJMZSVhSq4Ec0R2oYnyi6b3d4JXcL5Nw== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.11" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +internal-ip@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" + integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + dependencies: + default-gateway "^4.2.0" + ipaddr.js "^1.9.0" + +interpret@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.0, ipaddr.js@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" + integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-path-cwd@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= + dependencies: + has "^1.0.1" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-svg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" + integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ== + dependencies: + html-comment-regex "^1.1.0" + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + dependencies: + has-symbols "^1.0.0" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +jquery-ujs@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jquery-ujs/-/jquery-ujs-1.2.2.tgz#6a8ef1020e6b6dda385b90a4bddc128c21c56397" + integrity sha1-ao7xAg5rbdo4W5CkvdwSjCHFY5c= + dependencies: + jquery ">=1.8.0" + +jquery@>=1.8.0, jquery@^3.3.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" + integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== + +js-base64@^2.1.8: + version "2.5.1" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121" + integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw== + +js-levenshtein@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" + integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.0, js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +jshint@^2.10.2: + version "2.10.2" + resolved "https://registry.yarnpkg.com/jshint/-/jshint-2.10.2.tgz#ed6626c4f8223c98e94aaea62767435427a49a3d" + integrity sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA== + dependencies: + cli "~1.0.0" + console-browserify "1.1.x" + exit "0.1.x" + htmlparser2 "3.8.x" + lodash "~4.17.11" + minimatch "~3.0.2" + shelljs "0.3.x" + strip-json-comments "1.0.x" + +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json3@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" + integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== + dependencies: + minimist "^1.2.0" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +killable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +last-call-webpack-plugin@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" + integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== + dependencies: + lodash "^4.17.5" + webpack-sources "^1.1.0" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@1.2.3, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash._reinterpolate@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash.get@^4.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.has@^4.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862" + integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.tail@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" + integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= + +lodash.template@^4.2.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + integrity sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A= + dependencies: + lodash._reinterpolate "~3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + integrity sha1-K01OlbpEDZFf8IvImeRVNmZxMxY= + dependencies: + lodash._reinterpolate "~3.0.0" + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.5, lodash@~4.17.10, lodash@~4.17.11: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +loglevel@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280" + integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA== + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +mathjax@~2.7.1: + version "2.7.5" + resolved "https://registry.yarnpkg.com/mathjax/-/mathjax-2.7.5.tgz#c9c5947f86f9be31651f5f3667d3c9a8bb01efe4" + integrity sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdn-data@~1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01" + integrity sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.40.0, "mime-db@>= 1.40.0 < 2": + version "1.40.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" + integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.24" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" + integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + dependencies: + mime-db "1.40.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.2: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mini-css-extract-plugin@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.7.0.tgz#5ba8290fbb4179a43dd27cca444ba150bee743a0" + integrity sha512-RQIw6+7utTYn8DBGsf/LpRgZCJMpZt+kuawJ/fju0KiOL6nAaTBNmCJwS7HtwSCXfS47gCkmtBFS7HdsquhdxQ== + dependencies: + loader-utils "^1.1.0" + normalize-url "1.9.1" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +"minimatch@2 || 3", minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minipass@^2.2.1, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mixin-object@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" + integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= + dependencies: + for-in "^0.1.3" + is-extendable "^0.1.1" + +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + +mv@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" + integrity sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI= + dependencies: + mkdirp "~0.5.1" + ncp "~2.0.0" + rimraf "~2.4.0" + +nan@^2.12.1, nan@^2.13.2: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nano@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/nano/-/nano-8.1.0.tgz#22815e7bb9ce4eb24c67620da2225a454ec8e1f1" + integrity sha512-suMHW9XtTP8doR4FnId5+6ZfbAvDIZOAVp3qe7zTHXp7BvT/Cf4G9xBjXAthrIzoa+fkcionEr9xo8cZtvqMmg== + dependencies: + "@types/request" "^2.47.1" + cloudant-follow "^0.18.1" + debug "^4.1.1" + errs "^0.3.2" + request "^2.88.0" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +napi-build-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" + integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +ncp@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= + +needle@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" + integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + +next-tick@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-abi@^2.7.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.9.0.tgz#ae4075b298dab2d92dd1e22c48ccc7ffd7f06200" + integrity sha512-jmEOvv0eanWjhX8dX1pmjb7oJl1U1oR4FOh0b2GnvALwSYoOdU7sj+kLDSAyjo4pfC9aj/IxkloxdLJQhSSQBA== + dependencies: + semver "^5.4.1" + +node-forge@0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ== + +node-gyp@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-libs-browser@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^1.1.23: + version "1.1.25" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.25.tgz#0c2d7dbc7fed30fbe02a9ee3007b8c90bf0133d3" + integrity sha512-fI5BXuk83lKEoZDdH3gRhtsNgh05/wZacuXkgbiYkceE7+QIMXOg98n9ZV7mz27B+kFHnqHcUpscZZlGRSmTpQ== + dependencies: + semver "^5.3.0" + +node-sass@^4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017" + integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ== + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash "^4.17.11" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.13.2" + node-gyp "^3.8.0" + npmlog "^4.0.0" + request "^2.88.0" + sass-graph "^2.2.4" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" + +noop-logger@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" + integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= + +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw= + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +normalize-url@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-packlist@^1.1.6: + version "1.4.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" + integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +nth-check@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-keys@^1.0.11, object-keys@^1.0.12: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-path@0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.4.tgz#370ae752fbf37de3ea70a861c23bba8915691949" + integrity sha1-NwrnUvvzfePqcKhhwju6iRVpGUk= + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.entries@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" + integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.12.0" + function-bind "^1.1.1" + has "^1.0.3" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9" + integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.12.0" + function-bind "^1.1.1" + has "^1.0.3" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +opener@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" + integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== + +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +optimize-css-assets-webpack-plugin@^5.0.1: + version "5.0.3" + resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz#e2f1d4d94ad8c0af8967ebd7cf138dcb1ef14572" + integrity sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA== + dependencies: + cssnano "^4.1.10" + last-call-webpack-plugin "^3.0.0" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= + dependencies: + lcid "^1.0.0" + +os-locale@^3.0.0, os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@0, osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" + integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-retry@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" + integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== + dependencies: + retry "^0.12.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +"pagedown-extra@git+https://github.com/jmcmanus/pagedown-extra.git#ea782c3d11eb78f57d00aa819527338996a70721": + version "0.1.0" + resolved "git+https://github.com/jmcmanus/pagedown-extra.git#ea782c3d11eb78f57d00aa819527338996a70721" + +pako@~1.0.5: + version "1.0.10" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" + integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0: + version "5.1.4" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" + integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + dependencies: + better-assert "~1.0.0" + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-complete-extname@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-complete-extname/-/path-complete-extname-1.0.0.tgz#f889985dc91000c815515c0bfed06c5acda0752b" + integrity sha512-CVjiWcMRdGU8ubs08YQVzhutOR5DEfO97ipRIlOGMK5Bek5nQySknBpuxVAVJ36hseTNs+vdIcv57ZrWxH7zvg== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + +path@^0.12.7: + version "0.12.7" + resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" + integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8= + dependencies: + process "^0.11.1" + util "^0.10.3" + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pnp-webpack-plugin@^1.4.3: + version "1.5.0" + resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.5.0.tgz#62a1cd3068f46d564bb33c56eb250e4d586676eb" + integrity sha512-jd9olUr9D7do+RN8Wspzhpxhgp1n6Vd0NtQ4SFkmIACZoEL1nkyAdW9Ygrinjec0vgDcWjscFQQ1gDW8rsfKTg== + dependencies: + ts-pnp "^1.1.2" + +popper.js@^1.14.3: + version "1.15.0" + resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2" + integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA== + +portfinder@^1.0.20: + version "1.0.20" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" + integrity sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw== + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-attribute-case-insensitive@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.1.tgz#b2a721a0d279c2f9103a36331c88981526428cc7" + integrity sha512-L2YKB3vF4PetdTIthQVeT+7YiSzMoNMLLYxPXXppOOP7NoazEAy45sh2LvJ8leCQjfBcfkYQs8TtCcQjeZTp8A== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0" + +postcss-calc@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.1.tgz#36d77bab023b0ecbb9789d84dcb23c4941145436" + integrity sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ== + dependencies: + css-unit-converter "^1.1.1" + postcss "^7.0.5" + postcss-selector-parser "^5.0.0-rc.4" + postcss-value-parser "^3.3.1" + +postcss-color-functional-notation@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0" + integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-gray@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547" + integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-color-hex-alpha@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388" + integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw== + dependencies: + postcss "^7.0.14" + postcss-values-parser "^2.0.1" + +postcss-color-mod-function@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d" + integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-rebeccapurple@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77" + integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-colormin@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" + integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" + integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-custom-media@^7.0.7: + version "7.0.8" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c" + integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg== + dependencies: + postcss "^7.0.14" + +postcss-custom-properties@^8.0.9: + version "8.0.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97" + integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA== + dependencies: + postcss "^7.0.17" + postcss-values-parser "^2.0.1" + +postcss-custom-selectors@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba" + integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-dir-pseudo-class@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2" + integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-discard-comments@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" + integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== + dependencies: + postcss "^7.0.0" + +postcss-discard-duplicates@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" + integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== + dependencies: + postcss "^7.0.0" + +postcss-discard-empty@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" + integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== + dependencies: + postcss "^7.0.0" + +postcss-discard-overridden@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" + integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== + dependencies: + postcss "^7.0.0" + +postcss-double-position-gradients@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" + integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA== + dependencies: + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-env-function@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7" + integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-flexbugs-fixes@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz#e094a9df1783e2200b7b19f875dcad3b3aff8b20" + integrity sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA== + dependencies: + postcss "^7.0.0" + +postcss-focus-visible@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e" + integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g== + dependencies: + postcss "^7.0.2" + +postcss-focus-within@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680" + integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w== + dependencies: + postcss "^7.0.2" + +postcss-font-variant@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.0.tgz#71dd3c6c10a0d846c5eda07803439617bbbabacc" + integrity sha512-M8BFYKOvCrI2aITzDad7kWuXXTm0YhGdP9Q8HanmN4EF1Hmcgs1KK5rSHylt/lUJe8yLxiSwWAHdScoEiIxztg== + dependencies: + postcss "^7.0.2" + +postcss-gap-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715" + integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg== + dependencies: + postcss "^7.0.2" + +postcss-image-set-function@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288" + integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-import@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-12.0.1.tgz#cf8c7ab0b5ccab5649024536e565f841928b7153" + integrity sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw== + dependencies: + postcss "^7.0.1" + postcss-value-parser "^3.2.3" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-initial@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.0.tgz#1772512faf11421b791fb2ca6879df5f68aa0517" + integrity sha512-WzrqZ5nG9R9fUtrA+we92R4jhVvEB32IIRTzfIG/PLL8UV4CvbF1ugTEHEFX6vWxl41Xt5RTCJPEZkuWzrOM+Q== + dependencies: + lodash.template "^4.2.4" + postcss "^7.0.2" + +postcss-lab-function@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" + integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-load-config@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003" + integrity sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q== + dependencies: + cosmiconfig "^5.0.0" + import-cwd "^2.0.0" + +postcss-loader@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" + integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== + dependencies: + loader-utils "^1.1.0" + postcss "^7.0.0" + postcss-load-config "^2.0.0" + schema-utils "^1.0.0" + +postcss-logical@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" + integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA== + dependencies: + postcss "^7.0.2" + +postcss-media-minmax@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5" + integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw== + dependencies: + postcss "^7.0.2" + +postcss-merge-longhand@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" + integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== + dependencies: + css-color-names "0.0.4" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" + integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + cssnano-util-same-parent "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + vendors "^1.0.0" + +postcss-minify-font-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" + integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" + integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" + integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== + dependencies: + alphanum-sort "^1.0.0" + browserslist "^4.0.0" + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + uniqs "^2.0.0" + +postcss-minify-selectors@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" + integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63" + integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + postcss-value-parser "^3.3.1" + +postcss-modules-scope@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb" + integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + +postcss-modules-values@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64" + integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w== + dependencies: + icss-replace-symbols "^1.1.0" + postcss "^7.0.6" + +postcss-nesting@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.0.tgz#6e26a770a0c8fcba33782a6b6f350845e1a448f6" + integrity sha512-WSsbVd5Ampi3Y0nk/SKr5+K34n52PqMqEfswu6RtU4r7wA8vSD+gM8/D9qq4aJkHImwn1+9iEFTbjoWsQeqtaQ== + dependencies: + postcss "^7.0.2" + +postcss-normalize-charset@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" + integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== + dependencies: + postcss "^7.0.0" + +postcss-normalize-display-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" + integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" + integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" + integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" + integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" + integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" + integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" + integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" + integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-ordered-values@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" + integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-overflow-shorthand@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30" + integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g== + dependencies: + postcss "^7.0.2" + +postcss-page-break@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf" + integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ== + dependencies: + postcss "^7.0.2" + +postcss-place@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62" + integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-preset-env@^6.6, postcss-preset-env@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.6.0.tgz#642e7d962e2bdc2e355db117c1eb63952690ed5b" + integrity sha512-I3zAiycfqXpPIFD6HXhLfWXIewAWO8emOKz+QSsxaUZb9Dp8HbF5kUf+4Wy/AxR33o+LRoO8blEWCHth0ZsCLA== + dependencies: + autoprefixer "^9.4.9" + browserslist "^4.4.2" + caniuse-lite "^1.0.30000939" + css-blank-pseudo "^0.1.4" + css-has-pseudo "^0.10.0" + css-prefers-color-scheme "^3.1.1" + cssdb "^4.3.0" + postcss "^7.0.14" + postcss-attribute-case-insensitive "^4.0.1" + postcss-color-functional-notation "^2.0.1" + postcss-color-gray "^5.0.0" + postcss-color-hex-alpha "^5.0.2" + postcss-color-mod-function "^3.0.3" + postcss-color-rebeccapurple "^4.0.1" + postcss-custom-media "^7.0.7" + postcss-custom-properties "^8.0.9" + postcss-custom-selectors "^5.1.2" + postcss-dir-pseudo-class "^5.0.0" + postcss-double-position-gradients "^1.0.0" + postcss-env-function "^2.0.2" + postcss-focus-visible "^4.0.0" + postcss-focus-within "^3.0.0" + postcss-font-variant "^4.0.0" + postcss-gap-properties "^2.0.0" + postcss-image-set-function "^3.0.1" + postcss-initial "^3.0.0" + postcss-lab-function "^2.0.1" + postcss-logical "^3.0.0" + postcss-media-minmax "^4.0.0" + postcss-nesting "^7.0.0" + postcss-overflow-shorthand "^2.0.0" + postcss-page-break "^2.0.0" + postcss-place "^4.0.1" + postcss-pseudo-class-any-link "^6.0.0" + postcss-replace-overflow-wrap "^3.0.0" + postcss-selector-matches "^4.0.0" + postcss-selector-not "^4.0.0" + +postcss-pseudo-class-any-link@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1" + integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-reduce-initial@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" + integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + +postcss-reduce-transforms@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" + integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-replace-overflow-wrap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c" + integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw== + dependencies: + postcss "^7.0.2" + +postcss-safe-parser@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz#8756d9e4c36fdce2c72b091bbc8ca176ab1fcdea" + integrity sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ== + dependencies: + postcss "^7.0.0" + +postcss-selector-matches@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff" + integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-not@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz#c68ff7ba96527499e832724a2674d65603b645c0" + integrity sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-parser@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" + integrity sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU= + dependencies: + dot-prop "^4.1.1" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^5.0.0, postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== + dependencies: + cssesc "^3.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" + integrity sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw== + dependencies: + is-svg "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" + integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== + dependencies: + alphanum-sort "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss-value-parser@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz#99a983d365f7b2ad8d0f9b8c3094926eab4b936d" + integrity sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ== + +postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f" + integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss@7.0.14: + version "7.0.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5" + integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.17" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f" + integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +prebuild-install@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8" + integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== + dependencies: + detect-libc "^1.0.3" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.0" + mkdirp "^0.5.1" + napi-build-utils "^1.0.1" + node-abi "^2.7.0" + noop-logger "^0.1.1" + npmlog "^4.0.1" + os-homedir "^1.0.1" + pump "^2.0.1" + rc "^1.2.7" + simple-get "^2.7.0" + tar-fs "^1.13.0" + tunnel-agent "^0.6.0" + which-pm-runs "^1.0.0" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +prettier@^1.17.0: + version "1.18.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" + integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== + +private@^0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.1, process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +proxy-addr@~2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" + integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.0" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.24: + version "1.2.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.2.0.tgz#df12b5b1b3a30f51c329eacbdef98f3a6e136dc6" + integrity sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@^1.1.2, q@^1.4.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" + integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== + +rails-ujs@^5.2.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/rails-ujs/-/rails-ujs-5.2.3.tgz#4b65ea781a6befe62e96da6362165286a1fe4099" + integrity sha512-rYgj185MowWFBJI1wdac2FkX4yFYe4+3jJPlB+CTY7a4rmIyg0TqE4vYZmSBBesp7blPUa57oqKzwQjN7eVbEQ== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha1-5mTvMRYRZsl1HNvo28+GtftY93Q= + dependencies: + pify "^2.3.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@1.1: + version "1.1.13" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e" + integrity sha1-9u73ZPUUyJ4rniMUanW6EGdW0j4= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^3.0.6: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" + integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +regenerate-unicode-properties@^8.0.2: + version "8.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" + integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-runtime@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" + integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== + +regenerator-transform@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf" + integrity sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w== + dependencies: + private "^0.1.6" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regex-parser@2.2.10: + version "2.2.10" + resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.10.tgz#9e66a8f73d89a107616e63b39d4deddfee912b37" + integrity sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA== + +regexp-tree@^0.1.6: + version "0.1.11" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.11.tgz#c9c7f00fcf722e0a56c7390983a7a63dd6c272f3" + integrity sha512-7/l/DgapVVDzZobwMCCgMlqiqyLFJ0cduo/j+3BcDJIB+yJdsYCfKuI3l/04NV+H/rfNRdPIDbXNZHM9XvQatg== + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpu-core@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae" + integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.0.2" + regjsgen "^0.5.0" + regjsparser "^0.6.0" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.1.0" + +regjsgen@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" + integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== + +regjsparser@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" + integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +request@^2.87.0, request@^2.88.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-css@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/require-css/-/require-css-0.1.5.tgz#7040958fe10910fe225337da659f1a9bde588c5a" + integrity sha1-cECVj+EJEP4iUzfaZZ8am95YjFo= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-url-loader@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.0.tgz#54d8181d33cd1b66a59544d05cadf8e4aa7d37cc" + integrity sha512-2QcrA+2QgVqsMJ1Hn5NnJXIGCX1clQ1F6QJTqOeiaDw9ACo1G2k+8/shq3mtqne03HOFyskAClqfxKyFBriXZg== + dependencies: + adjust-sourcemap-loader "2.0.0" + camelcase "5.0.0" + compose-function "3.0.3" + convert-source-map "1.6.0" + es6-iterator "2.0.3" + loader-utils "1.2.3" + postcss "7.0.14" + rework "1.0.1" + rework-visit "1.0.0" + source-map "0.6.1" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.8.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" + integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== + dependencies: + path-parse "^1.0.6" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +rework-visit@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rework-visit/-/rework-visit-1.0.0.tgz#9945b2803f219e2f7aca00adb8bc9f640f842c9a" + integrity sha1-mUWygD8hni96ygCtuLyfZA+ELJo= + +rework@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rework/-/rework-1.0.1.tgz#30806a841342b54510aa4110850cd48534144aa7" + integrity sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc= + dependencies: + convert-source-map "^0.3.3" + css "^2.0.0" + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + +rimraf@2, rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +rimraf@~2.4.0: + version "2.4.5" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" + integrity sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto= + dependencies: + glob "^6.0.1" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= + dependencies: + is-promise "^2.1.0" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +rxjs@^6.4.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" + integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sass-graph@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k= + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + +sass-loader@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d" + integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w== + dependencies: + clone-deep "^2.0.1" + loader-utils "^1.0.1" + lodash.tail "^4.1.1" + neo-async "^2.5.0" + pify "^3.0.0" + semver "^5.5.0" + +sax@^1.2.4, sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selfsigned@^1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd" + integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw== + dependencies: + node-forge "0.7.5" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +semver@^6.1.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" + integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serialize-javascript@^1.4.0, serialize-javascript@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" + integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shallow-clone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" + integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== + dependencies: + is-extendable "^0.1.1" + kind-of "^5.0.0" + mixin-object "^2.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shelljs@0.3.x: + version "0.3.0" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1" + integrity sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E= + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= + +simple-get@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" + integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +socket.io-adapter@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= + +socket.io-client@2.2.0, socket.io-client@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" + integrity sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA== + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.3.1" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" + integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b" + integrity sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w== + dependencies: + debug "~4.1.0" + engine.io "~3.3.1" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.2.0" + socket.io-parser "~3.3.0" + +sockjs-client@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" + integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg== + dependencies: + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" + json3 "^3.3.2" + url-parse "^1.4.3" + +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== + dependencies: + faye-websocket "^0.10.0" + uuid "^3.0.1" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@~0.5.12: + version "0.5.12" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" + integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" + integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" + integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +stdout-stream@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" + integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + dependencies: + readable-stream "^2.0.1" + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + integrity sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E= + +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +style-loader@^0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + +stylehacks@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" + integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +supports-color@6.1.0, supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +svgo@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.2.2.tgz#0253d34eccf2aed4ad4f283e11ee75198f9d7316" + integrity sha512-rAfulcwp2D9jjdGu+0CuqlrAUin6bBWrpoqXWwKDZZZJfXcUXQSxLJOFJCQCSA0x0pP2U0TxSlJu2ROq5Bq6qA== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.28" + css-url-regex "^1.1.0" + csso "^3.5.1" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +table@^5.2.3: + version "5.4.1" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.1.tgz#0691ae2ebe8259858efb63e550b6d5f9300171e8" + integrity sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w== + dependencies: + ajv "^6.9.1" + lodash "^4.17.11" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +tapable@^1.0.0, tapable@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tar-fs@^1.13.0: + version "1.16.3" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" + integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + +tar-stream@^1.1.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tar@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== + dependencies: + block-stream "*" + fstream "^1.0.12" + inherits "2" + +tar@^4: + version "4.4.10" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" + integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.5" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz#69aa22426299f4b5b3775cbed8cb2c5d419aa1d4" + integrity sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg== + dependencies: + cacache "^11.3.2" + find-cache-dir "^2.0.0" + is-wsl "^1.1.0" + loader-utils "^1.2.3" + schema-utils "^1.0.0" + serialize-javascript "^1.7.0" + source-map "^0.6.1" + terser "^4.0.0" + webpack-sources "^1.3.0" + worker-farm "^1.7.0" + +terser@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.1.0.tgz#fe949a2189345b2f1789f2bafc6c3b056dab16ed" + integrity sha512-O2MzVShUr/B+bxTh83ycpDR+Ocesg5qLR8kphWApRbWCkSnfKq1YPmydnVNfsJuJKHvzSgDNqFq4cr1O36oQ2A== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +thunky@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" + integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== + dependencies: + setimmediate "^1.0.4" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + +"true-case-path@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" + integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== + dependencies: + glob "^7.1.2" + +tryer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" + integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== + +ts-pnp@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.2.tgz#be8e4bfce5d00f0f58e0666a82260c34a57af552" + integrity sha512-f5Knjh7XCyRIzoC/z1Su1yLLRrPrFCgtUAh/9fCSP6NKbATwpOL1+idQVXQokK9GRFURn/jYPGPfegIctwunoA== + +tslib@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +type@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/type/-/type-1.0.1.tgz#084c9a17fcc9151a2cdb1459905c2e45e4bb7d61" + integrity sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw== + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +underscore@^1.8: + version "1.9.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" + integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" + integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-parse@^1.4.3: + version "1.4.7" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" + integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.0.1, uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +v8-compile-cache@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" + integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vendors@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.3.tgz#a6467781abd366217c050f8202e7e50cc9eef8c0" + integrity sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019" + integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw== + +watchpack@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webpack-assets-manifest@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/webpack-assets-manifest/-/webpack-assets-manifest-3.1.1.tgz#39bbc3bf2ee57fcd8ba07cda51c9ba4a3c6ae1de" + integrity sha512-JV9V2QKc5wEWQptdIjvXDUL1ucbPLH2f27toAY3SNdGZp+xSaStAgpoMcvMZmqtFrBc9a5pTS1058vxyMPOzRQ== + dependencies: + chalk "^2.0" + lodash.get "^4.0" + lodash.has "^4.0" + mkdirp "^0.5" + schema-utils "^1.0.0" + tapable "^1.0.0" + webpack-sources "^1.0.0" + +webpack-bundle-analyzer@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.3.2.tgz#3da733a900f515914e729fcebcd4c40dde71fc6f" + integrity sha512-7qvJLPKB4rRWZGjVp5U1KEjwutbDHSKboAl0IfafnrdXMrgC0tOtZbQD6Rw0u4cmpgRN4O02Fc0t8eAT+FgGzA== + dependencies: + acorn "^6.0.7" + acorn-walk "^6.1.1" + bfj "^6.1.1" + chalk "^2.4.1" + commander "^2.18.0" + ejs "^2.6.1" + express "^4.16.3" + filesize "^3.6.1" + gzip-size "^5.0.0" + lodash "^4.17.10" + mkdirp "^0.5.1" + opener "^1.5.1" + ws "^6.0.0" + +webpack-cli@^3.3.2: + version "3.3.5" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.5.tgz#f4d1238a66a2843d9cebf189835ea22142e72767" + integrity sha512-w0j/s42c5UhchwTmV/45MLQnTVwRoaUTu9fM5LuyOd/8lFoCNCELDogFoecx5NzRUndO0yD/gF2b02XKMnmAWQ== + dependencies: + chalk "2.4.2" + cross-spawn "6.0.5" + enhanced-resolve "4.1.0" + findup-sync "3.0.0" + global-modules "2.0.0" + import-local "2.0.0" + interpret "1.2.0" + loader-utils "1.2.3" + supports-color "6.1.0" + v8-compile-cache "2.0.3" + yargs "13.2.4" + +webpack-dev-middleware@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz#ef751d25f4e9a5c8a35da600c5fda3582b5c6cff" + integrity sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.2" + range-parser "^1.2.1" + webpack-log "^2.0.0" + +webpack-dev-server@^3.3.1: + version "3.7.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.7.2.tgz#f79caa5974b7f8b63268ef5421222a8486d792f5" + integrity sha512-mjWtrKJW2T9SsjJ4/dxDC2fkFVUw8jlpemDERqV0ZJIkjjjamR2AbQlr3oz+j4JLhYCHImHnXZK5H06P2wvUew== + dependencies: + ansi-html "0.0.7" + bonjour "^3.5.0" + chokidar "^2.1.6" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + debug "^4.1.1" + del "^4.1.1" + express "^4.17.1" + html-entities "^1.2.1" + http-proxy-middleware "^0.19.1" + import-local "^2.0.0" + internal-ip "^4.3.0" + ip "^1.1.5" + killable "^1.0.1" + loglevel "^1.6.3" + opn "^5.5.0" + p-retry "^3.0.1" + portfinder "^1.0.20" + schema-utils "^1.0.0" + selfsigned "^1.10.4" + semver "^6.1.1" + serve-index "^1.9.1" + sockjs "0.3.19" + sockjs-client "1.3.0" + spdy "^4.0.0" + strip-ansi "^3.0.1" + supports-color "^6.1.0" + url "^0.11.0" + webpack-dev-middleware "^3.7.0" + webpack-log "^2.0.0" + yargs "12.0.5" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-sources@^1.0.0, webpack-sources@^1.0.1, webpack-sources@^1.0.2, webpack-sources@^1.1.0, webpack-sources@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^4.30.0, webpack@^4.32.2: + version "4.35.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.35.2.tgz#5c8b8a66602cbbd6ec65c6e6747914a61c1449b1" + integrity sha512-TZAmorNymV4q66gAM/h90cEjG+N3627Q2MnkSgKlX/z3DlNVKUtqy57lz1WmZU2+FUZwzM+qm7cGaO95PyrX5A== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.0.5" + acorn-dynamic-import "^4.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^1.0.0" + tapable "^1.1.0" + terser-webpack-plugin "^1.1.0" + watchpack "^1.5.0" + webpack-sources "^1.3.0" + +websocket-driver@>=0.5.1: + version "0.7.3" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9" + integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg== + dependencies: + http-parser-js ">=0.4.0 <0.4.11" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which-pm-runs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + +which@1, which@^1.2.14, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +ws@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== + dependencies: + async-limiter "~1.0.0" + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yamljs@^0.2.4: + version "0.2.10" + resolved "https://registry.yarnpkg.com/yamljs/-/yamljs-0.2.10.tgz#481cc7c25ca73af59f591f0c96e3ce56c757a40f" + integrity sha1-SBzHwlynOvWfWR8MluPOVsdXpA8= + dependencies: + argparse "^1.0.7" + glob "^7.0.5" + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^13.1.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= + dependencies: + camelcase "^3.0.0" + +yargs@12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" + +yargs@13.2.4: + version "13.2.4" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" + integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.0" + +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=